From 4122038d42b233a9fc176156b72c760376926a88 Mon Sep 17 00:00:00 2001 From: arvinxx Date: Sun, 19 Feb 2023 17:49:38 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20feat:=20createInstance=20=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E6=94=AF=E6=8C=81=E5=A3=B0=E6=98=8E=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=20token=20=E9=BB=98=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/createCSS.ts | 2 +- src/core/insertStyles.ts | 1 + src/factories/createStyles/index.ts | 8 +--- src/factories/createThemeProvider/index.tsx | 18 +++++++-- src/factories/createUseTheme.ts | 29 +++++++++++---- src/functions/createInstance.ts | 41 +++++++++++++++++---- src/index.ts | 1 + src/utils/css.ts | 2 + 8 files changed, 76 insertions(+), 26 deletions(-) diff --git a/src/core/createCSS.ts b/src/core/createCSS.ts index 2f39584c..32996a88 100644 --- a/src/core/createCSS.ts +++ b/src/core/createCSS.ts @@ -5,7 +5,7 @@ import { EmotionCache } from '@emotion/css/create-instance'; import { serializeStyles } from '@emotion/serialize'; const createClassNameGenerator = - (cache: EmotionCache, hashPriority: HashPriority = 'high'): ClassNameGenerator => + (cache: EmotionCache, hashPriority: HashPriority): ClassNameGenerator => (...args) => { const serialized = serializeStyles(args, cache.registered, undefined); insertStyles(cache, serialized, false, hashPriority); diff --git a/src/core/insertStyles.ts b/src/core/insertStyles.ts index f8f23ca0..e1ffbec1 100644 --- a/src/core/insertStyles.ts +++ b/src/core/insertStyles.ts @@ -1,4 +1,5 @@ /* istanbul ignore file */ + // copied from https://github.com/emotion-js/emotion/blob/main/packages/utils/src/index.js import type { HashPriority } from '@/types'; import type { EmotionCache } from '@emotion/css/create-instance'; diff --git a/src/factories/createStyles/index.ts b/src/factories/createStyles/index.ts index 944da319..57c50030 100644 --- a/src/factories/createStyles/index.ts +++ b/src/factories/createStyles/index.ts @@ -1,14 +1,12 @@ import { useMemo } from 'react'; import { createCSS, serializeCSS } from '@/core'; -import { createUseTheme } from '@/factories/createUseTheme'; import type { BaseReturnType, CSSObject, HashPriority, ResponsiveUtil, ReturnStyleToUse, - UseTheme, } from '@/types'; import { isReactCssResult } from '@/utils'; import { EmotionCache } from '@emotion/css/create-instance'; @@ -18,8 +16,8 @@ import { ReturnStyles, StyleOrGetStyleFn } from './types'; interface CreateStylesFactory { cache: EmotionCache; - styledUseTheme?: UseTheme; hashPriority?: HashPriority; + useTheme: () => any; } export interface CreateStyleOptions { @@ -30,7 +28,7 @@ export interface CreateStyleOptions { * 创建样式基础写法 */ export const createStylesFactory = - ({ styledUseTheme, hashPriority, cache }: CreateStylesFactory) => + ({ hashPriority, cache, useTheme }: CreateStylesFactory) => ( styleOrGetStyle: StyleOrGetStyleFn, options?: CreateStyleOptions, @@ -38,8 +36,6 @@ export const createStylesFactory = // 由于 toClassName 方法依赖了用户给 createStyle 传递的 hashPriority,所以需要在这里重新生成 cx 和 toClassName 方法 const { cx, css: toClassName } = createCSS(cache, options?.hashPriority || hashPriority); - const useTheme = createUseTheme(styledUseTheme); - // 返回 useStyles 方法,作为 hooks 使用 return (props?: Props): ReturnStyles => { const theme = useTheme(); diff --git a/src/factories/createThemeProvider/index.tsx b/src/factories/createThemeProvider/index.tsx index 3a03d529..86a4534f 100644 --- a/src/factories/createThemeProvider/index.tsx +++ b/src/factories/createThemeProvider/index.tsx @@ -1,4 +1,4 @@ -import { memo, ReactElement } from 'react'; +import { Context, memo, ReactElement } from 'react'; import { createUseTheme } from '@/factories/createUseTheme'; import { DEFAULT_THEME_PROVIDER, DEFAULT_USE_THEME } from '@/functions/setupStyled'; @@ -11,8 +11,14 @@ import { ThemeProviderProps } from './type'; export * from './type'; +interface CreateThemeProviderOptions { + styledConfig?: StyledConfig; + CustomThemeContext: Context; + prefixCls?: string; +} + export const createThemeProvider = ( - styledConfig?: StyledConfig, + option: CreateThemeProviderOptions, ): ((props: ThemeProviderProps) => ReactElement | null) => memo( ({ @@ -37,7 +43,11 @@ export const createThemeProvider = ( defaultAppearance={defaultAppearance} appearance={appearance} onAppearanceChange={onAppearanceChange} - useTheme={createUseTheme(styled?.useTheme || styledConfig?.useTheme || DEFAULT_USE_THEME)} + useTheme={createUseTheme({ + prefixCls: prefixCls || option.prefixCls, + styledUseTheme: styled?.useTheme || option.styledConfig?.useTheme || DEFAULT_USE_THEME, + CustomThemeContext: option.CustomThemeContext, + })} > {children} diff --git a/src/factories/createUseTheme.ts b/src/factories/createUseTheme.ts index f79f4931..a9caffb9 100644 --- a/src/factories/createUseTheme.ts +++ b/src/factories/createUseTheme.ts @@ -1,24 +1,39 @@ import { Theme, UseTheme } from '@/types'; -import { useMemo } from 'react'; +import { Context, useContext, useMemo } from 'react'; import { DEFAULT_USE_THEME } from '@/functions/setupStyled'; import { useAntdTheme } from '@/hooks/useAntdTheme'; import { useThemeMode } from '@/hooks/useThemeMode'; -export const createUseTheme = (useDefaultTheme?: UseTheme) => (): Theme => { +interface CreateUseThemeOptions { + prefixCls?: string; + CustomThemeContext: Context; + styledUseTheme?: UseTheme; +} + +export const createUseTheme = (options: CreateUseThemeOptions) => (): Theme => { + const { prefixCls, styledUseTheme, CustomThemeContext } = options; const antdTheme = useAntdTheme(); const themeState = useThemeMode(); - const defaultTheme = useDefaultTheme ? useDefaultTheme() : DEFAULT_USE_THEME() || {}; + + const defaultCustomTheme = useContext(CustomThemeContext); + + const styledTheme = styledUseTheme ? styledUseTheme() : DEFAULT_USE_THEME() || {}; const initTheme = useMemo( - () => ({ ...antdTheme, ...themeState, prefixCls: 'ant' }), - [antdTheme, themeState], + () => ({ + ...antdTheme, + ...themeState, + ...defaultCustomTheme, + prefixCls: prefixCls || 'ant', + }), + [antdTheme, themeState, prefixCls, defaultCustomTheme], ); // 如果是个空值,说明没有套 Provider,返回 antdTheme 的默认值 - if (!defaultTheme || Object.keys(defaultTheme).length === 0) { + if (!styledTheme || Object.keys(styledTheme).length === 0) { return initTheme; } - return defaultTheme as Theme; + return styledTheme as Theme; }; diff --git a/src/functions/createInstance.ts b/src/functions/createInstance.ts index 75b28a05..3af051f2 100644 --- a/src/functions/createInstance.ts +++ b/src/functions/createInstance.ts @@ -1,4 +1,4 @@ -import { useContext } from 'react'; +import { createContext, useContext } from 'react'; import { createCSS, createEmotion, serializeCSS } from '@/core'; @@ -18,12 +18,21 @@ export interface CreateOptions { * @default ant-css */ key?: string; + + /** + * 默认的组件 prefixCls + */ + prefixCls?: string; /** * 是否开启急速模式 * * @default false */ speedy?: boolean; + /** + * 默认的自定义 Token + */ + defaultCustomToken?: T; hashPriority?: HashPriority; ThemeProvider?: Omit, 'children'>; @@ -37,26 +46,43 @@ export interface CreateOptions { export const createInstance = (options: CreateOptions) => { const defaultKey = options.key || 'ant-css'; - const styledUseTheme = options.styled?.useTheme as () => Theme; - const emotion = createEmotion({ key: defaultKey, speedy: options.speedy }); const { cache, injectGlobal, keyframes } = emotion; const { cx } = createCSS(cache, options.hashPriority); - const useTheme = createUseTheme(styledUseTheme); + // ******* 下面这些都和主题相关,如果做了任何改动,都需要排查一遍 ************* // + + const CustomThemeContext = createContext( + (options.defaultCustomToken ? options.defaultCustomToken : {}) as T, + ); + + const styledUseTheme = options.styled?.useTheme as () => Theme; + + const useTheme = createUseTheme({ + prefixCls: options?.prefixCls, + CustomThemeContext, + styledUseTheme, + }); const createStyles = createStylesFactory({ cache, - styledUseTheme, hashPriority: options.hashPriority, + useTheme, }); - const createGlobalStyle = createGlobalStyleFactory(useTheme); const createStylish = createStylishFactory(createStyles); + const ThemeProvider = createThemeProvider({ + styledConfig: options.styled, + CustomThemeContext, + prefixCls: options.prefixCls, + }); + + // ******** 上面这些都和主题相关,如果做了任何改动,都需要排查一遍 ************ // + const EmotionContext = createEmotionContext(emotion); const StyleProvider = createStyleProvider(EmotionContext, { @@ -64,9 +90,8 @@ export const createInstance = (options: CreateOptions) => { prefix: defaultKey, }); - const ThemeProvider = createThemeProvider(options.styled); - const useEmotion = () => useContext(EmotionContext); + return { // ******************** // // **** 样式生成相关 **** // diff --git a/src/index.ts b/src/index.ts index c3b8a820..1c34b4d6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ // 等应用层完成迁移后,移除该导出 export { default as styled } from '@emotion/styled'; +export * from './factories/createStyles/types'; export * from './factories/createThemeProvider/type'; export * from './functions'; export * from './hooks'; diff --git a/src/utils/css.ts b/src/utils/css.ts index df46365d..d71caa80 100644 --- a/src/utils/css.ts +++ b/src/utils/css.ts @@ -1,3 +1,5 @@ +/* istanbul ignore file */ + import { getRegisteredStyles, RegisteredCache } from '@emotion/utils'; /**