Skip to content

Commit f4e0ced

Browse files
committed
feat: enhance layer configuration with composer support in StyleContext and useStyleRegister
1 parent 35f041c commit f4e0ced

File tree

2 files changed

+61
-20
lines changed

2 files changed

+61
-20
lines changed

src/StyleContext.tsx

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,13 @@ export function createCache() {
5252

5353
export type HashPriority = 'low' | 'high';
5454

55-
export interface StyleContextProps {
55+
export type LayerComposer = (dependency: ReadonlySet<string>) => string;
56+
export type LayerConfig = {
57+
/** Define the hierarchical order here */
58+
composer: LayerComposer;
59+
};
60+
61+
export interface StyleContextValue {
5662
autoClear?: boolean;
5763
/** @private Test only. Not work in production. */
5864
mock?: 'server' | 'client';
@@ -77,38 +83,63 @@ export interface StyleContextProps {
7783
* Please note that `linters` do not support dynamic update.
7884
*/
7985
linters?: Linter[];
80-
/** Wrap css in a layer to avoid global style conflict */
81-
layer?: boolean;
86+
/**
87+
* Wrap css in a layer to avoid global style conflict
88+
* @see [MDN-CSS Layer](https://developer.mozilla.org/en-US/docs/Web/CSS/@layer)
89+
*/
90+
layer?: LayerConfig;
8291
}
8392

84-
const StyleContext = React.createContext<StyleContextProps>({
93+
export const defaultLayerComposer: LayerComposer = (dependency) =>
94+
Array.from(dependency).join();
95+
96+
const noop = () => ``;
97+
98+
const StyleContext = React.createContext<StyleContextValue>({
8599
hashPriority: 'low',
86100
cache: createCache(),
87101
defaultCache: true,
88102
});
89103

90-
export type StyleProviderProps = Partial<StyleContextProps> & {
91-
children?: React.ReactNode;
92-
};
104+
export interface StyleProviderProps
105+
extends Omit<Partial<StyleContextValue>, 'layer'> {
106+
layer: boolean | LayerConfig;
107+
}
93108

94-
export const StyleProvider: React.FC<StyleProviderProps> = (props) => {
109+
export const StyleProvider = (
110+
props: React.PropsWithChildren<StyleProviderProps>,
111+
) => {
95112
const { children, ...restProps } = props;
96113

97114
const parentContext = React.useContext(StyleContext);
98115

99-
const context = useMemo<StyleContextProps>(
116+
const context = useMemo<StyleContextValue>(
100117
() => {
101-
const mergedContext: StyleContextProps = {
118+
const mergedContext: StyleContextValue = {
102119
...parentContext,
103120
};
104121

105-
(Object.keys(restProps) as (keyof StyleContextProps)[]).forEach((key) => {
122+
(Object.keys(restProps) as (keyof StyleContextValue)[]).forEach((key) => {
106123
const value = restProps[key];
107124
if (restProps[key] !== undefined) {
108125
(mergedContext as any)[key] = value;
109126
}
110127
});
111128

129+
// Standardize layer
130+
const { layer } = mergedContext;
131+
if (typeof layer === 'boolean') {
132+
mergedContext.layer = layer
133+
? { composer: defaultLayerComposer }
134+
: { composer: noop };
135+
} else if (typeof layer === 'object') {
136+
mergedContext.layer = {
137+
...layer,
138+
// Ensure composer is always a function
139+
composer: layer.composer ?? defaultLayerComposer,
140+
};
141+
}
142+
112143
const { cache } = restProps;
113144
mergedContext.cache = mergedContext.cache || createCache();
114145
mergedContext.defaultCache = !cache && parentContext.defaultCache;

src/hooks/useStyleRegister.tsx

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type { Theme, Transformer } from '..';
99
import type Keyframes from '../Keyframes';
1010
import type { Linter } from '../linters';
1111
import { contentQuotesLinter, hashedAnimationLinter } from '../linters';
12-
import type { HashPriority } from '../StyleContext';
12+
import type { HashPriority, LayerComposer } from '../StyleContext';
1313
import StyleContext, {
1414
ATTR_CACHE_PATH,
1515
ATTR_MARK,
@@ -128,7 +128,9 @@ function injectSelectorHash(
128128
export interface ParseConfig {
129129
hashId?: string;
130130
hashPriority?: HashPriority;
131-
layer?: LayerConfig;
131+
layer?: LayerConfig & {
132+
composer?: LayerComposer;
133+
};
132134
path?: string;
133135
transformers?: Transformer[];
134136
linters?: Linter[];
@@ -333,15 +335,17 @@ export const parseStyle = (
333335
if (!root) {
334336
styleStr = `{${styleStr}}`;
335337
} else if (layer) {
338+
const { name, dependencies, composer } = layer;
336339
// fixme: https://github.com/thysultan/stylis/pull/339
337340
if (styleStr) {
338-
styleStr = `@layer ${layer.name} {${styleStr}}`;
341+
styleStr = `@layer ${name} {${styleStr}}`;
339342
}
340343

341-
if (layer.dependencies) {
342-
effectStyle[`@layer ${layer.name}`] = layer.dependencies
343-
.map((deps) => `@layer ${deps}, ${layer.name};`)
344-
.join('\n');
344+
if (dependencies) {
345+
const dependency = new Set([...dependencies, name]);
346+
const combinedDependencies =
347+
composer?.(dependency) ?? Array.from(dependency).join(', ');
348+
effectStyle[`@layer ${name}`] = `@layer ${combinedDependencies};`;
345349
}
346350
}
347351

@@ -402,9 +406,10 @@ export default function useStyleRegister(
402406
transformers,
403407
linters,
404408
cache,
405-
layer: enableLayer,
409+
layer: ctxLayer,
406410
} = React.useContext(StyleContext);
407411
const tokenKey = token._tokenKey as string;
412+
const enableLayer = 'composer' in (ctxLayer || {});
408413

409414
const fullPath = [tokenKey];
410415
if (enableLayer) {
@@ -446,7 +451,12 @@ export default function useStyleRegister(
446451
const [parsedStyle, effectStyle] = parseStyle(styleObj, {
447452
hashId,
448453
hashPriority,
449-
layer: enableLayer ? layer : undefined,
454+
layer: enableLayer
455+
? {
456+
...layer!,
457+
composer: ctxLayer!.composer,
458+
}
459+
: undefined,
450460
path: path.join('-'),
451461
transformers,
452462
linters,

0 commit comments

Comments
 (0)