@manohub/ui 0.7.0 → 0.8.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 (75) hide show
  1. package/README.md +4 -4
  2. package/dist/components/button/index.d.ts +14 -8
  3. package/dist/components/capsule/index.d.ts +13 -9
  4. package/dist/components/capsule/index.js +1 -1
  5. package/dist/components/card/index.d.ts +1 -1
  6. package/dist/components/card/index.js +7 -4
  7. package/dist/components/checkbox/index.js +1 -0
  8. package/dist/components/dialog/index.d.ts +1 -1
  9. package/dist/components/form/index.d.ts +142 -62
  10. package/dist/components/form/index.js +41 -29
  11. package/dist/components/input/index.d.ts +74 -6
  12. package/dist/components/input/index.js +13 -1
  13. package/dist/components/layout/index.d.ts +43 -1
  14. package/dist/components/layout/index.js +22 -2
  15. package/dist/components/list-view/index.d.ts +1 -1
  16. package/dist/components/notice/index.d.ts +2 -2
  17. package/dist/components/notification/index.d.ts +2 -2
  18. package/dist/components/page/index.js +4 -4
  19. package/dist/components/pagination/index.d.ts +2 -2
  20. package/dist/components/pagination/index.js +1 -1
  21. package/dist/components/panel/index.js +4 -4
  22. package/dist/components/part-padding.d.ts +9 -6
  23. package/dist/components/part-padding.js +2 -1
  24. package/dist/components/query-state/index.d.ts +18 -2
  25. package/dist/components/radio/index.d.ts +1 -1
  26. package/dist/components/radio/index.js +1 -0
  27. package/dist/components/select/index.d.ts +32 -30
  28. package/dist/components/select/index.js +46 -82
  29. package/dist/components/select/select-list.d.ts +125 -0
  30. package/dist/components/select/select-list.js +95 -0
  31. package/dist/components/select/select-panel.d.ts +106 -0
  32. package/dist/components/select/select-panel.js +72 -0
  33. package/dist/components/select/select-shared.d.ts +64 -0
  34. package/dist/components/select/select-shared.js +24 -0
  35. package/dist/components/select/select-tree-filter.d.ts +61 -0
  36. package/dist/components/select/select-tree-filter.js +63 -0
  37. package/dist/components/select/select-tree.d.ts +274 -0
  38. package/dist/components/select/select-tree.js +263 -0
  39. package/dist/components/select/select-trigger.d.ts +132 -0
  40. package/dist/components/select/select-trigger.js +101 -0
  41. package/dist/components/steps/index.d.ts +232 -6
  42. package/dist/components/steps/index.js +84 -26
  43. package/dist/components/switch/index.d.ts +29 -5
  44. package/dist/components/switch/index.js +8 -2
  45. package/dist/components/tabbar/index.d.ts +184 -0
  46. package/dist/components/tabbar/index.js +161 -0
  47. package/dist/components/table/index.d.ts +99 -12
  48. package/dist/components/table/index.js +69 -16
  49. package/dist/components/tabs/index.d.ts +142 -126
  50. package/dist/components/tabs/index.js +87 -119
  51. package/dist/components/tag/index.d.ts +2 -2
  52. package/dist/components/text/index.d.ts +7 -2
  53. package/dist/components/toast/index.d.ts +8 -8
  54. package/dist/components/tree/index.d.ts +28 -2
  55. package/dist/components/tree/index.js +14 -1
  56. package/dist/index.d.ts +6 -6
  57. package/dist/index.js +6 -3
  58. package/dist/styles/components/capsule.css +4 -4
  59. package/dist/styles/components/form.css +198 -39
  60. package/dist/styles/components/input.css +53 -1
  61. package/dist/styles/components/layout.css +2 -0
  62. package/dist/styles/components/select.css +21 -0
  63. package/dist/styles/components/select.tokens.css +3 -0
  64. package/dist/styles/components/steps.css +48 -0
  65. package/dist/styles/components/{tabs.css → tabbar.css} +66 -65
  66. package/dist/styles/components/tabbar.tokens.css +30 -0
  67. package/dist/styles/components/table.css +50 -1
  68. package/dist/styles/components/table.tokens.css +3 -0
  69. package/dist/styles/index.css +3 -3
  70. package/dist/styles/operations/tabs.css +73 -0
  71. package/package.json +2 -2
  72. package/dist/components/tabset/index.d.ts +0 -109
  73. package/dist/components/tabset/index.js +0 -75
  74. package/dist/styles/components/tabs.tokens.css +0 -30
  75. package/dist/styles/operations/tabset.css +0 -57
