diff --git a/src/hooks/useRestyle.ts b/src/hooks/useRestyle.ts index 01d71441..fbb5e7d8 100644 --- a/src/hooks/useRestyle.ts +++ b/src/hooks/useRestyle.ts @@ -1,19 +1,19 @@ -import {useMemo} from 'react'; -import {StyleProp, useWindowDimensions} from 'react-native'; +import { useMemo } from 'react'; +import { StyleProp, useWindowDimensions } from 'react-native'; -import {BaseTheme, RNStyle, Dimensions} from '../types'; +import { BaseTheme, RNStyle, Dimensions } from '../types'; import useTheme from './useTheme'; const filterRestyleProps = < TRestyleProps, - TProps extends {[key: string]: unknown} & TRestyleProps, + TProps extends { [key: string]: unknown } & TRestyleProps, >( componentProps: TProps, - omitPropertiesMap: {[key in keyof TProps]: boolean}, + omitPropertiesMap: { [key in keyof TProps]: boolean }, ) => { const cleanProps: TProps = {} as TProps; - const restyleProps: TProps & {variant?: unknown} = {} as TProps; + const restyleProps: TProps & { variant?: unknown } = {} as TProps; let serializedRestyleProps = ''; if (omitPropertiesMap.variant) { restyleProps.variant = componentProps.variant ?? 'defaults'; @@ -27,14 +27,14 @@ const filterRestyleProps = < } } - const keys = {cleanProps, restyleProps, serializedRestyleProps}; + const keys = { cleanProps, restyleProps, serializedRestyleProps }; return keys; }; const useRestyle = < Theme extends BaseTheme, - TRestyleProps extends {[key: string]: any}, - TProps extends TRestyleProps & {style?: StyleProp}, + TRestyleProps extends { [key: string]: any }, + TProps extends TRestyleProps & { style?: StyleProp, variant?: string }, >( composedRestyleFunction: { buildStyle: ( @@ -48,7 +48,7 @@ const useRestyle = < }, ) => RNStyle; properties: (keyof TProps)[]; - propertiesMap: {[key in keyof TProps]: boolean}; + propertiesMap: { [key in keyof TProps]: boolean }; }, props: TProps, ) => { @@ -59,10 +59,10 @@ const useRestyle = < // as this hook is called extremely often and incurs some performance hit. const dimensions = theme.breakpoints ? // eslint-disable-next-line react-hooks/rules-of-hooks - useWindowDimensions() + useWindowDimensions() : null; - const {cleanProps, restyleProps, serializedRestyleProps} = filterRestyleProps( + const { cleanProps, restyleProps, serializedRestyleProps } = filterRestyleProps( props, composedRestyleFunction.propertiesMap, ); @@ -93,6 +93,9 @@ const useRestyle = < ]); cleanProps.style = calculatedStyle; + if (restyleProps.variant) { + cleanProps.variant = restyleProps.variant + } return cleanProps; }; diff --git a/src/test/createRestyleComponent.test.tsx b/src/test/createRestyleComponent.test.tsx index 9fe1abce..a3acc239 100644 --- a/src/test/createRestyleComponent.test.tsx +++ b/src/test/createRestyleComponent.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import {create as render} from 'react-test-renderer'; -import {View, ViewProps} from 'react-native'; +import { create as render } from 'react-test-renderer'; +import { View, ViewProps } from 'react-native'; import createRestyleComponent from '../createRestyleComponent'; import { @@ -13,8 +13,8 @@ import { OpacityProps, opacity, } from '../restyleFunctions'; -import {ThemeProvider} from '../context'; -import createVariant, {VariantProps} from '../createVariant'; +import { ThemeProvider } from '../context'; +import createVariant, { VariantProps } from '../createVariant'; const theme = { colors: { @@ -48,7 +48,7 @@ const themeWithVariant = { }, }; -const {breakpoints, ...themeWithoutBreakpoints} = theme; +const { breakpoints, ...themeWithoutBreakpoints } = theme; type Theme = typeof theme; type ThemeWithVariant = typeof themeWithVariant; @@ -61,10 +61,10 @@ jest.mock('react-native/Libraries/Utilities/useWindowDimensions', () => ({ const Component = createRestyleComponent< BackgroundColorProps & - SpacingProps & - SpacingShorthandProps & - OpacityProps & - ViewProps, + SpacingProps & + SpacingShorthandProps & + OpacityProps & + ViewProps, Theme >([backgroundColor, spacing, spacingShorthand, opacity]); const cardVariant = createVariant({ @@ -72,94 +72,94 @@ const cardVariant = createVariant({ }); const ComponentWithVariant = createRestyleComponent< BackgroundColorProps & - SpacingProps & - SpacingShorthandProps & - OpacityProps & - VariantProps & - ViewProps, + SpacingProps & + SpacingShorthandProps & + OpacityProps & + VariantProps & + ViewProps, ThemeWithVariant >([backgroundColor, spacing, spacingShorthand, opacity, cardVariant]); describe('createRestyleComponent', () => { describe('creates a component that', () => { beforeEach(() => { - mockUseWindowDimensions.mockReturnValue({width: 375, height: 667}); + mockUseWindowDimensions.mockReturnValue({ width: 375, height: 667 }); }); it('passes styles based on the given props', () => { - const {root} = render( + const { root } = render( , ); - expect(root.findByType(View).props.style).toStrictEqual([{opacity: 0.5}]); + expect(root.findByType(View).props.style).toStrictEqual([{ opacity: 0.5 }]); }); it('passes styles based on the given props for theme without breakpoints', () => { - const {root} = render( + const { root } = render( , ); - expect(root.findByType(View).props.style).toStrictEqual([{opacity: 0.5}]); + expect(root.findByType(View).props.style).toStrictEqual([{ opacity: 0.5 }]); }); it('appends style prop to the end', () => { - const {root} = render( + const { root } = render( - + , ); expect(root.findByType(View).props.style).toStrictEqual([ - {opacity: 0.5}, - {width: 100}, + { opacity: 0.5 }, + { width: 100 }, ]); }); it('does not pass styling properties to the child', () => { - const {root} = render( + const { root } = render( , ); expect(root.findByType(View).props).toStrictEqual({ - style: [{opacity: 0.5}], + style: [{ opacity: 0.5 }], pointerEvents: 'auto', }); }); it('picks up values from the theme provided with ThemeProvider', () => { - const {root} = render( + const { root } = render( , ); expect(root.findByType(View).props).toStrictEqual({ - style: [{backgroundColor: '#FFE6E4'}], + style: [{ backgroundColor: '#FFE6E4' }], }); }); it('renders with phone-specific style', async () => { - const {root} = render( + const { root } = render( - + , ); expect(root.findByType(View).props).toStrictEqual({ - style: [{opacity: 0.5}], + style: [{ opacity: 0.5 }], }); await new Promise(resolve => setTimeout(resolve, 0)); }); it('renders with tablet-specific style when dimensions are bigger', async () => { - mockUseWindowDimensions.mockReturnValue({width: 768, height: 1024}); - const {root} = render( + mockUseWindowDimensions.mockReturnValue({ width: 768, height: 1024 }); + const { root } = render( - + , ); expect(root.findByType(View).props).toStrictEqual({ - style: [{opacity: 0.8}], + style: [{ opacity: 0.8 }], }); await new Promise(resolve => setTimeout(resolve, 0)); }); @@ -174,61 +174,80 @@ describe('createRestyleComponent', () => { expect(spy).toHaveBeenCalledWith( expect.objectContaining({ - props: expect.objectContaining({testID: 'RENDERED_COMPONENT'}), + props: expect.objectContaining({ testID: 'RENDERED_COMPONENT' }), }), ); }); - it('passes styles from default variant when no variant prop is defined', () => { - const {root} = render( - - - , - ); - expect(root.findByType(View).props.style).toStrictEqual([ - { - alignItems: 'flex-start', - backgroundColor: '#FFB6C1', - margin: 8, - }, - ]); - }); - - it('passes styles from the defined variant', () => { - const {root} = render( - - - , - ); - expect(root.findByType(View).props.style).toStrictEqual([ - { - alignItems: 'center', - backgroundColor: '#E0FFFF', - margin: 8, - }, - ]); - }); - it('uses gap values from the theme', () => { - const {root} = render( + const { root } = render( , ); expect(root.findByType(View).props).toStrictEqual({ - style: [{gap: 8, columnGap: 8, rowGap: 8}], + style: [{ gap: 8, columnGap: 8, rowGap: 8 }], }); }); it('passes gap shorthands as gap values', () => { - const {root} = render( + const { root } = render( , ); expect(root.findByType(View).props).toStrictEqual({ - style: [{gap: 8, columnGap: 8, rowGap: 8}], + style: [{ gap: 8, columnGap: 8, rowGap: 8 }], }); }); + + describe('variant', () => { + it('does not pass variant prop if no variant is created', () => { + const { root } = render( + + + , + ); + expect(root.findByType(View).props).toStrictEqual({ + style: [{ opacity: 0.5 }] + }); + }); + + it('passes styles from default variant when no variant prop is defined', () => { + const { root } = render( + + + , + ); + expect(root.findByType(View).props).toStrictEqual({ + variant: 'defaults', + style: [ + { + alignItems: 'flex-start', + backgroundColor: '#FFB6C1', + margin: 8, + }, + ] + }) + }); + + it('passes styles from the defined variant', () => { + const { root } = render( + + + , + ); + expect(root.findByType(View).props).toStrictEqual({ + variant: 'regular', + style: [ + { + alignItems: 'center', + backgroundColor: '#E0FFFF', + margin: 8, + }, + ] + }) + }); + }) }); });