From 37438c64a33d1ae8ffff46a5a23ac49cc46072b6 Mon Sep 17 00:00:00 2001 From: Oleksandr Fediashov Date: Thu, 10 Mar 2022 16:59:01 +0100 Subject: [PATCH] wip --- packages/core/src/index.ts | 1 + packages/react/src/__styles.ts | 30 ++++++++++++++--- packages/react/src/makeStyles.ts | 41 ++++++++++++++++++++---- packages/react/src/useInsertionEffect.ts | 7 ++++ 4 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 packages/react/src/useInsertionEffect.ts diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 0819c0835..f953c1513 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -43,6 +43,7 @@ export { makeStyles } from './makeStyles'; export { resolveStyleRulesForSlots } from './resolveStyleRulesForSlots'; // Private exports, are used by build time transforms +export { reduceToClassNameForSlots } from './runtime/reduceToClassNameForSlots'; export { resolveStyleRules } from './runtime/resolveStyleRules'; export { __styles } from './__styles'; diff --git a/packages/react/src/__styles.ts b/packages/react/src/__styles.ts index 345627ec6..b81f0bec5 100644 --- a/packages/react/src/__styles.ts +++ b/packages/react/src/__styles.ts @@ -1,8 +1,9 @@ -import { __styles as vanillaStyles } from '@griffel/core'; +import { reduceToClassNameForSlots } from '@griffel/core'; import type { CSSClassesMapBySlot, CSSRulesByBucket } from '@griffel/core'; import { useRenderer } from './RendererContext'; import { useTextDirection } from './TextDirectionContext'; +import { useInsertionEffect } from './useInsertionEffect'; /** * A version of makeStyles() that accepts build output as an input and skips all runtime transforms. @@ -14,12 +15,31 @@ export function __styles( classesMapBySlot: CSSClassesMapBySlot, cssRules: CSSRulesByBucket, ) { - const getStyles = vanillaStyles(classesMapBySlot, cssRules); + let ltrClassNamesForSlots: Record | null = null; + let rtlClassNamesForSlots: Record | null = null; - return function useClasses(): Record { + function computeClasses(): Record { const dir = useTextDirection(); const renderer = useRenderer(); - return getStyles({ dir, renderer }); - }; + const isLTR = dir === 'ltr'; + + if (isLTR) { + if (ltrClassNamesForSlots === null) { + ltrClassNamesForSlots = reduceToClassNameForSlots(classesMapBySlot, dir); + } + } else { + if (rtlClassNamesForSlots === null) { + rtlClassNamesForSlots = reduceToClassNameForSlots(classesMapBySlot, dir); + } + } + + useInsertionEffect(() => { + renderer.insertCSSRules(cssRules!); + }, [isLTR, renderer]); + + return isLTR ? (ltrClassNamesForSlots as Record) : (rtlClassNamesForSlots as Record); + } + + return computeClasses; } diff --git a/packages/react/src/makeStyles.ts b/packages/react/src/makeStyles.ts index ecd4b7c5d..78cbeb8ef 100644 --- a/packages/react/src/makeStyles.ts +++ b/packages/react/src/makeStyles.ts @@ -1,9 +1,10 @@ -import { makeStyles as vanillaMakeStyles } from '@griffel/core'; +import { reduceToClassNameForSlots, resolveStyleRulesForSlots } from '@griffel/core'; import * as React from 'react'; -import type { GriffelStyle } from '@griffel/core'; +import type { CSSClassesMapBySlot, CSSRulesByBucket, GriffelStyle } from '@griffel/core'; import { useRenderer } from './RendererContext'; import { useTextDirection } from './TextDirectionContext'; +import { useInsertionEffect } from './useInsertionEffect'; function isInsideComponent() { try { @@ -16,8 +17,6 @@ function isInsideComponent() { } export function makeStyles(stylesBySlots: Record) { - const getStyles = vanillaMakeStyles(stylesBySlots); - if (process.env.NODE_ENV !== 'production') { if (isInsideComponent()) { throw new Error( @@ -29,10 +28,38 @@ export function makeStyles(stylesBySlots: Record< } } - return function useClasses(): Record { + let classesMapBySlot: CSSClassesMapBySlot | null = null; + let cssRules: CSSRulesByBucket | null = null; + + let ltrClassNamesForSlots: Record | null = null; + let rtlClassNamesForSlots: Record | null = null; + + function computeClasses(): Record { const dir = useTextDirection(); const renderer = useRenderer(); - return getStyles({ dir, renderer }); - }; + const isLTR = dir === 'ltr'; + + if (classesMapBySlot === null) { + [classesMapBySlot, cssRules] = resolveStyleRulesForSlots(stylesBySlots); + } + + if (isLTR) { + if (ltrClassNamesForSlots === null) { + ltrClassNamesForSlots = reduceToClassNameForSlots(classesMapBySlot, dir); + } + } else { + if (rtlClassNamesForSlots === null) { + rtlClassNamesForSlots = reduceToClassNameForSlots(classesMapBySlot, dir); + } + } + + useInsertionEffect(() => { + renderer.insertCSSRules(cssRules!); + }, [isLTR, renderer]); + + return isLTR ? (ltrClassNamesForSlots as Record) : (rtlClassNamesForSlots as Record); + } + + return computeClasses; } diff --git a/packages/react/src/useInsertionEffect.ts b/packages/react/src/useInsertionEffect.ts new file mode 100644 index 000000000..cdf832698 --- /dev/null +++ b/packages/react/src/useInsertionEffect.ts @@ -0,0 +1,7 @@ +import * as React from 'react'; + +// @ts-expect-error +export const useInsertionEffect = React['useInsertion' + 'Effect'] + ? // @ts-expect-error + React['useInsertion' + 'Effect'] + : React.useLayoutEffect;