@@ -4,6 +4,33 @@ import { type Padding } from '../part-padding';
4
4
  export type FormPadding = Padding;
5
5
  /** label 列的水平对齐:`right`(默认,与 farris / 主流水平表单一致)或 `left` */
6
6
  export type FormLabelAlign = 'left' | 'right';
7
+ /**
8
+ * 字段行的排布档:
9
+ *
10
+ * - `1`(默认):逐行;
11
+ * - `2 ~ 6`:**列数上限** —— 容器放得下 N 列就并排,放不下**少排一列**(不会把控件压成窄条)。
12
+ * 高列数(5 / 6)在默认最小宽 320 下要容器 1632 / 1960px 才排得出来,普通表单页用不到 ——
13
+ * 留着它是给「宽屏展示页 / 大屏看板」这类场景,配 `columnMinWidth` 才好落地;
14
+ * - `'auto'`:**列数随容器宽度动态变化** —— 能排几列排几列,每列宽由 `columnMinWidth` 决定。
15
+ *
16
+ * 两类的差别是**可预期性**(不是能力高低):
17
+ *
18
+ * - 数字档承诺「最多 N 列」,所以「哪几个字段同排」在够宽的容器里是确定的;
19
+ * - 动态档会一路排下去(默认参数下 1320px 就够 4 列),窄了就减 ——
20
+ * 同一个表单在不同容器里列数不同 ⇒ **字段的相对位置会变**。要「两个字段必须并肩」就别用它。
21
+ */
22
+ export type FormColumns = 1 | 2 | 3 | 4 | 5 | 6 | 'auto';
23
+ /**
24
+ * 行内**垂直**对齐(label 与控件在控件行内怎么对齐):
25
+ *
26
+ * - `center`(默认):label 文字与控件**中线**对齐 —— 单行控件(输入框 / 选择器 / 开关)用它;
27
+ * - `start`:label 与控件**首行文字**对齐 —— 多行控件(文本域)与整块内容用它,
28
+ * 否则 label 会落到整块高度的中间。
29
+ *
30
+ * 不传即**自动判定**(样式按控件类型切档:文本域行零配置就是顶对齐);
31
+ * 显式传入优先于自动判定,用于自绘内容(卡片组 / 表格 / 富文本这类样式认不出来的块)。
32
+ */
33
+ export type FormItemAlign = 'center' | 'start';
7
34
  /** 表单值:**字段名 → 值**(键就是 `Form.Item` 的 `name`) */
8
35
  export type FormValues = Record<string, unknown>;
9
36
  /**
@@ -31,16 +58,27 @@ export interface FormProps {
31
58
  *
32
59
  * 宽表单(>600px)里让输入框一路拉到右边缘很难看,两种收法二选一:
33
60
  * ① 收宽度 —— 传 `controlWidth={360}`,控件列封顶、右侧留白;
34
- * ② 分两列 —— 传 `columns={2}`,把行并排起来(更充分地用宽度,见下)。
61
+ * ② 分列 —— 传 `columns`(`2 | 3 | 4` 上限档,或 `'auto'` 动态),把行并排起来(见下)。
35
62
  */
36
63
  controlWidth?: number;
37
64
  /**
38
- * 列数:`1`(默认,逐行)或 `2`(**容器够宽才并排**,窄了按列最小宽度自动回落一列)。
65
+ * 列数:`1`(默认,逐行)/ `2 ~ 6`(**容器够宽才并排**,窄了按列最小宽度自动回落一列)/
66
+ * `'auto'`(列数随容器宽度动态变化,取舍见 `FormColumns`)。
67
+ *
68
+ * 多列下每一行都要能独立成格,所以「整行内容」(说明行、卡片组、表格、文本域)记得
69
+ * 在对应 `Form.Item` 上给 `fullWidth`,否则会被压成一格。
70
+ */
71
+ columns?: FormColumns;
72
+ /**
73
+ * 一列的**最小宽度**(px);缺省取令牌 `--ui-form-column-min`(320 = 「label 120 + 一个还能用的
74
+ * 输入框」的下限)。
39
75
  *
40
- * 两列下每一行都要能独立成格,所以「整行内容」(说明行、卡片组、表格、文本域)记得
41
- * 在对应 `Form.Item` 上给 `fullWidth`,否则会被压成半宽。
76
+ * 它同时是**回落阈值**与**动态列数的除数**:数字档下容器窄于
77
+ * `N × 最小宽 + (N − 1) × 行距` 就少排一列;动态档下列数 =
78
+ * `floor((容器宽 + 行距) / (最小宽 + 行距))`。抽屉 / 弹窗里嫌字段太窄就调小(如 280),
79
+ * 宽页面里嫌列太多就调大(如 380)。
42
80
  */
