From 8fd4da4429c0e7efb9c06801703b51163f9e1c67 Mon Sep 17 00:00:00 2001 From: Chase Adams Date: Wed, 7 Dec 2022 09:20:23 -0700 Subject: [PATCH] Fixed runtime styles (#43) * fix: fixed runtime styles * fix: fixes based on memo feedback * test: added more tests --- src/internals/index.js | 25 +++++--- src/internals/utils.js | 88 +++++++++++++-------------- src/tests/index.test.tsx | 126 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+), 56 deletions(-) diff --git a/src/internals/index.js b/src/internals/index.js index 908dfde..4125c6f 100644 --- a/src/internals/index.js +++ b/src/internals/index.js @@ -92,19 +92,28 @@ export function createStitches(config = {}) { const styles = _styles; - const styleSheets = utils.createStyleSheets({ - styles, - config, - themes, - variants, - compoundVariants, - }); + const styleSheets = {}; let attrsFn; let Comp = forwardRef((props, ref) => { const theme = useThemeInternal(); - const styleSheet = styleSheets[theme.definition.__ID__]; + + const styleSheet = useMemo(() => { + const _styleSheet = styleSheets[theme.definition.__ID__]; + if (_styleSheet) { + return _styleSheet; + } + styleSheets[theme.definition.__ID__] = utils.createStyleSheet({ + styles, + config, + theme, + variants, + compoundVariants, + }); + return styleSheets[theme.definition.__ID__]; + }, [theme]); + const { width: windowWidth } = useWindowDimensions(); let variantStyles = []; diff --git a/src/internals/utils.js b/src/internals/utils.js index 3da3159..81e10d6 100644 --- a/src/internals/utils.js +++ b/src/internals/utils.js @@ -175,58 +175,50 @@ export function processStyles({ styles, theme, config }) { }, {}); } -export function createStyleSheets({ - themes, +export function createStyleSheet({ + theme, styles, config, variants, compoundVariants, }) { - const styleSheets = themes.reduce((styleSheetAcc, theme) => { - styleSheetAcc[theme.definition.__ID__] = StyleSheet.create({ - base: styles - ? processStyles({ styles, config, theme: theme.values }) - : {}, - // Variant styles - ...Object.entries(variants).reduce( - (variantsAcc, [vartiantProp, variantValues]) => { - Object.entries(variantValues).forEach( - ([variantName, variantStyles]) => { - // Eg. `color_primary` or `size_small` - const key = `${vartiantProp}_${variantName}`; - - variantsAcc[key] = processStyles({ - styles: variantStyles, - config, - theme: theme.values, - }); - } - ); - return variantsAcc; - }, - {} - ), - // Compound variant styles - ...compoundVariants.reduce((compoundAcc, compoundVariant) => { - const { css, ...compounds } = compoundVariant; - const compoundEntries = Object.entries(compounds); - - if (compoundEntries.length > 1) { - const key = getCompoundKey(compoundEntries); - - compoundAcc[key] = processStyles({ - styles: css || {}, - config, - theme: theme.values, - }); - } - - return compoundAcc; - }, {}), - }); - - return styleSheetAcc; - }, {}); + return StyleSheet.create({ + base: styles ? processStyles({ styles, config, theme: theme.values }) : {}, + // Variant styles + ...Object.entries(variants).reduce( + (variantsAcc, [variantProp, variantValues]) => { + Object.entries(variantValues).forEach( + ([variantName, variantStyles]) => { + // Eg. `color_primary` or `size_small` + const key = `${variantProp}_${variantName}`; + + variantsAcc[key] = processStyles({ + styles: variantStyles, + config, + theme: theme.values, + }); + } + ); + return variantsAcc; + }, + {} + ), + // Compound variant styles + ...compoundVariants.reduce((compoundAcc, compoundVariant) => { + const { css, ...compounds } = compoundVariant; + const compoundEntries = Object.entries(compounds); + + if (compoundEntries.length > 1) { + const key = getCompoundKey(compoundEntries); + + compoundAcc[key] = processStyles({ + styles: css || {}, + config, + theme: theme.values, + }); + } - return styleSheets; + return compoundAcc; + }, {}), + }); } diff --git a/src/tests/index.test.tsx b/src/tests/index.test.tsx index 9532b51..fc06d69 100644 --- a/src/tests/index.test.tsx +++ b/src/tests/index.test.tsx @@ -26,4 +26,130 @@ describe('Basic', () => { width: 100, }); }); + + it('Functionality of styled() should not trigger recompute when a runtime theme is not used', () => { + const { styled, createTheme } = createStitches({ + theme: { + sizes: { demoWidth: 100 }, + }, + }); + + const Comp = styled('View', { + backgroundColor: 'red', + height: 100, + width: '$demoWidth', + }); + + render(); + + createTheme({ sizes: { demoWidth: 10 } }); + + const { toJSON } = render(); + + const result = toJSON(); + + expect(result?.type).toEqual('View'); + expect(result?.props.style[0]).toMatchObject({ + backgroundColor: 'red', + height: 100, + width: 100, + }); + }); +}); + +describe('Runtime', () => { + it('Functionality of ThemeProvider', () => { + const { styled, createTheme, ThemeProvider } = createStitches({ + theme: { + sizes: { demoWidth: 100 }, + }, + }); + + const Comp = styled('View', { + backgroundColor: 'red', + height: 100, + width: '$demoWidth', + }); + + const newTheme = createTheme({ sizes: { demoWidth: 30 } }); + + const { toJSON } = render( + + + + ); + + const result = toJSON(); + + expect(result?.type).toEqual('View'); + expect(result?.props.style[0]).toMatchObject({ + backgroundColor: 'red', + height: 100, + width: 30, + }); + }); + + it('Functionality of ThemeProvider should use new theme when a runtime theme is added', () => { + const { styled, createTheme, ThemeProvider } = createStitches({ + theme: { + sizes: { demoWidth: 100 }, + }, + }); + + const Comp = styled('View', { + backgroundColor: 'red', + height: 100, + width: '$demoWidth', + }); + + const newTheme = createTheme({ sizes: { demoWidth: 10 } }); + + const { toJSON } = render( + + + + ); + + const result = toJSON(); + + expect(result?.type).toEqual('View'); + expect(result?.props.style[0]).toMatchObject({ + backgroundColor: 'red', + height: 100, + width: 10, + }); + }); + + it('Functionality of ThemeProvider should trigger recompute when a runtime theme is added', () => { + const { styled, createTheme, ThemeProvider } = createStitches({ + theme: { + sizes: { demoWidth: 100 }, + }, + }); + + const Comp = styled('View', { + backgroundColor: 'red', + height: 100, + width: '$demoWidth', + }); + + render(); + + const newTheme = createTheme({ sizes: { demoWidth: 10 } }); + + const { toJSON } = render( + + + + ); + + const result = toJSON(); + + expect(result?.type).toEqual('View'); + expect(result?.props.style[0]).toMatchObject({ + backgroundColor: 'red', + height: 100, + width: 10, + }); + }); });