@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,351 @@
1
+ import { type PropType, type SlotsType, type VNodeChild } from 'vue';
2
+ import type { ControlSize } from '../control-size';
3
+ export interface TableColumn {
4
+ /** 取数键(也是单元格插槽的标识) */
5
+ key: string;
6
+ /** 列标题 */
7
+ title: string;
8
+ /** 列宽(`width` 或 `min-width` 都能写,如 `'120px'`、`'20%'`) */
9
+ width?: string;
10
+ align?: 'left' | 'center' | 'right';
11
+ /** 长文本省略(表头仍完整) */
12
+ ellipsis?: boolean;
13
+ /** 必填列:表头加星号 */
14
+ required?: boolean;
15
+ /** 可排序:本件只发事件与显示态,**排序算法归调用方** */
16
+ sortable?: boolean;
17
+ }
18
+ export type TableSortOrder = 'asc' | 'desc' | null;
19
+ /** 行数据:至少能用 `rowKey` 取到稳定标识 */
20
+ export type TableRow = Record<string, unknown>;
21
+ /** 行级事件(`onRow` 的返回):给整行挂点击与类,省掉「每列都写一次 onClick」 */
22
+ export interface TableRowProps {
23
+ class?: string;
24
+ onClick?: (row: TableRow, index: number, event: MouseEvent) => void;
25
+ }
26
+ /** 分页档:`false` 不渲染;给对象就渲染分页条(**本件不切片,`data` 是当前页数据**) */
27
+ export interface TablePagination {
28
+ total: number;
29
+ current?: number;
30
+ pageSize?: number;
31
+ pageSizeOptions?: number[];
32
+ onChange?: (page: number, pageSize: number) => void;
33
+ }
34
+ /**
35
+ * 表格(**自绘**;列 × 数据的表格骨架 + 选择列 + 展开行 + 排序事件 + 分页 + 三态)。
36
+ *
37
+ * ## 这个组件负责什么、不负责什么(都是刻意的)
38
+ *
39
+ * **负责**:把 `columns` × `data` 渲成表格;列对齐/宽度/省略/必填;行选中(勾选列复用本包的 `Checkbox`
40
+ * 组件 —— 它内部才是真实 `<input type="checkbox">`,故面上的 `tr:has(input:checked)` 零 JS 路径仍成立);
41
+ * 展开行;排序按钮的**状态与事件**;加载态与空态;分页条的排布与事件透传;
42
+ * `rowClass` / `onRow` 让调用方标分组行、禁用行与挂行级点击。
43
+ *
44
+ * **不负责**:
45
+ *
46
+ * - **排序与列宽拖拽的算法**:规范只给了 `↕` 字形与拖拽线这两处视觉,而 `↕` 是文字符号(本包禁拿文字
47
+ * 符号冒充图标),故朝向改用现成字形 `chevron-up` / `chevron-down` 表达 —— 本件发 `sort` 事件、画态,
48
+ * 真正排序、真正改列宽由调用方决定(它有数据、也知道业务口径);
49
+ * - **分页切片**:`pagination` 只渲染分页条并把页码事件透传出去,**`data` 始终是当前页数据** ——
50
+ * 组件自己切片会让「服务端分页」与「客户端分页」两套口径藏在同一个 prop 里;
51
+ * - **错误态**:归 `QueryState`(表格只管列数据)。
52
+ *
53
+ * @example
54
+ * <Table
55
+ * :columns="[{key:'name',title:'名称'},{key:'amount',title:'金额',align:'right'}]"
56
+ * :data="rows" row-key="id" striped selectable v-model="selected"
57
+ * :pagination="{ total: 120, current: page, onChange: (p) => (page = p) }"
58
+ * @sort="({ key, order }) => (sortKey = key, sortOrder = order)"
59
+ * />
60
+ */
61
+ export declare const Table: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
62
+ columns: {
63
+ type: PropType<TableColumn[]>;
64
+ required: true;
65
+ };
66
+ data: {
67
+ type: PropType<TableRow[]>;
68
+ default: () => never[];
69
+ };
70
+ /** 行标识字段名(选中态记的是它的值) */
71
+ rowKey: {
72
+ type: StringConstructor;
73
+ default: string;
74
+ };
75
+ /** 选中行的 key 列表(`v-model`) */
76
+ modelValue: {
77
+ type: PropType<Array<string | number>>;
78
+ default: undefined;
79
+ };
80
+ /** 选择列 */
81
+ selectable: {
82
+ type: BooleanConstructor;
83
+ default: boolean;
84
+ };
85
+ /** 斑马纹(**显式类**而非 nth-child:表里可能有分组行) */
86
+ striped: {
87
+ type: BooleanConstructor;
88
+ default: boolean;
89
+ };
90
+ /** 尺寸档:`sm` 紧凑(表格嵌在卡片里)/ `md` 标准 / `lg` 宽松(详情页) */
91
+ size: {
92
+ type: PropType<ControlSize>;
93
+ default: string;
94
+ };
95
+ /** 紧凑档(= `size="sm"`,保留的既有写法) */
96
+ compact: {
97
+ type: BooleanConstructor;
98
+ default: boolean;
99
+ };
100
+ borderless: {
101
+ type: BooleanConstructor;
102
+ default: boolean;
103
+ };
104
+ /** 外框交给包裹层(满高表格用) */
105
+ fill: {
106
+ type: BooleanConstructor;
107
+ default: boolean;
108
+ };
109
+ stickyHead: {
110
+ type: BooleanConstructor;
111
+ default: boolean;
112
+ };
113
+ stickyCol: {
114
+ type: BooleanConstructor;
115
+ default: boolean;
116
+ };
117
+ /** 加载态:内容上盖一层浅罩 + 转圈(**行高不塌**,避免加载时表格跳动) */
118
+ loading: {
119
+ type: BooleanConstructor;
120
+ default: boolean;
121
+ };
122
+ /** 隐藏表头(纯展示的键值表用) */
123
+ showHeader: {
124
+ type: BooleanConstructor;
125
+ default: boolean;
126
+ };
127
+ /** 空数据文案(表格内的空态;要插画与操作按钮就用 `empty` 插槽) */
128
+ emptyText: {
129
+ type: StringConstructor;
130
+ default: string;
131
+ };
132
+ /** 受控排序键与方向(由调用方给,本件只显示) */
133
+ sortKey: {
134
+ type: StringConstructor;
135
+ default: undefined;
136
+ };
137
+ sortOrder: {
138
+ type: PropType<TableSortOrder>;
139
+ default: null;
140
+ };
141
+ /** 给某行追加类(分组行 / 禁用行 / 静态选中档由调用方标) */
142
+ rowClass: {
143
+ type: PropType<(row: TableRow, index: number) => string>;
144
+ default: undefined;
145
+ };
146
+ /** 行级事件:`(row, index) => ({ class, onClick })` */
147
+ onRow: {
148
+ type: PropType<(row: TableRow, index: number) => TableRowProps>;
149
+ default: undefined;
150
+ };
151
+ /** 展开行:给了就出现展开列;返回的内容渲染在行下方的整宽格子里 */
152
+ expandable: {
153
+ type: PropType<(row: TableRow, index: number) => VNodeChild>;
154
+ default: undefined;
155
+ };
156
+ /** 展开行的 key(受控) */
157
+ expandedKeys: {
158
+ type: PropType<Array<string | number>>;
159
+ default: undefined;
160
+ };
161
+ /** 展开行的 key(非受控初值) */
162
+ defaultExpandedKeys: {
163
+ type: PropType<Array<string | number>>;
164
+ default: () => never[];
165
+ };
166
+ /** 展开变化(受控与非受控都会调) */
167
+ onExpandChange: {
168
+ type: PropType<(keys: Array<string | number>) => void>;
169
+ default: undefined;
170
+ };
171
+ /** 分页档:`false` 不渲染底部分页条 */
172
+ pagination: {
173
+ type: PropType<false | TablePagination>;
174
+ default: boolean;
175
+ };
176
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
177
+ /** 选中行 key 列表(`v-model`) */
178
+ 'update:modelValue': (keys: Array<string | number>) => boolean;
179
+ /** 选中变化(与 `v-model` 同时发,方便只听不接管) */
180
+ change: (keys: Array<string | number>) => boolean;
181
+ /** 排序请求:本件只发事件与显示态,**排序由调用方做** */
182
+ sort: (payload: {
183
+ key: string;
184
+ order: TableSortOrder;
185
+ }) => boolean;
186
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
187
+ columns: {
188
+ type: PropType<TableColumn[]>;
189
+ required: true;
190
+ };
191
+ data: {
192
+ type: PropType<TableRow[]>;
193
+ default: () => never[];
194
+ };
195
+ /** 行标识字段名(选中态记的是它的值) */
196
+ rowKey: {
197
+ type: StringConstructor;
198
+ default: string;
199
+ };
200
+ /** 选中行的 key 列表(`v-model`) */
201
+ modelValue: {
202
+ type: PropType<Array<string | number>>;
203
+ default: undefined;
204
+ };
205
+ /** 选择列 */
206
+ selectable: {
207
+ type: BooleanConstructor;
208
+ default: boolean;
209
+ };
210
+ /** 斑马纹(**显式类**而非 nth-child:表里可能有分组行) */
211
+ striped: {
212
+ type: BooleanConstructor;
213
+ default: boolean;
214
+ };
215
+ /** 尺寸档:`sm` 紧凑(表格嵌在卡片里)/ `md` 标准 / `lg` 宽松(详情页) */
216
+ size: {
217
+ type: PropType<ControlSize>;
218
+ default: string;
219
+ };
220
+ /** 紧凑档(= `size="sm"`,保留的既有写法) */
221
+ compact: {
222
+ type: BooleanConstructor;
223
+ default: boolean;
224
+ };
225
+ borderless: {
226
+ type: BooleanConstructor;
227
+ default: boolean;
228
+ };
229
+ /** 外框交给包裹层(满高表格用) */
230
+ fill: {
231
+ type: BooleanConstructor;
232
+ default: boolean;
233
+ };
234
+ stickyHead: {
235
+ type: BooleanConstructor;
236
+ default: boolean;
237
+ };
238
+ stickyCol: {
239
+ type: BooleanConstructor;
240
+ default: boolean;
241
+ };
242
+ /** 加载态:内容上盖一层浅罩 + 转圈(**行高不塌**,避免加载时表格跳动) */
243
+ loading: {
244
+ type: BooleanConstructor;
245
+ default: boolean;
246
+ };
247
+ /** 隐藏表头(纯展示的键值表用) */
248
+ showHeader: {
249
+ type: BooleanConstructor;
250
+ default: boolean;
251
+ };
252
+ /** 空数据文案(表格内的空态;要插画与操作按钮就用 `empty` 插槽) */
253
+ emptyText: {
254
+ type: StringConstructor;
255
+ default: string;
256
+ };
257
+ /** 受控排序键与方向(由调用方给,本件只显示) */
258
+ sortKey: {
259
+ type: StringConstructor;
260
+ default: undefined;
261
+ };
262
+ sortOrder: {
263
+ type: PropType<TableSortOrder>;
264
+ default: null;
265
+ };
266
+ /** 给某行追加类(分组行 / 禁用行 / 静态选中档由调用方标) */
267
+ rowClass: {
268
+ type: PropType<(row: TableRow, index: number) => string>;
269
+ default: undefined;
270
+ };
271
+ /** 行级事件:`(row, index) => ({ class, onClick })` */
272
+ onRow: {
273
+ type: PropType<(row: TableRow, index: number) => TableRowProps>;
274
+ default: undefined;
275
+ };
276
+ /** 展开行:给了就出现展开列;返回的内容渲染在行下方的整宽格子里 */
277
+ expandable: {
278
+ type: PropType<(row: TableRow, index: number) => VNodeChild>;
279
+ default: undefined;
280
+ };
281
+ /** 展开行的 key(受控) */
282
+ expandedKeys: {
283
+ type: PropType<Array<string | number>>;
284
+ default: undefined;
285
+ };
286
+ /** 展开行的 key(非受控初值) */
287
+ defaultExpandedKeys: {
288
+ type: PropType<Array<string | number>>;
289
+ default: () => never[];
290
+ };
291
+ /** 展开变化(受控与非受控都会调) */
292
+ onExpandChange: {
293
+ type: PropType<(keys: Array<string | number>) => void>;
294
+ default: undefined;
295
+ };
296
+ /** 分页档:`false` 不渲染底部分页条 */
297
+ pagination: {
298
+ type: PropType<false | TablePagination>;
299
+ default: boolean;
300
+ };
301
+ }>> & Readonly<{
302
+ onSort?: ((payload: {
303
+ key: string;
304
+ order: TableSortOrder;
305
+ }) => any) | undefined;
306
+ onChange?: ((keys: (string | number)[]) => any) | undefined;
307
+ "onUpdate:modelValue"?: ((keys: (string | number)[]) => any) | undefined;
308
+ }>, {
309
+ fill: boolean;
310
+ size: ControlSize;
311
+ compact: boolean;
312
+ data: TableRow[];
313
+ loading: boolean;
314
+ rowKey: string;
315
+ expandedKeys: (string | number)[];
316
+ defaultExpandedKeys: (string | number)[];
317
+ onExpandChange: (keys: Array<string | number>) => void;
318
+ modelValue: (string | number)[];
319
+ emptyText: string;
320
+ selectable: boolean;
321
+ striped: boolean;
322
+ borderless: boolean;
323
+ stickyHead: boolean;
324
+ stickyCol: boolean;
325
+ showHeader: boolean;
326
+ sortKey: string;
327
+ sortOrder: TableSortOrder;
328
+ rowClass: (row: TableRow, index: number) => string;
329
+ onRow: (row: TableRow, index: number) => TableRowProps;
330
+ expandable: (row: TableRow, index: number) => VNodeChild;
331
+ pagination: false | TablePagination;
332
+ }, SlotsType<{
333
+ /** 单元格:`{ row, column, value, index }`(不给则直接输出原值) */
334
+ cell?: (context: {
335
+ row: TableRow;
336
+ column: TableColumn;
337
+ value: unknown;
338
+ index: number;
339
+ }) => VNodeChild;
340
+ /** 行尾操作区:`{ row, index }`(面里用 `align: 'right'` 的列承载) */
341
+ actions?: (context: {
342
+ row: TableRow;
343
+ index: number;
344
+ }) => VNodeChild;
345
+ /** 批量栏:选中非空时出现在表格上方(`{ selected }`) */
346
+ batch?: (context: {
347
+ selected: Array<string | number>;
348
+ }) => VNodeChild;
349
+ /** 空态自定义(插画 + 操作按钮);不给则渲染 `emptyText` 一行 */
350
+ empty?: () => VNodeChild;
351
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -0,0 +1,286 @@
1
+ import { defineComponent, computed, ref, createVNode } from "vue";
2
+ import { Icon } from "@manohub/icon";
3
+ import { Checkbox } from "../checkbox/index.js";
4
+ import { Pagination } from "../pagination/index.js";
5
+ const Table = /* @__PURE__ */ defineComponent({
6
+ name: "Table",
7
+ inheritAttrs: false,
8
+ props: {
9
+ columns: {
10
+ type: Array,
11
+ required: true
12
+ },
13
+ data: {
14
+ type: Array,
15
+ default: () => []
16
+ },
17
+ /** 行标识字段名(选中态记的是它的值) */
18
+ rowKey: {
19
+ type: String,
20
+ default: "id"
21
+ },
22
+ /** 选中行的 key 列表(`v-model`) */
23
+ modelValue: {
24
+ type: Array,
25
+ default: void 0
26
+ },
27
+ /** 选择列 */
28
+ selectable: {
29
+ type: Boolean,
30
+ default: false
31
+ },
32
+ /** 斑马纹(**显式类**而非 nth-child:表里可能有分组行) */
33
+ striped: {
34
+ type: Boolean,
35
+ default: false
36
+ },
37
+ /** 尺寸档:`sm` 紧凑(表格嵌在卡片里)/ `md` 标准 / `lg` 宽松(详情页) */
38
+ size: {
39
+ type: String,
40
+ default: "md"
41
+ },
42
+ /** 紧凑档(= `size="sm"`,保留的既有写法) */
43
+ compact: {
44
+ type: Boolean,
45
+ default: false
46
+ },
47
+ borderless: {
48
+ type: Boolean,
49
+ default: false
50
+ },
51
+ /** 外框交给包裹层(满高表格用) */
52
+ fill: {
53
+ type: Boolean,
54
+ default: false
55
+ },
56
+ stickyHead: {
57
+ type: Boolean,
58
+ default: false
59
+ },
60
+ stickyCol: {
61
+ type: Boolean,
62
+ default: false
63
+ },
64
+ /** 加载态:内容上盖一层浅罩 + 转圈(**行高不塌**,避免加载时表格跳动) */
65
+ loading: {
66
+ type: Boolean,
67
+ default: false
68
+ },
69
+ /** 隐藏表头(纯展示的键值表用) */
70
+ showHeader: {
71
+ type: Boolean,
72
+ default: true
73
+ },
74
+ /** 空数据文案(表格内的空态;要插画与操作按钮就用 `empty` 插槽) */
75
+ emptyText: {
76
+ type: String,
77
+ default: "暂无数据"
78
+ },
79
+ /** 受控排序键与方向(由调用方给,本件只显示) */
80
+ sortKey: {
81
+ type: String,
82
+ default: void 0
83
+ },
84
+ sortOrder: {
85
+ type: String,
86
+ default: null
87
+ },
88
+ /** 给某行追加类(分组行 / 禁用行 / 静态选中档由调用方标) */
89
+ rowClass: {
90
+ type: Function,
91
+ default: void 0
92
+ },
93
+ /** 行级事件:`(row, index) => ({ class, onClick })` */
94
+ onRow: {
95
+ type: Function,
96
+ default: void 0
97
+ },
98
+ /** 展开行:给了就出现展开列;返回的内容渲染在行下方的整宽格子里 */
99
+ expandable: {
100
+ type: Function,
101
+ default: void 0
102
+ },
103
+ /** 展开行的 key(受控) */
104
+ expandedKeys: {
105
+ type: Array,
106
+ default: void 0
107
+ },
108
+ /** 展开行的 key(非受控初值) */
109
+ defaultExpandedKeys: {
110
+ type: Array,
111
+ default: () => []
112
+ },
113
+ /** 展开变化(受控与非受控都会调) */
114
+ onExpandChange: {
115
+ type: Function,
116
+ default: void 0
117
+ },
118
+ /** 分页档:`false` 不渲染底部分页条 */
119
+ pagination: {
120
+ type: [Boolean, Object],
121
+ default: false
122
+ }
123
+ },
124
+ emits: {
125
+ /** 选中行 key 列表(`v-model`) */
126
+ "update:modelValue": (keys) => Array.isArray(keys),
127
+ /** 选中变化(与 `v-model` 同时发,方便只听不接管) */
128
+ change: (keys) => Array.isArray(keys),
129
+ /** 排序请求:本件只发事件与显示态,**排序由调用方做** */
130
+ sort: (payload) => typeof payload.key === "string"
131
+ },
132
+ slots: Object,
133
+ setup(props, {
134
+ slots,
135
+ attrs,
136
+ emit
137
+ }) {
138
+ const keys = computed(() => props.data.map((row) => row[props.rowKey]));
139
+ const selected = computed(() => props.modelValue ?? []);
140
+ const allSelected = computed(() => keys.value.length > 0 && selected.value.length >= keys.value.length);
141
+ const someSelected = computed(() => selected.value.length > 0 && !allSelected.value);
142
+ const innerExpanded = ref(props.defaultExpandedKeys);
143
+ const expanded = computed(() => props.expandedKeys ?? innerExpanded.value);
144
+ const toggleExpand = (key) => {
145
+ const next = expanded.value.includes(key) ? expanded.value.filter((item) => item !== key) : [...expanded.value, key];
146
+ if (props.expandedKeys === void 0) innerExpanded.value = next;
147
+ props.onExpandChange?.(next);
148
+ };
149
+ const resolvedSize = computed(() => props.compact ? "sm" : props.size);
150
+ const leadColumns = computed(() => (props.selectable ? 1 : 0) + (props.expandable ? 1 : 0));
151
+ const columnCount = computed(() => leadColumns.value + props.columns.length);
152
+ const isEmpty = computed(() => props.data.length === 0);
153
+ const cellClass = (column) => [column.align === "center" ? "mh-table__cell-center" : "", column.align === "right" ? "mh-table__cell-amount" : "", column.ellipsis ? "mh-table__cell-ellipsis" : ""].filter(Boolean);
154
+ const commit = (next) => {
155
+ emit("update:modelValue", next);
156
+ emit("change", next);
157
+ };
158
+ const toggleRow = (key) => {
159
+ const has = selected.value.includes(key);
160
+ commit(has ? selected.value.filter((item) => item !== key) : [...selected.value, key]);
161
+ };
162
+ const toggleAll = () => commit(allSelected.value ? [] : [...keys.value]);
163
+ const nextOrder = (key) => {
164
+ if (props.sortKey !== key) return "asc";
165
+ if (props.sortOrder === "asc") return "desc";
166
+ if (props.sortOrder === "desc") return null;
167
+ return "asc";
168
+ };
169
+ const sortGlyph = (key) => props.sortKey === key && props.sortOrder === "asc" ? "chevron-up" : "chevron-down";
170
+ return () => {
171
+ const tableClass = ["mh-table", resolvedSize.value === "sm" ? "mh-table--xs" : "", resolvedSize.value === "lg" ? "mh-table--lg" : "", props.borderless ? "mh-table--borderless" : "", props.fill ? "mh-table--fill" : "", props.stickyHead ? "mh-table--sticky-head" : "", props.stickyCol ? "mh-table--sticky-col" : "", attrs.class].filter(Boolean).join(" ");
172
+ const pager = typeof props.pagination === "object" ? props.pagination : null;
173
+ return createVNode("div", {
174
+ "class": "mh-table-wrapper",
175
+ "style": attrs.style
176
+ }, [slots.batch && selected.value.length > 0 ? createVNode("div", {
177
+ "class": "mh-table__batch"
178
+ }, [slots.batch({
179
+ selected: selected.value
180
+ })]) : null, createVNode("table", {
181
+ "class": tableClass
182
+ }, [props.showHeader ? createVNode("thead", null, [createVNode("tr", null, [props.expandable ? createVNode("th", {
183
+ "class": "mh-table__col-expand",
184
+ "aria-label": "展开"
185
+ }, null) : null, props.selectable ? createVNode("th", {
186
+ "class": "mh-table__col-check"
187
+ }, [createVNode(Checkbox, {
188
+ "aria-label": "全选",
189
+ "modelValue": allSelected.value,
190
+ "indeterminate": someSelected.value && !allSelected.value,
191
+ "onChange": toggleAll
192
+ }, null)]) : null, props.columns.map((column) => createVNode("th", {
193
+ "key": column.key,
194
+ "class": [column.required ? "mh-table__cell-required" : "", column.align === "center" ? "mh-table__cell-center" : "", column.align === "right" ? "mh-table__col-actions" : ""].filter(Boolean).join(" "),
195
+ "style": column.width ? {
196
+ width: column.width
197
+ } : void 0
198
+ }, [column.title, column.sortable ? createVNode("button", {
199
+ "type": "button",
200
+ "class": ["mh-table__sort", props.sortKey === column.key && props.sortOrder ? "mh-table__sort--active" : ""].filter(Boolean).join(" "),
201
+ "aria-label": `按${column.title}排序`,
202
+ "onClick": () => emit("sort", {
203
+ key: column.key,
204
+ order: nextOrder(column.key)
205
+ })
206
+ }, [createVNode(Icon, {
207
+ "name": sortGlyph(column.key),
208
+ "class": ["mh-table__sort-icon", props.sortKey === column.key && props.sortOrder === "asc" ? "mh-table__sort-icon--asc" : "", props.sortKey === column.key && props.sortOrder === "desc" ? "mh-table__sort-icon--desc" : ""].filter(Boolean).join(" ")
209
+ }, null)]) : null]))])]) : null, createVNode("tbody", null, [isEmpty.value ? createVNode("tr", {
210
+ "class": "mh-table__empty-row"
211
+ }, [createVNode("td", {
212
+ "class": "mh-table__empty",
213
+ "colspan": columnCount.value
214
+ }, [slots.empty ? slots.empty() : props.emptyText])]) : null, props.data.map((row, index) => {
215
+ const key = row[props.rowKey];
216
+ const rowProps = props.onRow?.(row, index);
217
+ const isExpanded = expanded.value.includes(key);
218
+ const rowState = [props.striped && index % 2 === 1 ? "is-striped" : "", selected.value.includes(key) ? "is-selected" : "", rowProps?.onClick ? "is-clickable" : "", rowProps?.class ?? "", props.rowClass?.(row, index) ?? ""].filter(Boolean).join(" ");
219
+ return [createVNode("tr", {
220
+ "key": key,
221
+ "class": rowState,
222
+ "data-state": selected.value.includes(key) ? "selected" : "idle",
223
+ "onClick": rowProps?.onClick ? (event) => rowProps.onClick?.(row, index, event) : void 0
224
+ }, [props.expandable ? createVNode("td", {
225
+ "class": "mh-table__col-expand"
226
+ }, [createVNode("button", {
227
+ "type": "button",
228
+ "class": "mh-table__expand",
229
+ "aria-label": isExpanded ? "收起" : "展开",
230
+ "aria-expanded": isExpanded ? "true" : "false",
231
+ "onClick": (event) => {
232
+ event.stopPropagation();
233
+ toggleExpand(key);
234
+ }
235
+ }, [createVNode(Icon, {
236
+ "name": "chevron-down",
237
+ "class": "mh-table__expand-icon"
238
+ }, null)])]) : null, props.selectable ? (
239
+ /* 勾选列复用 `Checkbox`(不在表格里手写原生 input)。行本身可能带 onClick(onRow):
240
+ 勾选不该顺带触发行点击 —— 阻断挂在**单元格**上,因为 `Checkbox` 的根是 `label`,
241
+ 点它会冒泡两次(label 自身一次 + 转发给 input 一次),只挡 input 挡不住行点击。 */
242
+ createVNode("td", {
243
+ "class": "mh-table__col-check",
244
+ "onClick": (event) => event.stopPropagation()
245
+ }, [createVNode(Checkbox, {
246
+ "aria-label": "选择本行",
247
+ "modelValue": selected.value.includes(key),
248
+ "onChange": () => toggleRow(key)
249
+ }, null)])
250
+ ) : null, props.columns.map((column) => createVNode("td", {
251
+ "key": column.key,
252
+ "class": cellClass(column).join(" ")
253
+ }, [slots.cell ? slots.cell({
254
+ row,
255
+ column,
256
+ value: row[column.key],
257
+ index
258
+ }) : slots.actions && column.align === "right" ? slots.actions({
259
+ row,
260
+ index
261
+ }) : String(row[column.key] ?? "")]))]), isExpanded ? createVNode("tr", {
262
+ "key": `${key}-expand`,
263
+ "class": "mh-table__expand-row"
264
+ }, [createVNode("td", {
265
+ "colspan": columnCount.value
266
+ }, [props.expandable?.(row, index)])]) : null];
267
+ })])]), props.loading ? createVNode("div", {
268
+ "class": "mh-table__loading",
269
+ "aria-busy": "true"
270
+ }, [createVNode("span", {
271
+ "class": "mh-table__spinner"
272
+ }, null)]) : null, pager ? createVNode("div", {
273
+ "class": "mh-table__pagination"
274
+ }, [createVNode(Pagination, {
275
+ "total": pager.total,
276
+ "modelValue": pager.current ?? 1,
277
+ "pageSize": pager.pageSize ?? 10,
278
+ "pageSizeOptions": pager.pageSizeOptions,
279
+ "onChange": (payload) => pager.onChange?.(payload.page, payload.pageSize)
280
+ }, null)]) : null]);
281
+ };
282
+ }
283
+ });
284
+ export {
285
+ Table
286
+ };