From c6e756c1f0638737649ea28b9ccea400beceae26 Mon Sep 17 00:00:00 2001 From: devin Date: Fri, 6 Jan 2023 09:35:33 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=A2=9E=E5=8A=A0tabs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/docs/tab.md | 17 ++++++ .../src/components/tabs/OTabPane.vue | 52 +++++++++++++++++++ .../opendesign/src/components/tabs/OTabs.vue | 46 ++++++++++++++++ .../components/tabs/__demo__/IndexTabs.vue | 11 ++++ .../components/tabs/__demo__/TabsDefault.vue | 28 ++++++++++ .../opendesign/src/components/tabs/index.ts | 12 +++++ .../opendesign/src/components/tabs/provide.ts | 10 ++++ .../src/components/tabs/style/index.scss | 8 +++ .../src/components/tabs/style/index.ts | 1 + .../src/components/tabs/style/var.scss | 33 ++++++++++++ .../opendesign/src/components/tabs/types.ts | 0 packages/portal/src/router.ts | 6 +++ 12 files changed, 224 insertions(+) create mode 100644 packages/docs/tab.md create mode 100644 packages/opendesign/src/components/tabs/OTabPane.vue create mode 100644 packages/opendesign/src/components/tabs/OTabs.vue create mode 100644 packages/opendesign/src/components/tabs/__demo__/IndexTabs.vue create mode 100644 packages/opendesign/src/components/tabs/__demo__/TabsDefault.vue create mode 100644 packages/opendesign/src/components/tabs/index.ts create mode 100644 packages/opendesign/src/components/tabs/provide.ts create mode 100644 packages/opendesign/src/components/tabs/style/index.scss create mode 100644 packages/opendesign/src/components/tabs/style/index.ts create mode 100644 packages/opendesign/src/components/tabs/style/var.scss create mode 100644 packages/opendesign/src/components/tabs/types.ts diff --git a/packages/docs/tab.md b/packages/docs/tab.md new file mode 100644 index 00000000..7e970cae --- /dev/null +++ b/packages/docs/tab.md @@ -0,0 +1,17 @@ +# Tab 页签 + +## props + +| name | type | 默认值 | 说明 | +| :--------- | :-------------------------- | :----- | -------- | +| modelValue | string \| number(v-model) | false | 开关状态 | + +## event + +| name | 参数 | 说明 | +| :----- | :------------------------ | :------------- | +| change | value: boolean; ev: Event | 选择切换后触发 | + +## expose + +## slot diff --git a/packages/opendesign/src/components/tabs/OTabPane.vue b/packages/opendesign/src/components/tabs/OTabPane.vue new file mode 100644 index 00000000..f013f9ad --- /dev/null +++ b/packages/opendesign/src/components/tabs/OTabPane.vue @@ -0,0 +1,52 @@ + + diff --git a/packages/opendesign/src/components/tabs/OTabs.vue b/packages/opendesign/src/components/tabs/OTabs.vue new file mode 100644 index 00000000..d64de569 --- /dev/null +++ b/packages/opendesign/src/components/tabs/OTabs.vue @@ -0,0 +1,46 @@ + + diff --git a/packages/opendesign/src/components/tabs/__demo__/IndexTabs.vue b/packages/opendesign/src/components/tabs/__demo__/IndexTabs.vue new file mode 100644 index 00000000..35e857c7 --- /dev/null +++ b/packages/opendesign/src/components/tabs/__demo__/IndexTabs.vue @@ -0,0 +1,11 @@ + + + diff --git a/packages/opendesign/src/components/tabs/__demo__/TabsDefault.vue b/packages/opendesign/src/components/tabs/__demo__/TabsDefault.vue new file mode 100644 index 00000000..f24ac97b --- /dev/null +++ b/packages/opendesign/src/components/tabs/__demo__/TabsDefault.vue @@ -0,0 +1,28 @@ + + + diff --git a/packages/opendesign/src/components/tabs/index.ts b/packages/opendesign/src/components/tabs/index.ts new file mode 100644 index 00000000..4290a713 --- /dev/null +++ b/packages/opendesign/src/components/tabs/index.ts @@ -0,0 +1,12 @@ +import _OTabs from './OTabs.vue'; +import OTabPane from './OTabPane.vue'; +import type { App } from 'vue'; + +const OTabs = Object.assign(_OTabs, { + OTabPane, + install(app: App) { + app.component(_OTabs.name, _OTabs); + }, +}); + +export { OTabs, OTabPane }; diff --git a/packages/opendesign/src/components/tabs/provide.ts b/packages/opendesign/src/components/tabs/provide.ts new file mode 100644 index 00000000..b661adef --- /dev/null +++ b/packages/opendesign/src/components/tabs/provide.ts @@ -0,0 +1,10 @@ +import { InjectionKey, Ref } from 'vue'; + + +export const tabsInjectKey: InjectionKey<{ + value: Ref + navRefs: Record>, + addTabNav: (value: string | number) => void, +}> = + Symbol('provide-tabs'); + diff --git a/packages/opendesign/src/components/tabs/style/index.scss b/packages/opendesign/src/components/tabs/style/index.scss new file mode 100644 index 00000000..25d3f8f9 --- /dev/null +++ b/packages/opendesign/src/components/tabs/style/index.scss @@ -0,0 +1,8 @@ +@import './var.scss'; + +.o-tabs-navs { + display: flex; +} +.o-tabs-nav { + padding: 4px 8px; +} diff --git a/packages/opendesign/src/components/tabs/style/index.ts b/packages/opendesign/src/components/tabs/style/index.ts new file mode 100644 index 00000000..67aac616 --- /dev/null +++ b/packages/opendesign/src/components/tabs/style/index.ts @@ -0,0 +1 @@ +import './index.scss'; diff --git a/packages/opendesign/src/components/tabs/style/var.scss b/packages/opendesign/src/components/tabs/style/var.scss new file mode 100644 index 00000000..3788e559 --- /dev/null +++ b/packages/opendesign/src/components/tabs/style/var.scss @@ -0,0 +1,33 @@ +.o-select { + --select-text-size: var(--o-font_size-text); + --select-text-height: var(--o-line_height-text); + + --select-height-s: var(--o-size-s); + --select-height-m: var(--o-size-m); + --select-height-l: var(--o-size-l); + + --select-radius-s: var(--o-radius-s); + --select-radius-m: var(--o-radius-s); + --select-radius-l: var(--o-radius-s); + + --select-border: var(--o-color-info1); + --select-border_hover: var(--o-color-primary2); + --select-border_active: var(--o-color-primary3); + --select-border_disabled: var(--o-color-info1); + + --select-bg: var(--o-color-bg1); + --select-bg_hover: var(--o-color-bg2); + --select-bg_disabled: var(--o-color-info4); + + --select-color: var(--o-color-text2); + --select-color_disabled: var(--o-color-text4); + + --select-icon-color: var(--o-color-text3); +} + +.o-select-options { + --select-options-bg: var(--o-color-bg2); + --select-options-shadow: none; + --select-options-border: 1px solid var(--o-color-primary2); + --select-options-radius: var(--o-radius-s); +} diff --git a/packages/opendesign/src/components/tabs/types.ts b/packages/opendesign/src/components/tabs/types.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/portal/src/router.ts b/packages/portal/src/router.ts index ce56d602..d7fea009 100644 --- a/packages/portal/src/router.ts +++ b/packages/portal/src/router.ts @@ -69,6 +69,12 @@ export const routes = [ label: '多选', component: () => import('@demo/checkbox/__demo__/IndexCheckbox.vue'), }, + { + path: '/tabs', + name: 'Tabs', + label: '标签页', + component: () => import('@demo/tabs/__demo__/IndexTabs.vue'), + }, ]; export const router = createRouter({ -- Gitee From 5d8a109120dc5845bb28a8b3acad0ea695b45cfc Mon Sep 17 00:00:00 2001 From: devin Date: Fri, 6 Jan 2023 23:05:58 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E5=A2=9E=E5=8A=A0tabs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/docs/tab.md | 42 +++++- .../src/components/_shared/icons.ts | 10 +- .../src/components/_shared/vue-utils.ts | 60 +++++++++ .../src/components/popover/OPopover.vue | 4 +- .../src/components/popup/OPopup.vue | 15 ++- .../popup/__demo__/PopupContainer.vue | 2 +- .../src/components/select/OSelect.vue | 12 +- .../src/components/style/animation.scss | 40 +++++- .../src/components/style/index.scss | 4 +- .../src/components/tabs/OTabPane.vue | 124 +++++++++++------- .../opendesign/src/components/tabs/OTabs.vue | 98 +++++++++++--- .../src/components/tabs/TabContent.vue | 83 ++++++++++++ .../opendesign/src/components/tabs/TabNav.vue | 96 ++++++++++++++ .../components/tabs/__demo__/TabsDefault.vue | 48 ++++--- .../opendesign/src/components/tabs/provide.ts | 24 +++- .../src/components/tabs/style/index.scss | 71 +++++++++- .../src/components/tabs/style/var.scss | 35 +---- 17 files changed, 627 insertions(+), 141 deletions(-) create mode 100644 packages/opendesign/src/components/_shared/vue-utils.ts create mode 100644 packages/opendesign/src/components/tabs/TabContent.vue create mode 100644 packages/opendesign/src/components/tabs/TabNav.vue diff --git a/packages/docs/tab.md b/packages/docs/tab.md index 7e970cae..d66adef0 100644 --- a/packages/docs/tab.md +++ b/packages/docs/tab.md @@ -2,16 +2,46 @@ ## props -| name | type | 默认值 | 说明 | -| :--------- | :-------------------------- | :----- | -------- | -| modelValue | string \| number(v-model) | false | 开关状态 | +### OTabs + +| name | type | 默认值 | 说明 | +| :--------- | :-------------------------- | :----- | ------------------------------ | +| modelValue | string \| number(v-model) | '' | 开关状态 | +| lazy | boolean | false | 是否在首次激活标签时再挂载内容 | + +### OTabPane + +| name | type | 默认值 | 说明 | +| :------------ | :--------------- | :-------------- | ------------------------------ | +| value | string \| number | uid | tab id | +| label | string | undefined | 页签文本 | +| transition | string | o-fade-up-enter | 页签切换时过渡动画 | +| lazy | boolean | false | 是否在首次激活标签时再挂载内容 | +| unmountOnHide | boolean | false | 是否在未激活时卸载页签内容 | +| disabled | boolean | false | 是否禁用选中 | +| closable | boolean | false | 是否可以删除 | ## event -| name | 参数 | 说明 | -| :----- | :------------------------ | :------------- | -| change | value: boolean; ev: Event | 选择切换后触发 | +### OTabs + +| name | 参数 | 说明 | +| :----- | :-------------------------------------------------- | :------------- | +| change | value: string \| number, oldValue: string \| number | 页签切换后触发 | +| delete | value: string \| number | 页签删除后触发 | ## expose ## slot + +### OTabs + +| name | 说明 | +| :--- | :------------------- | +| act | 页签右侧额外内容插槽 | + +### OTabPane + +| name | 说明 | +| :--- | :------- | +| nav | 页签插槽 | diff --git a/packages/opendesign/src/components/_shared/icons.ts b/packages/opendesign/src/components/_shared/icons.ts index 27320a3a..97c71eb7 100644 --- a/packages/opendesign/src/components/_shared/icons.ts +++ b/packages/opendesign/src/components/_shared/icons.ts @@ -5,7 +5,8 @@ import { Component, shallowRef } from 'vue'; import { IconLoading as _IconLoading, IconLink as IconLink, - IconArrowRight + IconArrowRight, + IconX } from '../icons'; /** @@ -30,4 +31,11 @@ export function initLinkPrefixIcon(icon: Component) { export const IconLinkArrow = shallowRef(IconArrowRight); export function initLinkArrowIcon(icon: Component) { IconLinkArrow.value = icon; +} +/** + * close图标 + */ +export const IconClose = shallowRef(IconX); +export function initCloseIcon(icon: Component) { + IconClose.value = icon; } \ No newline at end of file diff --git a/packages/opendesign/src/components/_shared/vue-utils.ts b/packages/opendesign/src/components/_shared/vue-utils.ts new file mode 100644 index 00000000..8a5dbc94 --- /dev/null +++ b/packages/opendesign/src/components/_shared/vue-utils.ts @@ -0,0 +1,60 @@ +import { Component, onMounted, Slots, VNode, VNodeTypes } from 'vue'; + +// 来着vuejs/core +// https://github.com/vuejs/core/blob/main/packages/shared/src/shapeFlags.ts +export const enum ShapeFlags { + ELEMENT = 1, + FUNCTIONAL_COMPONENT = 1 << 1, + STATEFUL_COMPONENT = 1 << 2, + TEXT_CHILDREN = 1 << 3, + ARRAY_CHILDREN = 1 << 4, + SLOTS_CHILDREN = 1 << 5, + TELEPORT = 1 << 6, + SUSPENSE = 1 << 7, + COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8, + COMPONENT_KEPT_ALIVE = 1 << 9, + COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT +} +/** + * 判断vnode是不是element + */ +export const isElement = (vnode: VNode) => { + return Boolean(vnode && vnode.shapeFlag & ShapeFlags.ELEMENT); +}; + +/** + * 判断vnode是不是vue组件 + * @param vnode vnode节点 + * @param type 组件信息 + */ +export function isComponent(vnode: VNode, type?: VNodeTypes): type is Component { + return Boolean(vnode && vnode.shapeFlag & ShapeFlags.COMPONENT); +} +/** + * 判断vnode是不是vue组件 + */ +export const isSlotsChildren = (vnode: VNode, children: VNode['children']): children is Slots => { + return Boolean(vnode && vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN); +}; + +// TODO +export function useSlotElement(componentName?: string) { + let children: VNode[] | null = null; + const components = []; + // const + onMounted(() => { + children?.forEach(child => { + console.log(child, isComponent(child)); + if (isComponent(child, child.type)) { + if (componentName && child.type.name === componentName) { + components.push(child); + } + } + }); + }); + return { + setSlotChildren(nodes: VNode[]) { + children = nodes; + } + }; +} \ No newline at end of file diff --git a/packages/opendesign/src/components/popover/OPopover.vue b/packages/opendesign/src/components/popover/OPopover.vue index dd13980a..174d3993 100644 --- a/packages/opendesign/src/components/popover/OPopover.vue +++ b/packages/opendesign/src/components/popover/OPopover.vue @@ -43,7 +43,7 @@ const props = defineProps({ /** * 是否在隐藏时卸载 */ - unmountOnClose: { + unmountOnHide: { type: Boolean, default: true, }, @@ -71,7 +71,7 @@ const updateVisible = (val: boolean) => { :target="props.target" :wrapper="props.wrapper" anchor-class="o-popover-anchor" - :unmount-on-close="props.unmountOnClose" + :unmount-on-hide="props.unmountOnHide" @update:visible="updateVisible" >
diff --git a/packages/opendesign/src/components/popup/OPopup.vue b/packages/opendesign/src/components/popup/OPopup.vue index 8f4c04d8..7ef18ecc 100644 --- a/packages/opendesign/src/components/popup/OPopup.vue +++ b/packages/opendesign/src/components/popup/OPopup.vue @@ -85,7 +85,7 @@ const props = defineProps({ /** * 是否在popup隐藏时unmout */ - unmountOnClose: { + unmountOnHide: { type: Boolean, default: true, }, @@ -117,6 +117,13 @@ const props = defineProps({ type: Boolean, default: true, }, + /** + * 过渡名称 + */ + transition: { + type: String, + default: 'o-zoom-fade', + }, }); const emits = defineEmits<{ (e: 'update:visible', val: boolean): void; (e: 'change', val: boolean): void }>(); @@ -307,7 +314,7 @@ const handleTransitionStart = () => { }; const handleTransitionEnd = () => { isAnimating.value = false; - if (!visible.value && props.unmountOnClose) { + if (!visible.value && props.unmountOnHide) { toMount.value = false; } }; @@ -424,7 +431,7 @@ onUnmounted(() => {