From 2a74d88c9109dce07440be122cfafe299bcd2a21 Mon Sep 17 00:00:00 2001 From: neverland Date: Tue, 6 Jul 2021 17:24:22 +0800 Subject: [PATCH] feat(ConfigProvider): add icon-prefix prop (#8986) --- src/config-provider/ConfigProvider.tsx | 27 +++++++++++++------ src/config-provider/README.md | 9 ++++--- src/config-provider/README.zh-CN.md | 9 ++++--- .../test/__snapshots__/index.spec.ts.snap | 6 ----- .../test/__snapshots__/index.spec.tsx.snap | 13 +++++++++ src/config-provider/test/index.spec.ts | 11 -------- src/config-provider/test/index.spec.tsx | 25 +++++++++++++++++ src/icon/Icon.tsx | 23 ++++++++++------ src/utils/format/string.ts | 7 +++++ 9 files changed, 89 insertions(+), 41 deletions(-) delete mode 100644 src/config-provider/test/__snapshots__/index.spec.ts.snap create mode 100644 src/config-provider/test/__snapshots__/index.spec.tsx.snap delete mode 100644 src/config-provider/test/index.spec.ts create mode 100644 src/config-provider/test/index.spec.tsx diff --git a/src/config-provider/ConfigProvider.tsx b/src/config-provider/ConfigProvider.tsx index 8df5ee949..33bbb2ce0 100644 --- a/src/config-provider/ConfigProvider.tsx +++ b/src/config-provider/ConfigProvider.tsx @@ -1,14 +1,22 @@ -import { computed, CSSProperties, defineComponent, PropType } from 'vue'; -import { createNamespace } from '../utils'; +import { + provide, + computed, + PropType, + CSSProperties, + InjectionKey, + defineComponent, +} from 'vue'; +import { createNamespace, kebabCase } from '../utils'; const [name, bem] = createNamespace('config-provider'); -export function kebabCase(word: string) { - return word - .replace(/([A-Z])/g, '-$1') - .toLowerCase() - .replace(/^-/, ''); -} +export type ConfigProviderProvide = { + iconPrefix?: string; +}; + +export const CONFIG_PROVIDER_KEY: InjectionKey = Symbol( + name +); function mapThemeVarsToCSSVars(themeVars: Record) { const cssVars: Record = {}; @@ -23,6 +31,7 @@ export default defineComponent({ props: { themeVars: Object as PropType>, + iconPrefix: String, tag: { type: String as PropType, default: 'div', @@ -36,6 +45,8 @@ export default defineComponent({ } }); + provide(CONFIG_PROVIDER_KEY, props); + return () => ( {slots.default?.()} diff --git a/src/config-provider/README.md b/src/config-provider/README.md index 93a67fe76..070800718 100644 --- a/src/config-provider/README.md +++ b/src/config-provider/README.md @@ -195,7 +195,8 @@ There are some **Basic Variables** below, for component CSS Variables, please re ### Props -| Attribute | Description | Type | Default | -| ------------ | ------------------------ | -------- | ------- | -| theme-vars | Theme variables | _object_ | - | -| tag `v3.1.2` | HTML Tag of root element | _string_ | `div` | +| Attribute | Description | Type | Default | +| -------------------- | ------------------------ | -------- | ---------- | +| theme-vars | Theme variables | _object_ | - | +| tag `v3.1.2` | HTML Tag of root element | _string_ | `div` | +| icon-prefix `v3.1.3` | Icon className prefix | _string_ | `van-icon` | diff --git a/src/config-provider/README.zh-CN.md b/src/config-provider/README.zh-CN.md index d594548c5..7937cc0dd 100644 --- a/src/config-provider/README.zh-CN.md +++ b/src/config-provider/README.zh-CN.md @@ -195,7 +195,8 @@ export default { ### Props -| 参数 | 说明 | 类型 | 默认值 | -| ------------ | ------------------------ | -------- | ------ | -| theme-vars | 自定义主题变量 | _object_ | - | -| tag `v3.1.2` | 根节点对应的 HTML 标签名 | _string_ | `div` | +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| theme-vars | 自定义主题变量 | _object_ | - | +| tag `v3.1.2` | 根节点对应的 HTML 标签名 | _string_ | `div` | +| icon-prefix `v3.1.3` | 所有图标的类名前缀,同 Icon 组件的 [class-prefix 属性](#/zh-CN/icon#props) | _string_ | `van-icon` | diff --git a/src/config-provider/test/__snapshots__/index.spec.ts.snap b/src/config-provider/test/__snapshots__/index.spec.ts.snap deleted file mode 100644 index b481a936f..000000000 --- a/src/config-provider/test/__snapshots__/index.spec.ts.snap +++ /dev/null @@ -1,6 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render tag prop correctly 1`] = ` -
-
-`; diff --git a/src/config-provider/test/__snapshots__/index.spec.tsx.snap b/src/config-provider/test/__snapshots__/index.spec.tsx.snap new file mode 100644 index 000000000..06bb35e4d --- /dev/null +++ b/src/config-provider/test/__snapshots__/index.spec.tsx.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should change icon class-prefix when using icon-prefix prop 1`] = ` +
+ + +
+`; + +exports[`should render tag prop correctly 1`] = ` +
+
+`; diff --git a/src/config-provider/test/index.spec.ts b/src/config-provider/test/index.spec.ts deleted file mode 100644 index 86b0c3ddd..000000000 --- a/src/config-provider/test/index.spec.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ConfigProvider } from '..'; -import { mount } from '../../../test'; - -test('should render tag prop correctly', () => { - const wrapper = mount(ConfigProvider, { - props: { - tag: 'section', - }, - }); - expect(wrapper.html()).toMatchSnapshot(); -}); diff --git a/src/config-provider/test/index.spec.tsx b/src/config-provider/test/index.spec.tsx new file mode 100644 index 000000000..929240fc7 --- /dev/null +++ b/src/config-provider/test/index.spec.tsx @@ -0,0 +1,25 @@ +import { ConfigProvider } from '..'; +import { Icon } from '../../icon'; +import { mount } from '../../../test'; + +test('should render tag prop correctly', () => { + const wrapper = mount(ConfigProvider, { + props: { + tag: 'section', + }, + }); + expect(wrapper.html()).toMatchSnapshot(); +}); + +test('should change icon class-prefix when using icon-prefix prop', () => { + const wrapper = mount({ + render() { + return ( + + + + ); + }, + }); + expect(wrapper.html()).toMatchSnapshot(); +}); diff --git a/src/icon/Icon.tsx b/src/icon/Icon.tsx index 4d8a27abb..8302d1f55 100644 --- a/src/icon/Icon.tsx +++ b/src/icon/Icon.tsx @@ -1,11 +1,12 @@ -import { PropType, defineComponent } from 'vue'; +import { PropType, defineComponent, inject, computed } from 'vue'; import { addUnit, createNamespace } from '../utils'; import { Badge } from '../badge'; +import { CONFIG_PROVIDER_KEY } from '../config-provider/ConfigProvider'; const [name, bem] = createNamespace('icon'); function isImage(name?: string) { - return name ? name.includes('/') : false; + return name?.includes('/'); } export default defineComponent({ @@ -17,19 +18,22 @@ export default defineComponent({ size: [Number, String], badge: [Number, String], color: String, + classPrefix: String, tag: { type: String as PropType, default: 'i', }, - classPrefix: { - type: String, - default: bem(), - }, }, setup(props, { slots }) { + const config = inject(CONFIG_PROVIDER_KEY, null); + + const classPrefix = computed( + () => props.classPrefix || config?.iconPrefix || bem() + ); + return () => { - const { tag, dot, name, size, badge, color, classPrefix } = props; + const { tag, dot, name, size, badge, color } = props; const isImageIcon = isImage(name); return ( @@ -37,7 +41,10 @@ export default defineComponent({ dot={dot} tag={tag} content={badge} - class={[classPrefix, isImageIcon ? '' : `${classPrefix}-${name}`]} + class={[ + classPrefix.value, + isImageIcon ? '' : `${classPrefix.value}-${name}`, + ]} style={{ color, fontSize: addUnit(size), diff --git a/src/utils/format/string.ts b/src/utils/format/string.ts index f801d910b..e1a0cde9f 100644 --- a/src/utils/format/string.ts +++ b/src/utils/format/string.ts @@ -4,6 +4,13 @@ export function camelize(str: string): string { return str.replace(camelizeRE, (_, c) => c.toUpperCase()); } +export function kebabCase(str: string) { + return str + .replace(/([A-Z])/g, '-$1') + .toLowerCase() + .replace(/^-/, ''); +} + export function padZero(num: number | string, targetLength = 2): string { let str = num + '';