diff --git a/components.d.ts b/components.d.ts index 7bd4c86..1030ebd 100644 --- a/components.d.ts +++ b/components.d.ts @@ -12,46 +12,40 @@ export {} /* prettier-ignore */ declare module 'vue' { export interface GlobalComponents { + Avatar: typeof import('./src/components/ui/avatar/index.vue')['default'] + Collapse: typeof import('./src/components/ui/collapse/index.vue')['default'] + Datetime: typeof import('./src/components/ui/datetime/index.vue')['default'] + Default: typeof import('./src/components/layout/default.vue')['default'] + Divider: typeof import('./src/components/ui/divider/index.vue')['default'] IIcBaselineDataSaverOff: typeof import('~icons/ic/baseline-data-saver-off')['default'] IIcBaselineDownloading: typeof import('~icons/ic/baseline-downloading')['default'] IIcRoundArrowForwardIos: typeof import('~icons/ic/round-arrow-forward-ios')['default'] + Input: typeof import('./src/components/ui/input/index.vue')['default'] + InputLabel: typeof import('./src/components/ui/input-label/index.vue')['default'] IonApp: typeof import('@ionic/vue')['IonApp'] IonAvatar: typeof import('@ionic/vue')['IonAvatar'] - IonBackButton: typeof import('@ionic/vue')['IonBackButton'] - IonBreadcrumb: typeof import('@ionic/vue')['IonBreadcrumb'] - IonBreadcrumbs: typeof import('@ionic/vue')['IonBreadcrumbs'] IonButton: typeof import('@ionic/vue')['IonButton'] - IonButtons: typeof import('@ionic/vue')['IonButtons'] IonContent: typeof import('@ionic/vue')['IonContent'] - IonDatetime: typeof import('@ionic/vue')['IonDatetime'] - IonDatetimeButton: typeof import('@ionic/vue')['IonDatetimeButton'] IonHeader: typeof import('@ionic/vue')['IonHeader'] IonIcon: typeof import('@ionic/vue')['IonIcon'] - IonInputOtp: typeof import('@ionic/vue')['IonInputOtp'] IonItem: typeof import('@ionic/vue')['IonItem'] IonLabel: typeof import('@ionic/vue')['IonLabel'] IonList: typeof import('@ionic/vue')['IonList'] IonModal: typeof import('@ionic/vue')['IonModal'] - IonNote: typeof import('@ionic/vue')['IonNote'] IonPage: typeof import('@ionic/vue')['IonPage'] - IonRadio: typeof import('@ionic/vue')['IonRadio'] - IonRadioGroup: typeof import('@ionic/vue')['IonRadioGroup'] - IonRippleEffect: typeof import('@ionic/vue')['IonRippleEffect'] IonRouterOutlet: typeof import('@ionic/vue')['IonRouterOutlet'] IonSearchbar: typeof import('@ionic/vue')['IonSearchbar'] - IonSegment: typeof import('@ionic/vue')['IonSegment'] - IonSegmentButton: typeof import('@ionic/vue')['IonSegmentButton'] - IonSelect: typeof import('@ionic/vue')['IonSelect'] - IonSelectOption: typeof import('@ionic/vue')['IonSelectOption'] IonTabBar: typeof import('@ionic/vue')['IonTabBar'] IonTabButton: typeof import('@ionic/vue')['IonTabButton'] IonTabs: typeof import('@ionic/vue')['IonTabs'] - IonText: typeof import('@ionic/vue')['IonText'] IonTitle: typeof import('@ionic/vue')['IonTitle'] IonToolbar: typeof import('@ionic/vue')['IonToolbar'] LayoutDefault: typeof import('./src/components/layout/default.vue')['default'] + Result: typeof import('./src/components/ui/result/index.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] + TabPane: typeof import('./src/components/ui/tabs/tab-pane.vue')['default'] + Tabs: typeof import('./src/components/ui/tabs/index.vue')['default'] UiAvatar: typeof import('./src/components/ui/avatar/index.vue')['default'] UiCollapse: typeof import('./src/components/ui/collapse/index.vue')['default'] UiDatetime: typeof import('./src/components/ui/datetime/index.vue')['default'] @@ -59,51 +53,48 @@ declare module 'vue' { UiInput: typeof import('./src/components/ui/input/index.vue')['default'] UiInputLabel: typeof import('./src/components/ui/input-label/index.vue')['default'] UiResult: typeof import('./src/components/ui/result/index.vue')['default'] + UiTabPane: typeof import('./src/components/ui/tab-pane/index.vue')['default'] + UiTabs: typeof import('./src/components/ui/tabs/index.vue')['default'] + UiTabsTabPane: typeof import('./src/components/ui/tabs/tab-pane.vue')['default'] } } // For TSX support declare global { + const Avatar: typeof import('./src/components/ui/avatar/index.vue')['default'] + const Collapse: typeof import('./src/components/ui/collapse/index.vue')['default'] + const Datetime: typeof import('./src/components/ui/datetime/index.vue')['default'] + const Default: typeof import('./src/components/layout/default.vue')['default'] + const Divider: typeof import('./src/components/ui/divider/index.vue')['default'] const IIcBaselineDataSaverOff: typeof import('~icons/ic/baseline-data-saver-off')['default'] const IIcBaselineDownloading: typeof import('~icons/ic/baseline-downloading')['default'] const IIcRoundArrowForwardIos: typeof import('~icons/ic/round-arrow-forward-ios')['default'] + const Input: typeof import('./src/components/ui/input/index.vue')['default'] + const InputLabel: typeof import('./src/components/ui/input-label/index.vue')['default'] const IonApp: typeof import('@ionic/vue')['IonApp'] const IonAvatar: typeof import('@ionic/vue')['IonAvatar'] - const IonBackButton: typeof import('@ionic/vue')['IonBackButton'] - const IonBreadcrumb: typeof import('@ionic/vue')['IonBreadcrumb'] - const IonBreadcrumbs: typeof import('@ionic/vue')['IonBreadcrumbs'] const IonButton: typeof import('@ionic/vue')['IonButton'] - const IonButtons: typeof import('@ionic/vue')['IonButtons'] const IonContent: typeof import('@ionic/vue')['IonContent'] - const IonDatetime: typeof import('@ionic/vue')['IonDatetime'] - const IonDatetimeButton: typeof import('@ionic/vue')['IonDatetimeButton'] const IonHeader: typeof import('@ionic/vue')['IonHeader'] const IonIcon: typeof import('@ionic/vue')['IonIcon'] - const IonInputOtp: typeof import('@ionic/vue')['IonInputOtp'] const IonItem: typeof import('@ionic/vue')['IonItem'] const IonLabel: typeof import('@ionic/vue')['IonLabel'] const IonList: typeof import('@ionic/vue')['IonList'] const IonModal: typeof import('@ionic/vue')['IonModal'] - const IonNote: typeof import('@ionic/vue')['IonNote'] const IonPage: typeof import('@ionic/vue')['IonPage'] - const IonRadio: typeof import('@ionic/vue')['IonRadio'] - const IonRadioGroup: typeof import('@ionic/vue')['IonRadioGroup'] - const IonRippleEffect: typeof import('@ionic/vue')['IonRippleEffect'] const IonRouterOutlet: typeof import('@ionic/vue')['IonRouterOutlet'] const IonSearchbar: typeof import('@ionic/vue')['IonSearchbar'] - const IonSegment: typeof import('@ionic/vue')['IonSegment'] - const IonSegmentButton: typeof import('@ionic/vue')['IonSegmentButton'] - const IonSelect: typeof import('@ionic/vue')['IonSelect'] - const IonSelectOption: typeof import('@ionic/vue')['IonSelectOption'] const IonTabBar: typeof import('@ionic/vue')['IonTabBar'] const IonTabButton: typeof import('@ionic/vue')['IonTabButton'] const IonTabs: typeof import('@ionic/vue')['IonTabs'] - const IonText: typeof import('@ionic/vue')['IonText'] const IonTitle: typeof import('@ionic/vue')['IonTitle'] const IonToolbar: typeof import('@ionic/vue')['IonToolbar'] const LayoutDefault: typeof import('./src/components/layout/default.vue')['default'] + const Result: typeof import('./src/components/ui/result/index.vue')['default'] const RouterLink: typeof import('vue-router')['RouterLink'] const RouterView: typeof import('vue-router')['RouterView'] + const TabPane: typeof import('./src/components/ui/tabs/tab-pane.vue')['default'] + const Tabs: typeof import('./src/components/ui/tabs/index.vue')['default'] const UiAvatar: typeof import('./src/components/ui/avatar/index.vue')['default'] const UiCollapse: typeof import('./src/components/ui/collapse/index.vue')['default'] const UiDatetime: typeof import('./src/components/ui/datetime/index.vue')['default'] @@ -111,4 +102,7 @@ declare global { const UiInput: typeof import('./src/components/ui/input/index.vue')['default'] const UiInputLabel: typeof import('./src/components/ui/input-label/index.vue')['default'] const UiResult: typeof import('./src/components/ui/result/index.vue')['default'] + const UiTabPane: typeof import('./src/components/ui/tab-pane/index.vue')['default'] + const UiTabs: typeof import('./src/components/ui/tabs/index.vue')['default'] + const UiTabsTabPane: typeof import('./src/components/ui/tabs/tab-pane.vue')['default'] } \ No newline at end of file diff --git a/src/components/ui/tab-pane/index.vue b/src/components/ui/tab-pane/index.vue new file mode 100644 index 0000000..0674c10 --- /dev/null +++ b/src/components/ui/tab-pane/index.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/src/components/ui/tabs/index.vue b/src/components/ui/tabs/index.vue new file mode 100644 index 0000000..3cebe79 --- /dev/null +++ b/src/components/ui/tabs/index.vue @@ -0,0 +1,602 @@ + + + + + diff --git a/src/components/ui/tabs/types.ts b/src/components/ui/tabs/types.ts new file mode 100644 index 0000000..9d6edb4 --- /dev/null +++ b/src/components/ui/tabs/types.ts @@ -0,0 +1,97 @@ +export interface TabItem { + name: string | number; + title: string; + disabled?: boolean; + closable?: boolean; + lazy?: boolean; +} + +export interface TabsProps { + /** 当前激活的标签页名称 */ + modelValue?: string | number; + /** 标签页类型 */ + type?: "bar" | "line" | "segment"; + /** 标签页尺寸 */ + size?: "small" | "medium" | "large"; + /** 是否开启切换动画 */ + animated?: boolean; + /** 是否可关闭 */ + closable?: boolean; + /** 是否可添加 */ + addable?: boolean; + /** 标签页位置 */ + placement?: "top" | "bottom" | "left" | "right"; + /** 标签样式 */ + tabStyle?: string | Record; + /** 标签类名 */ + tabClass?: string; + /** 面板样式 */ + paneStyle?: string | Record; + /** 面板类名 */ + paneClass?: string; +} + +export interface TabsEmits { + /** 当前激活标签页发生变化时触发 */ + (e: "update:modelValue", value: string | number): void; + /** 点击标签时触发 */ + (e: "tabClick", key: string | number, event: Event): void; + /** 关闭标签时触发 */ + (e: "tabClose", key: string | number): void; + /** 添加标签时触发 */ + (e: "tabAdd"): void; +} + +export interface TabPaneProps { + /** 标签页标识,必须唯一 */ + name: string | number; + /** 标签页标题 */ + title: string; + /** 是否禁用 */ + disabled?: boolean; + /** 是否可关闭 */ + closable?: boolean; + /** 是否懒加载 */ + lazy?: boolean; +} + +export interface TabsContext { + /** 当前激活的标签页 */ + currentTab: Readonly>; + /** 标签页类型 */ + type: Readonly>; + /** 标签页尺寸 */ + size: Readonly>; + /** 是否可关闭 */ + closable: Readonly>; + /** 是否开启动画 */ + animated: Readonly>; + /** 标签页位置 */ + placement: Readonly>; + /** 标签样式 */ + tabStyle: Readonly | undefined>>; + /** 标签类名 */ + tabClass: Readonly>; + /** 面板样式 */ + paneStyle: Readonly | undefined>>; + /** 面板类名 */ + paneClass: Readonly>; + /** 激活标签页方法 */ + activateTab: (key: string | number, event?: Event) => void; + /** 关闭标签页方法 */ + closeTab: (key: string | number) => void; + /** 注册标签页 */ + registerTabPane: (pane: TabItem) => void; + /** 注销标签页 */ + unregisterTabPane: (pane: TabItem) => void; +} + +/** Tabs 组件实例类型 */ +export interface TabsInstance { + /** 注册标签页 */ + registerTabPane: (pane: TabItem) => void; + /** 注销标签页 */ + unregisterTabPane: (pane: TabItem) => void; + /** 更新活跃指示条位置 */ + updateActiveBar: () => void; +} diff --git a/tsconfig.json b/tsconfig.json index 1106af2..b499f61 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,22 +1,22 @@ { "compilerOptions": { "target": "ESNext", + "jsx": "preserve", + "lib": ["ESNext", "DOM"], "useDefineForClassFields": true, "module": "ESNext", "moduleResolution": "bundler", - "strict": true, - "jsx": "preserve", - "resolveJsonModule": true, - "isolatedModules": true, - "esModuleInterop": true, - "lib": ["ESNext", "DOM"], - "skipLibCheck": true, - "noEmit": true, "paths": { "@/*": ["./src/*"] }, - "types": ["./components"] + "resolveJsonModule": true, + "types": ["./components"], + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "isolatedModules": true, + "skipLibCheck": true }, - "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "components.d.ts", "auto-imports.d.ts", "types/*.d.ts"], - "references": [{ "path": "./tsconfig.node.json" }] + "references": [{ "path": "./tsconfig.node.json" }], + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "components.d.ts", "auto-imports.d.ts", "types/*.d.ts"] }