43
- columns?: 1 | 2;
81
+ columnMinWidth?: number;
44
82
  /**
45
83
  * 表单内距(**px 数字**,与 `Panel` 同一口径):`number` = 四边同值;`{ y, x }` = 上下 / 左右分别给。
46
84
  *
@@ -95,23 +133,22 @@ export interface FormItemProps {
95
133
  /** 在两列表单里跨满整行(说明行 / 卡片组 / 表格 / 文本域等整块内容) */
96
134
  fullWidth?: boolean;
97
135
  /**
98
- * **只读文本形态**:传了它(含空串)即不走控件插槽,改为在控件位渲染纯文本 ——
99
- * 用于「摘要 / 详情」这类静态表单行(同一个表单里 label 列、行距、错误、说明全部复用)。
136
+ * **只读展示行**:把 label 降一档**次要色**(与值拉开层级),内容仍走默认插槽。
100
137
  *
101
- * 空值(`''` / 全空白)由组件统一显示 `—`,消费方不必每处写 `value || '—'`;
102
- * 换行符原样保留(SQL where 这类多行文本回显不会被压成一行)。
138
+ * 用于「摘要 / 详情」这类只读行 —— 控件位可以是文本值,也可以是徽标 / 链接这类非文本内容:
103
139
  *
104
- * 传了它这一行的 label 会降一档**次要色**(与正文色的值拉开层级),控件行不受影响。
140
+ * - **文本值**:控件位放 `<Input model-value={…} readonly bordered={false} />` ——
141
+ * 几何复用输入面(与可编辑输入框**同高、同内距**,值文字落在同一条竖线与中线上),
142
+ * 并且「无框 + 只读」会自动退掉输入框的交互线索(不显悬停底与聚焦框环,仍可选中复制);
143
+ * 空值占位由业务侧自己拼(如 `model-value="v || '—'"`);
144
+ * - **非文本内容**:内容直接从默认插槽进,`readonly` 只负责弱化 label。
105
145
  */
106
- text?: string;
146
+ readonly?: boolean;
107
147
  /**
108
- * **只读展示行**:只把 label 弱化(次要色),内容仍走默认插槽 ——
109
- * 用于控件位不是纯文本的只读内容(徽标 / 链接这类)。
110
- *
111
- * 纯文本一律用 `text`(它自带只读语义,不必再传本开关);本开关与 `text` 互斥不会冲突 ——
112
- * 两个都给时 `text` 优先(`readonly` 只是把 label 的弱化带过去)。
148
+ * 行内**垂直**对齐:`center`(默认,label 与控件中线对齐)/ `start`(label 与控件首行文字对齐,
149
+ * 用于多行与整块内容)。不传即按控件类型自动判定(文本域自动顶对齐),显式传入优先。
113
150
  */
114
- readonly?: boolean;
151
+ align?: FormItemAlign;
115
152
  }
