From 2b2ef3a3fb90fe7cca0da04ec789fc6e693809b1 Mon Sep 17 00:00:00 2001 From: aibayanyu Date: Sun, 26 Mar 2023 15:49:59 +0800 Subject: [PATCH] feat: add config --- components/components.ts | 1 + components/config-provider/context.ts | 32 ++++-- components/config-provider/hooks/config.ts | 9 ++ components/config-provider/index.tsx | 116 ++++++++++++++++++++- components/config-provider/style/index.ts | 23 ++++ components/theme/internal.ts | 19 +++- 6 files changed, 185 insertions(+), 15 deletions(-) create mode 100644 components/config-provider/hooks/config.ts create mode 100644 components/config-provider/style/index.ts diff --git a/components/components.ts b/components/components.ts index 9743944..fdc9797 100644 --- a/components/components.ts +++ b/components/components.ts @@ -1 +1,2 @@ export { default as Button } from './button' +export { default as ConfigProvider } from './config-provider' diff --git a/components/config-provider/context.ts b/components/config-provider/context.ts index e4319f2..cfcea07 100644 --- a/components/config-provider/context.ts +++ b/components/config-provider/context.ts @@ -4,6 +4,7 @@ import { computed } from 'vue' import type { DerivativeFunc } from '@antd-tiny-vue/cssinjs' import type { AliasToken, MapToken, OverrideToken, SeedToken } from '../theme/interface' import type { RenderEmptyHandler } from './default-render-empty' +import type { ConfigProviderProps } from './index' export type SizeType = 'small' | 'middle' | 'large' | undefined @@ -77,21 +78,36 @@ export const configConsumerProps = { export type ConfigConsumerProps = ExtractPropTypes -const [useProviderConfigProvide, useProviderConfigInject] = createInjectionState(() => { - const getPrefixCls = defaultGetPrefixCls - const iconPrefixCls = computed(() => defaultIconPrefixCls) +const configState = (props: ConfigProviderProps) => { + const getPrefixCls = (suffixCls?: string, customizePrefixCls?: string) => { + const { prefixCls, getPrefixCls } = props + if (customizePrefixCls) return customizePrefixCls + const mergedPrefixCls = prefixCls || getPrefixCls?.('') || defaultGetPrefixCls('') + return suffixCls ? `${mergedPrefixCls}-${suffixCls}` : mergedPrefixCls + } + const iconPrefixCls = computed(() => props?.iconPrefixCls ?? defaultIconPrefixCls) + const shouldWrapSSR = computed(() => iconPrefixCls.value !== defaultIconPrefixCls) + const csp = computed(() => props?.csp) + const componentSize = computed(() => props?.componentSize) + const componentDisabled = computed(() => props?.componentDisabled) return { getPrefixCls, - iconPrefixCls + iconPrefixCls, + shouldWrapSSR, + csp, + componentSize, + componentDisabled } -}) +} +const [useProviderConfigProvide, useProviderConfigInject] = createInjectionState(configState) export { useProviderConfigProvide } -export const useProviderConfigState = () => { +export const useProviderConfigState = (): ReturnType => { return ( - useProviderConfigInject() ?? { + useProviderConfigInject() ?? + ({ getPrefixCls: defaultGetPrefixCls, iconPrefixCls: computed(() => defaultIconPrefixCls) - } + } as any) ) } diff --git a/components/config-provider/hooks/config.ts b/components/config-provider/hooks/config.ts new file mode 100644 index 0000000..5da9fc5 --- /dev/null +++ b/components/config-provider/hooks/config.ts @@ -0,0 +1,9 @@ +import { useProviderConfigState } from '../context' + +export const useConfig = () => { + const { componentDisabled, componentSize } = useProviderConfigState() + return { + componentDisabled, + componentSize + } +} diff --git a/components/config-provider/index.tsx b/components/config-provider/index.tsx index ef471c2..f182f50 100644 --- a/components/config-provider/index.tsx +++ b/components/config-provider/index.tsx @@ -1,19 +1,44 @@ -import { booleanType, someType, stringType } from '@v-c/utils' -import type { ExtractPropTypes } from 'vue' -import type { SizeType, Theme } from './context' -import { configConsumerProps, defaultIconPrefixCls } from './context' +import { booleanType, objectType, someType, stringType } from '@v-c/utils' +import type { App, ExtractPropTypes } from 'vue' +import { computed, defineComponent } from 'vue' +import { createTheme } from '@antd-tiny-vue/cssinjs' +import defaultSeedToken from '../theme/themes/seed' +import type { DesignTokenConfig } from '../theme/internal' +import { DesignTokenProviderContext } from '../theme/internal' +import type { CSPConfig, ConfigConsumerProps, DirectionType, SizeType, Theme, ThemeConfig } from './context' +import { configConsumerProps, defaultIconPrefixCls, useProviderConfigProvide } from './context' import { registerTheme } from './css-variables' +import type { RenderEmptyHandler } from './default-render-empty' +import useStyle from './style' +import { useConfig } from './hooks/config' +export type { RenderEmptyHandler, CSPConfig, DirectionType, ConfigConsumerProps, ThemeConfig } + +export { defaultIconPrefixCls } export const configProviderProps = { ...configConsumerProps, prefixCls: stringType(), componentSize: someType([String]), - componentDisabled: booleanType() + componentDisabled: booleanType(), + legacyLocale: objectType() } export type ConfigProviderProps = Partial> export const defaultPrefixCls = 'ant' + +// These props is used by `useContext` directly in sub component +// const PASSED_PROPS: Exclude[] = [ +// 'getTargetContainer', +// 'getPopupContainer', +// 'renderEmpty', +// 'pageHeader', +// 'input', +// 'pagination', +// 'form', +// 'select' +// ] + let globalPrefixCls: string let globalIconPrefixCls: string @@ -54,3 +79,84 @@ export const globalConfig = () => ({ return getGlobalPrefixCls() } }) + +const ConfigProvider = defineComponent({ + name: 'AConfigProvider', + props: { + ...configProviderProps + }, + setup(props, { slots }) { + // 依赖注入 + const { shouldWrapSSR, iconPrefixCls } = useProviderConfigProvide(props) + const wrapSSR = useStyle(iconPrefixCls) + const memoTheme = computed(() => { + const { algorithm, token, ...rest } = props.theme || {} + const themeObj = algorithm && (!Array.isArray(algorithm) || algorithm.length > 0) ? createTheme(algorithm) : undefined + return { + ...rest, + theme: themeObj, + token: { + ...defaultSeedToken, + ...token + } + } + }) + + return () => { + const { locale, theme } = props + const children = slots.default?.() + let childNode = shouldWrapSSR.value ? wrapSSR(children) : children + + /** + * Form + */ + // const validateMessages = React.useMemo( + // () => + // setValues( + // {}, + // defaultLocale.Form?.defaultValidateMessages || {}, + // memoedConfig.locale?.Form?.defaultValidateMessages || {}, + // form?.validateMessages || {}, + // ), + // [memoedConfig, form?.validateMessages], + // ); + // + // if (Object.keys(validateMessages).length > 0) { + // childNode = {children}; + // } + /** + * 多语言实现部分 + */ + if (locale) { + // 多语言部分 + // childNode = {childNode}; + } + + if (theme) { + childNode = ( + + {childNode} + + ) + } + + return childNode + } + } +}) + +ConfigProvider.install = (app: App) => { + app.component(ConfigProvider.name, ConfigProvider) +} + +ConfigProvider.config = setGlobalConfig + +ConfigProvider.useConfig = useConfig +export default ConfigProvider as typeof ConfigProvider & { + install(app: App): void + config: typeof setGlobalConfig + useConfig: typeof useConfig +} diff --git a/components/config-provider/style/index.ts b/components/config-provider/style/index.ts new file mode 100644 index 0000000..2594dd1 --- /dev/null +++ b/components/config-provider/style/index.ts @@ -0,0 +1,23 @@ +import { useStyleRegister } from '@antd-tiny-vue/cssinjs' +import type { Ref } from 'vue' +import { computed } from 'vue' +import { resetIcon } from '../../style' +import { useToken } from '../../theme/internal' + +const useStyle = (iconPrefixCls: Ref) => { + const [theme, token] = useToken() + // Generate style for icons + const info = computed(() => ({ theme: theme.value, token: token.value, hashId: '', path: ['ant-design-icons', iconPrefixCls.value] })) + return useStyleRegister(info, () => [ + { + [`.${iconPrefixCls.value}`]: { + ...resetIcon(), + [`.${iconPrefixCls.value} .${iconPrefixCls.value}-icon`]: { + display: 'block' + } + } + } + ]) +} + +export default useStyle diff --git a/components/theme/internal.ts b/components/theme/internal.ts index 6b5a5e2..f4f9358 100644 --- a/components/theme/internal.ts +++ b/components/theme/internal.ts @@ -1,8 +1,8 @@ import type { CSSInterpolation, Theme } from '@antd-tiny-vue/cssinjs' import { createTheme, useCacheToken, useStyleRegister } from '@antd-tiny-vue/cssinjs' -import { createInjectionState } from '@v-c/utils' +import { createInjectionState, objectType, someType } from '@v-c/utils' import type { ComputedRef, VNodeChild } from 'vue' -import { computed } from 'vue' +import { computed, defineComponent } from 'vue' import version from '../version' import type { AliasToken, GlobalToken, MapToken, OverrideToken, PresetColorKey, PresetColorType, SeedToken } from './interface' import { PresetColors } from './interface' @@ -54,6 +54,21 @@ const [useDesignTokenProvider, useDesignTokenInject] = createInjectionState((tok return token }) +export const DesignTokenProviderContext = defineComponent({ + props: { + token: objectType(), + theme: objectType>(), + components: objectType(), + hashed: someType([String, Boolean]) + }, + setup(props, { slots }) { + useDesignTokenProvider(props) + return () => { + return slots.default?.() + } + } +}) + export { useDesignTokenProvider } export const useDesignTokenState = () => useDesignTokenInject() ?? defaultConfig