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",