diff --git a/docs/demo/auto-clear.md b/docs/demo/auto-clear.md deleted file mode 100644 index 471669cf..00000000 --- a/docs/demo/auto-clear.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Auto Clear -nav: - title: Demo - path: /demo ---- - - diff --git a/docs/examples/auto-clear.tsx b/docs/examples/auto-clear.tsx deleted file mode 100644 index 76e1f7c2..00000000 --- a/docs/examples/auto-clear.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; -import Button from './components/Button'; -import { StyleProvider } from '@ant-design/cssinjs'; - -export default function App() { - const [show, setShow] = React.useState(true); - - const [, forceUpdate] = React.useState({}); - React.useEffect(() => { - forceUpdate({}); - }, []); - - return ( - -
-

配置同步自动删除添加的样式

- - - - {show && ( - <> - - - - - )} -
-
- ); -} diff --git a/docs/examples/components/Button.tsx b/docs/examples/components/Button.tsx index 6b8d1459..bec55b5e 100644 --- a/docs/examples/components/Button.tsx +++ b/docs/examples/components/Button.tsx @@ -111,7 +111,7 @@ const Button = ({ className, type, ...restProps }: ButtonProps) => { const ghostCls = `${prefixCls}-ghost`; // 全局注册,内部会做缓存优化 - const wrapSSR = useStyleRegister( + useStyleRegister( { theme, token, hashId, path: [prefixCls] }, () => [ genDefaultButtonStyle(defaultCls, token), @@ -128,11 +128,11 @@ const Button = ({ className, type, ...restProps }: ButtonProps) => { } as any )[type as any] || defaultCls; - return wrapSSR( + return ( @@ -36,7 +36,7 @@ export default function App() { value={{ token: { primaryColor: 'green' }, cssVar: { key: 'default2' }, - hashed: true, + hashed: false, }} > diff --git a/package.json b/package.json index 6106f44b..29d5cbc6 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@ctrl/tinycolor": "^3.4.0", "@rc-component/father-plugin": "^1.0.1", "@testing-library/jest-dom": "^5.16.3", - "@testing-library/react": "^13.0.0", + "@testing-library/react": "^14.0.0", "@types/classnames": "^2.2.9", "@types/enzyme": "^3.10.11", "@types/react": "^18.0.0", diff --git a/src/StyleContext.tsx b/src/StyleContext.tsx index 923155b4..e9dbccd3 100644 --- a/src/StyleContext.tsx +++ b/src/StyleContext.tsx @@ -53,7 +53,6 @@ export function createCache() { export type HashPriority = 'low' | 'high'; export interface StyleContextProps { - autoClear?: boolean; /** @private Test only. Not work in production. */ mock?: 'server' | 'client'; /** diff --git a/src/hooks/useCacheToken.tsx b/src/hooks/useCacheToken.tsx index a5a3a301..57511453 100644 --- a/src/hooks/useCacheToken.tsx +++ b/src/hooks/useCacheToken.tsx @@ -55,7 +55,7 @@ export interface Option { /** * Transform token to css variables. */ - cssVar?: { + cssVar: { /** Prefix for css variables */ prefix?: string; /** Tokens that should not be appended with unit */ @@ -65,7 +65,7 @@ export interface Option { /** Tokens that preserves origin value */ preserve?: Record; /** Key for current theme. Useful for customizing and should be unique */ - key?: string; + key: string; }; } @@ -86,7 +86,7 @@ function removeStyleTags(key: string, instanceId: string) { } } -const TOKEN_THRESHOLD = 0; +const TOKEN_THRESHOLD = -1; // Remove will check current keys first function cleanTokenStyle(tokenKey: string, instanceId: string) { @@ -136,9 +136,9 @@ export const getComputedToken = < export const TOKEN_PREFIX = 'token'; type TokenCacheValue = [ - token: DerivativeToken & { _tokenKey: string; _themeKey: string }, + token: DerivativeToken, hashId: string, - realToken: DerivativeToken & { _tokenKey: string }, + realToken: DerivativeToken, cssVarStr: string, cssVarKey: string, ]; @@ -156,7 +156,7 @@ export default function useCacheToken< >( theme: Theme, tokens: Partial[], - option: Option = {}, + option: Option, ): TokenCacheValue { const { cache: { instanceId }, @@ -182,68 +182,53 @@ export default function useCacheToken< TOKEN_PREFIX, [salt, theme.id, tokenStr, overrideTokenStr, cssVarStr], () => { - let mergedDerivativeToken = compute + const mergedDerivativeToken = compute ? compute(mergedToken, override, theme) : getComputedToken(mergedToken, override, theme, formatToken); // Replace token value with css variables const actualToken = { ...mergedDerivativeToken }; - let cssVarsStr = ''; - if (!!cssVar) { - [mergedDerivativeToken, cssVarsStr] = transformToken( - mergedDerivativeToken, - cssVar.key!, - { - prefix: cssVar.prefix, - ignore: cssVar.ignore, - unitless: cssVar.unitless, - preserve: cssVar.preserve, - }, - ); - } + const [tokenWithCssVar, cssVarsStr] = transformToken( + mergedDerivativeToken, + cssVar.key, + { + prefix: cssVar.prefix, + ignore: cssVar.ignore, + unitless: cssVar.unitless, + preserve: cssVar.preserve, + }, + ) as [any, string]; // Optimize for `useStyleRegister` performance - const tokenKey = token2key(mergedDerivativeToken, salt); - mergedDerivativeToken._tokenKey = tokenKey; - actualToken._tokenKey = token2key(actualToken, salt); + const mergedSalt = `${salt}_${cssVar.prefix || ''}`; + actualToken._tokenKey = token2key(actualToken, mergedSalt); - const themeKey = cssVar?.key ?? tokenKey; - mergedDerivativeToken._themeKey = themeKey; + const themeKey = cssVar.key; recordCleanToken(themeKey); - const hashId = `${hashPrefix}-${hash(tokenKey)}`; - mergedDerivativeToken._hashId = hashId; // Not used + const hashId = `${hashPrefix}-${hash(mergedSalt)}`; - return [ - mergedDerivativeToken, - hashId, - actualToken, - cssVarsStr, - cssVar?.key || '', - ]; + return [tokenWithCssVar, hashId, actualToken, cssVarsStr, cssVar.key]; }, - (cache) => { + ([, , , , themeKey]) => { // Remove token will remove all related style - cleanTokenStyle(cache[0]._themeKey, instanceId); + cleanTokenStyle(themeKey, instanceId); }, - ([token, , , cssVarsStr]) => { - if (cssVar && cssVarsStr) { - const style = updateCSS( - cssVarsStr, - hash(`css-variables-${token._themeKey}`), - { - mark: ATTR_MARK, - prepend: 'queue', - attachTo: container, - priority: -999, - }, - ); - - (style as any)[CSS_IN_JS_INSTANCE] = instanceId; - - // Used for `useCacheToken` to remove on batch when token removed - style.setAttribute(ATTR_TOKEN, token._themeKey); + ([, , , cssVarsStr, themeKey]) => { + if (!cssVarsStr) { + return; } + const style = updateCSS(cssVarsStr, hash(`css-var-${themeKey}`), { + mark: ATTR_MARK, + prepend: 'queue', + attachTo: container, + priority: -999, + }); + + (style as any)[CSS_IN_JS_INSTANCE] = instanceId; + + // Used for `useCacheToken` to remove on batch when token removed + style.setAttribute(ATTR_TOKEN, themeKey); }, ); diff --git a/src/hooks/useStyleRegister.tsx b/src/hooks/useStyleRegister.tsx index 529d29df..efc9f030 100644 --- a/src/hooks/useStyleRegister.tsx +++ b/src/hooks/useStyleRegister.tsx @@ -13,7 +13,6 @@ import type { HashPriority } from '../StyleContext'; import StyleContext, { ATTR_CACHE_PATH, ATTR_MARK, - ATTR_TOKEN, CSS_IN_JS_INSTANCE, } from '../StyleContext'; import { isClientSide, toStyleStr } from '../util'; @@ -333,7 +332,6 @@ export const parseStyle = ( if (!root) { styleStr = `{${styleStr}}`; } else if (layer) { - // fixme: https://github.com/thysultan/stylis/pull/339 if (styleStr) { styleStr = `@layer ${layer.name} {${styleStr}}`; @@ -364,7 +362,6 @@ export const STYLE_PREFIX = 'style'; type StyleCacheValue = [ styleStr: string, - tokenKey: string, styleId: string, effectStyle: Record, clientOnly: boolean | undefined, @@ -394,7 +391,6 @@ export default function useStyleRegister( ) { const { token, path, hashId, layer, nonce, clientOnly, order = 0 } = info; const { - autoClear, mock, defaultCache, hashPriority, @@ -405,9 +401,8 @@ export default function useStyleRegister( cache, layer: enableLayer, } = React.useContext(StyleContext); - const tokenKey = token._tokenKey as string; - const fullPath = [tokenKey]; + const fullPath: string[] = [token._cssVarPrefix]; if (enableLayer) { fullPath.push('layer'); } @@ -431,14 +426,7 @@ export default function useStyleRegister( if (existPath(cachePath)) { const [inlineCacheStyleStr, styleHash] = getStyleAndHash(cachePath); if (inlineCacheStyleStr) { - return [ - inlineCacheStyleStr, - tokenKey, - styleHash, - {}, - clientOnly, - order, - ]; + return [inlineCacheStyleStr, styleHash, {}, clientOnly, order]; } } @@ -456,18 +444,18 @@ export default function useStyleRegister( const styleStr = normalizeStyle(parsedStyle); const styleId = uniqueHash(fullPath, styleStr); - return [styleStr, tokenKey, styleId, effectStyle, clientOnly, order]; + return [styleStr, styleId, effectStyle, clientOnly, order]; }, // Remove cache if no need - ([, , styleId], fromHMR) => { - if ((fromHMR || autoClear) && isClientSide) { + ([, styleId], fromHMR) => { + if (fromHMR && isClientSide) { removeCSS(styleId, { mark: ATTR_MARK }); } }, // Effect: Inject style here - ([styleStr, _, styleId, effectStyle]) => { + ([styleStr, styleId, effectStyle]) => { if (isMergedClientSide && styleStr !== CSS_FILE_STYLE) { const mergedCSSConfig: Parameters[2] = { mark: ATTR_MARK, @@ -511,9 +499,6 @@ export default function useStyleRegister( (style as any)[CSS_IN_JS_INSTANCE] = cache.instanceId; - // Used for `useCacheToken` to remove on batch when token removed - style.setAttribute(ATTR_TOKEN, tokenKey); - // Debug usage. Dev only if (process.env.NODE_ENV !== 'production') { style.setAttribute(ATTR_CACHE_PATH, fullPath.join('|')); @@ -531,31 +516,6 @@ export default function useStyleRegister( } }, ); - - return (node: React.ReactElement) => { - let styleNode: React.ReactElement; - - if (!ssrInline || isMergedClientSide || !defaultCache) { - styleNode = ; - } else { - styleNode = ( - "`; +exports[`CSS Variables > support ssr 1`] = `""`; diff --git a/tests/__snapshots__/index.spec.tsx.snap b/tests/__snapshots__/index.spec.tsx.snap new file mode 100644 index 00000000..33c5f10f --- /dev/null +++ b/tests/__snapshots__/index.spec.tsx.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`csssinjs > hash & nest style 1`] = `":where(.css-dev-only-do-not-override-1c7qaqv) a{color:red;}"`; diff --git a/tests/animation.spec.tsx b/tests/animation.spec.tsx index cb69f527..34a5d86e 100644 --- a/tests/animation.spec.tsx +++ b/tests/animation.spec.tsx @@ -53,7 +53,7 @@ describe('animation', () => { ]; const Box = () => { - const [token] = useCacheToken(theme, [baseToken]); + const [token] = useCacheToken(theme, [baseToken], { cssVar: {key: 'css-var-test'}}); useStyleRegister({ theme, token, path: ['.box'] }, () => [genStyle()]); @@ -67,10 +67,10 @@ describe('animation', () => { render(); const styles = Array.from(document.head.querySelectorAll('style')); - expect(styles).toHaveLength(2); + expect(styles).toHaveLength(3); - expect(styles[0].innerHTML).toEqual('.box{animation:anim 1s;}'); - expect(styles[1].innerHTML).toEqual( + expect(styles[1].innerHTML).toEqual('.box{animation:anim 1s;}'); + expect(styles[2].innerHTML).toEqual( '@keyframes anim{to{transform:rotate(360deg);}}', ); }); @@ -81,7 +81,7 @@ describe('animation', () => { let testHashId = ''; const Demo = () => { - const [token, hashId] = useCacheToken(theme, [baseToken]); + const [token, hashId] = useCacheToken(theme, [baseToken], { cssVar: {key: 'css-var-test'}}); testHashId = hashId; useStyleRegister( { theme, token, path: ['keyframes-hashed'], hashId }, @@ -92,12 +92,12 @@ describe('animation', () => { render(); const styles = Array.from(document.head.querySelectorAll('style')); - expect(styles).toHaveLength(2); + expect(styles).toHaveLength(3); - expect(styles[0].innerHTML).toEqual( + expect(styles[1].innerHTML).toEqual( `:where(.${testHashId}).demo{animation-name:${testHashId}-anim;}`, ); - expect(styles[1].innerHTML).toEqual( + expect(styles[2].innerHTML).toEqual( `@keyframes ${testHashId}-anim{to{transform:rotate(360deg);}}`, ); }); @@ -106,7 +106,7 @@ describe('animation', () => { let testHashId = ''; const Demo = () => { - const [token, hashId] = useCacheToken(theme, [baseToken]); + const [token, hashId] = useCacheToken(theme, [baseToken], { cssVar: {key: 'css-var-test'}}); testHashId = hashId; useStyleRegister( { theme, token, path: ['keyframes-in-CSSObject'], hashId }, @@ -117,12 +117,12 @@ describe('animation', () => { render(); const styles = Array.from(document.head.querySelectorAll('style')); - expect(styles).toHaveLength(2); + expect(styles).toHaveLength(3); - expect(styles[0].innerHTML).toEqual( + expect(styles[1].innerHTML).toEqual( `:where(.${testHashId}).demo{animation-name:${testHashId}-anim;}`, ); - expect(styles[1].innerHTML).toEqual( + expect(styles[2].innerHTML).toEqual( `@keyframes ${testHashId}-anim{to{transform:rotate(360deg);}}`, ); }); @@ -131,7 +131,7 @@ describe('animation', () => { let testHashId = ''; const Demo = () => { - const [token, hashId] = useCacheToken(theme, [baseToken]); + const [token, hashId] = useCacheToken(theme, [baseToken], { cssVar: {key: 'css-var-test'}}); testHashId = hashId; useStyleRegister( { theme, token, path: ['keyframes-not-declared'], hashId }, @@ -142,12 +142,12 @@ describe('animation', () => { render(); const styles = Array.from(document.head.querySelectorAll('style')); - expect(styles).toHaveLength(2); + expect(styles).toHaveLength(3); - expect(styles[0].innerHTML).toEqual( + expect(styles[1].innerHTML).toEqual( `:where(.${testHashId}).demo{animation-name:${testHashId}-anim;}`, ); - expect(styles[1].innerHTML).toEqual( + expect(styles[2].innerHTML).toEqual( `@keyframes ${testHashId}-anim{to{transform:rotate(360deg);}}`, ); }); @@ -157,7 +157,7 @@ describe('animation', () => { const anim = animation; const Demo = () => { - const [token, hashId] = useCacheToken(theme, [baseToken]); + const [token, hashId] = useCacheToken(theme, [baseToken], { cssVar: {key: 'css-var-test'}}); testHashId = hashId; useStyleRegister( { theme, token, path: ['keyframes-declared-once'], hashId }, @@ -168,12 +168,12 @@ describe('animation', () => { render(); const styles = Array.from(document.head.querySelectorAll('style')); - expect(styles).toHaveLength(2); + expect(styles).toHaveLength(3); - expect(styles[0].innerHTML).toEqual( + expect(styles[1].innerHTML).toEqual( `:where(.${testHashId}).demo{animation-name:${testHashId}-anim;}`, ); - expect(styles[1].innerHTML).toEqual( + expect(styles[2].innerHTML).toEqual( `@keyframes ${testHashId}-anim{to{transform:rotate(360deg);}}`, ); }); @@ -184,6 +184,7 @@ describe('animation', () => { return () => { const [token, hashId] = useCacheToken(theme, [baseToken], { salt: 're-mount', + cssVar: {key: 'css-var-test'} }); useStyleRegister({ theme, token, path: [cls], hashId }, () => [ @@ -205,7 +206,7 @@ describe('animation', () => { , ); - expect(document.querySelectorAll('style')).toHaveLength(3); + expect(document.querySelectorAll('style')).toHaveLength(4); // Clean up document.head.innerHTML = ''; @@ -217,6 +218,6 @@ describe('animation', () => { , ); - expect(document.querySelectorAll('style')).toHaveLength(3); + expect(document.querySelectorAll('style')).toHaveLength(4); }); }); diff --git a/tests/css-variables.spec.tsx b/tests/css-variables.spec.tsx index 21e8e8b6..89a085e4 100644 --- a/tests/css-variables.spec.tsx +++ b/tests/css-variables.spec.tsx @@ -62,7 +62,7 @@ const theme = createTheme(derivative); type DesignTokenProviderProps = { token?: Partial; hashed?: string | boolean; - cssVar?: { + cssVar: { key: string; prefix?: string; }; @@ -70,7 +70,10 @@ type DesignTokenProviderProps = { const DesignTokenContext = React.createContext({ token: defaultDesignToken, - hashed: true, + hashed: false, + cssVar: { + key: 'css-var-root' + } }); const DesignTokenProvider: React.FC< @@ -232,96 +235,6 @@ describe('CSS Variables', () => { }); }); - it('could mix with non-css-var', () => { - const { container } = render( - <> - - - - - - - - - - - , - ); - - const styles = Array.from(document.head.querySelectorAll('style')); - expect(styles).toHaveLength(7); - - const nonCssVarBox = container.querySelector('.non-css-var')!; - expect(nonCssVarBox).toHaveStyle({ - lineHeight: '1.5', - border: '1px solid black', - backgroundColor: '#1890ff', - color: '#5c21ff', - }); - - const cssVarBox = container.querySelector('.css-var')!; - expect(cssVarBox).toHaveStyle({ - '--rc-line-height': '1.5', - '--rc-border-width': '1px', - '--rc-border-color': 'black', - '--rc-primary-color': '#1677ff', - '--rc-box-box-color': '#5c21ff', - lineHeight: 'var(--rc-line-height)', - border: 'var(--rc-border-width) solid var(--rc-border-color)', - backgroundColor: 'var(--rc-primary-color)', - color: 'var(--rc-box-box-color)', - }); - - const cssVarBox2 = container.querySelector('.css-var-2')!; - expect(cssVarBox2).toHaveClass('banana'); - expect(cssVarBox2).not.toHaveClass('apple'); - expect(cssVarBox2).toHaveStyle({ - '--rc-line-height': '1.5', - '--rc-border-width': '2px', - '--rc-border-color': 'black', - '--rc-primary-color': '#1677ff', - '--rc-box-box-color': '#5c21ff', - lineHeight: 'var(--rc-line-height)', - border: 'var(--rc-border-width) solid var(--rc-border-color)', - backgroundColor: 'var(--rc-primary-color)', - color: 'var(--rc-box-box-color)', - }); - - const nonCssVarBox2 = container.querySelector('.non-css-var-2')!; - expect(nonCssVarBox2).not.toHaveClass('banana'); - expect(nonCssVarBox2).not.toHaveClass('apple'); - expect(nonCssVarBox2).toHaveStyle({ - lineHeight: '1.5', - border: '3px solid black', - backgroundColor: '#1677ff', - color: '#5c21ff', - }); - }); - it('dynamic', () => { const Demo = (props: { token?: Partial }) => ( { it('could autoClear', () => { const { rerender } = render( - + { expect(styles.length).toBe(3); rerender( - + { ); styles = Array.from(document.head.querySelectorAll('style')); + // component style still remains expect(styles.length).toBe(1); + expect(styles[0].textContent).toContain('.box{'); }); it('support ssr', () => { @@ -423,6 +338,7 @@ describe('CSS Variables', () => { key: 'apple', prefix: 'app', }, + hashed: true }} > @@ -431,6 +347,7 @@ describe('CSS Variables', () => { let styles = Array.from(document.head.querySelectorAll('style')); expect(styles.length).toBe(3); + expect( styles.some((style) => style.textContent?.includes('var(--app-')), ).toBe(true); @@ -445,6 +362,7 @@ describe('CSS Variables', () => { key: 'apple', prefix: 'bank', }, + hashed: true }} > diff --git a/tests/index.spec.tsx b/tests/index.spec.tsx index 22930e68..1b6e1eb3 100644 --- a/tests/index.spec.tsx +++ b/tests/index.spec.tsx @@ -55,7 +55,9 @@ describe('csssinjs', () => { } const Box = ({ propToken = baseToken }: BoxProps) => { - const [token] = useCacheToken(theme, [propToken]); + const [token] = useCacheToken(theme, [propToken], { cssVar: { + key: 'css-var-test', + }}); useStyleRegister({ theme, token, path: ['.box'] }, () => [genStyle(token)]); @@ -81,11 +83,13 @@ describe('csssinjs', () => { ); const styles = Array.from(document.head.querySelectorAll('style')); - expect(styles).toHaveLength(1); + expect(styles).toHaveLength(2); // css var and style - const style = styles[0]; - expect(style.innerHTML).toEqual( - '.box{width:93px;line-height:1;background-color:#1890ff;}', + expect(styles[0].innerHTML).toEqual( + '.css-var-test{--primary-color:#1890ff;--primary-color-disabled:#1890ff;}', + ); + expect(styles[1].innerHTML).toEqual( + '.box{width:93px;line-height:1;background-color:var(--primary-color);}', ); // Default not remove style @@ -108,7 +112,7 @@ describe('csssinjs', () => { }; const { rerender } = render(getBox()); - expect(document.head.querySelectorAll('style')).toHaveLength(1); + expect(document.head.querySelectorAll('style')).toHaveLength(2); // First change rerender( @@ -118,7 +122,7 @@ describe('csssinjs', () => { }, }), ); - expect(document.head.querySelectorAll('style')).toHaveLength(1); + expect(document.head.querySelectorAll('style')).toHaveLength(2); // Second change rerender( @@ -128,7 +132,7 @@ describe('csssinjs', () => { }, }), ); - expect(document.head.querySelectorAll('style')).toHaveLength(1); + expect(document.head.querySelectorAll('style')).toHaveLength(2); }); } @@ -137,18 +141,18 @@ describe('csssinjs', () => { test('StrictMode', (ele) => {ele}); }); - it('remove style when unmount', () => { + it('remain style when unmount', () => { const Demo = () => ( - + ); const { unmount } = render(); - expect(document.head.querySelectorAll('style')).toHaveLength(1); + expect(document.head.querySelectorAll('style')).toHaveLength(2); unmount(); - expect(document.head.querySelectorAll('style')).toHaveLength(0); + expect(document.head.querySelectorAll('style')).toHaveLength(1); }); }); @@ -166,7 +170,7 @@ describe('csssinjs', () => { }); const Nest = () => { - const [token] = useCacheToken(theme, [baseToken]); + const [token] = useCacheToken(theme, [baseToken], { cssVar: {key: 'css-var-test'}}); useStyleRegister({ theme, token, path: ['.parent'] }, () => [ genNestStyle(token), @@ -178,31 +182,33 @@ describe('csssinjs', () => { render(); const styles = Array.from(document.head.querySelectorAll('style')); - expect(styles).toHaveLength(1); + expect(styles).toHaveLength(2); - const style = styles[0]; - expect(style.innerHTML).toEqual( - '.parent .child{background:#1890ff;}.parent .child:hover{border-color:#1890ff;}', + expect(styles[0].innerHTML).toEqual( + '.css-var-test{--primary-color:#1890ff;--primary-color-disabled:#1890ff;}', + ); + expect(styles[1].innerHTML).toEqual( + '.parent .child{background:var(--primary-color);}.parent .child:hover{border-color:var(--primary-color);}', ); }); it('serialize nest object token', () => { const TokenShower = (): any => { - const [token] = useCacheToken(theme, [ + const [,,token] = useCacheToken(theme, [ { nest: { nothing: 1, }, }, - ]); + ], { cssVar: {key: 'css-var-test'}}); - return token._tokenKey; + return (token as any)._tokenKey; }; const { container } = render(); // src/util.tsx - token2key func - expect(container.textContent).toEqual('1fs647j'); + expect(container.textContent).toEqual('8o31vm'); }); it('hash', () => { @@ -215,6 +221,7 @@ describe('csssinjs', () => { const Holder = () => { const [token, hashId] = useCacheToken(theme, [], { salt: 'test', + cssVar: {key: 'css-var-test'}, }); useStyleRegister({ theme, token, hashId, path: ['holder'] }, () => [ @@ -228,16 +235,15 @@ describe('csssinjs', () => { const styles = Array.from(document.head.querySelectorAll('style')); expect(styles).toHaveLength(1); - const style = styles[0]; expect(style.innerHTML).toContain( - ':where(.css-dev-only-do-not-override-1ldpa3u).a', + ':where(.css-dev-only-do-not-override-1c7qaqv).a', ); expect(style.innerHTML).toContain( - ':where(.css-dev-only-do-not-override-1ldpa3u).b', + ':where(.css-dev-only-do-not-override-1c7qaqv).b', ); expect(style.innerHTML).toContain( - ':where(.css-dev-only-do-not-override-1ldpa3u).c .d', + ':where(.css-dev-only-do-not-override-1c7qaqv).c .d', ); unmount(); @@ -264,6 +270,7 @@ describe('csssinjs', () => { override: object; }) => { const [token] = useCacheToken(theme, [baseToken], { + cssVar: {key: 'css-var-test'}, override, formatToken: (origin: DerivativeToken) => ({ ...origin, @@ -292,11 +299,10 @@ describe('csssinjs', () => { const { unmount } = render(); const styles = Array.from(document.head.querySelectorAll('style')); - expect(styles).toHaveLength(1); + expect(styles).toHaveLength(2); - const style = styles[0]; - expect(style.innerHTML).toContain('background-color:#010203;'); - expect(style.innerHTML).toContain('color:#010203;'); + expect(styles[0].innerHTML).toEqual('.css-var-test{--primary-color:#010203;--primary-color-disabled:#1890ff;--color:#010203;}') + expect(styles[1].innerHTML).toContain('.box{width:93px;line-height:1;background-color:var(--primary-color);color:var(--color);}') unmount(); }); @@ -315,6 +321,7 @@ describe('csssinjs', () => { [{ primaryColor: colorPrimary }], { salt: 'test', + cssVar: {key: 'css-var-test'}, }, ); @@ -347,12 +354,7 @@ describe('csssinjs', () => { rerender(); const stylesRe2 = document.querySelectorAll(`style[${ATTR_TOKEN}]`); - expect(stylesRe2.length).toBe(2); - expect( - Array.from(stylesRe2).some((style) => - style.innerHTML.includes('color:blue'), - ), - ).toBeTruthy(); + expect(stylesRe2.length).toBe(1); expect( Array.from(stylesRe2).some((style) => style.innerHTML.includes('color:yellow'), @@ -380,6 +382,7 @@ describe('csssinjs', () => { [{ primaryColor: colorPrimary }], { salt: 'test', + cssVar: {key: 'css-var-test'}, }, ); hash = hashId; @@ -404,11 +407,11 @@ describe('csssinjs', () => { render(); const styles = Array.from(document.head.querySelectorAll('style')); - expect(styles).toHaveLength(2); + expect(styles).toHaveLength(3); - expect(styles[0].innerHTML).toBe('a{color:red;}div{color:blue;}'); - expect(styles[1].innerHTML).toBe( - `:where(.${hash}) a{color:red;}:where(.${hash}) div{color:blue;}`, + expect(styles[1].innerHTML).toBe('a{color:var(--primary-color);}div{color:blue;}'); + expect(styles[2].innerHTML).toBe( + `:where(.${hash}) a{color:var(--primary-color);}:where(.${hash}) div{color:blue;}`, ); }); @@ -423,7 +426,7 @@ describe('csssinjs', () => { , ); - expect(container.querySelectorAll('style')).toHaveLength(1); + expect(container.querySelectorAll('style')).toHaveLength(2); }); describe('nonce', () => { @@ -468,6 +471,7 @@ describe('csssinjs', () => { [{ primaryColor: colorPrimary }], { salt: 'test', + cssVar: {key: 'css-var-test'}, }, ); @@ -494,7 +498,7 @@ describe('csssinjs', () => { render(, { container: childContainer }); expect(document.body); - expect(document.querySelectorAll(`style[${ATTR_MARK}]`).length).toBe(2); + expect(document.querySelectorAll(`style[${ATTR_MARK}]`).length).toBe(3); expect(document.body.querySelectorAll(`style[${ATTR_MARK}]`).length).toBe( 1, ); @@ -516,6 +520,7 @@ describe('csssinjs', () => { const Demo = () => { const [token, hashId] = useCacheToken(theme, [], { salt: 'test', + cssVar: {key: 'css-var-test'}, }); useStyleRegister( @@ -543,6 +548,7 @@ describe('csssinjs', () => { const Demo = () => { const [token, hashId] = useCacheToken(theme, [], { salt: 'test', + cssVar: {key: 'css-var-test'}, }); useStyleRegister( @@ -575,6 +581,7 @@ describe('csssinjs', () => { theme, [{ primaryColor: 'blue' }], { + cssVar: {key: 'css-var-test'}, salt: 'test', override: { myToken, @@ -602,16 +609,16 @@ describe('csssinjs', () => { const { rerender } = render(); const styles = Array.from(document.head.querySelectorAll('style')); - expect(styles).toHaveLength(1); - expect(styles[0].innerHTML).toContain('color:test'); - expect(styles[0].innerHTML).toContain('background:blue'); + expect(styles).toHaveLength(2); + expect(styles[0].innerHTML).toContain('--my-token:test'); + expect(styles[0].innerHTML).toContain('--primary-color:blue'); rerender(); const styles2 = Array.from(document.head.querySelectorAll('style')); - expect(styles2).toHaveLength(1); - expect(styles2[0].innerHTML).toContain('color:apple'); - expect(styles2[0].innerHTML).toContain('background:blue'); + expect(styles2).toHaveLength(2); + expect(styles2[0].innerHTML).toContain('--my-token:apple'); + expect(styles2[0].innerHTML).toContain('--primary-color:blue'); rerender( { ); const styles3 = Array.from(document.head.querySelectorAll('style')); - expect(styles3).toHaveLength(1); - expect(styles3[0].innerHTML).toContain('color:banana'); - expect(styles3[0].innerHTML).toContain('background:green'); + expect(styles3).toHaveLength(2); + expect(styles3[0].innerHTML).toContain('--my-token:banana'); + expect(styles3[0].innerHTML).toContain('--primary-color:green'); }); describe('should not cleanup token before finishing rendering', () => { @@ -663,6 +670,7 @@ describe('csssinjs', () => { [{ primaryColor: myToken }], { salt: 'test', + cssVar: {key: `css-var-${myToken}`}, }, ); @@ -676,8 +684,8 @@ describe('csssinjs', () => { const { rerender } = render(wrapper()); const styles = Array.from(document.head.querySelectorAll('style')); - expect(styles).toHaveLength(1); - expect(styles[0].innerHTML).toContain('color:token1'); + expect(styles).toHaveLength(2); + expect(styles[0].innerHTML).toContain('--primary-color:token1'); rerender( wrapper( @@ -687,14 +695,15 @@ describe('csssinjs', () => { ), ); const styles2 = Array.from(document.head.querySelectorAll('style')); - expect(styles2).toHaveLength(2); - expect(styles2[0].innerHTML).toContain('color:token1'); - expect(styles2[1].innerHTML).toContain('color:token2'); + expect(styles2).toHaveLength(3); + + expect(styles2[1].innerHTML).toContain('--primary-color:token2'); + expect(styles2[0].innerHTML).toContain('--primary-color:token1'); rerender(wrapper()); const styles3 = Array.from(document.head.querySelectorAll('style')); - expect(styles3).toHaveLength(1); - expect(styles3[0].innerHTML).toContain('color:token1'); + expect(styles3).toHaveLength(2); + expect(styles3[0].innerHTML).toContain('--primary-color:token1'); expect(spy).not.toHaveBeenCalledWith( expect.stringContaining( @@ -733,6 +742,7 @@ describe('csssinjs', () => { [{ primaryColor: myToken }], { salt: 'test', + cssVar: {key: 'css-var-test'}, }, ); @@ -752,7 +762,7 @@ describe('csssinjs', () => { const { rerender } = render(wrapper()); const styles = Array.from(document.head.querySelectorAll('style')); - expect(styles).toHaveLength(1); + expect(styles).toHaveLength(2); rerender( wrapper( @@ -762,7 +772,7 @@ describe('csssinjs', () => { ), ); const styles2 = Array.from(document.head.querySelectorAll('style')); - expect(styles2).toHaveLength(1); + expect(styles2).toHaveLength(2); spy.mockRestore(); }; @@ -790,6 +800,7 @@ describe('csssinjs', () => { const Holder = () => { const [token, hashId] = useCacheToken(theme, [], { salt: 'test', + cssVar: {key: 'css-var-test'}, }); useStyleRegister({ theme, token, hashId, path: ['holder'] }, () => [ @@ -805,9 +816,7 @@ describe('csssinjs', () => { expect(styles).toHaveLength(1); const style = styles[0]; - expect(style.innerHTML).toContain( - ':where(.css-dev-only-do-not-override-1ldpa3u) a{color:red;}', - ); + expect(style.innerHTML).toMatchSnapshot(); unmount(); }); diff --git a/tests/keyframes.spec.tsx b/tests/keyframes.spec.tsx index 708c7c3b..8ad8cfea 100644 --- a/tests/keyframes.spec.tsx +++ b/tests/keyframes.spec.tsx @@ -36,7 +36,7 @@ describe('animation', () => { describe('without hashed', () => { const Box = () => { - const [token, hashId] = useCacheToken(theme, [baseToken]); + const [token, hashId] = useCacheToken(theme, [baseToken],{cssVar: {key: 'css-var-test'}}); useStyleRegister({ theme, token, hashId, path: ['.box'] }, () => ({ '.box': { diff --git a/tests/linter.spec.tsx b/tests/linter.spec.tsx index 4b7097ee..9b5c87c4 100644 --- a/tests/linter.spec.tsx +++ b/tests/linter.spec.tsx @@ -67,7 +67,7 @@ describe('style warning', () => { [prop]: 1, }); const Demo = () => { - const [token] = useCacheToken(theme, []); + const [token] = useCacheToken(theme, [], { cssVar: {key: 'css-var-test'}}); useStyleRegister({ theme, token, path: [`${prop}`] }, () => [ genStyle(), ]); @@ -92,7 +92,7 @@ describe('style warning', () => { content: 'test', }); const Demo = () => { - const [token] = useCacheToken(theme, []); + const [token] = useCacheToken(theme, [], { cssVar: {key: 'css-var-test'}}); useStyleRegister({ theme, token, path: ['content'] }, () => [genStyle()]); return
; }; @@ -110,7 +110,7 @@ describe('style warning', () => { [prop]: '0 1px 0 3px', }); const Demo = () => { - const [token] = useCacheToken(theme, []); + const [token] = useCacheToken(theme, [], { cssVar: {key: 'css-var-test'}}); useStyleRegister({ theme, token, path: [prop] }, () => [genStyle()]); return
; }; @@ -133,7 +133,7 @@ describe('style warning', () => { [prop]: 'left', }); const Demo = () => { - const [token] = useCacheToken(theme, []); + const [token] = useCacheToken(theme, [], { cssVar: {key: 'css-var-test'}}); useStyleRegister({ theme, token, path: [prop] }, () => [genStyle()]); return
; }; @@ -162,7 +162,7 @@ describe('style warning', () => { borderRadius: value, }); const Demo = () => { - const [token] = useCacheToken(theme, []); + const [token] = useCacheToken(theme, [], { cssVar: {key: 'css-var-test'}}); useStyleRegister( { theme, token, path: [`borderRadius: ${value}`] }, () => [genStyle()], @@ -187,7 +187,7 @@ describe('style warning', () => { content: { _skip_check_: true, value: 'content' }, }); const Demo = () => { - const [token] = useCacheToken(theme, []); + const [token] = useCacheToken(theme, [], { cssVar: {key: 'css-var-test'}}); useStyleRegister({ theme, token, path: ['content_skip'] }, () => [ genStyle(), ]); @@ -202,7 +202,7 @@ describe('style warning', () => { content: '', }); const Demo = () => { - const [token] = useCacheToken(theme, []); + const [token] = useCacheToken(theme, [], { cssVar: {key: 'css-var-test'}}); useStyleRegister({ theme, token, path: ['component-msg'] }, () => [ genStyle(), ]); @@ -221,7 +221,7 @@ describe('style warning', () => { }, }); const Demo = () => { - const [token] = useCacheToken(theme, []); + const [token] = useCacheToken(theme, [], { cssVar: {key: 'css-var-test'}}); useStyleRegister({ theme, token, path: ['selector-in-warning'] }, () => [ genStyle(), ]); @@ -252,7 +252,7 @@ describe('style warning', () => { animation: anim.getName(), }); const Demo = () => { - const [token, hashId] = useCacheToken(theme, []); + const [token, hashId] = useCacheToken(theme, [], { cssVar: {key: 'css-var-test'}}); useStyleRegister( { theme, token, path: ['anim-hashed-animation'], hashId }, () => [genStyle(), anim], @@ -278,7 +278,7 @@ describe('style warning', () => { }, }); const Demo = () => { - const [token] = useCacheToken(theme, []); + const [token] = useCacheToken(theme, [], { cssVar: {key: 'css-var-test'}}); useStyleRegister({ theme, token, path: ['content'] }, () => [ genStyle(), ]); @@ -308,7 +308,7 @@ describe('style warning', () => { }, }); const Demo = () => { - const [token] = useCacheToken(theme, []); + const [token] = useCacheToken(theme, [], { cssVar: {key: 'css-var-test'}}); useStyleRegister( { theme, token, path: ['attribute selector in :not'] }, () => [genStyle()], @@ -342,7 +342,7 @@ describe('style warning', () => { }, }); const Demo = () => { - const [token] = useCacheToken(theme, []); + const [token] = useCacheToken(theme, [], { cssVar: {key: 'css-var-test'}}); useStyleRegister({ theme, token, path: ['parent selector'] }, () => [ genStyle(), ]); @@ -370,7 +370,7 @@ describe('style warning', () => { }, }); const Demo = () => { - const [token] = useCacheToken(theme, []); + const [token] = useCacheToken(theme, [], { cssVar: {key: 'css-var-test'}}); useStyleRegister({ theme, token, path: ['parent selector2'] }, () => [ genStyle(), ]); @@ -400,7 +400,7 @@ describe('style warning', () => { }, }); const Demo = () => { - const [token] = useCacheToken(theme, []); + const [token] = useCacheToken(theme, [], { cssVar: {key: 'css-var-test'}}); useStyleRegister({ theme, token, path: ['parent selector3'] }, () => [ genStyle(), ]); diff --git a/tests/server.spec.tsx b/tests/server.spec.tsx index 739ab3f7..2058ec9b 100644 --- a/tests/server.spec.tsx +++ b/tests/server.spec.tsx @@ -70,13 +70,13 @@ describe('SSR', () => { }); const Box = ({ children }: { children?: React.ReactNode }) => { - const [token] = useCacheToken(theme, [baseToken]); + const [token] = useCacheToken(theme, [baseToken], { cssVar: {key: 'css-var-test'}}); - const wrapSSR = useStyleRegister({ theme, token, path: ['.box'] }, () => [ + useStyleRegister({ theme, token, path: ['.box'] }, () => [ genStyle(token), ]); - return wrapSSR(
{children}
); + return
{children}
; }; const IdHolder = () => { @@ -88,12 +88,6 @@ describe('SSR', () => { ); }; - it('should not use cache', () => { - render(); - - expect(document.head.querySelectorAll('style')).toHaveLength(0); - }); - it('ssr extract style', () => { // >>> SSR const cache = createCache(); @@ -112,13 +106,13 @@ describe('SSR', () => { const plainStyle = extractStyle(cache, true); expect(html).toEqual( - '
:R1:
:Ra:
:R3:
', + '
:R1:
:R2:
:R3:
', ); expect(style).toEqual( - '', + '', ); expect(plainStyle).toEqual( - '.box{background-color:#1890ff;}.data-ant-cssinjs-cache-path{content:"z4ntcy|.box:7g9s98";}', + '.css-var-test{--primary-color:#1890ff;--primary-color-disabled:#1890ff;}.box{background-color:var(--primary-color);}.data-ant-cssinjs-cache-path{content:"|.box:1bbkdf1";}', ); expect(document.head.querySelectorAll('style')).toHaveLength(0); @@ -131,10 +125,10 @@ describe('SSR', () => { document.head.innerHTML = `${style}`; root.innerHTML = html; - expect(document.head.querySelectorAll('style')).toHaveLength(3); + expect(document.head.querySelectorAll('style')).toHaveLength(4); reset( { - 'z4ntcy|.box': '7g9s98', + '|.box': '1bbkdf1', }, false, ); @@ -165,15 +159,15 @@ describe('SSR', () => { ); expect(getStyleAndHash).toHaveBeenCalled(); - expect(getStyleAndHash).toHaveBeenCalledWith('z4ntcy|.box'); + expect(getStyleAndHash).toHaveBeenCalledWith('|.box'); expect(getStyleAndHash).toHaveReturnedWith([ - '.box{background-color:#1890ff;}', - '7g9s98', + '.box{background-color:var(--primary-color);}', + '1bbkdf1', ]); // Not remove other style expect(document.head.querySelectorAll('#otherStyle')).toHaveLength(1); - expect(document.head.querySelectorAll('style')).toHaveLength(3); + expect(document.head.querySelectorAll('style')).toHaveLength(5); expect(errorSpy).not.toHaveBeenCalled(); @@ -182,9 +176,9 @@ describe('SSR', () => { it('not extract clientOnly style', () => { const Client = ({ children }: { children?: React.ReactNode }) => { - const [token] = useCacheToken(theme, [baseToken]); + const [token] = useCacheToken(theme, [baseToken], { cssVar: {key: 'css-var-test'}}); - const wrapSSR = useStyleRegister( + useStyleRegister( { theme, token, path: ['.client'], clientOnly: true }, () => ({ '.client': { @@ -193,7 +187,7 @@ describe('SSR', () => { }), ); - return wrapSSR(
{children}
); + return
{children}
; }; const cache = createCache(); @@ -218,17 +212,16 @@ describe('SSR', () => { [baseToken], { salt: 'hashPriority', + cssVar: {key: 'css-var-test'} }, ); - const wrapSSR = useStyleRegister( + useStyleRegister( { theme, token, hashId, path: ['.hashPriority'] }, () => [genStyle(token)], ); - return wrapSSR( -
{children}
, - ); + return
{children}
; }; renderToString( @@ -241,63 +234,10 @@ describe('SSR', () => { const style = extractStyle(cache); expect(style).toEqual( - '', + '', ); }); - it('tricky ssr', () => { - const html = renderToString( - - - - - - - , - ); - - // >>> Exist style - const root = document.createElement('div'); - root.id = 'root'; - root.innerHTML = html; - expect(root.querySelectorAll('style')).toHaveLength(1); - - // >>> Hydrate - canUseDom.mockReturnValue(true); - document.body.appendChild(root); - const cache = createCache(); - render( - - - - - - - , - { - hydrate: true, - container: root, - }, - ); - - // Remove inline style - expect(root.querySelectorAll('style')).toHaveLength(0); - - // Patch to header - expect(document.head.querySelectorAll('style')).toHaveLength(1); - expect( - (document.head.querySelector(`style[${ATTR_MARK}]`) as any)[ - CSS_IN_JS_INSTANCE - ], - ).toBe(cache.instanceId); - - expect(errorSpy).not.toHaveBeenCalled(); - }); - it('!ssrInline', () => { const html = renderToString( @@ -330,27 +270,7 @@ describe('SSR', () => { expect(html).toEqual('
'); expect(style).toEqual( - '', - ); - }); - - it('tricky', () => { - const html = renderToString( - - - - - - - - - - - , - ); - - expect(html).toEqual( - '
', + '', ); }); }); @@ -390,9 +310,9 @@ describe('SSR', () => { it('ssr keep order', () => { const createComponent = (name: string, order?: number) => { const OrderDefault = ({ children }: { children?: React.ReactNode }) => { - const [token] = useCacheToken(theme, [baseToken]); + const [token] = useCacheToken(theme, [baseToken], { cssVar: {key: 'css-var-test'}}); - const wrapSSR = useStyleRegister( + useStyleRegister( { theme, token, path: [name], order }, () => ({ [`.${name}`]: { @@ -401,7 +321,7 @@ describe('SSR', () => { }), ); - return wrapSSR(
{children}
); + return
{children}
; }; return OrderDefault; @@ -426,18 +346,19 @@ describe('SSR', () => { holder.innerHTML = style; const styles = Array.from(holder.querySelectorAll('style')); - expect(styles[0].getAttribute('data-rc-priority')).toEqual('0'); - expect(styles[1].getAttribute('data-rc-priority')).toEqual('1'); - expect(styles[2].getAttribute('data-rc-priority')).toEqual('2'); + expect(styles[1].getAttribute('data-rc-priority')).toEqual('0'); + expect(styles[2].getAttribute('data-rc-priority')).toEqual('1'); + expect(styles[3].getAttribute('data-rc-priority')).toEqual('2'); // Pure style const pureStyle = extractStyle(cache, true); expect(pureStyle).toEqual( [ - `.order0{background-color:#1890ff;}`, - `.order1{background-color:#1890ff;}`, - `.order2{background-color:#1890ff;}`, - `.data-ant-cssinjs-cache-path{content:"z4ntcy|order1:wcvshe;z4ntcy|order0:1ec9a;z4ntcy|order2:v5oiw3";}`, + '.css-var-test{--primary-color:#1890ff;--primary-color-disabled:#1890ff;}', + `.order0{background-color:var(--primary-color);}`, + `.order1{background-color:var(--primary-color);}`, + `.order2{background-color:var(--primary-color);}`, + `.data-ant-cssinjs-cache-path{content:"|order1:1rqllqf;|order0:12ogt2g;|order2:1jmwgle";}`, ].join(''), ); }); diff --git a/tests/theme.spec.tsx b/tests/theme.spec.tsx index 7959488e..f3872826 100644 --- a/tests/theme.spec.tsx +++ b/tests/theme.spec.tsx @@ -112,11 +112,11 @@ describe('Theme', () => { const sameSeed = { primaryColor: 'red' }; const Demo = ({ theme }: { theme: Theme }) => { - const [token] = useCacheToken(theme, [ + const [, , realToken] = useCacheToken(theme, [ sameSeed, - ]); + ], { cssVar: {key: 'css-var-test'}}); - return {JSON.stringify(token)}; + return {JSON.stringify(realToken)}; }; let calledTimes = 0; @@ -158,9 +158,9 @@ describe('Theme', () => { const sameSeed = { primaryColor: 'red' }; const Demo = ({ theme }: { theme: Theme }) => { - const [token] = useCacheToken(theme, [ + const [,,token] = useCacheToken(theme, [ sameSeed, - ]); + ], { cssVar: {key: 'css-var-test'}}); return {JSON.stringify(token)}; };