116
153
  /**
117
154
  * 表单行(**自建**):`label + 控件 + 错误 + 说明` 四件。
@@ -128,27 +165,52 @@ export interface FormItemProps {
128
165
  * ## 宽表单怎么处理(两条杠杆,可叠加)
129
166
  *
130
167
  * - **限宽**:`controlWidth` 封顶控件列(表单级给默认、逐行可覆盖)—— 单列表单不至于把输入框拉成长条;
131
- * - **分两列**:`columns={2}` 让行并排,宽度用得更充分;列最小宽度取令牌
132
- * `--ui-form-column-min`(默认 320),所以窄容器会**自动回落成一列**,不需要消费方写媒体查询。
133
- * 两列下「整块内容」记得 `fullWidth`。
168
+ * - **分列**:`columns` 让行并排,宽度用得更充分。档位见 `FormColumns`:
169
+ * `2 ~ 6` 是**列数上限**(宽够就并排、窄了自动少排一列);`'auto'` 是**列数随宽度动态变化**。
170
+ * 回落阈值与动态列数都由 `columnMinWidth`(缺省令牌 `--ui-form-column-min` = 320)决定,
171
+ * **不需要消费方写媒体查询**;多列下「整块内容」记得 `fullWidth`。
134
172
  *
135
173
  * `Form.Item` 是唯一入口(`Form` 只承载表单级设置、行间距/列数与容器内距),
136
174
  * 控件从默认插槽进,因此输入框 / 下拉 / 文本域 / 自绘分组卡片共用同一个容器。
137
175
  *
176
+ * ## 行内垂直对齐(label 与控件怎么对齐)
177
+ *
178
+ * 对齐参照是**控件那一行**,不是整行:控件列与 label 同处第 1 行,错误 / 说明自然落第 2 行起 ——
179
+ * 所以提示文案的有无与长短都不会带动 label 的位置。规则按控件形态自动切档,消费方零配置:
180
+ *
181
+ * - **单行控件**(输入框 / 选择器 / 开关 / 自绘单行内容):label 与控件**中线**对齐,**与控件高度无关**
182
+ * —— 档位切 sm/md/lg、换主题、放自绘控件都自动成立;
183
+ * - **多行与整块内容**(文本域这类样式认得出形态的):label 与控件**首行文字**对齐,不会落到整块中间;
184
+ * - 样式认不出形态的自绘块(卡片组 / 表格 / 富文本)用 `align="start"` 显式声明;要强制居中用 `align="center"`。
185
+ *
186
+ * **本件不再依赖任何「控件高度」常量**:从前用一个外部注入的高度变量把 label 撑到控件高,
187
+ * 而那个变量在骨架层没有任何出处(回退成 `auto`),于是 label 盒退化成一行文字并贴行顶 ——
188
+ * 输入框中线偏高 6px、大号档偏高 10px、文本域偏高 9px,档位越高错得越多。
189
+ *
138
190
  * ## 容器内距(`padding`)
139
191
  *
140
192
  * 与 `Panel` **同一口径同一实现**(`src/components/part-padding.ts`):`number` 四边同值、
141
193
  * `{ y, x }` 上下 / 左右分别给,缺省 0(贴容器边)。页面里的表单在 `Panel.Body` 里、内距由那块给;
142
194
  * **弹窗 / 抽屉里没有别的容器**给内距,就用表单自带的 `padding={{ y: 16, x: 20 }}`。
143
195
  *
144
- * ## 静态表单(摘要 / 详情)
196
+ * ## 只读值(摘要 / 详情)
145
197
  *
146
- * `Form.Item` 传 `text` 即切成**只读文本行**,三类行可以在同一个表单里混排 ——
147
- * label 列宽、行距、错误与说明全部共用,所以「向导最后一步的确认摘要」「详情弹窗」不需要
148
- * 另起一套描述列表件(自绘表格的 label/value 几何与表单行迟早会漂开)。
149
- * 空值占位 `—`、长文案折行、换行符保留都由组件给;只读行的 label 自动降一档次要色,
150
- * 字段名与取值一眼分得开(应用侧写不了 `color`,这层区分只能由组件给)。
151
- * 控件位要放徽标 / 链接这类**非文本**只读内容时传 `readonly`:内容走默认插槽,label 的弱化照旧。
198
+ * 「向导最后一步的确认摘要」「详情弹窗」不需要另起一套描述列表件 —— 只用表单行本身,
199
+ * label 列宽、行距、错误与说明全部复用。控件位放**只读 + 无框**的输入框即可(本件不给
200
+ * 「静态文本」形态:那套几何与输入框迟早会漂开 —— 从前它没有高度与内距,值文字既不在
201
+ * 输入框那条竖线上、也不在同一条中线上):
202
+ *
203
+ * ```tsx
204
+ * <Form.Item label="创建人" readonly>
205
+ * <Input model-value={row.creator || '—'} readonly bordered={false} />
206
+ * </Form.Item>
207
+ * ```
208
+ *
209
+ * - **几何与可编辑行完全一致**:值文字与输入框内的值同高、同左缘、同中线,混排时节奏整齐;
210
+ * - **没有「可编辑」的线索**:不显悬停底色、不给聚焦边框与主色环,但仍可点进去选中 / 复制;
211
+ * - **空值占位归业务**:组件不再替你把 `''` 显示成 `—`,按上面的写法自己拼;
212
+ * - **label 弱化**:传 `readonly` 把 label 降一档次要色,字段名与取值一眼分得开;
213
+ * - 控件位是徽标 / 链接这类**非文本**只读内容时同样传 `readonly`:内容直接走默认插槽。
152
214
  *
153
215
  * @example
154
216
  * <Form labelWidth={120} columns={2}>
@@ -201,16 +263,16 @@ export declare const FormItem: import("vue").DefineComponent<import("vue").Extra
201
263
  type: BooleanConstructor;
202
264
  default: boolean;
203
265
  };
204
- /** `undefined` 与「传了空串」必须区分:前者走插槽(控件形态),后者是「值为空的只读行」 */
205
- text: {
206
- type: StringConstructor;
207
- default: undefined;
208
- };
209
- /** 只读展示行(label 弱化,内容走插槽):用于控件位是徽标 / 链接这类非文本的只读内容 */
266
+ /** 只读展示行(label 弱化):文本值放 Input 的只读 + 无框形态,非文本内容走默认插槽 */
210
267
  readonly: {
211
268
  type: BooleanConstructor;
212
269
  default: boolean;
213
270
  };
