From 42e6c8c0e68f64463de6221be7b8084999dd0c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=B8=85?= Date: Sun, 2 Oct 2022 16:38:32 +0800 Subject: [PATCH] =?UTF-8?q?=EF=BC=9A=E6=A0=87=E7=AD=BE=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E5=8A=9F=E8=83=BD=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tabs/src/components/tab-page.props.ts | 3 +- .../tabs/src/composition/use-tabs.ts | 19 +++ .../components/tabs/src/tabs.component.tsx | 108 +++++++++++++----- packages/ui-vue/components/tabs/src/tabs.css | 84 ++++++++++++++ .../ui-vue/components/tabs/src/tabs.props.ts | 1 + packages/ui-vue/src/App.vue | 2 + packages/ui-vue/src/components/tabs.vue | 13 +++ 7 files changed, 201 insertions(+), 29 deletions(-) create mode 100644 packages/ui-vue/components/tabs/src/composition/use-tabs.ts create mode 100644 packages/ui-vue/components/tabs/src/tabs.css create mode 100644 packages/ui-vue/src/components/tabs.vue diff --git a/packages/ui-vue/components/tabs/src/components/tab-page.props.ts b/packages/ui-vue/components/tabs/src/components/tab-page.props.ts index 5d62783..9950369 100644 --- a/packages/ui-vue/components/tabs/src/components/tab-page.props.ts +++ b/packages/ui-vue/components/tabs/src/components/tab-page.props.ts @@ -8,6 +8,7 @@ export const tabPageProps = { title: { type: String, default: '' }, selected: { type: Boolean, default: false }, disabled: { type: Boolean, default: false }, - removeable: { type: Boolean, default: false } + removeable: { type: Boolean, default: false }, + show: { type: Boolean, default: true } }; export type TabPageProps = ExtractPropTypes; diff --git a/packages/ui-vue/components/tabs/src/composition/use-tabs.ts b/packages/ui-vue/components/tabs/src/composition/use-tabs.ts new file mode 100644 index 0000000..49601bd --- /dev/null +++ b/packages/ui-vue/components/tabs/src/composition/use-tabs.ts @@ -0,0 +1,19 @@ +import { computed, ComputedRef, Ref, ref, SetupContext, watch } from 'vue'; +import { TabsProps } from '../tabs.props'; + +export function useTabs( + props: TabsProps, + context: SetupContext +): any { + + function setActiveId(tabs: Ref, activeId: Ref) { + const index = tabs.value.findIndex(tab => tab.show !== false && !activeId.value && !tab.disabled) + if (!activeId.value && index !== -1) { + activeId.value = tabs.value[index].id + } + } + + return { + setActiveId + }; +} diff --git a/packages/ui-vue/components/tabs/src/tabs.component.tsx b/packages/ui-vue/components/tabs/src/tabs.component.tsx index 49211be..98819d8 100644 --- a/packages/ui-vue/components/tabs/src/tabs.component.tsx +++ b/packages/ui-vue/components/tabs/src/tabs.component.tsx @@ -1,12 +1,14 @@ import { computed, defineComponent, ref, SetupContext } from 'vue'; import { TabsProps, tabsProps } from './tabs.props'; +import './tabs.css' +import { useTabs } from './composition/use-tabs'; export default defineComponent({ name: 'FTabs', props: tabsProps, emits: [], setup(props: TabsProps, context: SetupContext) { - const hideButtons = ref(false); + const hideButtons = ref(true); const hideDropDown = ref(false); @@ -20,7 +22,9 @@ export default defineComponent({ const position = ref(props.position); - const tabs = ref([]); + const tabs = ref([] as any[]); + + const activeId = ref(props.activeId); const shouldShowNavFill = computed(() => { fill.value || tabType.value === 'fill'; @@ -28,6 +32,8 @@ export default defineComponent({ const shouldShowNavPills = computed(() => {}); + const { setActiveId } = useTabs(props, context) + const tabsHeaderClass = computed(() => ({ 'farris-tabs-header': true, 'farris-tabs-inHead': hasInHeadClass.value, @@ -64,16 +70,39 @@ export default defineComponent({ 'flex-row': position.value === 'top' || position.value === 'bottom', 'flex-column': position.value === 'left' || position.value === 'right', })); + + let tabPages = context.slots.default && context.slots.default() + + tabPages?.forEach((tabPage: any) => { + tabs.value.push(tabPage.props) + }) + + setActiveId(tabs, activeId) + + const tabsContainerClass = computed(() => ({ + 'farris-tabs': true, + 'farris-tabs-top': position.value === 'top', + 'farris-tabs-bottom': position.value === 'bottom', + 'farris-tabs-left': position.value === 'left', + 'farris-tabs-right': position.value === 'right' + })) function getTabClass(tab: any) { return { 'nav-item': true, - 'd-none': !tab.show, - 'f-state-active': tab.id === activeId, + 'd-none': tab.show !== undefined ? !tab.show : false, + 'f-state-active': tab.id === activeId.value, 'f-state-disable': tab.disabled, }; } + function getTabPageStyle(tabPage) { + const props: any = tabPage.props + return { + display: props.id === activeId.value ? '' : 'none' + } + } + function getTabStyle(tab: any) { return { width: `${tab.tabWidth}px` }; } @@ -81,13 +110,17 @@ export default defineComponent({ function getTabNavLinkClass(tab: any) { return { 'nav-link': true, - 'tabs-text-truncate': true, - active: tab.id === activeId, + // 'tabs-text-truncate': true, + active: tab.id === activeId.value, disabled: tab.disabled, }; } - function selectTabByIndex($event: Event, targetTabId: string) {} + function selectTabByIndex($event: Event, targetTabId: string) { + activeId.value = targetTabId + $event.preventDefault(); + $event.stopPropagation(); + } function getTabTextClass(tab: any) { return { @@ -97,33 +130,52 @@ export default defineComponent({ }; } + function removeTab($event: Event, targetTabId: string) { + tabs.value = tabs.value.filter(tab => tab.id !== targetTabId) + tabPages = tabPages?.filter(tabPage => (tabPage.props as any).id !== targetTabId) + if (activeId.value === targetTabId) { + activeId.value = '' + setActiveId(tabs, activeId) + } + $event.preventDefault(); + $event.stopPropagation(); + } + return () => { return ( <> -
-
- -
- +
+ +
+ { + tabPages?.map(tabPage => { + return
{tabPage}
+ }) + } +
- {context.slots.default && context.slots.default()} ); }; diff --git a/packages/ui-vue/components/tabs/src/tabs.css b/packages/ui-vue/components/tabs/src/tabs.css new file mode 100644 index 0000000..c69a216 --- /dev/null +++ b/packages/ui-vue/components/tabs/src/tabs.css @@ -0,0 +1,84 @@ +.farris-tabs { + box-sizing: border-box; + margin: 0; + padding: 0; + color: #000000d9; + font-size: 14px; + font-variant: tabular-nums; + line-height: 1.5715; + list-style: none; + font-feature-settings: "tnum"; + display: flex; + overflow: hidden; +} + +.farris-tabs.farris-tabs-top { + flex-direction: column; +} + +.farris-tabs.farris-tabs-top .farris-tabs-header{ + margin-bottom: 12px; +} + +.farris-tabs.farris-tabs-bottom { + flex-direction: column-reverse; +} + +.farris-tabs.farris-tabs-left { + flex-direction: row; +} + +.farris-tabs.farris-tabs-right { + flex-direction: row-reverse; +} + +.farris-tabs-header { + position: relative; + display: flex; + flex: none; + align-items: center; +} + +.farris-tabs-header .nav-item { + position: relative; + display: inline-flex; + align-items: center; + font-size: 14px; + background: transparent; + border: 1px solid #ddd; + outline: none; + cursor: pointer; + margin-right: 30px; + line-height: 20px; + box-sizing: content-box; +} + +.farris-tabs-header .nav-item.f-state-active { + border-bottom: 1px solid #1890ff; +} + +.farris-tabs-header .nav-item .nav-link { + font-weight: normal; +} + +.farris-tabs-header .nav-item.f-state-active .nav-link { + color: #1890ff; + text-shadow: 0 0 .25px #f1f1f1; +} + +.farris-tabs-header .nav-item.f-state-disable { + cursor: not-allowed; +} + +.farris-tabs-content { + flex: auto; + min-width: 0; + min-height: 0; +} + +.farris-tabs-content .farris-tab-page { + flex: none; + width: 100%; + outline: none; +} + diff --git a/packages/ui-vue/components/tabs/src/tabs.props.ts b/packages/ui-vue/components/tabs/src/tabs.props.ts index 2830d50..aa883a5 100644 --- a/packages/ui-vue/components/tabs/src/tabs.props.ts +++ b/packages/ui-vue/components/tabs/src/tabs.props.ts @@ -19,6 +19,7 @@ export const tabsProps = { searchBoxVisible: { type: Boolean, default: true }, titleWidth: { type: Number, default: 0 }, customClass: { type: String, default: '' }, + activeId: { type: String } }; export type TabsProps = ExtractPropTypes; diff --git a/packages/ui-vue/src/App.vue b/packages/ui-vue/src/App.vue index 369c814..443e4dd 100644 --- a/packages/ui-vue/src/App.vue +++ b/packages/ui-vue/src/App.vue @@ -5,6 +5,7 @@ import { ref } from "vue"; import HelloWorld from './components/hello-world.vue'; import ButtonEdit from "../components/button-edit/src/button-edit.component"; import Avatar from './components/avatar.vue'; +import Tabs from './components/tabs.vue' const canEdit = ref(true); const canAutoComplete = ref(false); @@ -27,6 +28,7 @@ const canAutoComplete = ref(false); +