Skip to content

Commit

Permalink
feat: Support layer config (#179)
Browse files Browse the repository at this point in the history
* feat: support layer

* test: fix layer test

* chore: opt cache
  • Loading branch information
zombieJ authored Apr 2, 2024
1 parent 6a4bb3b commit 396b471
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 60 deletions.
3 changes: 0 additions & 3 deletions docs/examples/layer.less

This file was deleted.

57 changes: 31 additions & 26 deletions docs/examples/layer.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,24 @@
import { StyleProvider, Theme, useStyleRegister } from '@ant-design/cssinjs';
import classNames from 'classnames';
import React from 'react';
import './layer.less';
import { useStyleRegister, Theme } from '@ant-design/cssinjs';

const theme = new Theme([() => ({})]);

const Div = ({ className, ...rest }: React.HTMLAttributes<HTMLDivElement>) => {
// Shared
useStyleRegister(
{
theme,
token: { _tokenKey: 'test' },
path: ['shared'],
layer: 'shared',
},
() => ({
'html body .layer-div': {
color: 'rgba(0,0,0,0.65)',
},
}),
);

// Layer
useStyleRegister(
{
theme,
token: { _tokenKey: 'test' },
path: ['layer'],
layer: 'shared, layer',
layer: {
name: 'layer',
dependencies: ['shared'],
},
},
() => ({
'.layer-div': {
// color: 'blue',
color: 'pink',
color: 'blue',

a: {
color: 'orange',
Expand All @@ -46,16 +32,35 @@ const Div = ({ className, ...rest }: React.HTMLAttributes<HTMLDivElement>) => {
}),
);

// Shared
useStyleRegister(
{
theme,
token: { _tokenKey: 'test' },
path: ['shared'],
layer: {
name: 'shared',
},
},
() => ({
'html body .layer-div': {
color: 'green',
},
}),
);

return <div className={classNames(className, 'layer-div')} {...rest} />;
};

export default function App() {
return (
<Div>
Layer: blue & `a` orange. User: `a` green
<div>
A simple <a>link</a>
</div>
</Div>
<StyleProvider layer>
<Div>
Text should be pink:
<div>
A simple <a>link</a>
</div>
</Div>
</StyleProvider>
);
}
2 changes: 2 additions & 0 deletions src/StyleContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export interface StyleContextProps {
* Please note that `linters` do not support dynamic update.
*/
linters?: Linter[];
/** Wrap css in a layer to avoid global style conflict */
layer?: boolean;
}

const StyleContext = React.createContext<StyleContextProps>({
Expand Down
75 changes: 58 additions & 17 deletions src/hooks/useStyleRegister.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import StyleContext, {
ATTR_TOKEN,
CSS_IN_JS_INSTANCE,
} from '../StyleContext';
import { isClientSide, supportLayer, toStyleStr } from '../util';
import { isClientSide, toStyleStr } from '../util';
import {
CSS_FILE_STYLE,
existPath,
Expand All @@ -28,6 +28,11 @@ import useGlobalCache from './useGlobalCache';
const SKIP_CHECK = '_skip_check_';
const MULTI_VALUE = '_multi_value_';

export interface LayerConfig {
name: string;
dependencies?: string[];
}

export type CSSProperties = Omit<
CSS.PropertiesFallback<number | string>,
'animationName'
Expand Down Expand Up @@ -123,7 +128,7 @@ function injectSelectorHash(
export interface ParseConfig {
hashId?: string;
hashPriority?: HashPriority;
layer?: string;
layer?: LayerConfig;
path?: string;
transformers?: Transformer[];
linters?: Linter[];
Expand Down Expand Up @@ -324,15 +329,13 @@ export const parseStyle = (

if (!root) {
styleStr = `{${styleStr}}`;
} else if (layer && supportLayer()) {
const layerCells = layer.split(',');
const layerName = layerCells[layerCells.length - 1].trim();
styleStr = `@layer ${layerName} {${styleStr}}`;

// Order of layer if needed
if (layerCells.length > 1) {
// zombieJ: stylis do not support layer order, so we need to handle it manually.
styleStr = `@layer ${layer}{%%%:%}${styleStr}`;
} else if (layer) {
styleStr = `@layer ${layer.name} {${styleStr}}`;

if (layer.dependencies) {
effectStyle[`@layer ${layer.name}`] = layer.dependencies
.map((deps) => `@layer ${deps}, ${layer.name};`)
.join('\n');
}
}

Expand Down Expand Up @@ -370,7 +373,7 @@ export default function useStyleRegister(
token: any;
path: string[];
hashId?: string;
layer?: string;
layer?: LayerConfig;
nonce?: string | (() => string);
clientOnly?: boolean;
/**
Expand All @@ -393,10 +396,15 @@ export default function useStyleRegister(
transformers,
linters,
cache,
layer: enableLayer,
} = React.useContext(StyleContext);
const tokenKey = token._tokenKey as string;

const fullPath = [tokenKey, ...path];
const fullPath = [tokenKey];
if (enableLayer) {
fullPath.push('layer');
}
fullPath.push(...path);

// Check if need insert style
let isMergedClientSide = isClientSide;
Expand Down Expand Up @@ -432,7 +440,7 @@ export default function useStyleRegister(
const [parsedStyle, effectStyle] = parseStyle(styleObj, {
hashId,
hashPriority,
layer,
layer: enableLayer ? layer : undefined,
path: path.join('-'),
transformers,
linters,
Expand Down Expand Up @@ -467,6 +475,31 @@ export default function useStyleRegister(
mergedCSSConfig.csp = { nonce: nonceStr };
}

// ================= Split Effect Style =================
// We will split effectStyle here since @layer should be at the top level
const effectLayerKeys: string[] = [];
const effectRestKeys: string[] = [];

Object.keys(effectStyle).forEach((key) => {
if (key.startsWith('@layer')) {
effectLayerKeys.push(key);
} else {
effectRestKeys.push(key);
}
});

// ================= Inject Layer Style =================
// Inject layer style
effectLayerKeys.forEach((effectKey) => {
updateCSS(
normalizeStyle(effectStyle[effectKey]),
`_layer-${effectKey}`,
mergedCSSConfig,
);
});

// ==================== Inject Style ====================
// Inject style
const style = updateCSS(styleStr, styleId, mergedCSSConfig);

(style as any)[CSS_IN_JS_INSTANCE] = cache.instanceId;
Expand All @@ -479,8 +512,9 @@ export default function useStyleRegister(
style.setAttribute(ATTR_CACHE_PATH, fullPath.join('|'));
}

// ================ Inject Effect Style =================
// Inject client side effect style
Object.keys(effectStyle).forEach((effectKey) => {
effectRestKeys.forEach((effectKey) => {
updateCSS(
normalizeStyle(effectStyle[effectKey]),
`_effect-${effectKey}`,
Expand Down Expand Up @@ -539,13 +573,14 @@ export const extract: ExtractStyle<StyleCacheValue> = (

let keyStyleText = styleStr;

// ====================== Style ======================
// ====================== Share ======================
// Used for rc-util
const sharedAttrs = {
'data-rc-order': 'prependQueue',
'data-rc-priority': `${order}`,
};

// ====================== Style ======================
keyStyleText = toStyleStr(styleStr, tokenKey, styleId, sharedAttrs, plain);

// =============== Create effect style ===============
Expand All @@ -555,13 +590,19 @@ export const extract: ExtractStyle<StyleCacheValue> = (
if (!effectStyles[effectKey]) {
effectStyles[effectKey] = true;
const effectStyleStr = normalizeStyle(effectStyle[effectKey]);
keyStyleText += toStyleStr(
const effectStyleHTML = toStyleStr(
effectStyleStr,
tokenKey,
`_effect-${effectKey}`,
sharedAttrs,
plain,
);

if (effectKey.startsWith('@layer')) {
keyStyleText = effectStyleHTML + keyStyleText;
} else {
keyStyleText += effectStyleHTML;
}
}
});
}
Expand Down
32 changes: 18 additions & 14 deletions tests/util.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,29 +74,33 @@ describe('util', () => {
},
},
],
{ hashId: 'hashed', layer: 'test-layer' },
{ hashId: 'hashed', layer: { name: 'test-layer' } },
);

expect(str).toEqual('@layer test-layer {p.hashed{color:red;}}');
});

it('order', () => {
const str = normalizeStyle(
parseStyle(
[
{
p: {
color: 'red',
},
const parsedStyle = parseStyle(
[
{
p: {
color: 'red',
},
],
{ hashId: 'hashed', layer: 'shared, test-layer' },
)[0],
},
],
{
hashId: 'hashed',
layer: { name: 'test-layer', dependencies: ['shared'] },
},
);

expect(str).toEqual(
'@layer shared,test-layer;@layer test-layer{p.hashed{color:red;}}',
);
const str = normalizeStyle(parsedStyle[0]);

expect(str).toEqual('@layer test-layer{p.hashed{color:red;}}');
expect(parsedStyle[1]).toEqual({
'@layer test-layer': '@layer shared, test-layer;',
});
});

it('raw order', () => {
Expand Down

0 comments on commit 396b471

Please sign in to comment.