@manohub/ui 1.0.5 → 1.0.8
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.
- package/README.md +8 -2
- package/dist/components/badge/index.d.ts +24 -46
- package/dist/components/badge/index.js +7 -11
- package/dist/components/button/index.d.ts +11 -31
- package/dist/components/capsule/index.d.ts +13 -27
- package/dist/components/card/index.d.ts +21 -54
- package/dist/components/checkbox/index.d.ts +1 -9
- package/dist/components/code-block/index.d.ts +35 -62
- package/dist/components/collapse/index.d.ts +2 -0
- package/dist/components/dialog/index.d.ts +6 -15
- package/dist/components/divider/index.d.ts +1 -12
- package/dist/components/drawer/index.d.ts +7 -15
- package/dist/components/filter/index.d.ts +27 -69
- package/dist/components/filter/index.js +3 -8
- package/dist/components/form/index.d.ts +52 -132
- package/dist/components/form/index.js +5 -12
- package/dist/components/input/bordered.d.ts +4 -6
- package/dist/components/input/index.d.ts +47 -66
- package/dist/components/input/index.js +7 -8
- package/dist/components/input/number-input.d.ts +11 -23
- package/dist/components/layout/index.d.ts +21 -28
- package/dist/components/layout/index.js +5 -8
- package/dist/components/list-view/index.d.ts +10 -43
- package/dist/components/loading/index.d.ts +8 -19
- package/dist/components/nav/index.d.ts +14 -35
- package/dist/components/nav/index.js +1 -3
- package/dist/components/notice/index.d.ts +13 -33
- package/dist/components/notice/index.js +3 -5
- package/dist/components/notification/index.d.ts +0 -9
- package/dist/components/page/index.d.ts +8 -43
- package/dist/components/page/split-resize.d.ts +9 -18
- package/dist/components/pagination/index.d.ts +1 -5
- package/dist/components/panel/index.d.ts +27 -62
- package/dist/components/panel/index.js +1 -4
- package/dist/components/part-padding.d.ts +5 -13
- package/dist/components/query-state/index.d.ts +8 -32
- package/dist/components/radio/index.d.ts +2 -3
- package/dist/components/search/index.d.ts +12 -32
- package/dist/components/select/index.d.ts +7 -14
- package/dist/components/select/index.js +3 -3
- package/dist/components/select/select-panel.d.ts +23 -35
- package/dist/components/select/select-panel.js +5 -10
- package/dist/components/select/select-shared.d.ts +18 -44
- package/dist/components/select/select-tree.d.ts +11 -16
- package/dist/components/select/select-trigger.d.ts +6 -16
- package/dist/components/select/select-trigger.js +5 -11
- package/dist/components/skeleton/index.d.ts +1 -5
- package/dist/components/steps/index.d.ts +55 -111
- package/dist/components/steps/index.js +8 -16
- package/dist/components/switch/index.d.ts +17 -33
- package/dist/components/switch/index.js +2 -4
- package/dist/components/tabbar/index.d.ts +1 -6
- package/dist/components/table/index.d.ts +43 -105
- package/dist/components/table/index.js +166 -125
- package/dist/components/tabs/index.d.ts +22 -44
- package/dist/components/text/index.d.ts +10 -21
- package/dist/components/toast/index.d.ts +4 -13
- package/dist/components/tooltip/index.d.ts +1 -12
- package/dist/components/tree/index.d.ts +35 -77
- package/dist/components/tree/index.js +17 -33
- package/dist/components/upload/index.d.ts +1 -4
- package/dist/index.d.ts +3 -3
- package/dist/services/base.d.ts +32 -8
- package/dist/services/dialog.d.ts +10 -22
- package/dist/services/index.d.ts +2 -2
- package/dist/services/loading.d.ts +9 -12
- package/dist/services/loading.js +8 -1
- package/dist/services/toast.d.ts +4 -14
- package/dist/styles/components/button.css +2 -0
- package/dist/styles/components/capsule.css +2 -0
- package/dist/styles/components/checkbox.css +2 -0
- package/dist/styles/components/form.css +23 -28
- package/dist/styles/components/input.css +53 -71
- package/dist/styles/components/notice.css +2 -0
- package/dist/styles/components/page.css +25 -31
- package/dist/styles/components/pagination.css +4 -0
- package/dist/styles/components/radio.css +2 -0
- package/dist/styles/components/search.css +8 -10
- package/dist/styles/components/switch.css +2 -0
- package/dist/styles/components/tabbar.css +2 -0
- package/dist/styles/components/table.css +72 -58
- package/dist/styles/components/table.tokens.css +1 -1
- package/dist/styles/components/upload.css +2 -0
- package/package.json +2 -2
|
@@ -13,6 +13,8 @@ export interface TableColumn {
|
|
|
13
13
|
* - `'120px'` —— 固定宽(`fixed` 下是硬宽,**容器变窄也不收缩**,可能横向滚动)
|
|
14
14
|
* - `'20%'` —— 百分比(**吃满 + 严格按比例 + 任意容器宽不溢出**,响应式首选)
|
|
15
15
|
* - 不传 —— 单用时吃剩余/等分;**与 `px` 混用会被压到 0**,不建议
|
|
16
|
+
*
|
|
17
|
+
* 用法见 `docs/demos/table/`(每个维度一份可运行样例;文档页 `docs/components/table.md`)。
|
|
16
18
|
*/
|
|
17
19
|
width?: string | number;
|
|
18
20
|
align?: 'left' | 'center' | 'right';
|
|
@@ -30,11 +32,9 @@ export interface TableColumn {
|
|
|
30
32
|
*/
|
|
31
33
|
wrap?: boolean;
|
|
32
34
|
/**
|
|
33
|
-
* 列下限(px):防止窄容器把该列压没。**给了才下发 `min-width
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* 想要真下限得换机制(该列直接给 px 硬宽,或把内容包一层带 `min-width` 的盒)。
|
|
37
|
-
* 只在调用方显式要时才下发(`<col>` 上不写时不会出现)。
|
|
35
|
+
* 列下限(px):防止窄容器把该列压没。**给了才下发 `min-width`**(`<col>` 上不写就不会出现)。⚠️ **不是硬下限**:
|
|
36
|
+
* 实测 `<col>` 上的 `min-width` 会被当成**分配权重**参与按比例分摊 —— 800 宽容器下 `width:50% + min-width:500px`
|
|
37
|
+
* 的列只有 **444**。想要真下限得换机制(该列直接给 px 硬宽,或把内容包一层带 `min-width` 的盒)。
|
|
38
38
|
*/
|
|
39
39
|
minWidth?: number;
|
|
40
40
|
/** 必填列:表头加星号 */
|
|
@@ -43,6 +43,8 @@ export interface TableColumn {
|
|
|
43
43
|
sortable?: boolean;
|
|
44
44
|
}
|
|
45
45
|
export type TableSortOrder = 'asc' | 'desc' | null;
|
|
46
|
+
/** 满高档取值:不传 / `false` = 高度由内容撑起;`true` / `'parent'` = 占满父级;`number` = 表体滚动上限(px) */
|
|
47
|
+
export type TableFill = boolean | 'parent' | number;
|
|
46
48
|
/** 行数据:至少能用 `rowKey` 取到稳定标识 */
|
|
47
49
|
export type TableRow = Record<string, unknown>;
|
|
48
50
|
/** 行级事件(`onRow` 的返回):给整行挂点击与类,省掉「每列都写一次 onClick」 */
|
|
@@ -61,15 +63,6 @@ export interface TableRowProps {
|
|
|
61
63
|
* **回写是受控的**:`setValue(next)` 只把「这一格变成了什么」上报出去
|
|
62
64
|
* (= 发一次 `onCellChange(row, column.key, next, index)`)。本件**从不改 `data`** ——
|
|
63
65
|
* 新数组与「这次改动该不该被接受」都由调用方决定,与行选中同一套受控口径。
|
|
64
|
-
*
|
|
65
|
-
* @example 编辑格:套 `Form.Item` 拿错误位,控件自己绑值、回写走 `setValue`
|
|
66
|
-
* <Table :columns="columns" :data="rows" row-key="id" layout="fixed" :on-cell-change="write">
|
|
67
|
-
* <template #cell="{ row, column, value, index, setValue }">
|
|
68
|
-
* <!-- 格子里的框由控件自己带:默认有框 / `:bordered="false"` 无框 / `bordered="focus"` 聚焦才显框 -->
|
|
69
|
-
* <Input v-if="column.key === 'name'" :model-value="String(value ?? '')" @change="setValue" />
|
|
70
|
-
* <template v-else>{{ value }}</template>
|
|
71
|
-
* </template>
|
|
72
|
-
* </Table>
|
|
73
66
|
*/
|
|
74
67
|
export interface TableCellSlotScope {
|
|
75
68
|
row: TableRow;
|
|
@@ -80,28 +73,17 @@ export interface TableCellSlotScope {
|
|
|
80
73
|
/** 上报该格的新值(= 发一次 `onCellChange`);调用方没接 `onCellChange` 时是空操作 */
|
|
81
74
|
setValue: (next: unknown) => void;
|
|
82
75
|
}
|
|
83
|
-
/**
|
|
84
|
-
* 行级可勾选判定(`selectable` 的函数形态):返回 `false` 的行渲染**禁用态**勾选框,
|
|
85
|
-
* 且不进表头全选的增删范围。签名与 `onRow` / `rowClass` 一致(都给 `index`)。
|
|
86
|
-
*/
|
|
76
|
+
/** 行级可勾选判定(`selectable` 的函数形态):返回 `false` 的行渲染**禁用态**勾选框,且不进表头全选的增删范围;签名与 `onRow` / `rowClass` 一致(都给 `index`)。 */
|
|
87
77
|
export type TableRowSelectable = (row: TableRow, index: number) => boolean;
|
|
88
|
-
/** 分页档:`false` 不渲染;给对象就渲染分页条(**本件不切片,`data` 是当前页数据**) */
|
|
89
|
-
export interface TablePagination {
|
|
90
|
-
total: number;
|
|
91
|
-
current?: number;
|
|
92
|
-
pageSize?: number;
|
|
93
|
-
pageSizeOptions?: number[];
|
|
94
|
-
onChange?: (page: number, pageSize: number) => void;
|
|
95
|
-
}
|
|
96
78
|
/**
|
|
97
|
-
* 表格(**自绘**;列 × 数据的表格骨架 + 选择列 + 展开行 + 排序事件 +
|
|
79
|
+
* 表格(**自绘**;列 × 数据的表格骨架 + 选择列 + 展开行 + 排序事件 + 三态)。
|
|
98
80
|
*
|
|
99
81
|
* ## 这个组件负责什么、不负责什么(都是刻意的)
|
|
100
82
|
*
|
|
101
83
|
* **负责**:把 `columns` × `data` 渲成表格;列对齐 / 宽度 / 省略 / 必填;行选中(勾选列复用本包的
|
|
102
84
|
* `Checkbox` 组件 —— 它内部才是真实 `<input type="checkbox">`,故面上的
|
|
103
85
|
* `tr:has(.mh-table__col-check input:checked)` 零 JS 路径仍成立;选择器**限定在勾选列内**,否则功能列的
|
|
104
|
-
* `Switch`
|
|
86
|
+
* `Switch` 也会把整行点亮);展开行;排序按钮的**状态与事件**;加载态与空态;
|
|
105
87
|
* `rowClass` / `onRow` 让调用方标分组行、禁用行与挂行级点击。
|
|
106
88
|
*
|
|
107
89
|
* **不负责**:
|
|
@@ -109,38 +91,8 @@ export interface TablePagination {
|
|
|
109
91
|
* - **排序算法归调用方**(列宽拖拽同理):规范只给了 `↕` 字形与拖拽线两处视觉,而 `↕` 是文字符号(本包禁
|
|
110
92
|
* 拿文字符号冒充图标),故朝向改用现成字形 `chevron-up` / `chevron-down` 表达 —— 本件发 `sort` 事件、
|
|
111
93
|
* 画态,真正排序 / 改列宽由调用方决定(它有数据、也知道业务口径);
|
|
112
|
-
* -
|
|
113
|
-
* 让「服务端分页」与「客户端分页」两套口径藏在同一个 prop 里;
|
|
94
|
+
* - **分页条**:本件不内建(`data` 始终是给它的那页数据),页码状态、切片与分页条的摆放都归调用方;
|
|
114
95
|
* - **错误态**:归 `QueryState`(表格只管列数据)。
|
|
115
|
-
*
|
|
116
|
-
* @example 基本列表(表默认满宽;列宽给权重 + `fixed` 才严格按比例)
|
|
117
|
-
* <Table
|
|
118
|
-
* layout="fixed" striped row-key="id" :data="rows"
|
|
119
|
-
* :columns="[
|
|
120
|
-
* { key: 'name', title: '名称', width: 3 },
|
|
121
|
-
* { key: 'amount', title: '金额', width: 1, align: 'right' },
|
|
122
|
-
* { key: 'description', title: '描述', width: 4, wrap: true },
|
|
123
|
-
* ]"
|
|
124
|
-
* :pagination="{ total: 120, current: page, onChange: (p) => (page = p) }"
|
|
125
|
-
* />
|
|
126
|
-
*
|
|
127
|
-
* @example 操作列(用 `actions` 插槽 + 一列 `align:'right'`;行内操作同族,`Button.Group` 收口)
|
|
128
|
-
* <Table :columns="columns" :data="rows" row-key="id">
|
|
129
|
-
* {{
|
|
130
|
-
* actions: ({ row }) => (
|
|
131
|
-
* <Button.Group>
|
|
132
|
-
* <Button variant="text" onClick={() => open(row)}>编辑</Button>
|
|
133
|
-
* <Button variant="text" danger onClick={() => remove(row)}>删除</Button>
|
|
134
|
-
* </Button.Group>
|
|
135
|
-
* ),
|
|
136
|
-
* }}
|
|
137
|
-
* </Table>
|
|
138
|
-
*
|
|
139
|
-
* @example 单元格自定义 + 按行判定可勾选
|
|
140
|
-
* <Table :columns="columns" :data="rows" row-key="id" v-model="selected"
|
|
141
|
-
* :selectable="(row) => row.status === 'draft'">
|
|
142
|
-
* {{ cell: ({ value, column }) => column.key === 'status' ? <Text tone="success">{value}</Text> : value }}
|
|
143
|
-
* </Table>
|
|
144
96
|
*/
|
|
145
97
|
export declare const Table: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
146
98
|
columns: {
|
|
@@ -181,11 +133,8 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
181
133
|
default: boolean;
|
|
182
134
|
};
|
|
183
135
|
/**
|
|
184
|
-
* 单元格值变更 —— 由 `#cell` 插槽里的 `setValue`
|
|
185
|
-
*
|
|
186
|
-
* 本件**不改 `data`**(与本仓表格一贯的克制口径一致:全受控、只发事件、不排序、不切片);
|
|
187
|
-
* 要不要接受、以及新数组怎么产生,都由调用方决定。
|
|
188
|
-
* 没接这个回调时 `setValue` 是空操作(插槽里的控件照旧可绑,不会报错)。
|
|
136
|
+
* 单元格值变更 —— 由 `#cell` 插槽里的 `setValue` 触发,是**唯一的回写通道**。本件**不改 `data`**(全受控、只发
|
|
137
|
+
* 事件、不排序、不切片);要不要接受、新数组怎么产生都由调用方决定;没接这个回调时 `setValue` 是空操作。
|
|
189
138
|
*/
|
|
190
139
|
onCellChange: {
|
|
191
140
|
type: PropType<(row: TableRow, key: string, value: unknown, index: number) => void>;
|
|
@@ -216,9 +165,19 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
216
165
|
type: BooleanConstructor;
|
|
217
166
|
default: boolean;
|
|
218
167
|
};
|
|
219
|
-
/**
|
|
168
|
+
/**
|
|
169
|
+
* 满高档(高度与滚动归属;详见 `docs/components/table.md` 的「满高与滚动」):
|
|
170
|
+
*
|
|
171
|
+
* - 不传 / `false` —— 高度由内容撑起(单表结构,与不带本 prop 时完全一致);
|
|
172
|
+
* - `true` / `'parent'` —— 占满父级高度(`height: 100%`),**表体滚、表头固定在表体上方**,
|
|
173
|
+
* 外框与圆角归包裹层;父级需可确定高度(`auto` 父级下 `100%` 解析不出来);
|
|
174
|
+
* - `number` —— 表体滚动上限 = 该像素值,**父级高度不确定时的显式兜底档**
|
|
175
|
+
* (CSS 无法探测父级是否定高,故兜底只能由调用方声明)。
|
|
176
|
+
*
|
|
177
|
+
* 满高档一律按 `table-layout: fixed` 渲染(表头与表体是两个表格盒,`auto` 各自算宽必然错列)。
|
|
178
|
+
*/
|
|
220
179
|
fill: {
|
|
221
|
-
type:
|
|
180
|
+
type: PropType<TableFill>;
|
|
222
181
|
default: boolean;
|
|
223
182
|
};
|
|
224
183
|
/**
|
|
@@ -234,10 +193,6 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
234
193
|
type: PropType<"auto" | "fixed">;
|
|
235
194
|
default: string;
|
|
236
195
|
};
|
|
237
|
-
stickyHead: {
|
|
238
|
-
type: BooleanConstructor;
|
|
239
|
-
default: boolean;
|
|
240
|
-
};
|
|
241
196
|
stickyCol: {
|
|
242
197
|
type: BooleanConstructor;
|
|
243
198
|
default: boolean;
|
|
@@ -296,11 +251,6 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
296
251
|
type: PropType<(keys: Array<string | number>) => void>;
|
|
297
252
|
default: undefined;
|
|
298
253
|
};
|
|
299
|
-
/** 分页档:`false` 不渲染底部分页条 */
|
|
300
|
-
pagination: {
|
|
301
|
-
type: PropType<false | TablePagination>;
|
|
302
|
-
default: boolean;
|
|
303
|
-
};
|
|
304
254
|
}>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
305
255
|
/** 选中行 key 列表(`v-model`) */
|
|
306
256
|
'update:modelValue': (keys: Array<string | number>) => boolean;
|
|
@@ -350,11 +300,8 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
350
300
|
default: boolean;
|
|
351
301
|
};
|
|
352
302
|
/**
|
|
353
|
-
* 单元格值变更 —— 由 `#cell` 插槽里的 `setValue`
|
|
354
|
-
*
|
|
355
|
-
* 本件**不改 `data`**(与本仓表格一贯的克制口径一致:全受控、只发事件、不排序、不切片);
|
|
356
|
-
* 要不要接受、以及新数组怎么产生,都由调用方决定。
|
|
357
|
-
* 没接这个回调时 `setValue` 是空操作(插槽里的控件照旧可绑,不会报错)。
|
|
303
|
+
* 单元格值变更 —— 由 `#cell` 插槽里的 `setValue` 触发,是**唯一的回写通道**。本件**不改 `data`**(全受控、只发
|
|
304
|
+
* 事件、不排序、不切片);要不要接受、新数组怎么产生都由调用方决定;没接这个回调时 `setValue` 是空操作。
|
|
358
305
|
*/
|
|
359
306
|
onCellChange: {
|
|
360
307
|
type: PropType<(row: TableRow, key: string, value: unknown, index: number) => void>;
|
|
@@ -385,9 +332,19 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
385
332
|
type: BooleanConstructor;
|
|
386
333
|
default: boolean;
|
|
387
334
|
};
|
|
388
|
-
/**
|
|
335
|
+
/**
|
|
336
|
+
* 满高档(高度与滚动归属;详见 `docs/components/table.md` 的「满高与滚动」):
|
|
337
|
+
*
|
|
338
|
+
* - 不传 / `false` —— 高度由内容撑起(单表结构,与不带本 prop 时完全一致);
|
|
339
|
+
* - `true` / `'parent'` —— 占满父级高度(`height: 100%`),**表体滚、表头固定在表体上方**,
|
|
340
|
+
* 外框与圆角归包裹层;父级需可确定高度(`auto` 父级下 `100%` 解析不出来);
|
|
341
|
+
* - `number` —— 表体滚动上限 = 该像素值,**父级高度不确定时的显式兜底档**
|
|
342
|
+
* (CSS 无法探测父级是否定高,故兜底只能由调用方声明)。
|
|
343
|
+
*
|
|
344
|
+
* 满高档一律按 `table-layout: fixed` 渲染(表头与表体是两个表格盒,`auto` 各自算宽必然错列)。
|
|
345
|
+
*/
|
|
389
346
|
fill: {
|
|
390
|
-
type:
|
|
347
|
+
type: PropType<TableFill>;
|
|
391
348
|
default: boolean;
|
|
392
349
|
};
|
|
393
350
|
/**
|
|
@@ -403,10 +360,6 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
403
360
|
type: PropType<"auto" | "fixed">;
|
|
404
361
|
default: string;
|
|
405
362
|
};
|
|
406
|
-
stickyHead: {
|
|
407
|
-
type: BooleanConstructor;
|
|
408
|
-
default: boolean;
|
|
409
|
-
};
|
|
410
363
|
stickyCol: {
|
|
411
364
|
type: BooleanConstructor;
|
|
412
365
|
default: boolean;
|
|
@@ -465,11 +418,6 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
465
418
|
type: PropType<(keys: Array<string | number>) => void>;
|
|
466
419
|
default: undefined;
|
|
467
420
|
};
|
|
468
|
-
/** 分页档:`false` 不渲染底部分页条 */
|
|
469
|
-
pagination: {
|
|
470
|
-
type: PropType<false | TablePagination>;
|
|
471
|
-
default: boolean;
|
|
472
|
-
};
|
|
473
421
|
}>> & Readonly<{
|
|
474
422
|
onSort?: ((payload: {
|
|
475
423
|
key: string;
|
|
@@ -478,7 +426,7 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
478
426
|
onChange?: ((keys: (string | number)[]) => any) | undefined;
|
|
479
427
|
"onUpdate:modelValue"?: ((keys: (string | number)[]) => any) | undefined;
|
|
480
428
|
}>, {
|
|
481
|
-
fill:
|
|
429
|
+
fill: TableFill;
|
|
482
430
|
layout: "fixed" | "auto";
|
|
483
431
|
size: ControlSize;
|
|
484
432
|
compact: boolean;
|
|
@@ -494,7 +442,6 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
494
442
|
selectable: boolean | TableRowSelectable;
|
|
495
443
|
striped: boolean;
|
|
496
444
|
onCellChange: (row: TableRow, key: string, value: unknown, index: number) => void;
|
|
497
|
-
stickyHead: boolean;
|
|
498
445
|
stickyCol: boolean;
|
|
499
446
|
showHeader: boolean;
|
|
500
447
|
sortKey: string;
|
|
@@ -502,24 +449,15 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
502
449
|
rowClass: (row: TableRow, index: number) => string;
|
|
503
450
|
onRow: (row: TableRow, index: number) => TableRowProps;
|
|
504
451
|
expandable: (row: TableRow, index: number) => VNodeChild;
|
|
505
|
-
pagination: false | TablePagination;
|
|
506
452
|
}, SlotsType<{
|
|
507
|
-
/**
|
|
508
|
-
* 单元格:`{ row, column, value, index, setValue }`(不给则直接输出原值)。
|
|
509
|
-
*
|
|
510
|
-
* **编辑格也走这里**(见 `TableCellSlotScope` 的说明):本件不替调用方渲染控件,
|
|
511
|
-
* 只给值、给位置、给一个受控的回写口 `setValue`。
|
|
512
|
-
*/
|
|
453
|
+
/** 单元格插槽:`{ row, column, value, index, setValue }`(不给则直接输出原值)。**编辑格也走这里** —— 本件不替调用方渲染控件,只给值、给位置、给一个受控的回写口。 */
|
|
513
454
|
cell?: (context: TableCellSlotScope) => VNodeChild;
|
|
514
|
-
/** 行尾操作区:`{ row, index }`(面里用 `align: 'right'` 的列承载) */
|
|
515
|
-
actions?: (context: {
|
|
516
|
-
row: TableRow;
|
|
517
|
-
index: number;
|
|
518
|
-
}) => VNodeChild;
|
|
519
455
|
/** 批量栏:选中非空时出现在表格上方(`{ selected }`) */
|
|
520
456
|
batch?: (context: {
|
|
521
457
|
selected: Array<string | number>;
|
|
522
458
|
}) => VNodeChild;
|
|
523
459
|
/** 空态自定义(插画 + 操作按钮);不给则渲染 `emptyText` 一行 */
|
|
524
460
|
empty?: () => VNodeChild;
|
|
461
|
+
/** 合计行:渲染在滚动区之外(表格下方),容器与标签 / 数值子样式见 `.mh-table__summary*` */
|
|
462
|
+
summary?: () => VNodeChild;
|
|
525
463
|
}>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { defineComponent, computed, ref, createVNode } from "vue";
|
|
1
|
+
import { defineComponent, computed, ref, onMounted, onUpdated, createVNode } from "vue";
|
|
2
2
|
import { Icon } from "@manohub/icon";
|
|
3
3
|
import { Checkbox } from "../checkbox/index.js";
|
|
4
|
-
import { Pagination } from "../pagination/index.js";
|
|
5
4
|
const Table = /* @__PURE__ */ defineComponent({
|
|
6
5
|
name: "Table",
|
|
7
6
|
inheritAttrs: false,
|
|
@@ -44,11 +43,8 @@ const Table = /* @__PURE__ */ defineComponent({
|
|
|
44
43
|
default: false
|
|
45
44
|
},
|
|
46
45
|
/**
|
|
47
|
-
* 单元格值变更 —— 由 `#cell` 插槽里的 `setValue`
|
|
48
|
-
*
|
|
49
|
-
* 本件**不改 `data`**(与本仓表格一贯的克制口径一致:全受控、只发事件、不排序、不切片);
|
|
50
|
-
* 要不要接受、以及新数组怎么产生,都由调用方决定。
|
|
51
|
-
* 没接这个回调时 `setValue` 是空操作(插槽里的控件照旧可绑,不会报错)。
|
|
46
|
+
* 单元格值变更 —— 由 `#cell` 插槽里的 `setValue` 触发,是**唯一的回写通道**。本件**不改 `data`**(全受控、只发
|
|
47
|
+
* 事件、不排序、不切片);要不要接受、新数组怎么产生都由调用方决定;没接这个回调时 `setValue` 是空操作。
|
|
52
48
|
*/
|
|
53
49
|
onCellChange: {
|
|
54
50
|
type: Function,
|
|
@@ -79,9 +75,19 @@ const Table = /* @__PURE__ */ defineComponent({
|
|
|
79
75
|
type: Boolean,
|
|
80
76
|
default: true
|
|
81
77
|
},
|
|
82
|
-
/**
|
|
78
|
+
/**
|
|
79
|
+
* 满高档(高度与滚动归属;详见 `docs/components/table.md` 的「满高与滚动」):
|
|
80
|
+
*
|
|
81
|
+
* - 不传 / `false` —— 高度由内容撑起(单表结构,与不带本 prop 时完全一致);
|
|
82
|
+
* - `true` / `'parent'` —— 占满父级高度(`height: 100%`),**表体滚、表头固定在表体上方**,
|
|
83
|
+
* 外框与圆角归包裹层;父级需可确定高度(`auto` 父级下 `100%` 解析不出来);
|
|
84
|
+
* - `number` —— 表体滚动上限 = 该像素值,**父级高度不确定时的显式兜底档**
|
|
85
|
+
* (CSS 无法探测父级是否定高,故兜底只能由调用方声明)。
|
|
86
|
+
*
|
|
87
|
+
* 满高档一律按 `table-layout: fixed` 渲染(表头与表体是两个表格盒,`auto` 各自算宽必然错列)。
|
|
88
|
+
*/
|
|
83
89
|
fill: {
|
|
84
|
-
type: Boolean,
|
|
90
|
+
type: [Boolean, String, Number],
|
|
85
91
|
default: false
|
|
86
92
|
},
|
|
87
93
|
/**
|
|
@@ -97,10 +103,6 @@ const Table = /* @__PURE__ */ defineComponent({
|
|
|
97
103
|
type: String,
|
|
98
104
|
default: "auto"
|
|
99
105
|
},
|
|
100
|
-
stickyHead: {
|
|
101
|
-
type: Boolean,
|
|
102
|
-
default: false
|
|
103
|
-
},
|
|
104
106
|
stickyCol: {
|
|
105
107
|
type: Boolean,
|
|
106
108
|
default: false
|
|
@@ -158,11 +160,6 @@ const Table = /* @__PURE__ */ defineComponent({
|
|
|
158
160
|
onExpandChange: {
|
|
159
161
|
type: Function,
|
|
160
162
|
default: void 0
|
|
161
|
-
},
|
|
162
|
-
/** 分页档:`false` 不渲染底部分页条 */
|
|
163
|
-
pagination: {
|
|
164
|
-
type: [Boolean, Object],
|
|
165
|
-
default: false
|
|
166
163
|
}
|
|
167
164
|
},
|
|
168
165
|
emits: {
|
|
@@ -245,121 +242,165 @@ const Table = /* @__PURE__ */ defineComponent({
|
|
|
245
242
|
return "asc";
|
|
246
243
|
};
|
|
247
244
|
const sortGlyph = (key) => props.sortKey === key && props.sortOrder === "asc" ? "chevron-up" : "chevron-down";
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
245
|
+
const renderHead = () => createVNode("thead", null, [createVNode("tr", null, [props.expandable ? createVNode("th", {
|
|
246
|
+
"class": "mh-table__col-expand",
|
|
247
|
+
"aria-label": "展开"
|
|
248
|
+
}, null) : null, hasSelectColumn.value ? createVNode("th", {
|
|
249
|
+
"class": "mh-table__col-check"
|
|
250
|
+
}, [createVNode(Checkbox, {
|
|
251
|
+
"aria-label": "全选",
|
|
252
|
+
"modelValue": allSelected.value,
|
|
253
|
+
"indeterminate": someSelected.value && !allSelected.value,
|
|
254
|
+
"disabled": headerCheckboxDisabled.value,
|
|
255
|
+
"onChange": toggleAll
|
|
256
|
+
}, null)]) : null, props.columns.map((column) => createVNode("th", {
|
|
257
|
+
"key": column.key,
|
|
258
|
+
"class": [column.required ? "mh-table__cell-required" : "", column.align === "center" ? "mh-table__cell-center" : "", column.align === "right" ? "mh-table__col-right" : ""].filter(Boolean).join(" ")
|
|
259
|
+
}, [column.title, column.sortable ? createVNode("button", {
|
|
260
|
+
"type": "button",
|
|
261
|
+
"class": ["mh-table__sort", props.sortKey === column.key && props.sortOrder ? "mh-table__sort--active" : ""].filter(Boolean).join(" "),
|
|
262
|
+
"aria-label": `按${column.title}排序`,
|
|
263
|
+
"onClick": () => emit("sort", {
|
|
264
|
+
key: column.key,
|
|
265
|
+
order: nextOrder(column.key)
|
|
266
|
+
})
|
|
267
|
+
}, [createVNode(Icon, {
|
|
268
|
+
"name": sortGlyph(column.key),
|
|
269
|
+
"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(" ")
|
|
270
|
+
}, null)]) : null]))])]);
|
|
271
|
+
const renderBody = () => createVNode("tbody", null, [isEmpty.value ? createVNode("tr", {
|
|
272
|
+
"class": "mh-table__empty-row"
|
|
273
|
+
}, [createVNode("td", {
|
|
274
|
+
"class": "mh-table__empty",
|
|
275
|
+
"colspan": columnCount.value
|
|
276
|
+
}, [slots.empty ? slots.empty() : props.emptyText])]) : null, props.data.map((row, index) => {
|
|
277
|
+
const key = row[props.rowKey];
|
|
278
|
+
const rowProps = props.onRow?.(row, index);
|
|
279
|
+
const isExpanded = expanded.value.includes(key);
|
|
280
|
+
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(" ");
|
|
281
|
+
return [createVNode("tr", {
|
|
282
|
+
"key": key,
|
|
283
|
+
"class": rowState,
|
|
284
|
+
"data-state": selected.value.includes(key) ? "selected" : "idle",
|
|
285
|
+
"onClick": rowProps?.onClick ? (event) => rowProps.onClick?.(row, index, event) : void 0
|
|
286
|
+
}, [props.expandable ? createVNode("td", {
|
|
287
|
+
"class": "mh-table__col-expand"
|
|
288
|
+
}, [createVNode("button", {
|
|
275
289
|
"type": "button",
|
|
276
|
-
"class":
|
|
277
|
-
"aria-label":
|
|
278
|
-
"
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
290
|
+
"class": "mh-table__expand",
|
|
291
|
+
"aria-label": isExpanded ? "收起" : "展开",
|
|
292
|
+
"aria-expanded": isExpanded ? "true" : "false",
|
|
293
|
+
"onClick": (event) => {
|
|
294
|
+
event.stopPropagation();
|
|
295
|
+
toggleExpand(key);
|
|
296
|
+
}
|
|
282
297
|
}, [createVNode(Icon, {
|
|
283
|
-
"name":
|
|
284
|
-
"class":
|
|
285
|
-
}, null)])
|
|
286
|
-
|
|
298
|
+
"name": "chevron-down",
|
|
299
|
+
"class": "mh-table__expand-icon"
|
|
300
|
+
}, null)])]) : null, hasSelectColumn.value ? (
|
|
301
|
+
/* 勾选列复用 `Checkbox`(不手写原生 input)。行本身可能带 `onRow` 的 onClick:勾选不该顺带触发行
|
|
302
|
+
点击 —— 阻断挂在**单元格**上(`Checkbox` 的根是 `label`,点它会冒泡两次,只挡 input 挡不住)。
|
|
303
|
+
`selectable` 为函数时逐行判定:返回 `false` 的行给禁用态(置灰 + not-allowed)。 */
|
|
304
|
+
createVNode("td", {
|
|
305
|
+
"class": "mh-table__col-check",
|
|
306
|
+
"onClick": (event) => event.stopPropagation()
|
|
307
|
+
}, [createVNode(Checkbox, {
|
|
308
|
+
"aria-label": "选择本行",
|
|
309
|
+
"modelValue": selected.value.includes(key),
|
|
310
|
+
"disabled": !isRowSelectable(row, index),
|
|
311
|
+
"onChange": () => toggleRow(key)
|
|
312
|
+
}, null)])
|
|
313
|
+
) : null, props.columns.map((column) => createVNode("td", {
|
|
314
|
+
"key": column.key,
|
|
315
|
+
"class": cellClass(column).join(" ")
|
|
316
|
+
}, [slots.cell ? (
|
|
317
|
+
/* 展示格与编辑格都走这条(含行尾操作列):值、位置、回写口一并交给调用方 */
|
|
318
|
+
slots.cell({
|
|
319
|
+
row,
|
|
320
|
+
column,
|
|
321
|
+
value: row[column.key],
|
|
322
|
+
index,
|
|
323
|
+
setValue: cellSetValue(row, column, index)
|
|
324
|
+
})
|
|
325
|
+
) : String(row[column.key] ?? "")]))]), isExpanded ? createVNode("tr", {
|
|
326
|
+
"key": `${key}-expand`,
|
|
327
|
+
"class": "mh-table__expand-row"
|
|
287
328
|
}, [createVNode("td", {
|
|
288
|
-
"class": "mh-table__empty",
|
|
289
329
|
"colspan": columnCount.value
|
|
290
|
-
}, [
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
"aria-label": "选择本行",
|
|
324
|
-
"modelValue": selected.value.includes(key),
|
|
325
|
-
"disabled": !isRowSelectable(row, index),
|
|
326
|
-
"onChange": () => toggleRow(key)
|
|
327
|
-
}, null)])
|
|
328
|
-
) : null, props.columns.map((column) => createVNode("td", {
|
|
329
|
-
"key": column.key,
|
|
330
|
-
"class": cellClass(column).join(" ")
|
|
331
|
-
}, [slots.cell ? (
|
|
332
|
-
/* 编辑格与展示格都走这条:值、位置、回写口一并交给调用方 */
|
|
333
|
-
slots.cell({
|
|
334
|
-
row,
|
|
335
|
-
column,
|
|
336
|
-
value: row[column.key],
|
|
337
|
-
index,
|
|
338
|
-
setValue: cellSetValue(row, column, index)
|
|
339
|
-
})
|
|
340
|
-
) : slots.actions && column.align === "right" ? slots.actions({
|
|
341
|
-
row,
|
|
342
|
-
index
|
|
343
|
-
}) : String(row[column.key] ?? "")]))]), isExpanded ? createVNode("tr", {
|
|
344
|
-
"key": `${key}-expand`,
|
|
345
|
-
"class": "mh-table__expand-row"
|
|
346
|
-
}, [createVNode("td", {
|
|
347
|
-
"colspan": columnCount.value
|
|
348
|
-
}, [props.expandable?.(row, index)])]) : null];
|
|
349
|
-
})])]), props.loading ? createVNode("div", {
|
|
330
|
+
}, [props.expandable?.(row, index)])]) : null];
|
|
331
|
+
})]);
|
|
332
|
+
const headBoxRef = ref(null);
|
|
333
|
+
const headTableRef = ref(null);
|
|
334
|
+
const scrollBoxRef = ref(null);
|
|
335
|
+
const syncHead = () => {
|
|
336
|
+
const box = scrollBoxRef.value;
|
|
337
|
+
const head = headBoxRef.value;
|
|
338
|
+
if (!box) return;
|
|
339
|
+
if (headTableRef.value) headTableRef.value.style.transform = `translateX(${-box.scrollLeft}px)`;
|
|
340
|
+
if (head) {
|
|
341
|
+
const gutter = `${box.offsetWidth - box.clientWidth}px`;
|
|
342
|
+
if (head.style.paddingRight !== gutter) head.style.paddingRight = gutter;
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
onMounted(syncHead);
|
|
346
|
+
onUpdated(syncHead);
|
|
347
|
+
return () => {
|
|
348
|
+
const fill = props.fill !== false;
|
|
349
|
+
const tableClass = ["mh-table", resolvedSize.value === "sm" ? "mh-table--xs" : "", resolvedSize.value === "lg" ? "mh-table--lg" : "", props.bordered ? "" : "mh-table--borderless", fill ? "mh-table--fill" : "", fill || props.layout === "fixed" ? "mh-table--fixed" : "", attrs.class].filter(Boolean).join(" ");
|
|
350
|
+
const bodyTableClass = props.stickyCol ? `${tableClass} mh-table--sticky-col` : tableClass;
|
|
351
|
+
const cellTokens = fill || props.layout === "fixed" ? {
|
|
352
|
+
"--ui-control-min-width": "0"
|
|
353
|
+
} : void 0;
|
|
354
|
+
const batchBar = slots.batch && selected.value.length > 0 ? createVNode("div", {
|
|
355
|
+
"class": "mh-table__batch"
|
|
356
|
+
}, [slots.batch({
|
|
357
|
+
selected: selected.value
|
|
358
|
+
})]) : null;
|
|
359
|
+
const summaryBar = slots.summary ? createVNode("div", {
|
|
360
|
+
"class": "mh-table__summary"
|
|
361
|
+
}, [slots.summary()]) : null;
|
|
362
|
+
const loadingOverlay = props.loading ? createVNode("div", {
|
|
350
363
|
"class": "mh-table__loading",
|
|
351
364
|
"aria-busy": "true"
|
|
352
365
|
}, [createVNode("span", {
|
|
353
366
|
"class": "mh-table__spinner"
|
|
354
|
-
}, null)]) : null
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
"
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
367
|
+
}, null)]) : null;
|
|
368
|
+
if (!fill) {
|
|
369
|
+
return createVNode("div", {
|
|
370
|
+
"class": "mh-table-wrapper",
|
|
371
|
+
"style": attrs.style
|
|
372
|
+
}, [batchBar, createVNode("table", {
|
|
373
|
+
"class": bodyTableClass,
|
|
374
|
+
"style": cellTokens
|
|
375
|
+
}, [colElements(), props.showHeader ? renderHead() : null, renderBody()]), summaryBar, loadingOverlay]);
|
|
376
|
+
}
|
|
377
|
+
const wrapperStyle = props.fill === true || props.fill === "parent" ? [{
|
|
378
|
+
height: "100%"
|
|
379
|
+
}, attrs.style] : attrs.style;
|
|
380
|
+
const scrollStyle = typeof props.fill === "number" ? {
|
|
381
|
+
maxHeight: `${props.fill}px`
|
|
382
|
+
} : void 0;
|
|
383
|
+
return createVNode("div", {
|
|
384
|
+
"class": "mh-table-wrapper mh-table-wrapper--fill",
|
|
385
|
+
"style": wrapperStyle
|
|
386
|
+
}, [batchBar, props.showHeader ? createVNode("div", {
|
|
387
|
+
"class": "mh-table__head",
|
|
388
|
+
"ref": headBoxRef
|
|
389
|
+
}, [createVNode("table", {
|
|
390
|
+
"class": tableClass,
|
|
391
|
+
"ref": headTableRef,
|
|
392
|
+
"style": cellTokens
|
|
393
|
+
}, [colElements(), renderHead()])]) : null, createVNode("div", {
|
|
394
|
+
"class": "mh-table__body"
|
|
395
|
+
}, [createVNode("div", {
|
|
396
|
+
"class": "mh-table-scroll",
|
|
397
|
+
"ref": scrollBoxRef,
|
|
398
|
+
"onScroll": syncHead,
|
|
399
|
+
"style": scrollStyle
|
|
400
|
+
}, [createVNode("table", {
|
|
401
|
+
"class": bodyTableClass,
|
|
402
|
+
"style": cellTokens
|
|
403
|
+
}, [colElements(), renderBody()])]), loadingOverlay]), summaryBar]);
|
|
363
404
|
};
|
|
364
405
|
}
|
|
365
406
|
});
|