Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
456a1ce
feat: remove compatibility under React v18 (#210)
MadCcc Feb 5, 2025
7fc269b
2.0.0-alpha.0
MadCcc Feb 6, 2025
296d730
2.0.0-alpha.2
MadCcc Feb 6, 2025
fcb0e28
feat: rm style tokenKey (#213)
MadCcc Feb 14, 2025
afc4b67
feat: css var support hash (#214)
MadCcc Feb 18, 2025
db73b8d
chore: add useMemo back (#215)
MadCcc Feb 19, 2025
d5c0ad1
docs: add first render demo (#216)
MadCcc Feb 20, 2025
f433802
2.0.0-alpha.3
MadCcc Feb 20, 2025
cdd6675
fix: should not clean token when token change (#217)
MadCcc Feb 21, 2025
c13639f
2.0.0-alpha.4
MadCcc Feb 21, 2025
80f1368
perf: cache effect (#218)
MadCcc Feb 25, 2025
9de2638
chore: bump father-plugin (#219)
MadCcc Feb 25, 2025
9e0b3d7
chore: bump version to 2.0.0-alpha.5
MadCcc Feb 25, 2025
d0ec3f5
fix: Keep render order in ssr (#225)
zombieJ Jun 6, 2025
079f152
chore: bump father version
zombieJ Jun 6, 2025
eb0170f
chore: bump version to 2.0.0-alpha.6
zombieJ Jun 6, 2025
2b33bea
feat: extractStyle support once (#228)
MadCcc Jul 18, 2025
b5cab9b
feat: support autoPrefix (#230)
zombieJ Jul 21, 2025
aad3356
chore: bump version to 2.0.0-alpha.7
zombieJ Jul 21, 2025
4b65240
fix: not use func of autoPrefix
zombieJ Jul 21, 2025
c3d906a
chore: fix lint
zombieJ Jul 21, 2025
02d35a3
chore: bump version to 2.0.0-alpha.8
zombieJ Jul 21, 2025
c6283f7
fix: fix the issue of failed verification when content is cssvar (#235)
kimteayon Oct 31, 2025
5949a1b
chore: fix lint
zombieJ Oct 31, 2025
1d9867a
chore: bump version to 2.0.0-alpha.9
zombieJ Oct 31, 2025
68e4fed
Merge branch 'next' into chore/merge-next
MadCcc Nov 17, 2025
a4da2e9
test: update test case
MadCcc Nov 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
8 changes: 0 additions & 8 deletions docs/demo/auto-clear.md

This file was deleted.

8 changes: 8 additions & 0 deletions docs/demo/first-render.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: First Render
nav:
title: Demo
path: /demo
---

<code src="../examples/first-render.tsx"></code>
37 changes: 0 additions & 37 deletions docs/examples/auto-clear.tsx

This file was deleted.

51 changes: 51 additions & 0 deletions docs/examples/autoPrefix.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {
autoPrefixTransformer,
createTheme,
StyleProvider,
useStyleRegister,
} from '@ant-design/cssinjs';
import React from 'react';

const Demo = () => {
useStyleRegister(
{ theme: createTheme(() => ({})), token: {}, path: ['.auto-prefix-box'] },
() => ({
'.auto-prefix-box': {
width: '200px',
height: '200px',
backgroundColor: '#f0f0f0',
border: '1px solid #d9d9d9',
borderRadius: '8px',
// Properties that will get vendor prefixes
transform: 'translateX(50px) scale(1.1)',
transition: 'all 0.3s ease',
userSelect: 'none',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
backdropFilter: 'blur(10px)',
'&:hover': {
transform: 'translateX(50px) scale(1.2)',
backgroundColor: '#e6f7ff',
},
},
}),
);

return (
<div className="auto-prefix-box">
<h3>Auto Prefix Demo</h3>
<p>Hover to see effect</p>
<p style={{ fontSize: '12px', color: '#666' }}>
Check DevTools to see vendor prefixes in CSS
</p>
</div>
);
};

export default () => (
<StyleProvider transformers={[autoPrefixTransformer]}>
<Demo />
</StyleProvider>
);
72 changes: 54 additions & 18 deletions docs/examples/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
import type { CSSInterpolation, CSSObject } from '@ant-design/cssinjs';
import { unit, useStyleRegister } from '@ant-design/cssinjs';
import type {
CSSInterpolation,
CSSObject} from '@ant-design/cssinjs';
import {
unit,
useCSSVarRegister,
useStyleRegister,
} from '@ant-design/cssinjs';
import classNames from 'classnames';
import React from 'react';
import type { DerivativeToken } from './theme';
import { useToken } from './theme';

interface ButtonToken extends DerivativeToken {
buttonPadding: string;
buttonBorderBottomWidth: string;
}

// 通用框架
const genSharedButtonStyle = (
prefixCls: string,
token: DerivativeToken,
token: ButtonToken,
): CSSInterpolation => ({
[`.${prefixCls}`]: {
borderColor: token.borderColor,
borderWidth: token.borderWidth,
borderRadius: token.borderRadius,
lineHeight: token.lineHeight,
padding: token.buttonPadding,

cursor: 'pointer',

Expand All @@ -33,7 +45,7 @@ const genSharedButtonStyle = (
// 实心底色样式
const genSolidButtonStyle = (
prefixCls: string,
token: DerivativeToken,
token: ButtonToken,
postFn: () => CSSObject,
): CSSInterpolation => [
genSharedButtonStyle(prefixCls, token),
Expand All @@ -47,11 +59,12 @@ const genSolidButtonStyle = (
// 默认样式
const genDefaultButtonStyle = (
prefixCls: string,
token: DerivativeToken,
token: ButtonToken,
): CSSInterpolation =>
genSolidButtonStyle(prefixCls, token, () => ({
backgroundColor: token.componentBackgroundColor,
color: token.textColor,
borderWidth: token.buttonBorderBottomWidth,

'&:hover': {
borderColor: token.primaryColor,
Expand All @@ -62,7 +75,7 @@ const genDefaultButtonStyle = (
// 主色样式
const genPrimaryButtonStyle = (
prefixCls: string,
token: DerivativeToken,
token: ButtonToken,
): CSSInterpolation =>
genSolidButtonStyle(prefixCls, token, () => ({
backgroundColor: token.primaryColor,
Expand All @@ -77,7 +90,7 @@ const genPrimaryButtonStyle = (
// 透明按钮
const genGhostButtonStyle = (
prefixCls: string,
token: DerivativeToken,
token: ButtonToken,
): CSSInterpolation => [
genSharedButtonStyle(prefixCls, token),
{
Expand All @@ -103,23 +116,46 @@ const Button = ({ className, type, ...restProps }: ButtonProps) => {
const prefixCls = 'ant-btn';

// 【自定义】制造样式
const [theme, token, hashId, cssVarKey] = useToken();
const [theme, token, hashId, cssVarKey, realToken] = useToken();

// default 添加默认样式选择器后可以省很多冲突解决问题
const defaultCls = `${prefixCls}-default`;
const primaryCls = `${prefixCls}-primary`;
const ghostCls = `${prefixCls}-ghost`;

// 全局注册,内部会做缓存优化
const wrapSSR = useStyleRegister(
{ theme, token, hashId, path: [prefixCls] },
() => [
genDefaultButtonStyle(defaultCls, token),
genPrimaryButtonStyle(primaryCls, token),
genGhostButtonStyle(ghostCls, token),
],
const [cssVarToken] = useCSSVarRegister(
{
path: [prefixCls],
key: cssVarKey,
token: realToken,
prefix: prefixCls,
unitless: {
lineHeight: true,
},
ignore: {
lineHeightBase: true,
},
scope: prefixCls,
hashId,
},
() => ({
buttonPadding: '4px 8px',
buttonBorderBottomWidth: `calc(${token.borderWidth} * 2)`,
}),
);

const mergedToken: any = {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using any for mergedToken weakens type safety. A more specific type can be used here to ensure the mergedToken object conforms to the expected shape, which appears to be ButtonToken.

Suggested change
const mergedToken: any = {
const mergedToken: ButtonToken = {

...token,
...cssVarToken,
};

// 全局注册,内部会做缓存优化
useStyleRegister({ theme, token, hashId, path: [prefixCls] }, () => [
genDefaultButtonStyle(defaultCls, mergedToken),
genPrimaryButtonStyle(primaryCls, mergedToken),
genGhostButtonStyle(ghostCls, mergedToken),
]);

const typeCls =
(
{
Expand All @@ -128,11 +164,11 @@ const Button = ({ className, type, ...restProps }: ButtonProps) => {
} as any
)[type as any] || defaultCls;

return wrapSSR(
return (
<button
className={classNames(prefixCls, typeCls, hashId, className, cssVarKey)}
{...restProps}
/>,
/>
);
};

Expand Down
6 changes: 3 additions & 3 deletions docs/examples/components/Spin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ const Spin = ({ className, ...restProps }: SpinProps) => {
const [theme, token, hashId] = useToken();

// 全局注册,内部会做缓存优化
const wrapSSR = useStyleRegister(
useStyleRegister(
{ theme, token, hashId, path: [prefixCls] },
() => [genSpinStyle(prefixCls, token)],
);

return wrapSSR(
<div className={classNames(prefixCls, hashId, className)} {...restProps} />,
return (
<div className={classNames(prefixCls, hashId, className)} {...restProps} />
);
};

Expand Down
68 changes: 52 additions & 16 deletions docs/examples/components/theme.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { CSSObject, Theme } from '@ant-design/cssinjs';
import { createTheme, useCacheToken } from '@ant-design/cssinjs';
import { TinyColor } from '@ctrl/tinycolor';
import React from 'react';
import React, { PropsWithChildren } from 'react';

export type GetStyle = (prefixCls: string, token: DerivativeToken) => CSSObject;

Expand Down Expand Up @@ -61,32 +61,68 @@ export const DesignTokenContext = React.createContext<{
token: defaultDesignToken,
});

export const DesignTokenProvider: React.FC<
PropsWithChildren<{
value?: {
token?: Partial<DesignToken>;
hashed?: string | boolean;
cssVar?: {
key?: string;
prefix?: string;
};
};
}>
> = ({ children, value }) => {
const { token, hashed, cssVar } = value || {};
const themeKey = React.useId();
const cssVarKey = `css-var-${themeKey.replace(/:/g, '')}`;
return (
<DesignTokenContext.Provider
value={{
token,
hashed,
cssVar: {
...cssVar,
key: cssVar?.key || cssVarKey,
},
}}
>
{children}
</DesignTokenContext.Provider>
);
};
Comment on lines +64 to +93
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

DesignTokenProvider 实现良好,但需注意 React 版本依赖。

DesignTokenProvider 使用 React.useId() 生成唯一的 CSS 变量键,这是一个良好的实践。然而,useId() 是 React 18 引入的 API。

根据 PR 摘要,此版本已移除 React 18 以下版本的兼容性支持,因此使用 useId() 是安全的。建议确认 package.json 中的 React 最低版本要求是否已更新为 18.0.0 或更高:


🏁 Script executed:

#!/bin/bash
# 检查 package.json 中的 React 版本要求
cat package.json | jq -r '.peerDependencies.react, .devDependencies.react, .dependencies.react' | head -3

Length of output: 21


需要进一步验证 React.useId() 在代码库中的使用范围和这是否是一个新的breaking change。让我检查相关信息。


---

🏁 Script executed:

```shell
#!/bin/bash
# 检查代码库中是否还有其他地方使用 React.useId()
rg "useId" -n -C2

Length of output: 614


🏁 Script executed:

#!/bin/bash
# 检查 package.json 中是否有 breaking changes 的说明或版本号变化
cat package.json | jq -r '.version'

Length of output: 13


更新 package.json 中的 React peerDependencies 版本要求。

DesignTokenProvider 使用了 React.useId()(React 18+ API),但 package.jsonpeerDependencies 仍声明为 >=16.0.0,允许 React 16 及更早版本。这会导致在 React 16/17 环境中发生运行时错误。

package.json 中,需要将 peerDependencies.react>=16.0.0 更新为 ^18.0.0>=18.0.0,以匹配代码的实际要求。代码库中至少有两处使用了 React.useId()docs/examples/components/theme.tsx:77tests/server.spec.tsx:115)。

🤖 Prompt for AI Agents
In docs/examples/components/theme.tsx around lines 64 to 93, the component uses
React.useId() (React 18+), but package.json still declares
peerDependencies.react as >=16.0.0 allowing older React versions; update
package.json to require React 18+ (e.g., set peerDependencies.react to "^18.0.0"
or ">=18.0.0") so consumers cannot install with React 16/17, and run a quick
grep to confirm other instances (tests/server.spec.tsx:115 and any others) match
this requirement.


export function useToken(): [
Theme<any, any>,
DerivativeToken,
string,
string | undefined,
string,
DerivativeToken,
] {
const {
token: rootDesignToken = {},
hashed,
cssVar,
cssVar: ctxCssVar,
} = React.useContext(DesignTokenContext);
const theme = React.useContext(ThemeContext);

const [token, hashId] = useCacheToken<DerivativeToken, DesignToken>(
theme,
[defaultDesignToken, rootDesignToken],
{
salt: typeof hashed === 'string' ? hashed : '',
cssVar: cssVar && {
prefix: 'rc',
key: cssVar.key,
unitless: {
lineHeight: true,
},
const cssVar = {
key: ctxCssVar?.key || 'css-var-root',
};

const [token, hashId, actualToken] = useCacheToken<
DerivativeToken,
DesignToken
>(theme, [defaultDesignToken, rootDesignToken], {
salt: typeof hashed === 'string' ? hashed : '',
cssVar: {
prefix: 'rc',
key: cssVar?.key || 'css-var-root',
unitless: {
lineHeight: true,
},
hashed: !!hashed,
},
);
return [theme, token, hashed ? hashId : '', cssVar?.key];
});
return [theme, token, hashed ? hashId : '', cssVar.key, actualToken];
}
Loading