diff --git a/examples/sites/demos/apis/config-provider.js b/examples/sites/demos/apis/config-provider.js index 51cea1588a..102fece15b 100644 --- a/examples/sites/demos/apis/config-provider.js +++ b/examples/sites/demos/apis/config-provider.js @@ -38,6 +38,20 @@ export default { }, mode: ['pc'], pcDemo: 'tag' + }, + { + name: 'theme', + type: 'object', + defaultValue: '--', + meta: { + stable: '3.23.0' + }, + desc: { + 'zh-CN': '自定义主题色,格式:{data:{"tv-base-color-brand":"#595959",....}}', + 'en-US': 'Customized theme color, in {data:"tv-base-color-brand":"#595959",....} format.' + }, + mode: ['pc'], + pcDemo: 'theme' } ], events: [], diff --git a/examples/sites/demos/apis/tabs.js b/examples/sites/demos/apis/tabs.js index 9f556b946e..276c7ac249 100644 --- a/examples/sites/demos/apis/tabs.js +++ b/examples/sites/demos/apis/tabs.js @@ -138,6 +138,17 @@ export default { pcDemo: 'size', mfDemo: '' }, + { + name: 'swipeable', + type: 'boolean', + defaultValue: 'false', + desc: { + 'zh-CN': '是否开启滑动内容切换标签页', + 'en-US': 'Do you want to enable the sliding content switching tab function' + }, + mode: ['mobile-first'], + mfDemo: 'swipeable' + }, { name: 'stretch', type: 'boolean', diff --git a/examples/sites/demos/mobile-first/app/tabs/swipeable.vue b/examples/sites/demos/mobile-first/app/tabs/swipeable.vue new file mode 100644 index 0000000000..3250b1173d --- /dev/null +++ b/examples/sites/demos/mobile-first/app/tabs/swipeable.vue @@ -0,0 +1,50 @@ + + + diff --git a/examples/sites/demos/mobile-first/app/tabs/webdoc/tabs.js b/examples/sites/demos/mobile-first/app/tabs/webdoc/tabs.js index 1b65b13506..ee99235d3e 100644 --- a/examples/sites/demos/mobile-first/app/tabs/webdoc/tabs.js +++ b/examples/sites/demos/mobile-first/app/tabs/webdoc/tabs.js @@ -29,6 +29,19 @@ export default { }, codeFiles: ['align-center.vue'] }, + { + demoId: 'swipeable', + name: { + 'zh-CN': '滑动切换内容', + 'en-US': 'Slide to switch content' + }, + desc: { + 'zh-CN': + '

在关闭优化渲染并且所有标签项都不开启延时加载时,可通过 :swipeable=true 开启滑动内容切换标签页。在此模式下,标签项内容区可以是一个水平滚动列表,参考示例中 `表单组件` 标签项。

', + 'en-US': `

When optimizing rendering is turned off and all label items do not enable lazy loading, you can use: swift=trueto enable sliding content to switch tabs. In this mode, the tag item content area can be a horizontally scrolling list, as shown in the example of the 'form component' tag item.

` + }, + codeFiles: ['swipeable.vue'] + }, { demoId: 'tab-style-card', name: { diff --git a/examples/sites/demos/pc/app/config-provider/theme-composition-api.vue b/examples/sites/demos/pc/app/config-provider/theme-composition-api.vue new file mode 100644 index 0000000000..11bcef86b5 --- /dev/null +++ b/examples/sites/demos/pc/app/config-provider/theme-composition-api.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/examples/sites/demos/pc/app/config-provider/theme.vue b/examples/sites/demos/pc/app/config-provider/theme.vue new file mode 100644 index 0000000000..f687a11e69 --- /dev/null +++ b/examples/sites/demos/pc/app/config-provider/theme.vue @@ -0,0 +1,51 @@ + + + + + diff --git a/examples/sites/demos/pc/app/config-provider/webdoc/config-provider.js b/examples/sites/demos/pc/app/config-provider/webdoc/config-provider.js index b463ed71e0..f49b70845f 100644 --- a/examples/sites/demos/pc/app/config-provider/webdoc/config-provider.js +++ b/examples/sites/demos/pc/app/config-provider/webdoc/config-provider.js @@ -43,6 +43,18 @@ export default { 'en-US': 'Container labels can be customized throughtag.' }, codeFiles: ['tag.vue'] + }, + { + demoId: 'theme', + name: { + 'zh-CN': '自定义主题色', + 'en-US': 'Custom Colors' + }, + desc: { + 'zh-CN': '可通过theme属性设置自定义主题色常量。', + 'en-US': 'You can use the theme property to set a custom theme color constant.' + }, + codeFiles: ['theme.vue'] } ], features: [ diff --git a/packages/theme-saas/src/svgs/go-back.svg b/packages/theme-saas/src/svgs/go-back.svg index 1e9c3f0461..ae583f7823 100644 --- a/packages/theme-saas/src/svgs/go-back.svg +++ b/packages/theme-saas/src/svgs/go-back.svg @@ -1,16 +1,5 @@ - - - - - - + + + + diff --git a/packages/utils/src/common/index.ts b/packages/utils/src/common/index.ts index 365cd1d59f..1d377f868c 100644 --- a/packages/utils/src/common/index.ts +++ b/packages/utils/src/common/index.ts @@ -308,3 +308,27 @@ export const CASCADER: Record = { PropsHover: 'hoverThreshold', MenuConnector: 'cascader-menu-' } + +/** + * 检查对象是否具有任何一个指定的键 + * @param obj 需要检查的对象 + * @param keys 需要检查的键的数组 + * @return 如果对象具有任何一个指定的键,返回true,否则返回false + */ +export const hasAnyKey = (obj: any, keys: string[]): boolean => { + if (obj == null) { + return false + } + + if (keys.length === 0) { + return false + } + + for (const key of keys) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + return true + } + } + + return false +} diff --git a/packages/vue/src/config-provider/package.json b/packages/vue/src/config-provider/package.json index 1032b24292..862ddd0e23 100644 --- a/packages/vue/src/config-provider/package.json +++ b/packages/vue/src/config-provider/package.json @@ -15,7 +15,8 @@ }, "dependencies": { "@opentiny/vue-common": "workspace:~", - "@opentiny/vue-theme": "workspace:~" + "@opentiny/vue-theme": "workspace:~", + "@opentiny/utils": "workspace:~" }, "license": "MIT" } diff --git a/packages/vue/src/config-provider/src/index.vue b/packages/vue/src/config-provider/src/index.vue index 5747f84118..c1bdb12d52 100644 --- a/packages/vue/src/config-provider/src/index.vue +++ b/packages/vue/src/config-provider/src/index.vue @@ -4,6 +4,32 @@ import type { PropType } from '@opentiny/vue-common' import type { Tag, TextDirection, breakPoint } from './props' import { configProviderContextKey } from '../index' import '@opentiny/vue-theme/config-provider/index.less' +import TinyThemeTool from '@opentiny/vue-theme/theme-tool' +import { isObject } from '@opentiny/utils' + +/** + * 检查对象是否具有任何一个指定的键 + * @param obj 需要检查的对象 + * @param keys 需要检查的键的数组 + * @return 如果对象具有任何一个指定的键,返回true,否则返回false + */ +const hasAnyKey = (obj: any, keys: string[]): boolean => { + if (obj == null) { + return false + } + + if (keys.length === 0) { + return false + } + + for (const key of keys) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + return true + } + } + + return false +} export default defineComponent({ name: $prefix + 'ConfigProvider', @@ -42,6 +68,12 @@ export default defineComponent({ } } }, + theme: { + type: Object, + default: () => { + return null + } + }, ..._props .map((item) => { return { @@ -58,8 +90,28 @@ export default defineComponent({ }) }, setup(props, { slots }) { - const { direction, design } = hooks.toRefs(props) + const { direction, design, theme } = hooks.toRefs(props) provideDesignConfig(design) + hooks.watch( + () => theme.value, + () => { + if (isObject(theme.value) && hasAnyKey(theme.value, ['data'])) { + const themeTool = new TinyThemeTool() + themeTool.changeTheme(theme.value) + } + + if (isObject(theme.value) && !hasAnyKey(theme.value, ['data'])) { + console.warn(`configProvider组件的theme属性对象请配置data属性。e.g { data: {'tv-base-color-brand': '#000'}}`) + } + + if (theme.value && !isObject(theme.value)) { + console.warn(`configProvider组件的theme属性请配置对象格式数据`) + } + }, + { + immediate: true + } + ) const isRTL = hooks.computed(() => direction.value === 'rtl') const cssVar = hooks.computed(() => { return { diff --git a/packages/vue/src/config-provider/src/props.ts b/packages/vue/src/config-provider/src/props.ts index 121dc7ddca..ab13e2c81c 100644 --- a/packages/vue/src/config-provider/src/props.ts +++ b/packages/vue/src/config-provider/src/props.ts @@ -20,4 +20,5 @@ export interface ConfigProviderProps { enable?: boolean name?: string } + theme?: Object | null }