271
+ /** 行内垂直对齐;不传即自动(单行居中、多行顶对齐) */
272
+ align: {
273
+ type: PropType<FormItemAlign>;
274
+ default: undefined;
275
+ };
214
276
  }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
215
277
  /** 字段名(绑定的键);不传即纯布局行(值由消费方自己在控件上绑定) */
216
278
  name: {
@@ -249,22 +311,22 @@ export declare const FormItem: import("vue").DefineComponent<import("vue").Extra
249
311
  type: BooleanConstructor;
250
312
  default: boolean;
251
313
  };
252
- /** `undefined` 与「传了空串」必须区分:前者走插槽(控件形态),后者是「值为空的只读行」 */
253
- text: {
254
- type: StringConstructor;
255
- default: undefined;
256
- };
257
- /** 只读展示行(label 弱化,内容走插槽):用于控件位是徽标 / 链接这类非文本的只读内容 */
314
+ /** 只读展示行(label 弱化):文本值放 Input 的只读 + 无框形态,非文本内容走默认插槽 */
258
315
  readonly: {
259
316
  type: BooleanConstructor;
260
317
  default: boolean;
261
318
  };
319
+ /** 行内垂直对齐;不传即自动(单行居中、多行顶对齐) */
320
+ align: {
321
+ type: PropType<FormItemAlign>;
322
+ default: undefined;
323
+ };
262
324
  }>> & Readonly<{}>, {
263
- text: string;
264
325
  name: string;
265
326
  label: string;
266
327
  error: string;
267
328
  required: boolean;
329
+ align: FormItemAlign;
268
330
  readonly: boolean;
269
331
  hint: string;
270
332
  labelWidth: number;
@@ -345,11 +407,16 @@ export declare const Form: {
345
407
  type: NumberConstructor;
346
408
  default: undefined;
347
409
  };
348
- /** 列数:1(逐行,默认)/ 2(容器够宽才并排,窄了自动回落一列) */
410
+ /** 列数:1(逐行,默认)/ 2~6(够宽才并排,窄了回落一列)/ 'auto'(列数随容器宽度动态变化) */
349
411
  columns: {
350
- type: PropType<1 | 2>;
412
+ type: PropType<FormColumns>;
351
413
  default: number;
352
414
  };
415
+ /** 一列的最小宽度(px);缺省取令牌 --ui-form-column-min(320);它同时是回落阈值 */
416
+ columnMinWidth: {
417
+ type: NumberConstructor;
418
+ default: undefined;
419
+ };
353
420
  /** 表单内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边(弹窗 / 抽屉里常用它自带内距) */
354
421
  padding: {
355
422
  type: PropType<FormPadding>;
@@ -398,11 +465,12 @@ export declare const Form: {
398
465
  onChange: (values: FormValues) => void;
399
466
  defaultValue: FormValues;
400
467
  gap: number;
401
- columns: 1 | 2;
468
+ columns: FormColumns;
402
469
  modelValue: FormValues;
403
470
  labelWidth: number;
404
471
  labelAlign: FormLabelAlign;
405
472
  controlWidth: number;
473
+ columnMinWidth: number;
406
474
  }, true, {}, SlotsType<{
407
475
  default?: () => VNodeChild;
408
476
  }>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, {}, any, import("vue").ComponentProvideOptions, {
@@ -428,11 +496,16 @@ export declare const Form: {
428
496
  type: NumberConstructor;
429
497
  default: undefined;
430
498
  };
431
- /** 列数:1(逐行,默认)/ 2(容器够宽才并排,窄了自动回落一列) */
499
+ /** 列数:1(逐行,默认)/ 2~6(够宽才并排,窄了回落一列)/ 'auto'(列数随容器宽度动态变化) */
432
500
  columns: {
433
- type: PropType<1 | 2>;
501
+ type: PropType<FormColumns>;
434
502
  default: number;
435
503
  };
504
+ /** 一列的最小宽度(px);缺省取令牌 --ui-form-column-min(320);它同时是回落阈值 */
505
+ columnMinWidth: {
506
+ type: NumberConstructor;
507
+ default: undefined;
508
+ };
436
509
  /** 表单内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边(弹窗 / 抽屉里常用它自带内距) */
437
510
  padding: {
438
511
  type: PropType<FormPadding>;
@@ -479,11 +552,12 @@ export declare const Form: {
479
552
  onChange: (values: FormValues) => void;
480
553
  defaultValue: FormValues;
481
554
  gap: number;
482
- columns: 1 | 2;
555
+ columns: FormColumns;
483
556
  modelValue: FormValues;
484
557
  labelWidth: number;
485
558
  labelAlign: FormLabelAlign;
486
559
  controlWidth: number;
560
+ columnMinWidth: number;
487
561
  }>;
488
562
  __isFragment?: never;
489
563
  __isTeleport?: never;
@@ -504,11 +578,16 @@ export declare const Form: {
504
578
  type: NumberConstructor;
505
579
  default: undefined;
506
580
  };
507
- /** 列数:1(逐行,默认)/ 2(容器够宽才并排,窄了自动回落一列) */
581
+ /** 列数:1(逐行,默认)/ 2~6(够宽才并排,窄了回落一列)/ 'auto'(列数随容器宽度动态变化) */
508
582
  columns: {
509
- type: PropType<1 | 2>;
583
+ type: PropType<FormColumns>;
510
584
  default: number;
511
585
  };
586
+ /** 一列的最小宽度(px);缺省取令牌 --ui-form-column-min(320);它同时是回落阈值 */
587
+ columnMinWidth: {
588
+ type: NumberConstructor;
589
+ default: undefined;
590
+ };
512
591
  /** 表单内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边(弹窗 / 抽屉里常用它自带内距) */
513
592
  padding: {
514
593
  type: PropType<FormPadding>;
@@ -557,11 +636,12 @@ export declare const Form: {
557
636
  onChange: (values: FormValues) => void;
558
637
  defaultValue: FormValues;
559
638
  gap: number;
560
- columns: 1 | 2;
639
+ columns: FormColumns;
561
640
  modelValue: FormValues;
562
641
  labelWidth: number;
563
642
  labelAlign: FormLabelAlign;
564
643
  controlWidth: number;
644
+ columnMinWidth: number;
565
645
  }, {}, string, SlotsType<{
566
646
  default?: () => VNodeChild;
567
647
  }>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps & {
@@ -627,16 +707,16 @@ export declare const Form: {
627
707
  type: BooleanConstructor;
628
708
  default: boolean;
629
709
  };
630
- /** `undefined` 与「传了空串」必须区分:前者走插槽(控件形态),后者是「值为空的只读行」 */
631
- text: {
632
- type: StringConstructor;
633
- default: undefined;
634
- };
635
- /** 只读展示行(label 弱化,内容走插槽):用于控件位是徽标 / 链接这类非文本的只读内容 */
710
+ /** 只读展示行(label 弱化):文本值放 Input 的只读 + 无框形态,非文本内容走默认插槽 */
636
711
  readonly: {
637
712
  type: BooleanConstructor;
638
713
  default: boolean;
639
714
  };
715
+ /** 行内垂直对齐;不传即自动(单行居中、多行顶对齐) */
716
+ align: {
717
+ type: PropType<FormItemAlign>;
718
+ default: undefined;
719
+ };
640
720
  }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
641
721
  /** 字段名(绑定的键);不传即纯布局行(值由消费方自己在控件上绑定) */
642
722
  name: {
@@ -675,22 +755,22 @@ export declare const Form: {
675
755
  type: BooleanConstructor;
676
756
  default: boolean;
677
757
  };
678
- /** `undefined` 与「传了空串」必须区分:前者走插槽(控件形态),后者是「值为空的只读行」 */
679
- text: {
680
- type: StringConstructor;
681
- default: undefined;
682
- };
683
- /** 只读展示行(label 弱化,内容走插槽):用于控件位是徽标 / 链接这类非文本的只读内容 */
758
+ /** 只读展示行(label 弱化):文本值放 Input 的只读 + 无框形态,非文本内容走默认插槽 */
684
759
  readonly: {
685
760
  type: BooleanConstructor;
686
761
  default: boolean;
687
762
  };
763
+ /** 行内垂直对齐;不传即自动(单行居中、多行顶对齐) */
764
+ align: {
765
+ type: PropType<FormItemAlign>;
766
+ default: undefined;
767
+ };
688
768
  }>> & Readonly<{}>, {
689
- text: string;
690
769
  name: string;
691
770
  label: string;
692
771
  error: string;
693
772
  required: boolean;
773
+ align: FormItemAlign;
694
774
  readonly: boolean;
695
775
  hint: string;
696
776
  labelWidth: number;
@@ -3,7 +3,6 @@ import { mergePartStyle } from "../part-padding.js";
3
3
  const FORM_LABEL_WIDTH = /* @__PURE__ */ Symbol("mh-form-label-width");
4
4
  const FORM_CONTROL_WIDTH = /* @__PURE__ */ Symbol("mh-form-control-width");
5
5
  const FORM_LABEL_ALIGN = /* @__PURE__ */ Symbol("mh-form-label-align");
6
- const FORM_TEXT_EMPTY = "—";
7
6
  const FORM_STORE = /* @__PURE__ */ Symbol("mh-form-store");
8
7
  const FormItem = /* @__PURE__ */ defineComponent({
9
8
  name: "FormItem",
@@ -46,15 +45,15 @@ const FormItem = /* @__PURE__ */ defineComponent({
46
45
  type: Boolean,
47
46
  default: false
48
47
  },
49
- /** `undefined` 与「传了空串」必须区分:前者走插槽(控件形态),后者是「值为空的只读行」 */
50
- text: {
51
- type: String,
52
- default: void 0
53
- },
54
- /** 只读展示行(label 弱化,内容走插槽):用于控件位是徽标 / 链接这类非文本的只读内容 */
48
+ /** 只读展示行(label 弱化):文本值放 Input 的只读 + 无框形态,非文本内容走默认插槽 */
55
49
  readonly: {
56
50
  type: Boolean,
57
51
  default: false
52
+ },
53
+ /** 行内垂直对齐;不传即自动(单行居中、多行顶对齐) */
54
+ align: {
55
+ type: String,
56
+ default: void 0
58
57
  }
59
58
  },
60
59
  slots: Object,
@@ -87,18 +86,19 @@ const FormItem = /* @__PURE__ */ defineComponent({
87
86
  "--mh-form-label-width": `${labelWidth}px`
88
87
  } : null].filter(Boolean);
89
88
  const showLabel = !!props.label || props.required;
90
- const hasText = props.text !== void 0;
91
- const textIsEmpty = hasText && !props.text.trim();
92
- const isReadonlyRow = hasText || props.readonly;
93
89
  return createVNode("div", {
94
90
  "class": [
95
91
  "mh-form-item",
96
92
  props.error ? "is-invalid" : "",
97
93
  props.fullWidth ? "mh-form-item--full" : "",
94
+ // 无 label 列:控件位与提示横跨整行(两列 grid 下第一列不能留空位)
95
+ showLabel ? "" : "mh-form-item--no-label",
96
+ // 行内垂直对齐:**只在显式传入时**挂类;不传即由样式按控件类型自动判定(见 form.css 的顶对齐档)
97
+ props.align ? `mh-form-item--align-${props.align}` : "",
98
98
  // 右对齐是基类默认值,只有左对齐需要额外的修饰类(两处都挂会让「谁胜出」依赖源码顺序)
99
99
  labelAlign === "left" ? "mh-form-item--label-left" : "",
100
100
  // 只读展示行:label 降一档为次要色,与值拉开层级(样式见 `.mh-form-item--readonly .mh-form-item__label`)
101
- isReadonlyRow ? "mh-form-item--readonly" : "",
101
+ props.readonly ? "mh-form-item--readonly" : "",
102
102
  attrs.class
103
103
  ].filter(Boolean).join(" "),
104
104
  "data-invalid": props.error ? "true" : "false",
@@ -114,20 +114,11 @@ const FormItem = /* @__PURE__ */ defineComponent({
114
114
  "style": controlWidth ? {
115
115
  maxWidth: `${controlWidth}px`
116
116
  } : void 0
117
- }, [hasText ? (
118
- /*
119
- * 只读文本形态(摘要 / 详情行):控件位直接渲染业务值,占位与换行规则都在组件里
120
- * —— 应用侧不再自绘 label/value 表格(那套几何与表单行迟早会漂开)。
121
- */
122
- createVNode("div", {
123
- "class": "mh-form-item__text",
124
- "data-empty": textIsEmpty ? "true" : "false"
125
- }, [textIsEmpty ? FORM_TEXT_EMPTY : props.text])
126
- ) : slots.default?.(scope()), props.error ? createVNode("div", {
117
+ }, [slots.default?.(scope())]), props.error ? createVNode("div", {
127
118
  "class": "mh-form-item__error"
128
119
  }, [props.error]) : null, props.hint ? createVNode("div", {
129
120
  "class": "mh-form-item__hint"
130
- }, [props.hint]) : null])]);
121
+ }, [props.hint]) : null]);
131
122
  };
132
123
  }
133
124
  });
