Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions packages/devui-vue/devui/tabs/__tests__/tabs.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { mount, VueWrapper } from '@vue/test-utils';
import { ComponentPublicInstance, ref } from 'vue';
import { Tabs, Tab } from '..';

describe('Tabs', () => {
let wrapper: VueWrapper<ComponentPublicInstance>;

it('Basic tabs should render correctly.', () => {
wrapper = mount({
setup() {
const id = ref('tab1');

return () => {
return (
<Tabs v-model={id.value}>
<Tab id="tab1" title="Tab1">Tab1 Content</Tab>
<Tab id="tab2" title="Tab2">Tab2 Content</Tab>
<Tab id="tab3" title="Tab3">Tab3 Content</Tab>
</Tabs>
)
}
}
});

expect(wrapper.find('.devui-tabs').exists()).toBe(true);
expect(wrapper.find('.devui-nav').exists()).toBe(true);
expect(wrapper.find('.devui-tab-content').exists()).toBe(true);
});
});
13 changes: 5 additions & 8 deletions packages/devui-vue/devui/tabs/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import { App } from 'vue';
// import type { App } from 'vue';
import type { App } from 'vue';
import Tabs from './src/tabs';
import Tab from './src/tab';

Tabs.install = function (app: App) {
app.component(Tabs.name, Tabs);
app.component(Tab.name, Tab);
};
export * from './src/tabs-types';

export { Tabs };
export { Tabs, Tab };

export default {
title: 'Tabs 选项卡',
category: '导航',
status: '60%',
install(app: App): void {
app.use(Tabs as any);
app.component(Tabs.name, Tabs);
app.component(Tab.name, Tab);
}
};
18 changes: 18 additions & 0 deletions packages/devui-vue/devui/tabs/src/tab-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ExtractPropTypes, PropType } from 'vue';

export const tabProps = {
title: {
type: [String, Number] as PropType<string | number>,
default: null,
},
id: {
type: String,
default: null,
},
disabled: {
type: Boolean,
default: false,
},
} as const;

export type TabProps = ExtractPropTypes<typeof tabProps>;
22 changes: 5 additions & 17 deletions packages/devui-vue/devui/tabs/src/tab.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,10 @@
import { defineComponent, inject } from 'vue';
import { Tabs } from './tabs';
import { tabProps } from './tab-types';
import type { Tabs } from './tabs-types';

export default defineComponent({
name: 'DTab',
props: {
title: {
default: null,
type: [String, Number],
},
id: {
default: null,
type: String,
},
disabled: {
type: Boolean,
default: false,
},
},
props: tabProps,
setup(props, { slots }) {
const tabs = inject<Tabs>('tabs');
tabs.state.slots.push(slots.title);
Expand All @@ -25,8 +13,8 @@ export default defineComponent({
const { id } = props;
const content =
tabs.state.showContent && tabs.state.active === id ? (
<div class='devui-tab-content'>
<div role='tabpanel' class='devui-tab-pane in active'>
<div class="devui-tab-content">
<div role="tabpanel" class="devui-tab-pane in active">
{slots.default()}
</div>
</div>
Expand Down
54 changes: 54 additions & 0 deletions packages/devui-vue/devui/tabs/src/tabs-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { ExtractPropTypes, PropType, Slot } from 'vue';

export type Active = string | number | null;

export type ITabsType = 'tabs' | 'pills' | 'options' | 'wrapped' | 'slider';

export interface Tabs {
state: TabsState;
}

export interface TabsState {
data?: any[];
showContent: boolean;
active: string;
slots: Slot[];
}

export const tabsProps = {
modelValue: {
type: [String, Number] as PropType<string | number>,
default: null,
},

type: {
type: String as () => ITabsType,
default: 'tabs',
},
showContent: {
type: Boolean,
default: true,
},
vertical: {
type: Boolean,
default: false,
},
reactivable: {
type: Boolean,
default: true,
},
customWidth: {
type: String,
default: '',
},
cssClass: {
type: String,
default: '',
},
beforeChange: {
type: Function as PropType<(id: Active) => boolean>,
default: null,
},
} as const;

export type TabsProps = ExtractPropTypes<typeof tabsProps>;
58 changes: 7 additions & 51 deletions packages/devui-vue/devui/tabs/src/tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,10 @@
import { defineComponent, onBeforeMount, onMounted, onUpdated, PropType, provide, reactive, ref, Slot } from 'vue';
import { defineComponent, onBeforeMount, onMounted, onUpdated, provide, reactive, ref } from 'vue';
import { Active, Tabs, tabsProps, TabsState } from './tabs-types';
import './tabs.scss';

export type Active = string | number | null;
export type TabsType = 'tabs' | 'pills' | 'options' | 'wrapped' | 'slider';
export interface Tabs {
state: TabsState;
}
interface TabsState {
data?: any[];
showContent: boolean;
active: string;
slots: Slot[];
}
export default defineComponent({
name: 'DTabs',
props: {
modelValue: {
type: [String, Number],
default: null,
},

type: {
type: String as () => TabsType,
default: 'tabs',
},
showContent: {
type: Boolean,
default: true,
},
vertical: {
type: Boolean,
default: false,
},
reactivable: {
type: Boolean,
default: true,
},
customWidth: {
type: String,
default: '',
},
cssClass: {
type: String,
default: '',
},
beforeChange: {
type: Function as PropType<(id: Active) => boolean>,
default: null,
},
},
props: tabsProps,

emits: ['update:modelValue', 'active-tab-change'],
setup(props, { emit, slots }) {
Expand Down Expand Up @@ -126,18 +82,18 @@ export default defineComponent({
});
return () => {
return (
<div>
<ul ref={tabsEle} role='tablist' class={`devui-nav devui-nav-${ulClass.join(' ')}`} id='devuiTabs11'>
<div class="devui-tabs">
<ul ref={tabsEle} role="tablist" class={`devui-nav devui-nav-${ulClass.join(' ')}`}>
{state.data.map((item, i) => {
return (
<li
role='presentation'
role="presentation"
onClick={() => {
activeClick(item);
}}
class={(props.modelValue === (item.id || item.tabId) ? 'active' : '') + ' ' + (item.disabled ? 'disabled' : '')}
id={item.id || item.tabId}>
<a role='tab' data-toggle={item.id} aria-expanded={props.modelValue === (item.id || item.tabId)}>
<a role="tab" data-toggle={item.id} aria-expanded={props.modelValue === (item.id || item.tabId)}>
{state.slots[i] ? state.slots[i]() : <span>{item.title}</span>}
</a>
</li>
Expand Down
Loading