From 596104cc6868463c4eb1055dc123bfc1c76709e5 Mon Sep 17 00:00:00 2001
From: MadCcc <1075746765@qq.com>
Date: Mon, 5 Jun 2023 17:45:33 +0800
Subject: [PATCH] feat: static getDesignToken (#42723)
* feat: static getDesignToken
* chore: code clean
---
components/theme/__tests__/token.test.tsx | 55 +++++++++++++++++++++++
components/theme/getDesignToken.ts | 17 +++++++
components/theme/index.ts | 8 ++--
docs/react/customize-theme.en-US.md | 36 ++++++++++++++-
docs/react/customize-theme.zh-CN.md | 38 ++++++++++++++--
package.json | 2 +-
6 files changed, 147 insertions(+), 9 deletions(-)
create mode 100644 components/theme/getDesignToken.ts
diff --git a/components/theme/__tests__/token.test.tsx b/components/theme/__tests__/token.test.tsx
index 72d59a1279..3a2b1957e8 100644
--- a/components/theme/__tests__/token.test.tsx
+++ b/components/theme/__tests__/token.test.tsx
@@ -3,6 +3,7 @@ import * as React from 'react';
import theme from '..';
import { render, renderHook } from '../../../tests/utils';
import ConfigProvider from '../../config-provider';
+import type { ThemeConfig } from '../../config-provider/context';
import Row from '../../row';
import genRadius from '../themes/shared/genRadius';
@@ -221,4 +222,58 @@ describe('Theme', () => {
expect(container.querySelector('.duration')?.textContent).toEqual('0s');
});
+
+ describe('getDesignToken', () => {
+ const getHookToken = (config?: ThemeConfig) => {
+ let token: any;
+ const Demo = () => {
+ const { token: hookToken } = useToken();
+ token = hookToken;
+ return null;
+ };
+ render(
+
+
+ ,
+ );
+ delete token._hashId;
+ delete token._tokenKey;
+ return token;
+ };
+
+ it('default', () => {
+ const token = theme.getDesignToken();
+ const hookToken = getHookToken();
+ expect(token).toEqual(hookToken);
+ });
+
+ it('with custom token', () => {
+ const config: ThemeConfig = {
+ token: {
+ colorPrimary: '#189cff',
+ borderRadius: 8,
+ fontSizeLG: 20,
+ },
+ };
+ const token = theme.getDesignToken(config);
+ const hookToken = getHookToken(config);
+ expect(token).toEqual(hookToken);
+ expect(token.colorPrimary).toEqual('#189cff');
+ });
+
+ it('with custom algorithm', () => {
+ const config: ThemeConfig = {
+ token: {
+ colorPrimary: '#1677ff',
+ borderRadius: 8,
+ fontSizeLG: 20,
+ },
+ algorithm: [theme.darkAlgorithm, theme.compactAlgorithm],
+ };
+ const token = theme.getDesignToken(config);
+ const hookToken = getHookToken(config);
+ expect(token).toEqual(hookToken);
+ expect(token.colorPrimary).toEqual('#1668dc');
+ });
+ });
});
diff --git a/components/theme/getDesignToken.ts b/components/theme/getDesignToken.ts
new file mode 100644
index 0000000000..265dedc834
--- /dev/null
+++ b/components/theme/getDesignToken.ts
@@ -0,0 +1,17 @@
+import { createTheme, getComputedToken } from '@ant-design/cssinjs';
+import type { ThemeConfig } from '../config-provider/context';
+import type { AliasToken } from './interface';
+import defaultDerivative from './themes/default';
+import seedToken from './themes/seed';
+import formatToken from './util/alias';
+
+const getDesignToken = (config?: ThemeConfig): AliasToken => {
+ const theme = config?.algorithm ? createTheme(config.algorithm) : createTheme(defaultDerivative);
+ const mergedToken = {
+ ...seedToken,
+ ...config?.token,
+ };
+ return getComputedToken(mergedToken, { override: config?.token }, theme, formatToken);
+};
+
+export default getDesignToken;
diff --git a/components/theme/index.ts b/components/theme/index.ts
index 92eed83022..799126fb04 100644
--- a/components/theme/index.ts
+++ b/components/theme/index.ts
@@ -1,9 +1,10 @@
/* eslint-disable import/prefer-default-export */
-import { defaultConfig, useToken as useInternalToken } from './internal';
+import getDesignToken from './getDesignToken';
import type { GlobalToken } from './interface';
-import defaultAlgorithm from './themes/default';
-import darkAlgorithm from './themes/dark';
+import { defaultConfig, useToken as useInternalToken } from './internal';
import compactAlgorithm from './themes/compact';
+import darkAlgorithm from './themes/dark';
+import defaultAlgorithm from './themes/default';
// ZombieJ: We export as object to user but array in internal.
// This is used to minimize the bundle size for antd package but safe to refactor as object also.
@@ -28,4 +29,5 @@ export default {
defaultAlgorithm,
darkAlgorithm,
compactAlgorithm,
+ getDesignToken,
};
diff --git a/docs/react/customize-theme.en-US.md b/docs/react/customize-theme.en-US.md
index 1f92654219..de7dbb9cb8 100644
--- a/docs/react/customize-theme.en-US.md
+++ b/docs/react/customize-theme.en-US.md
@@ -160,9 +160,41 @@ When you need token out of React life cycle, you can use static function to get
```jsx
import { theme } from 'antd';
-const { defaultAlgorithm, defaultSeed } = theme;
+const { getDesignToken } = theme;
-const mapToken = defaultAlgorithm(defaultSeed);
+const globalToken = getDesignToken();
+```
+
+Same as ConfigProvider, `getDesignToken` could also accept a config object as `theme`:
+
+```tsx
+import type { ThemeConfig } from 'antd';
+import { theme } from 'antd';
+import { createRoot } from 'react-dom/client';
+
+const { getDesignToken, useToken } = theme;
+
+const config: ThemeConfig = {
+ token: {
+ colorPrimary: '#1890ff',
+ },
+};
+
+// By static function
+const globalToken = getDesignToken(config);
+
+// By hook
+const App = () => {
+ const { token } = useToken();
+ return null;
+};
+
+// Example for rendering
+createRoot(document.getElementById('#app')).render(
+
+
+ ,
+);
```
If you want to use in preprocess style framework like less, use less-loader for injection:
diff --git a/docs/react/customize-theme.zh-CN.md b/docs/react/customize-theme.zh-CN.md
index d4dff43fb3..4b05ce848b 100644
--- a/docs/react/customize-theme.zh-CN.md
+++ b/docs/react/customize-theme.zh-CN.md
@@ -155,14 +155,46 @@ export default App;
### 静态消费(如 less)
-当你需要非 React 生命周期消费 Token 变量时,可以通过静态方法将其导出:
+当你需要非 React 生命周期消费 Token 变量时,可以通过静态方法 `getDesignToken` 将其导出:
```jsx
import { theme } from 'antd';
-const { defaultAlgorithm, defaultSeed } = theme;
+const { getDesignToken } = theme;
-const mapToken = defaultAlgorithm(defaultSeed);
+const globalToken = getDesignToken();
+```
+
+`getDesignToken` 和 ConfigProvider 一样,支持传入 `theme` 属性,用于获取指定主题的 Design Token。
+
+```tsx
+import type { ThemeConfig } from 'antd';
+import { theme } from 'antd';
+import { createRoot } from 'react-dom/client';
+
+const { getDesignToken, useToken } = theme;
+
+const config: ThemeConfig = {
+ token: {
+ colorPrimary: '#1890ff',
+ },
+};
+
+// 通过静态方法获取
+const globalToken = getDesignToken(config);
+
+// 通过 hook 获取
+const App = () => {
+ const { token } = useToken();
+ return null;
+};
+
+// 渲染示意
+createRoot(document.getElementById('#app')).render(
+
+
+ ,
+);
```
如果需要将其应用到静态样式编译框架,如 less 可以通过 less-loader 注入:
diff --git a/package.json b/package.json
index d51d89e766..2d7340cc5e 100644
--- a/package.json
+++ b/package.json
@@ -109,7 +109,7 @@
],
"dependencies": {
"@ant-design/colors": "^7.0.0",
- "@ant-design/cssinjs": "^1.9.1",
+ "@ant-design/cssinjs": "^1.10.1",
"@ant-design/icons": "^5.1.0",
"@ant-design/react-slick": "~1.0.0",
"@babel/runtime": "^7.18.3",