From d4a57ae4b879b4fc13800c6ecefc111ba3bacd45 Mon Sep 17 00:00:00 2001 From: arvinxx Date: Sat, 4 Feb 2023 13:43:09 +0800 Subject: [PATCH] =?UTF-8?q?:label:=20feat:=20=E4=BC=98=E5=8C=96=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=AE=9A=E4=B9=89=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dumi/theme/components/GithubButton/index.tsx | 4 +-- src/containers/StyleProvider/index.tsx | 1 - .../ThemeProvider/TokenContainer.tsx | 3 +- src/functions/createStyles/index.ts | 23 ++++++------ src/functions/createStyles/response.ts | 11 ++++-- src/types/css.ts | 23 ++++++++++++ src/types/function.ts | 35 +++++++++---------- src/types/response.ts | 4 ++- 8 files changed, 67 insertions(+), 37 deletions(-) diff --git a/.dumi/theme/components/GithubButton/index.tsx b/.dumi/theme/components/GithubButton/index.tsx index 7c086261..563dde1b 100644 --- a/.dumi/theme/components/GithubButton/index.tsx +++ b/.dumi/theme/components/GithubButton/index.tsx @@ -1,7 +1,7 @@ -import { memo, type FC } from 'react'; - import { GithubFilled } from '@ant-design/icons'; import { Button, Tooltip } from 'antd'; +import { memo, type FC } from 'react'; + import { useSiteStore } from '../../store/useSiteStore'; const GithubButton: FC = () => { diff --git a/src/containers/StyleProvider/index.tsx b/src/containers/StyleProvider/index.tsx index 0942ef84..b4aea0c9 100644 --- a/src/containers/StyleProvider/index.tsx +++ b/src/containers/StyleProvider/index.tsx @@ -2,7 +2,6 @@ import { EmotionContext } from '@/context/EmotionContext'; import { createEmotion } from '@/functions'; import { StylisPlugin } from '@emotion/cache'; import { Emotion } from '@emotion/css/create-instance'; -import * as process from 'process'; import { FC, memo, ReactNode, useEffect, useMemo } from 'react'; interface StyleProviderProps { diff --git a/src/containers/ThemeProvider/TokenContainer.tsx b/src/containers/ThemeProvider/TokenContainer.tsx index 3858f911..4b385248 100644 --- a/src/containers/ThemeProvider/TokenContainer.tsx +++ b/src/containers/ThemeProvider/TokenContainer.tsx @@ -1,11 +1,10 @@ -import { SerializedStyles } from '@emotion/serialize'; import { ReactElement, useMemo } from 'react'; import { useAntdTheme, useThemeMode } from '@/hooks'; import { PedestalProvider, reactCss } from '@/pedestal'; +import { SerializedStyles, Theme } from '@/types'; import { convertStylishToString } from '@/utils/convertStylish'; -import { Theme } from '@/types'; import type { ThemeProviderProps } from './type'; type TokenContainerProps> = Pick< diff --git a/src/functions/createStyles/index.ts b/src/functions/createStyles/index.ts index b16e86bd..d65390ab 100644 --- a/src/functions/createStyles/index.ts +++ b/src/functions/createStyles/index.ts @@ -4,12 +4,12 @@ import { useEmotion, useTheme } from '@/hooks'; import { reactCss } from '@/pedestal'; import type { BaseReturnType, + ClassNamesUtil, CommonStyleUtils, CSSObject, - EmotionCX, FullStylish, FullToken, - ResponsiveStyleUtil, + ResponsiveUtil, ReturnStyleToUse, Theme, ThemeAppearance, @@ -19,9 +19,12 @@ import { isReactCssResult } from '@/utils'; import { convertResponsiveStyleToString, useMediaQueryMap } from './response'; /** - * 用户书写样式时使用的第一个参数 + * 书写样式时使用的第一个参数 */ export interface CreateStylesTheme extends CommonStyleUtils { + /** + * 包含 antd 的 token 和所有自定义 token + */ token: FullToken; stylish: FullStylish; /** @@ -76,6 +79,11 @@ export const createStyles = const responsiveMap = useMediaQueryMap(); const { css, cx } = useEmotion(); + // 由于使用了 reactCss 作为基础样式工具,因此在使用 cx 级联 className 时需要使用特殊处理的 cx + // 要将 reactCss 的产出转为 css 产物 + const reactCx: ClassNamesUtil = (...classNames) => + cx(...(classNames.map((c) => (isReactCssResult(c) ? css(c) : c)) as any[])); + const styles = useMemo(() => { let tempStyles: ReturnStyleToUse; @@ -83,13 +91,9 @@ export const createStyles = if (styleOrGetStyle instanceof Function) { const { stylish, appearance, isDarkMode, prefixCls, ...token } = theme; - // 由于使用了 reactCss 作为基础样式工具,因此在使用 cx 级联 className 时需要使用特殊处理的 cx,要将 reactCss 的产出转为 css 产物 - const reactCx: EmotionCX = (...classNames) => - cx(...classNames.map((c) => (isReactCssResult(c) ? css(c) : c))); - // 创建响应式断点选择器的工具函数 // @ts-ignore - const responsive: ResponsiveStyleUtil = (styles) => + const responsive: ResponsiveUtil = (styles) => convertResponsiveStyleToString(styles, responsiveMap); // 并赋予其相应的断点工具 Object.assign(responsive, responsiveMap); @@ -109,7 +113,6 @@ export const createStyles = props!, ) as any; } - // 没有函数时直接就是 object 或者 string else { tempStyles = styleOrGetStyle as any; @@ -142,6 +145,6 @@ export const createStyles = return useMemo(() => { const { prefixCls, ...res } = theme; - return { styles, cx, theme: res, prefixCls }; + return { styles, cx: reactCx, theme: res, prefixCls }; }, [styles, theme]); }; diff --git a/src/functions/createStyles/response.ts b/src/functions/createStyles/response.ts index 95b5244b..40195914 100644 --- a/src/functions/createStyles/response.ts +++ b/src/functions/createStyles/response.ts @@ -1,9 +1,14 @@ import { useAntdToken } from '@/hooks'; import { reactCss } from '@/pedestal'; -import type { Breakpoint, BreakpointMapParams, CSSObject, ResponsiveMap } from '@/types'; +import type { + Breakpoint, + BreakpointMapParams, + CSSObject, + ResponsiveMap, + SerializedStyles, +} from '@/types'; import { isReactCssResult } from '@/utils'; import { convertBreakpointToResponsive } from '@/utils/responsive'; -import type { SerializedStyles } from '@emotion/serialize'; import { useMemo } from 'react'; export const useMediaQueryMap = (): ResponsiveMap => { @@ -22,7 +27,7 @@ export const useMediaQueryMap = (): ResponsiveMap => { }; /** - * 将响应式对象转换为 + * 将响应式对象转换为字符串 * @param obj * @param map */ diff --git a/src/types/css.ts b/src/types/css.ts index 01f0bbc2..a3342fd2 100644 --- a/src/types/css.ts +++ b/src/types/css.ts @@ -1,6 +1,29 @@ import { Theme } from '@/types/theme'; +import { ArrayClassNamesArg } from '@emotion/css/create-instance'; +import { CSSInterpolation, SerializedStyles } from '@emotion/serialize'; import { Interpolation } from '@emotion/styled'; export type CSSStyle = Array>; export { type CSSObject } from '@emotion/css'; +export type { SerializedStyles } from '@emotion/serialize'; + +export interface CssUtil { + (template: TemplateStringsArray, ...args: Array): SerializedStyles; + (...args: Array): SerializedStyles; +} + +export type ClassNamesArg = + | undefined + | null + | string + | boolean + | { [className: string]: boolean | null | undefined } + | ArrayClassNamesArg + | SerializedStyles; + +/** + * 可以传入多个 css 对象 或者 className 字符串,最终会合并成一个 className 字符串 + * 支持入参:{SerializedStyles} | string + */ +export type ClassNamesUtil = (...classNames: ClassNamesArg[]) => string; diff --git a/src/types/function.ts b/src/types/function.ts index 21517432..56f00acd 100644 --- a/src/types/function.ts +++ b/src/types/function.ts @@ -1,32 +1,31 @@ -import { ClassNamesArg } from '@emotion/css/create-instance'; -import { CSSInterpolation, SerializedStyles } from '@emotion/serialize'; import { ThemeConfig } from 'antd/es/config-provider/context'; -import { AtomInputType } from 'antd-style/src'; import { ThemeAppearance } from './appearance'; +import { ClassNamesUtil, CssUtil, SerializedStyles } from './css'; +import { AtomInputType } from './genericUtils'; import { ResponsiveKey } from './response'; import type { AntdStylish, AntdToken, AppearanceState, FullToken } from './theme'; -export interface EmotionReactCss { - (template: TemplateStringsArray, ...args: Array): SerializedStyles; - (...args: Array): SerializedStyles; -} - -export type EmotionCX = (...classNames: ClassNamesArg[]) => string; - export type BreakpointMapParams = Partial>; -export interface ResponsiveStyleUtil extends Record { - (breakpoints: BreakpointMapParams): any; +/** + * 响应式断点工具函数 + */ +export interface ResponsiveUtil extends Record { + /** + * 支持使用函数表达式 + * @param breakpoints + */ + (breakpoints: BreakpointMapParams): SerializedStyles; } export interface CommonStyleUtils { - cx: EmotionCX; - css: EmotionReactCss; + cx: ClassNamesUtil; + css: CssUtil; /** - * 可以快速创建响应式样式的工具函数 + * 可以快速创建响应式媒体查询的工具函数 */ - responsive: ResponsiveStyleUtil; + responsive: ResponsiveUtil; } /** @@ -36,7 +35,7 @@ export type GetAntdThemeConfig = (appearance: ThemeAppearance) => ThemeConfig | export interface AntdStylishParams extends AppearanceState { token: AntdToken; - css: EmotionReactCss; + css: CssUtil; } /** @@ -58,7 +57,7 @@ export type GetCustomToken = (theme: CustomTokenParams) => T; export interface CustomStylishParams extends AppearanceState { token: FullToken; stylish: AntdStylish; - css: EmotionReactCss; + css: CssUtil; } /** diff --git a/src/types/response.ts b/src/types/response.ts index 6b5d8541..1d493d4b 100644 --- a/src/types/response.ts +++ b/src/types/response.ts @@ -1,3 +1,5 @@ +import { SerializedStyles } from './css'; + export type Breakpoint = | 'xxl' | 'xl' @@ -14,6 +16,6 @@ export type DeviceScreen = 'mobile' | 'tablet' | 'laptop' | 'desktop'; export type ResponsiveKey = Breakpoint | DeviceScreen; // eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface ResponsiveMap extends Record { +export interface ResponsiveMap extends Record { // 在此处扩展响应式映射表 }