@@ -198,14 +189,19 @@ const FormRoot = /* @__PURE__ */ defineComponent({
198
189
  type: Number,
199
190
  default: void 0
200
191
  },
201
- /** 列数:1(逐行,默认)/ 2(容器够宽才并排,窄了自动回落一列) */
192
+ /** 列数:1(逐行,默认)/ 2~6(够宽才并排,窄了回落一列)/ 'auto'(列数随容器宽度动态变化) */
202
193
  columns: {
203
- type: Number,
194
+ type: [Number, String],
204
195
  default: 1
205
196
  },
197
+ /** 一列的最小宽度(px);缺省取令牌 --ui-form-column-min(320);它同时是回落阈值 */
198
+ columnMinWidth: {
199
+ type: Number,
200
+ default: void 0
201
+ },
206
202
  /** 表单内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边(弹窗 / 抽屉里常用它自带内距) */
207
203
  padding: {
208
- type: [Number, Object],
204
+ type: [Number, Object, String],
209
205
  default: void 0
210
206
  },
211
207
  /**
@@ -302,6 +298,12 @@ const FormRoot = /* @__PURE__ */ defineComponent({
302
298
  return cleared;
303
299
  }
304
300
  });
301
+ const columnsClass = () => {
302
+ const value = props.columns;
303
+ if (value === "auto") return "mh-form--columns-auto";
304
+ if (typeof value !== "number" || value <= 1) return "";
305
+ return value === 2 ? "mh-form--two-column" : `mh-form--columns-${value}`;
306
+ };
305
307
  return () => {
306
308
  const raw = slots.default?.();
307
309
  const list = Array.isArray(raw) ? raw : raw == null ? [] : [raw];
@@ -310,10 +312,20 @@ const FormRoot = /* @__PURE__ */ defineComponent({
310
312
  rest
311
313
  } = splitFormHeader(list);
312
314
  return createVNode("div", {
313
- "class": ["mh-form", props.columns === 2 ? "mh-form--two-column" : "", props.layout === "vertical" ? "mh-form--vertical" : "", attrs.class].filter(Boolean).join(" "),
314
- "style": [mergePartStyle(attrs.style, props.padding), props.gap !== void 0 ? {
315
- gap: `${props.gap}px`
316
- } : null]
315
+ "class": ["mh-form", columnsClass(), props.layout === "vertical" ? "mh-form--vertical" : "", attrs.class].filter(Boolean).join(" "),
316
+ "style": [
317
+ mergePartStyle(attrs.style, props.padding),
318
+ /* 行距同时下发实体 `gap` 与变量:多列的轨道下限公式要用**同一个**行距值算 ——
319
+ 从前公式里硬编码 8px,`gap={16}` 时列宽会算偏(临界宽度上还会误判回落)。 */
320
+ props.gap !== void 0 ? {
321
+ gap: `${props.gap}px`,
322
+ "--mh-form-gap": `${props.gap}px`
323
+ } : null,
324
+ /* 一列最小宽度:动态档列数的除数、数字档的回落阈值 */
325
+ props.columnMinWidth !== void 0 ? {
326
+ "--mh-form-column-min": `${props.columnMinWidth}px`
327
+ } : null
328
+ ]
317
329
  }, [header, rest]);
318
330
  };
319
331
  }