@manohub/ui 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/README.md +141 -0
  2. package/dist/components/avatar/index.d.ts +283 -0
  3. package/dist/components/avatar/index.js +167 -0
  4. package/dist/components/badge/index.d.ts +132 -0
  5. package/dist/components/badge/index.js +99 -0
  6. package/dist/components/button/index.d.ts +578 -0
  7. package/dist/components/button/index.js +191 -0
  8. package/dist/components/capsule/index.d.ts +161 -0
  9. package/dist/components/capsule/index.js +101 -0
  10. package/dist/components/card/index.d.ts +456 -0
  11. package/dist/components/card/index.js +231 -0
  12. package/dist/components/checkbox/index.d.ts +331 -0
  13. package/dist/components/checkbox/index.js +165 -0
  14. package/dist/components/code/index.d.ts +134 -0
  15. package/dist/components/code/index.js +117 -0
  16. package/dist/components/code-editor/index.d.ts +163 -0
  17. package/dist/components/code-editor/index.js +98 -0
  18. package/dist/components/collapse/index.d.ts +125 -0
  19. package/dist/components/collapse/index.js +95 -0
  20. package/dist/components/control-size.d.ts +8 -0
  21. package/dist/components/dialog/index.d.ts +224 -0
  22. package/dist/components/dialog/index.js +194 -0
  23. package/dist/components/divider/index.d.ts +64 -0
  24. package/dist/components/divider/index.js +62 -0
  25. package/dist/components/drawer/index.d.ts +226 -0
  26. package/dist/components/drawer/index.js +190 -0
  27. package/dist/components/filter/index.d.ts +391 -0
  28. package/dist/components/filter/index.js +203 -0
  29. package/dist/components/form/index.d.ts +704 -0
  30. package/dist/components/form/index.js +329 -0
  31. package/dist/components/input/index.d.ts +980 -0
  32. package/dist/components/input/index.js +334 -0
  33. package/dist/components/layout/index.d.ts +162 -0
  34. package/dist/components/layout/index.js +100 -0
  35. package/dist/components/list-view/index.d.ts +563 -0
  36. package/dist/components/list-view/index.js +221 -0
  37. package/dist/components/loading/index.d.ts +77 -0
  38. package/dist/components/loading/index.js +40 -0
  39. package/dist/components/nav/index.d.ts +293 -0
  40. package/dist/components/nav/index.js +164 -0
  41. package/dist/components/notice/index.d.ts +137 -0
  42. package/dist/components/notice/index.js +101 -0
  43. package/dist/components/notification/index.d.ts +118 -0
  44. package/dist/components/notification/index.js +99 -0
  45. package/dist/components/page/index.d.ts +276 -0
  46. package/dist/components/page/index.js +351 -0
  47. package/dist/components/page/split-resize.d.ts +42 -0
  48. package/dist/components/page/split-resize.js +36 -0
  49. package/dist/components/pagination/index.d.ts +171 -0
  50. package/dist/components/pagination/index.js +226 -0
  51. package/dist/components/panel/index.d.ts +401 -0
  52. package/dist/components/panel/index.js +193 -0
  53. package/dist/components/part-padding.d.ts +27 -0
  54. package/dist/components/part-padding.js +23 -0
  55. package/dist/components/query-state/index.d.ts +207 -0
  56. package/dist/components/query-state/index.js +181 -0
  57. package/dist/components/radio/index.d.ts +473 -0
  58. package/dist/components/radio/index.js +250 -0
  59. package/dist/components/search/index.d.ts +167 -0
  60. package/dist/components/search/index.js +105 -0
  61. package/dist/components/select/index.d.ts +252 -0
  62. package/dist/components/select/index.js +281 -0
  63. package/dist/components/skeleton/index.d.ts +88 -0
  64. package/dist/components/skeleton/index.js +56 -0
  65. package/dist/components/steps/index.d.ts +199 -0
  66. package/dist/components/steps/index.js +117 -0
  67. package/dist/components/switch/index.d.ts +150 -0
  68. package/dist/components/switch/index.js +103 -0
  69. package/dist/components/table/index.d.ts +351 -0
  70. package/dist/components/table/index.js +286 -0
  71. package/dist/components/tabs/index.d.ts +179 -0
  72. package/dist/components/tabs/index.js +153 -0
  73. package/dist/components/tabset/index.d.ts +105 -0
  74. package/dist/components/tabset/index.js +68 -0
  75. package/dist/components/tag/index.d.ts +203 -0
  76. package/dist/components/tag/index.js +144 -0
  77. package/dist/components/toast/index.d.ts +271 -0
  78. package/dist/components/toast/index.js +116 -0
  79. package/dist/components/tooltip/index.d.ts +126 -0
  80. package/dist/components/tooltip/index.js +97 -0
  81. package/dist/components/tree/index.d.ts +317 -0
  82. package/dist/components/tree/index.js +251 -0
  83. package/dist/components/upload/index.d.ts +384 -0
  84. package/dist/components/upload/index.js +172 -0
  85. package/dist/index.d.ts +63 -0
  86. package/dist/index.js +102 -0
  87. package/dist/services/base.d.ts +21 -0
  88. package/dist/services/base.js +42 -0
  89. package/dist/services/dialog.d.ts +41 -0
  90. package/dist/services/dialog.js +83 -0
  91. package/dist/services/index.d.ts +12 -0
  92. package/dist/services/loading.d.ts +21 -0
  93. package/dist/services/loading.js +41 -0
  94. package/dist/services/toast.d.ts +40 -0
  95. package/dist/services/toast.js +74 -0
  96. package/dist/styles/components/avatar.css +128 -0
  97. package/dist/styles/components/avatar.tokens.css +24 -0
  98. package/dist/styles/components/badge.css +237 -0
  99. package/dist/styles/components/button.css +454 -0
  100. package/dist/styles/components/button.tokens.css +56 -0
  101. package/dist/styles/components/capsule.css +120 -0
  102. package/dist/styles/components/capsule.tokens.css +27 -0
  103. package/dist/styles/components/card.css +192 -0
  104. package/dist/styles/components/checkbox.css +145 -0
  105. package/dist/styles/components/checkbox.tokens.css +26 -0
  106. package/dist/styles/components/code-editor.css +91 -0
  107. package/dist/styles/components/code-editor.tokens.css +24 -0
  108. package/dist/styles/components/code.css +153 -0
  109. package/dist/styles/components/code.tokens.css +29 -0
  110. package/dist/styles/components/collapse.css +62 -0
  111. package/dist/styles/components/collapse.tokens.css +20 -0
  112. package/dist/styles/components/dialog.css +106 -0
  113. package/dist/styles/components/dialog.tokens.css +24 -0
  114. package/dist/styles/components/divider.css +71 -0
  115. package/dist/styles/components/divider.tokens.css +21 -0
  116. package/dist/styles/components/drawer.css +143 -0
  117. package/dist/styles/components/drawer.tokens.css +22 -0
  118. package/dist/styles/components/filter.css +41 -0
  119. package/dist/styles/components/filter.tokens.css +14 -0
  120. package/dist/styles/components/form.css +220 -0
  121. package/dist/styles/components/form.tokens.css +15 -0
  122. package/dist/styles/components/input.css +445 -0
  123. package/dist/styles/components/input.tokens.css +41 -0
  124. package/dist/styles/components/layout.css +198 -0
  125. package/dist/styles/components/list-view.css +244 -0
  126. package/dist/styles/components/loading.css +76 -0
  127. package/dist/styles/components/loading.tokens.css +23 -0
  128. package/dist/styles/components/nav.css +48 -0
  129. package/dist/styles/components/notice.css +153 -0
  130. package/dist/styles/components/notice.tokens.css +17 -0
  131. package/dist/styles/components/notification.css +159 -0
  132. package/dist/styles/components/notification.tokens.css +37 -0
  133. package/dist/styles/components/page.css +473 -0
  134. package/dist/styles/components/pagination.css +297 -0
  135. package/dist/styles/components/pagination.tokens.css +32 -0
  136. package/dist/styles/components/panel.css +77 -0
  137. package/dist/styles/components/query-state.css +88 -0
  138. package/dist/styles/components/radio.css +271 -0
  139. package/dist/styles/components/radio.tokens.css +26 -0
  140. package/dist/styles/components/search.css +30 -0
  141. package/dist/styles/components/select.css +242 -0
  142. package/dist/styles/components/select.tokens.css +33 -0
  143. package/dist/styles/components/skeleton.css +60 -0
  144. package/dist/styles/components/skeleton.tokens.css +27 -0
  145. package/dist/styles/components/steps.css +157 -0
  146. package/dist/styles/components/steps.tokens.css +42 -0
  147. package/dist/styles/components/switch.css +165 -0
  148. package/dist/styles/components/switch.tokens.css +26 -0
  149. package/dist/styles/components/table.css +439 -0
  150. package/dist/styles/components/table.tokens.css +41 -0
  151. package/dist/styles/components/tabs.css +234 -0
  152. package/dist/styles/components/tabs.tokens.css +30 -0
  153. package/dist/styles/components/tag.css +200 -0
  154. package/dist/styles/components/tag.tokens.css +30 -0
  155. package/dist/styles/components/toast.css +150 -0
  156. package/dist/styles/components/toast.tokens.css +26 -0
  157. package/dist/styles/components/tooltip.css +89 -0
  158. package/dist/styles/components/tooltip.tokens.css +25 -0
  159. package/dist/styles/components/tree.css +139 -0
  160. package/dist/styles/components/tree.tokens.css +20 -0
  161. package/dist/styles/components/upload.css +150 -0
  162. package/dist/styles/components/upload.tokens.css +27 -0
  163. package/dist/styles/index.css +149 -0
  164. package/dist/styles/operations/collapse.css +84 -0
  165. package/dist/styles/operations/popup.css +189 -0
  166. package/dist/styles/operations/tabset.css +57 -0
  167. package/dist/utils/state-illustration.d.ts +31 -0
  168. package/dist/utils/state-illustration.js +156 -0
  169. package/package.json +62 -0
@@ -0,0 +1,179 @@
1
+ import { type PropType, type SlotsType, type VNodeChild } from 'vue';
2
+ import type { ControlSize } from '../control-size';
3
+ export interface TabsOption {
4
+ /** 项文字 */
5
+ label: string;
6
+ /** 项值(受控值就是它) */
7
+ value: string | number;
8
+ /** 禁用项:不可选 */
9
+ disabled?: boolean;
10
+ /** 单项可关(`closable` 打开时用它例外掉某些项) */
11
+ closable?: boolean;
12
+ }
13
+ export type TabsValue = string | number;
14
+ /** 页签形态:`line` 下划线指示条 / `card` 选项卡(与内容区连成一体) */
15
+ export type TabsType = 'line' | 'card';
16
+ /**
17
+ * 页签条(**自绘**;下划线或选项卡两种形态 + 三档尺寸 + 居中 + 可关闭 + 可新增 + 「更多」收纳)。
18
+ *
19
+ * ## 与 `Tabset` / `Capsule` 的分工(三者都能"切换",判据在**可见形态**)
20
+ *
21
+ * - 本件:**页签条**(`line` 下划线 / `card` 选项卡,页面级分区切换)—— 就是这一族的皮肤;
22
+ * - `Capsule`:胶囊/分段按钮(块状选中底),用于筛选项那种"按钮感"切换;
23
+ * - `Tabset`:**骨架**(把某组互斥项与面板显隐接起来),它不含皮肤 —— 把本件塞进它的 `selector` 插槽即可。
24
+ *
25
+ * ## 指示条为什么不是一个滑块
26
+ *
27
+ * 每个项的指示条是它自己的伪元素、常驻但未选时 `opacity:0; scale:.75` —— "滑过去"的观感来自这两个属性的
28
+ * 过渡。做成一条共享滑块要 JS 量位置,且首帧会跳。**别在页签区加轨线**(会扣走区高 1px,规范明确警告)。
29
+ * (`card` 档不画指示条:选中由底色与顶边表达。)
30
+ *
31
+ * ## 超过一屏的页签怎么放
32
+ *
33
+ * 给 `more` 插槽即出「更多 ▾」页签 + 操作层浮层(原生 popover,零 JS 开合);哪些页签收进"更多"由调用方
34
+ * 决定 —— 收多久、收哪些是业务判断,不是皮肤能定的。
35
+ *
36
+ * @example 基本
37
+ * <Tabs :options="[{label:'全部',value:'all'},{label:'进行中',value:'doing'}]" v-model:value="current" />
38
+ *
39
+ * @example 选项卡形态 + 可关闭可新增
40
+ * <Tabs type="card" closable addable :options="tabs" v-model:value="current"
41
+ * :on-close="remove" :on-add="add" />
42
+ */
43
+ export declare const Tabs: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
44
+ options: {
45
+ type: PropType<TabsOption[]>;
46
+ required: true;
47
+ };
48
+ /** 受控选中值;不传即非受控(由 `defaultValue` 起) */
49
+ value: {
50
+ type: PropType<TabsValue | undefined>;
51
+ default: undefined;
52
+ };
53
+ /** 非受控初始选中值,缺省第一项 */
54
+ defaultValue: {
55
+ type: PropType<TabsValue | undefined>;
56
+ default: undefined;
57
+ };
58
+ /** 选中变化回调(受控与非受控都会调) */
59
+ onChange: {
60
+ type: PropType<(value: TabsValue) => void>;
61
+ default: undefined;
62
+ };
63
+ /** 形态:`line` 下划线 / `card` 选项卡 */
64
+ type: {
65
+ type: PropType<TabsType>;
66
+ default: string;
67
+ };
68
+ /** 整体居中(页签少、要撑满整行时用) */
69
+ centered: {
70
+ type: BooleanConstructor;
71
+ default: boolean;
72
+ };
73
+ /** 尺寸档(24 / 32 / 40,只覆盖令牌) */
74
+ size: {
75
+ type: PropType<ControlSize>;
76
+ default: string;
77
+ };
78
+ /** 每项带关闭位(单项可用 `option.closable` 覆写) */
79
+ closable: {
80
+ type: BooleanConstructor;
81
+ default: boolean;
82
+ };
83
+ /** 尾部「新增」按钮 */
84
+ addable: {
85
+ type: BooleanConstructor;
86
+ default: boolean;
87
+ };
88
+ /** 「更多」页签的文字 */
89
+ moreLabel: {
90
+ type: StringConstructor;
91
+ default: string;
92
+ };
93
+ /** 关闭某项(只回调,**不从 `options` 里删** —— 数据归调用方) */
94
+ onClose: {
95
+ type: PropType<(value: TabsValue) => void>;
96
+ default: undefined;
97
+ };
98
+ /** 点新增(只回调) */
99
+ onAdd: {
100
+ type: PropType<() => void>;
101
+ default: undefined;
102
+ };
103
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
104
+ options: {
105
+ type: PropType<TabsOption[]>;
106
+ required: true;
107
+ };
108
+ /** 受控选中值;不传即非受控(由 `defaultValue` 起) */
109
+ value: {
110
+ type: PropType<TabsValue | undefined>;
111
+ default: undefined;
112
+ };
113
+ /** 非受控初始选中值,缺省第一项 */
114
+ defaultValue: {
115
+ type: PropType<TabsValue | undefined>;
116
+ default: undefined;
117
+ };
118
+ /** 选中变化回调(受控与非受控都会调) */
119
+ onChange: {
120
+ type: PropType<(value: TabsValue) => void>;
121
+ default: undefined;
122
+ };
123
+ /** 形态:`line` 下划线 / `card` 选项卡 */
124
+ type: {
125
+ type: PropType<TabsType>;
126
+ default: string;
127
+ };
128
+ /** 整体居中(页签少、要撑满整行时用) */
129
+ centered: {
130
+ type: BooleanConstructor;
131
+ default: boolean;
132
+ };
133
+ /** 尺寸档(24 / 32 / 40,只覆盖令牌) */
134
+ size: {
135
+ type: PropType<ControlSize>;
136
+ default: string;
137
+ };
138
+ /** 每项带关闭位(单项可用 `option.closable` 覆写) */
139
+ closable: {
140
+ type: BooleanConstructor;
141
+ default: boolean;
142
+ };
143
+ /** 尾部「新增」按钮 */
144
+ addable: {
145
+ type: BooleanConstructor;
146
+ default: boolean;
147
+ };
148
+ /** 「更多」页签的文字 */
149
+ moreLabel: {
150
+ type: StringConstructor;
151
+ default: string;
152
+ };
153
+ /** 关闭某项(只回调,**不从 `options` 里删** —— 数据归调用方) */
154
+ onClose: {
155
+ type: PropType<(value: TabsValue) => void>;
156
+ default: undefined;
157
+ };
158
+ /** 点新增(只回调) */
159
+ onAdd: {
160
+ type: PropType<() => void>;
161
+ default: undefined;
162
+ };
163
+ }>> & Readonly<{}>, {
164
+ size: ControlSize;
165
+ value: TabsValue | undefined;
166
+ type: TabsType;
167
+ onChange: (value: TabsValue) => void;
168
+ onClose: (value: TabsValue) => void;
169
+ defaultValue: TabsValue | undefined;
170
+ closable: boolean;
171
+ centered: boolean;
172
+ addable: boolean;
173
+ moreLabel: string;
174
+ onAdd: () => void;
175
+ }, SlotsType<{
176
+ more?: (context: {
177
+ options: TabsOption[];
178
+ }) => VNodeChild;
179
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -0,0 +1,153 @@
1
+ import { defineComponent, ref, computed, createVNode, Fragment, mergeProps } from "vue";
2
+ import { Icon } from "@manohub/icon";
3
+ const Tabs = /* @__PURE__ */ defineComponent({
4
+ name: "Tabs",
5
+ inheritAttrs: false,
6
+ props: {
7
+ options: {
8
+ type: Array,
9
+ required: true
10
+ },
11
+ /** 受控选中值;不传即非受控(由 `defaultValue` 起) */
12
+ value: {
13
+ type: [String, Number],
14
+ default: void 0
15
+ },
16
+ /** 非受控初始选中值,缺省第一项 */
17
+ defaultValue: {
18
+ type: [String, Number],
19
+ default: void 0
20
+ },
21
+ /** 选中变化回调(受控与非受控都会调) */
22
+ onChange: {
23
+ type: Function,
24
+ default: void 0
25
+ },
26
+ /** 形态:`line` 下划线 / `card` 选项卡 */
27
+ type: {
28
+ type: String,
29
+ default: "line"
30
+ },
31
+ /** 整体居中(页签少、要撑满整行时用) */
32
+ centered: {
33
+ type: Boolean,
34
+ default: false
35
+ },
36
+ /** 尺寸档(24 / 32 / 40,只覆盖令牌) */
37
+ size: {
38
+ type: String,
39
+ default: "md"
40
+ },
41
+ /** 每项带关闭位(单项可用 `option.closable` 覆写) */
42
+ closable: {
43
+ type: Boolean,
44
+ default: false
45
+ },
46
+ /** 尾部「新增」按钮 */
47
+ addable: {
48
+ type: Boolean,
49
+ default: false
50
+ },
51
+ /** 「更多」页签的文字 */
52
+ moreLabel: {
53
+ type: String,
54
+ default: "更多"
55
+ },
56
+ /** 关闭某项(只回调,**不从 `options` 里删** —— 数据归调用方) */
57
+ onClose: {
58
+ type: Function,
59
+ default: void 0
60
+ },
61
+ /** 点新增(只回调) */
62
+ onAdd: {
63
+ type: Function,
64
+ default: void 0
65
+ }
66
+ },
67
+ slots: Object,
68
+ setup(props, {
69
+ slots,
70
+ attrs
71
+ }) {
72
+ const innerValue = ref(props.value ?? props.defaultValue ?? props.options[0]?.value);
73
+ const current = computed(() => props.value ?? innerValue.value);
74
+ const moreId = `mh-tabs-${Math.random().toString(36).slice(2, 10)}`;
75
+ const select = (value) => {
76
+ const target = props.options.find((option) => option.value === value);
77
+ if (target?.disabled) return;
78
+ if (props.value === void 0) innerValue.value = value;
79
+ props.onChange?.(value);
80
+ };
81
+ const isClosable = (option) => option.closable ?? props.closable;
82
+ return () => createVNode("nav", {
83
+ "class": [
84
+ "mh-tabs",
85
+ /* `mh-popup-host` 是操作层展开转向的**宿主标记**(popup.css 靠它 :has 反推面板开合):
86
+ 没有它,「更多」的 caret 展开时不会翻向 —— 与 Select / Tooltip 同一分工。 */
87
+ "mh-popup-host",
88
+ props.type === "card" ? "mh-tabs--card" : "",
89
+ props.centered ? "mh-tabs--centered" : "",
90
+ props.size === "md" ? "" : `mh-tabs--${props.size}`,
91
+ attrs.class
92
+ ].filter(Boolean).join(" "),
93
+ "style": attrs.style,
94
+ "role": "tablist"
95
+ }, [props.options.map((option) => {
96
+ const active = option.value === current.value;
97
+ return createVNode("button", {
98
+ "key": option.value,
99
+ "type": "button",
100
+ "role": "tab",
101
+ "class": ["mh-tabs__tab", active ? "is-selected" : "", option.disabled ? "is-disabled" : ""].filter(Boolean).join(" "),
102
+ "data-state": active ? "active" : "inactive",
103
+ "aria-selected": active,
104
+ "disabled": option.disabled,
105
+ "onClick": () => select(option.value)
106
+ }, [option.label, isClosable(option) && !option.disabled ? (
107
+ /* 关闭位不是 `<button>`:页签自己是按钮,按钮里嵌按钮是非法 HTML。
108
+ 用 `role="button"` + `stopPropagation` 表达同样的语义与行为。 */
109
+ createVNode("span", {
110
+ "class": "mh-tabs__close",
111
+ "role": "button",
112
+ "tabindex": -1,
113
+ "aria-label": `关闭${option.label}`,
114
+ "onClick": (event) => {
115
+ event.stopPropagation();
116
+ event.preventDefault();
117
+ props.onClose?.(option.value);
118
+ }
119
+ }, [createVNode(Icon, {
120
+ "name": "close"
121
+ }, null)])
122
+ ) : null]);
123
+ }), props.addable ? createVNode("button", {
124
+ "type": "button",
125
+ "class": "mh-tabs__add",
126
+ "aria-label": "新增页签",
127
+ "onClick": () => props.onAdd?.()
128
+ }, [createVNode(Icon, {
129
+ "name": "plus"
130
+ }, null)]) : null, slots.more ? createVNode(Fragment, null, [createVNode("button", mergeProps({
131
+ "type": "button",
132
+ "class": "mh-tabs__tab mh-tabs__tab--more",
133
+ "data-state": "inactive"
134
+ }, {
135
+ popovertarget: moreId
136
+ }), [props.moreLabel, createVNode(Icon, {
137
+ "name": "chevron-down",
138
+ "class": "mh-popup-caret"
139
+ }, null)]), createVNode("div", mergeProps({
140
+ "id": moreId,
141
+ "class": "mh-popup",
142
+ "data-side": "bottom",
143
+ "data-align": "end"
144
+ }, {
145
+ popover: "auto"
146
+ }), [slots.more({
147
+ options: props.options
148
+ })])]) : null]);
149
+ }
150
+ });
151
+ export {
152
+ Tabs
153
+ };
@@ -0,0 +1,105 @@
1
+ import { type PropType, type SlotsType, type VNodeChild } from 'vue';
2
+ export interface TabsetOption {
3
+ /** 项文字 */
4
+ label: string;
5
+ /** 项值(受控值就是它) */
6
+ value: string | number;
7
+ /** 禁用项:不可选(原生 radio 路径下方向键会跳过) */
8
+ disabled?: boolean;
9
+ }
10
+ export interface TabsetProps {
11
+ /** 轨道项(顺序即「第 n 项 ↔ 第 n 块面板」的档位表) */
12
+ options: TabsetOption[];
13
+ /** 受控选中值;不传即非受控(由 `defaultValue` 起) */
14
+ value?: string | number;
15
+ /** 非受控初始选中值,缺省第一项 */
16
+ defaultValue?: string | number;
17
+ /** 选中变化回调(受控与非受控都会调) */
18
+ onChange?: (value: string | number) => void;
19
+ }
20
+ /**
21
+ * 面板切换(**操作层骨架 + 组件路径显隐**)。
22
+ *
23
+ * ## 它是什么
24
+ * 把「一组互斥选项」与「按顺序排列的面板」接起来:第 n 个选项对应第 n 块面板。
25
+ * 骨架(根、面板组、档位表)在操作层 `styles/operations/tabset.css`,本件负责:
26
+ * 受控值、面板包装与显隐、把 `select` 交给选择控件。
27
+ *
28
+ * ## 两条显隐路径(结论一致,不冲突)
29
+ * - **原生路径**(推荐):选择控件用**原生 radio**(如 `Capsule`)→ 操作层的档位表
30
+ * `:has(input:nth-of-type(n):checked)` 直接显隐,**零 JS**;
31
+ * - **组件路径**:控件不是 radio 时,本件按受控值给非选中面板下发 `hidden`。
32
+ * 两条路径都由同一个值驱动,故同时成立不会互相打架。
33
+ *
34
+ * ## 与皮肤零互指
35
+ * 本件不认识任何选择控件的类名 —— 轨道由 `selector` 插槽提供(作用域参数 `{ value, options, select }`),
36
+ * 放胶囊、分段按钮、单选卡片都行;面板内容由默认插槽按 `options` 顺序给出。
37
+ *
38
+ * @example 胶囊 + 面板(`Capsule` 提供原生 radio,故走零 JS 路径)
39
+ * <Tabset :options="tabs" v-model:value="current">
40
+ * {{
41
+ * selector: ({ value, select }) => <Capsule :options="tabs" modelValue={value} onChange={select} />,
42
+ * default: () => [
43
+ * <Card key="all">全部:15 条</Card>,
44
+ * <Card key="doing">进行中:3 条</Card>,
45
+ * ],
46
+ * }}
47
+ * </Tabset>
48
+ */
49
+ export declare const Tabset: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
50
+ options: {
51
+ type: PropType<TabsetOption[]>;
52
+ required: true;
53
+ };
54
+ value: {
55
+ type: PropType<string | number | undefined>;
56
+ default: undefined;
57
+ };
58
+ defaultValue: {
59
+ type: PropType<string | number | undefined>;
60
+ default: undefined;
61
+ };
62
+ onChange: {
63
+ type: PropType<(value: string | number) => void>;
64
+ default: undefined;
65
+ };
66
+ /** 惰性档:只有激活的面板才渲染(切走即卸载),用于面板很重(图表 / 大表格)的场景 */
67
+ lazy: {
68
+ type: BooleanConstructor;
69
+ default: boolean;
70
+ };
71
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
72
+ options: {
73
+ type: PropType<TabsetOption[]>;
74
+ required: true;
75
+ };
76
+ value: {
77
+ type: PropType<string | number | undefined>;
78
+ default: undefined;
79
+ };
80
+ defaultValue: {
81
+ type: PropType<string | number | undefined>;
82
+ default: undefined;
83
+ };
84
+ onChange: {
85
+ type: PropType<(value: string | number) => void>;
86
+ default: undefined;
87
+ };
88
+ /** 惰性档:只有激活的面板才渲染(切走即卸载),用于面板很重(图表 / 大表格)的场景 */
89
+ lazy: {
90
+ type: BooleanConstructor;
91
+ default: boolean;
92
+ };
93
+ }>> & Readonly<{}>, {
94
+ value: string | number | undefined;
95
+ onChange: (value: string | number) => void;
96
+ defaultValue: string | number | undefined;
97
+ lazy: boolean;
98
+ }, SlotsType<{
99
+ default?: () => VNodeChild;
100
+ selector?: (context: {
101
+ value: string | number | undefined;
102
+ options: TabsetOption[];
103
+ select: (value: string | number) => void;
104
+ }) => VNodeChild;
105
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -0,0 +1,68 @@
1
+ import { defineComponent, ref, computed, createVNode } from "vue";
2
+ const Tabset = /* @__PURE__ */ defineComponent({
3
+ name: "Tabset",
4
+ inheritAttrs: false,
5
+ props: {
6
+ options: {
7
+ type: Array,
8
+ required: true
9
+ },
10
+ value: {
11
+ type: [String, Number],
12
+ default: void 0
13
+ },
14
+ defaultValue: {
15
+ type: [String, Number],
16
+ default: void 0
17
+ },
18
+ onChange: {
19
+ type: Function,
20
+ default: void 0
21
+ },
22
+ /** 惰性档:只有激活的面板才渲染(切走即卸载),用于面板很重(图表 / 大表格)的场景 */
23
+ lazy: {
24
+ type: Boolean,
25
+ default: false
26
+ }
27
+ },
28
+ slots: Object,
29
+ setup(props, {
30
+ slots,
31
+ attrs
32
+ }) {
33
+ const innerValue = ref(props.value ?? props.defaultValue ?? props.options[0]?.value);
34
+ const current = computed(() => props.value ?? innerValue.value);
35
+ const select = (value) => {
36
+ const target = props.options.find((option) => option.value === value);
37
+ if (target?.disabled) return;
38
+ if (props.value === void 0) innerValue.value = value;
39
+ props.onChange?.(value);
40
+ };
41
+ const panels = () => {
42
+ const children = slots.default?.();
43
+ const list = Array.isArray(children) ? children : children ? [children] : [];
44
+ return list.map((child, index) => {
45
+ const option = props.options[index];
46
+ const active = option !== void 0 && option.value === current.value;
47
+ if (props.lazy && !active) return null;
48
+ return createVNode("div", {
49
+ "class": "mh-tabset-panel",
50
+ "hidden": !active
51
+ }, [child]);
52
+ });
53
+ };
54
+ return () => createVNode("div", {
55
+ "class": ["mh-tabset", attrs.class].filter(Boolean).join(" "),
56
+ "style": attrs.style
57
+ }, [slots.selector?.({
58
+ value: current.value,
59
+ options: props.options,
60
+ select
61
+ }), createVNode("div", {
62
+ "class": "mh-tabset-panels"
63
+ }, [panels()])]);
64
+ }
65
+ });
66
+ export {
67
+ Tabset
68
+ };