@manohub/ui 0.6.1 → 0.7.1

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 (69) hide show
  1. package/README.md +12 -4
  2. package/dist/components/button/index.d.ts +8 -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.js +7 -4
  6. package/dist/components/checkbox/index.js +1 -0
  7. package/dist/components/dialog/index.d.ts +58 -6
  8. package/dist/components/dialog/index.js +45 -8
  9. package/dist/components/drawer/index.d.ts +18 -6
  10. package/dist/components/drawer/index.js +11 -5
  11. package/dist/components/form/index.d.ts +115 -17
  12. package/dist/components/form/index.js +39 -9
  13. package/dist/components/input/index.d.ts +4 -4
  14. package/dist/components/input/index.js +1 -1
  15. package/dist/components/layout/index.d.ts +43 -1
  16. package/dist/components/layout/index.js +22 -2
  17. package/dist/components/notice/index.d.ts +24 -11
  18. package/dist/components/notice/index.js +11 -5
  19. package/dist/components/notification/index.d.ts +2 -2
  20. package/dist/components/page/index.js +4 -4
  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/radio/index.d.ts +1 -1
  25. package/dist/components/radio/index.js +1 -0
  26. package/dist/components/search/index.d.ts +26 -6
  27. package/dist/components/search/index.js +22 -4
  28. package/dist/components/steps/index.d.ts +232 -6
  29. package/dist/components/steps/index.js +84 -26
  30. package/dist/components/switch/index.d.ts +29 -5
  31. package/dist/components/switch/index.js +8 -2
  32. package/dist/components/tabbar/index.d.ts +184 -0
  33. package/dist/components/tabbar/index.js +161 -0
  34. package/dist/components/table/index.d.ts +74 -8
  35. package/dist/components/table/index.js +69 -16
  36. package/dist/components/tabs/index.d.ts +145 -125
  37. package/dist/components/tabs/index.js +93 -117
  38. package/dist/components/tag/index.d.ts +2 -2
  39. package/dist/components/text/index.d.ts +120 -0
  40. package/dist/components/text/index.js +55 -0
  41. package/dist/components/toast/index.d.ts +8 -8
  42. package/dist/components/toast/index.js +11 -2
  43. package/dist/components/upload/index.d.ts +30 -0
  44. package/dist/components/upload/index.js +7 -1
  45. package/dist/index.d.ts +6 -5
  46. package/dist/index.js +6 -3
  47. package/dist/services/dialog.d.ts +20 -5
  48. package/dist/services/dialog.js +8 -1
  49. package/dist/styles/components/capsule.css +4 -4
  50. package/dist/styles/components/dialog.css +40 -1
  51. package/dist/styles/components/form.css +206 -26
  52. package/dist/styles/components/input.css +29 -2
  53. package/dist/styles/components/layout.css +2 -0
  54. package/dist/styles/components/select.css +11 -0
  55. package/dist/styles/components/steps.css +48 -0
  56. package/dist/styles/components/{tabs.css → tabbar.css} +66 -65
  57. package/dist/styles/components/tabbar.tokens.css +30 -0
  58. package/dist/styles/components/table.css +50 -1
  59. package/dist/styles/components/table.tokens.css +3 -0
  60. package/dist/styles/components/text.css +101 -0
  61. package/dist/styles/components/toast.css +12 -6
  62. package/dist/styles/index.css +8 -4
  63. package/dist/styles/operations/tabs.css +73 -0
  64. package/dist/styles/reset.css +205 -0
  65. package/package.json +2 -2
  66. package/dist/components/tabset/index.d.ts +0 -105
  67. package/dist/components/tabset/index.js +0 -68
  68. package/dist/styles/components/tabs.tokens.css +0 -30
  69. 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`)。
39
67
  *
40
- * 两列下每一行都要能独立成格,所以「整行内容」(说明行、卡片组、表格、文本域)记得
41
- * 在对应 `Form.Item` 上给 `fullWidth`,否则会被压成半宽。
68
+ * 多列下每一行都要能独立成格,所以「整行内容」(说明行、卡片组、表格、文本域)记得
69
+ * 在对应 `Form.Item` 上给 `fullWidth`,否则会被压成一格。
42
70
  */
43
- columns?: 1 | 2;
71
+ columns?: FormColumns;
72
+ /**
73
+ * 一列的**最小宽度**(px);缺省取令牌 `--ui-form-column-min`(320 = 「label 120 + 一个还能用的
74
+ * 输入框」的下限)。
75
+ *
76
+ * 它同时是**回落阈值**与**动态列数的除数**:数字档下容器窄于
77
+ * `N × 最小宽 + (N − 1) × 行距` 就少排一列;动态档下列数 =
78
+ * `floor((容器宽 + 行距) / (最小宽 + 行距))`。抽屉 / 弹窗里嫌字段太窄就调小(如 280),
79
+ * 宽页面里嫌列太多就调大(如 380)。
80
+ */
81
+ columnMinWidth?: number;
44
82
  /**
45
83
  * 表单内距(**px 数字**,与 `Panel` 同一口径):`number` = 四边同值;`{ y, x }` = 上下 / 左右分别给。
46
84
  *
@@ -112,6 +150,11 @@ export interface FormItemProps {
112
150
  * 两个都给时 `text` 优先(`readonly` 只是把 label 的弱化带过去)。
113
151
  */
114
152
  readonly?: boolean;
153
+ /**
154
+ * 行内**垂直**对齐:`center`(默认,label 与控件中线对齐)/ `start`(label 与控件首行文字对齐,
155
+ * 用于多行与整块内容)。不传即按控件类型自动判定(文本域自动顶对齐),显式传入优先。
156
+ */
157
+ align?: FormItemAlign;
115
158
  }
116
159
  /**
117
160
  * 表单行(**自建**):`label + 控件 + 错误 + 说明` 四件。
@@ -128,13 +171,28 @@ export interface FormItemProps {
128
171
  * ## 宽表单怎么处理(两条杠杆,可叠加)
129
172
  *
130
173
  * - **限宽**:`controlWidth` 封顶控件列(表单级给默认、逐行可覆盖)—— 单列表单不至于把输入框拉成长条;
131
- * - **分两列**:`columns={2}` 让行并排,宽度用得更充分;列最小宽度取令牌
132
- * `--ui-form-column-min`(默认 320),所以窄容器会**自动回落成一列**,不需要消费方写媒体查询。
133
- * 两列下「整块内容」记得 `fullWidth`。
174
+ * - **分列**:`columns` 让行并排,宽度用得更充分。档位见 `FormColumns`:
175
+ * `2 ~ 6` 是**列数上限**(宽够就并排、窄了自动少排一列);`'auto'` 是**列数随宽度动态变化**。
176
+ * 回落阈值与动态列数都由 `columnMinWidth`(缺省令牌 `--ui-form-column-min` = 320)决定,
177
+ * **不需要消费方写媒体查询**;多列下「整块内容」记得 `fullWidth`。
134
178
  *
135
179
  * `Form.Item` 是唯一入口(`Form` 只承载表单级设置、行间距/列数与容器内距),
136
180
  * 控件从默认插槽进,因此输入框 / 下拉 / 文本域 / 自绘分组卡片共用同一个容器。
137
181
  *
182
+ * ## 行内垂直对齐(label 与控件怎么对齐)
183
+ *
184
+ * 对齐参照是**控件那一行**,不是整行:控件列与 label 同处第 1 行,错误 / 说明自然落第 2 行起 ——
185
+ * 所以提示文案的有无与长短都不会带动 label 的位置。规则按控件形态自动切档,消费方零配置:
186
+ *
187
+ * - **单行控件**(输入框 / 选择器 / 开关 / 自绘单行内容):label 与控件**中线**对齐,**与控件高度无关**
188
+ * —— 档位切 sm/md/lg、换主题、放自绘控件都自动成立;
189
+ * - **多行与整块内容**(文本域这类样式认得出形态的):label 与控件**首行文字**对齐,不会落到整块中间;
190
+ * - 样式认不出形态的自绘块(卡片组 / 表格 / 富文本)用 `align="start"` 显式声明;要强制居中用 `align="center"`。
191
+ *
192
+ * **本件不再依赖任何「控件高度」常量**:从前用一个外部注入的高度变量把 label 撑到控件高,
193
+ * 而那个变量在骨架层没有任何出处(回退成 `auto`),于是 label 盒退化成一行文字并贴行顶 ——
194
+ * 输入框中线偏高 6px、大号档偏高 10px、文本域偏高 9px,档位越高错得越多。
195
+ *
138
196
  * ## 容器内距(`padding`)
139
197
  *
140
198
  * 与 `Panel` **同一口径同一实现**(`src/components/part-padding.ts`):`number` 四边同值、
@@ -211,6 +269,11 @@ export declare const FormItem: import("vue").DefineComponent<import("vue").Extra
211
269
  type: BooleanConstructor;
212
270
  default: boolean;
213
271
  };
272
+ /** 行内垂直对齐;不传即自动(单行居中、多行顶对齐) */
273
+ align: {
274
+ type: PropType<FormItemAlign>;
275
+ default: undefined;
276
+ };
214
277
  }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
215
278
  /** 字段名(绑定的键);不传即纯布局行(值由消费方自己在控件上绑定) */
216
279
  name: {
@@ -259,12 +322,18 @@ export declare const FormItem: import("vue").DefineComponent<import("vue").Extra
259
322
  type: BooleanConstructor;
260
323
  default: boolean;
261
324
  };
325
+ /** 行内垂直对齐;不传即自动(单行居中、多行顶对齐) */
326
+ align: {
327
+ type: PropType<FormItemAlign>;
328
+ default: undefined;
329
+ };
262
330
  }>> & Readonly<{}>, {
263
331
  text: string;
264
332
  name: string;
265
333
  label: string;
266
334
  error: string;
267
335
  required: boolean;
336
+ align: FormItemAlign;
268
337
  readonly: boolean;
269
338
  hint: string;
270
339
  labelWidth: number;
@@ -345,11 +414,16 @@ export declare const Form: {
345
414
  type: NumberConstructor;
346
415
  default: undefined;
347
416
  };
348
- /** 列数:1(逐行,默认)/ 2(容器够宽才并排,窄了自动回落一列) */
417
+ /** 列数:1(逐行,默认)/ 2~6(够宽才并排,窄了回落一列)/ 'auto'(列数随容器宽度动态变化) */
349
418
  columns: {
350
- type: PropType<1 | 2>;
419
+ type: PropType<FormColumns>;
351
420
  default: number;
352
421
  };
422
+ /** 一列的最小宽度(px);缺省取令牌 --ui-form-column-min(320);它同时是回落阈值 */
423
+ columnMinWidth: {
424
+ type: NumberConstructor;
425
+ default: undefined;
426
+ };
353
427
  /** 表单内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边(弹窗 / 抽屉里常用它自带内距) */
354
428
  padding: {
355
429
  type: PropType<FormPadding>;
@@ -398,11 +472,12 @@ export declare const Form: {
398
472
  onChange: (values: FormValues) => void;
399
473
  defaultValue: FormValues;
400
474
  gap: number;
401
- columns: 1 | 2;
475
+ columns: FormColumns;
402
476
  modelValue: FormValues;
403
477
  labelWidth: number;
404
478
  labelAlign: FormLabelAlign;
405
479
  controlWidth: number;
480
+ columnMinWidth: number;
406
481
  }, true, {}, SlotsType<{
407
482
  default?: () => VNodeChild;
408
483
  }>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, {}, any, import("vue").ComponentProvideOptions, {
@@ -428,11 +503,16 @@ export declare const Form: {
428
503
  type: NumberConstructor;
429
504
  default: undefined;
430
505
  };
431
- /** 列数:1(逐行,默认)/ 2(容器够宽才并排,窄了自动回落一列) */
506
+ /** 列数:1(逐行,默认)/ 2~6(够宽才并排,窄了回落一列)/ 'auto'(列数随容器宽度动态变化) */
432
507
  columns: {
433
- type: PropType<1 | 2>;
508
+ type: PropType<FormColumns>;
434
509
  default: number;
435
510
  };
511
+ /** 一列的最小宽度(px);缺省取令牌 --ui-form-column-min(320);它同时是回落阈值 */
512
+ columnMinWidth: {
513
+ type: NumberConstructor;
514
+ default: undefined;
515
+ };
436
516
  /** 表单内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边(弹窗 / 抽屉里常用它自带内距) */
437
517
  padding: {
438
518
  type: PropType<FormPadding>;
@@ -479,11 +559,12 @@ export declare const Form: {
479
559
  onChange: (values: FormValues) => void;
480
560
  defaultValue: FormValues;
481
561
  gap: number;
482
- columns: 1 | 2;
562
+ columns: FormColumns;
483
563
  modelValue: FormValues;
484
564
  labelWidth: number;
485
565
  labelAlign: FormLabelAlign;
486
566
  controlWidth: number;
567
+ columnMinWidth: number;
487
568
  }>;
488
569
  __isFragment?: never;
489
570
  __isTeleport?: never;
@@ -504,11 +585,16 @@ export declare const Form: {
504
585
  type: NumberConstructor;
505
586
  default: undefined;
506
587
  };
507
- /** 列数:1(逐行,默认)/ 2(容器够宽才并排,窄了自动回落一列) */
588
+ /** 列数:1(逐行,默认)/ 2~6(够宽才并排,窄了回落一列)/ 'auto'(列数随容器宽度动态变化) */
508
589
  columns: {
509
- type: PropType<1 | 2>;
590
+ type: PropType<FormColumns>;
510
591
  default: number;
511
592
  };
593
+ /** 一列的最小宽度(px);缺省取令牌 --ui-form-column-min(320);它同时是回落阈值 */
594
+ columnMinWidth: {
595
+ type: NumberConstructor;
596
+ default: undefined;
597
+ };
512
598
  /** 表单内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边(弹窗 / 抽屉里常用它自带内距) */
513
599
  padding: {
514
600
  type: PropType<FormPadding>;
@@ -557,11 +643,12 @@ export declare const Form: {
557
643
  onChange: (values: FormValues) => void;
558
644
  defaultValue: FormValues;
559
645
  gap: number;
560
- columns: 1 | 2;
646
+ columns: FormColumns;
561
647
  modelValue: FormValues;
562
648
  labelWidth: number;
563
649
  labelAlign: FormLabelAlign;
564
650
  controlWidth: number;
651
+ columnMinWidth: number;
565
652
  }, {}, string, SlotsType<{
566
653
  default?: () => VNodeChild;
567
654
  }>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps & {
@@ -637,6 +724,11 @@ export declare const Form: {
637
724
  type: BooleanConstructor;
638
725
  default: boolean;
639
726
  };
727
+ /** 行内垂直对齐;不传即自动(单行居中、多行顶对齐) */
728
+ align: {
729
+ type: PropType<FormItemAlign>;
730
+ default: undefined;
731
+ };
640
732
  }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
641
733
  /** 字段名(绑定的键);不传即纯布局行(值由消费方自己在控件上绑定) */
642
734
  name: {
@@ -685,12 +777,18 @@ export declare const Form: {
685
777
  type: BooleanConstructor;
686
778
  default: boolean;
687
779
  };
780
+ /** 行内垂直对齐;不传即自动(单行居中、多行顶对齐) */
781
+ align: {
782
+ type: PropType<FormItemAlign>;
783
+ default: undefined;
784
+ };
688
785
  }>> & Readonly<{}>, {
689
786
  text: string;
690
787
  name: string;
691
788
  label: string;
692
789
  error: string;
693
790
  required: boolean;
791
+ align: FormItemAlign;
694
792
  readonly: boolean;
695
793
  hint: string;
696
794
  labelWidth: number;
@@ -55,6 +55,11 @@ const FormItem = /* @__PURE__ */ defineComponent({
55
55
  readonly: {
56
56
  type: Boolean,
57
57
  default: false
58
+ },
59
+ /** 行内垂直对齐;不传即自动(单行居中、多行顶对齐) */
60
+ align: {
61
+ type: String,
62
+ default: void 0
58
63
  }
59
64
  },
60
65
  slots: Object,
@@ -95,6 +100,10 @@ const FormItem = /* @__PURE__ */ defineComponent({
95
100
  "mh-form-item",
96
101
  props.error ? "is-invalid" : "",
97
102
  props.fullWidth ? "mh-form-item--full" : "",
103
+ // 无 label 列:控件位与提示横跨整行(两列 grid 下第一列不能留空位)
104
+ showLabel ? "" : "mh-form-item--no-label",
105
+ // 行内垂直对齐:**只在显式传入时**挂类;不传即由样式按控件类型自动判定(见 form.css 的顶对齐档)
106
+ props.align ? `mh-form-item--align-${props.align}` : "",
98
107
  // 右对齐是基类默认值,只有左对齐需要额外的修饰类(两处都挂会让「谁胜出」依赖源码顺序)
99
108
  labelAlign === "left" ? "mh-form-item--label-left" : "",
100
109
  // 只读展示行:label 降一档为次要色,与值拉开层级(样式见 `.mh-form-item--readonly .mh-form-item__label`)
@@ -123,11 +132,11 @@ const FormItem = /* @__PURE__ */ defineComponent({
123
132
  "class": "mh-form-item__text",
124
133
  "data-empty": textIsEmpty ? "true" : "false"
125
134
  }, [textIsEmpty ? FORM_TEXT_EMPTY : props.text])
126
- ) : slots.default?.(scope()), props.error ? createVNode("div", {
135
+ ) : slots.default?.(scope())]), props.error ? createVNode("div", {
127
136
  "class": "mh-form-item__error"
128
137
  }, [props.error]) : null, props.hint ? createVNode("div", {
129
138
  "class": "mh-form-item__hint"
130
- }, [props.hint]) : null])]);
139
+ }, [props.hint]) : null]);
131
140
  };
132
141
  }
133
142
  });
@@ -198,14 +207,19 @@ const FormRoot = /* @__PURE__ */ defineComponent({
198
207
  type: Number,
199
208
  default: void 0
200
209
  },
201
- /** 列数:1(逐行,默认)/ 2(容器够宽才并排,窄了自动回落一列) */
210
+ /** 列数:1(逐行,默认)/ 2~6(够宽才并排,窄了回落一列)/ 'auto'(列数随容器宽度动态变化) */
202
211
  columns: {
203
- type: Number,
212
+ type: [Number, String],
204
213
  default: 1
205
214
  },
215
+ /** 一列的最小宽度(px);缺省取令牌 --ui-form-column-min(320);它同时是回落阈值 */
216
+ columnMinWidth: {
217
+ type: Number,
218
+ default: void 0
219
+ },
206
220
  /** 表单内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边(弹窗 / 抽屉里常用它自带内距) */
207
221
  padding: {
208
- type: [Number, Object],
222
+ type: [Number, Object, String],
209
223
  default: void 0
210
224
  },
211
225
  /**
@@ -302,6 +316,12 @@ const FormRoot = /* @__PURE__ */ defineComponent({
302
316
  return cleared;
303
317
  }
304
318
  });
319
+ const columnsClass = () => {
320
+ const value = props.columns;
321
+ if (value === "auto") return "mh-form--columns-auto";
322
+ if (typeof value !== "number" || value <= 1) return "";
323
+ return value === 2 ? "mh-form--two-column" : `mh-form--columns-${value}`;
324
+ };
305
325
  return () => {
306
326
  const raw = slots.default?.();
307
327
  const list = Array.isArray(raw) ? raw : raw == null ? [] : [raw];
@@ -310,10 +330,20 @@ const FormRoot = /* @__PURE__ */ defineComponent({
310
330
  rest
311
331
  } = splitFormHeader(list);
312
332
  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]
333
+ "class": ["mh-form", columnsClass(), props.layout === "vertical" ? "mh-form--vertical" : "", attrs.class].filter(Boolean).join(" "),
334
+ "style": [
335
+ mergePartStyle(attrs.style, props.padding),
336
+ /* 行距同时下发实体 `gap` 与变量:多列的轨道下限公式要用**同一个**行距值算 ——
337
+ 从前公式里硬编码 8px,`gap={16}` 时列宽会算偏(临界宽度上还会误判回落)。 */
338
+ props.gap !== void 0 ? {
339
+ gap: `${props.gap}px`,
340
+ "--mh-form-gap": `${props.gap}px`
341
+ } : null,
342
+ /* 一列最小宽度:动态档列数的除数、数字档的回落阈值 */
343
+ props.columnMinWidth !== void 0 ? {
344
+ "--mh-form-column-min": `${props.columnMinWidth}px`
345
+ } : null
346
+ ]
317
347
  }, [header, rest]);
318
348
  };
319
349
  }
@@ -249,12 +249,12 @@ export declare const Input: import("vue").DefineComponent<import("vue").ExtractP
249
249
  autofocus: boolean;
250
250
  modelValue: string;
251
251
  status: InputStatus;
252
+ as: "button" | "input";
252
253
  readonly: boolean;
253
254
  clearable: boolean;
254
255
  maxlength: number;
255
256
  showCount: boolean;
256
257
  onEnter: (v: string) => void;
257
- as: "button" | "input";
258
258
  controlClass: string;
259
259
  controlAttrs: Record<string, unknown>;
260
260
  hasValue: boolean;
@@ -547,12 +547,12 @@ export declare const InputCompound: {
547
547
  autofocus: boolean;
548
548
  modelValue: string;
549
549
  status: InputStatus;
550
+ as: "button" | "input";
550
551
  readonly: boolean;
551
552
  clearable: boolean;
552
553
  maxlength: number;
553
554
  showCount: boolean;
554
555
  onEnter: (v: string) => void;
555
- as: "button" | "input";
556
556
  controlClass: string;
557
557
  controlAttrs: Record<string, unknown>;
558
558
  hasValue: boolean;
@@ -678,12 +678,12 @@ export declare const InputCompound: {
678
678
  autofocus: boolean;
679
679
  modelValue: string;
680
680
  status: InputStatus;
681
+ as: "button" | "input";
681
682
  readonly: boolean;
682
683
  clearable: boolean;
683
684
  maxlength: number;
684
685
  showCount: boolean;
685
686
  onEnter: (v: string) => void;
686
- as: "button" | "input";
687
687
  controlClass: string;
688
688
  controlAttrs: Record<string, unknown>;
689
689
  hasValue: boolean;
@@ -804,12 +804,12 @@ export declare const InputCompound: {
804
804
  autofocus: boolean;
805
805
  modelValue: string;
806
806
  status: InputStatus;
807
+ as: "button" | "input";
807
808
  readonly: boolean;
808
809
  clearable: boolean;
809
810
  maxlength: number;
810
811
  showCount: boolean;
811
812
  onEnter: (v: string) => void;
812
- as: "button" | "input";
813
813
  controlClass: string;
814
814
  controlAttrs: Record<string, unknown>;
815
815
  hasValue: boolean;
@@ -184,7 +184,7 @@ const Input = /* @__PURE__ */ defineComponent({
184
184
  "tabindex": -1,
185
185
  "onClick": () => revealed.value = !revealed.value
186
186
  }, [createVNode(Icon, {
187
- "name": "eye",
187
+ "name": "preview",
188
188
  "class": "mh-input__eye-icon"
189
189
  }, null)]) : null, slots.suffix ? createVNode("span", {
190
190
  "class": "mh-input__suffix"
@@ -1,4 +1,5 @@
1
1
  import { type PropType, type SlotsType, type VNodeChild } from 'vue';
2
+ import { type Padding } from '../part-padding';
2
3
  /**
3
4
  * 布局间距档:**只开放令牌档位,不开放任意 px**(`none/sm/md/lg/xl` → `0 / --ui-space-1/2/3/4`)。
4
5
  *
@@ -32,7 +33,8 @@ export type LayoutSpan = 1 | 2 | 3 | 4;
32
33
  *
33
34
  * ## 与其它件的边界
34
35
  *
35
- * - 表单里并排字段用 `Form columns={2}`(它管 label 列与行距),不要用本族拼表单;
36
+ * - 表单里并排字段用 `Form` 的 `columns`(它管 label 列、行距与**回落**),不要用本族拼表单
37
+ * —— 本族的列数是**恒定**的,窄了只等分收窄,表单会被压出不可用的窄控件;
36
38
  * - 页面级两栏(各自滚动)用 `Page.Split`;
37
39
  * - 只有「块与块怎么摆」这一件事归本族,滚动 / 工具位 / 卡片外观都不归它。
38
40
  */
@@ -63,6 +65,20 @@ export declare const Layout: {
63
65
  type: NumberConstructor;
64
66
  default: undefined;
65
67
  };
68
+ /**
69
+ * 内距:**走骨架件共享口径**(`Padding`,同 `Card` / `Form` / `Page` / `Panel`)——
70
+ * `number` 四边同值、`{ y, x }` 分上下 / 左右、`string` 原样下发(CSS 简写,**逃生舱**)。
71
+ * 口径与理由见 `part-padding.ts`。
72
+ *
73
+ * ⚠️ 与 `gap` 不同口径:`gap` 只开放令牌档(防间距分叉),`padding` 接具体值 ——
74
+ * 内距在设计稿里常是**确定坐标**,令牌梯度(最大 24px)表达不了。
75
+ * ⚠️ 用它之前先想一次:这个数真是「内距」吗?若是「与某个内容列对齐」这类**布局坐标**,
76
+ * 优先改由结构表达(同轴容器 / `columns` / `minColumnWidth`)。
77
+ */
78
+ padding: {
79
+ type: PropType<Padding>;
80
+ default: undefined;
81
+ };
66
82
  }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
67
83
  /** 行间距档(默认 `md` 8px;要贴紧写 `none`) */
68
84
  gap: {
@@ -89,7 +105,22 @@ export declare const Layout: {
89
105
  type: NumberConstructor;
90
106
  default: undefined;
91
107
  };
108
+ /**
109
+ * 内距:**走骨架件共享口径**(`Padding`,同 `Card` / `Form` / `Page` / `Panel`)——
110
+ * `number` 四边同值、`{ y, x }` 分上下 / 左右、`string` 原样下发(CSS 简写,**逃生舱**)。
111
+ * 口径与理由见 `part-padding.ts`。
112
+ *
113
+ * ⚠️ 与 `gap` 不同口径:`gap` 只开放令牌档(防间距分叉),`padding` 接具体值 ——
114
+ * 内距在设计稿里常是**确定坐标**,令牌梯度(最大 24px)表达不了。
115
+ * ⚠️ 用它之前先想一次:这个数真是「内距」吗?若是「与某个内容列对齐」这类**布局坐标**,
116
+ * 优先改由结构表达(同轴容器 / `columns` / `minColumnWidth`)。
117
+ */
118
+ padding: {
119
+ type: PropType<Padding>;
120
+ default: undefined;
121
+ };
92
122
  }>> & Readonly<{}>, {
123
+ padding: Padding;
93
124
  justify: LayoutJustify;
94
125
  gap: LayoutGap;
95
126
  align: LayoutAlign;
@@ -124,6 +155,11 @@ export declare const Layout: {
124
155
  type: PropType<LayoutSpan>;
125
156
  default: number;
126
157
  };
158
+ /** 内距:口径同 `Layout.Row`(共享 `Padding`,复用 `mergePartStyle`) */
159
+ padding: {
160
+ type: PropType<Padding>;
161
+ default: undefined;
162
+ };
127
163
  }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
128
164
  /** 单元内间距档(默认 `md` 8px;要贴紧写 `none`) */
129
165
  gap: {
@@ -150,7 +186,13 @@ export declare const Layout: {
150
186
  type: PropType<LayoutSpan>;
151
187
  default: number;
152
188
  };
189
+ /** 内距:口径同 `Layout.Row`(共享 `Padding`,复用 `mergePartStyle`) */
190
+ padding: {
191
+ type: PropType<Padding>;
192
+ default: undefined;
193
+ };
153
194
  }>> & Readonly<{}>, {
195
+ padding: Padding;
154
196
  wrap: boolean;
155
197
  justify: LayoutJustify;
156
198
  span: LayoutSpan;
@@ -1,4 +1,5 @@
1
1
  import { defineComponent, createVNode } from "vue";
2
+ import { mergePartStyle } from "../part-padding.js";
2
3
  function modifier(base, name, value) {
3
4
  return value === void 0 || value === "" ? "" : `${base}--${name}-${value}`;
4
5
  }
@@ -30,6 +31,11 @@ const LayoutColumn = /* @__PURE__ */ defineComponent({
30
31
  span: {
31
32
  type: Number,
32
33
  default: 1
34
+ },
35
+ /** 内距:口径同 `Layout.Row`(共享 `Padding`,复用 `mergePartStyle`) */
36
+ padding: {
37
+ type: [Number, Object, String],
38
+ default: void 0
33
39
  }
34
40
  },
35
41
  slots: Object,
@@ -39,7 +45,7 @@ const LayoutColumn = /* @__PURE__ */ defineComponent({
39
45
  }) {
40
46
  return () => createVNode("div", {
41
47
  "class": ["mh-layout-column", modifier("mh-layout-column", "gap", props.gap), modifier("mh-layout-column", "align", props.align), props.justify && props.justify !== "start" ? modifier("mh-layout-column", "justify", props.justify) : "", props.wrap ? "mh-layout-column--wrap" : "", props.span > 1 ? `mh-layout-column--span-${props.span}` : "", attrs.class].filter(Boolean).join(" "),
42
- "style": attrs.style
48
+ "style": mergePartStyle(attrs.style, props.padding)
43
49
  }, [slots.default?.()]);
44
50
  }
45
51
  });
@@ -71,6 +77,20 @@ const LayoutRow = /* @__PURE__ */ defineComponent({
71
77
  minColumnWidth: {
72
78
  type: Number,
73
79
  default: void 0
80
+ },
81
+ /**
82
+ * 内距:**走骨架件共享口径**(`Padding`,同 `Card` / `Form` / `Page` / `Panel`)——
83
+ * `number` 四边同值、`{ y, x }` 分上下 / 左右、`string` 原样下发(CSS 简写,**逃生舱**)。
84
+ * 口径与理由见 `part-padding.ts`。
85
+ *
86
+ * ⚠️ 与 `gap` 不同口径:`gap` 只开放令牌档(防间距分叉),`padding` 接具体值 ——
87
+ * 内距在设计稿里常是**确定坐标**,令牌梯度(最大 24px)表达不了。
88
+ * ⚠️ 用它之前先想一次:这个数真是「内距」吗?若是「与某个内容列对齐」这类**布局坐标**,
89
+ * 优先改由结构表达(同轴容器 / `columns` / `minColumnWidth`)。
90
+ */
91
+ padding: {
92
+ type: [Number, Object, String],
93
+ default: void 0
74
94
  }
75
95
  },
76
96
  slots: Object,
@@ -86,7 +106,7 @@ const LayoutRow = /* @__PURE__ */ defineComponent({
86
106
  if (props.minColumnWidth) style["--mh-layout-row-min"] = `${props.minColumnWidth}px`;
87
107
  return createVNode("div", {
88
108
  "class": ["mh-layout-row", modifier("mh-layout-row", "gap", props.gap), modifier("mh-layout-row", "align", props.align), props.justify && props.justify !== "start" ? modifier("mh-layout-row", "justify", props.justify) : "", isGrid ? "mh-layout-row--grid" : "", isGrid ? modifier("mh-layout-row", "columns", props.columns) : "", attrs.class].filter(Boolean).join(" "),
89
- "style": style
109
+ "style": mergePartStyle(style, props.padding)
90
110
  }, [slots.default?.()]);
91
111
  };
92
112
  }
@@ -1,3 +1,4 @@
1
+ import { type IconName } from '@manohub/icon';
1
2
  import { type PropType, type SlotsType, type VNodeChild } from 'vue';
2
3
  export type NoticeTone = 'info' | 'success' | 'warning' | 'error';
3
4
  /**
@@ -24,10 +25,10 @@ export type NoticeTone = 'info' | 'success' | 'warning' | 'error';
24
25
  * | 有标题 | `message` + `description`(或插槽) | **标题行 + 描述行**两行 |
25
26
  *
26
27
  * @example 可关闭的说明条(列表页顶部)
27
- * <Notice closable onClose={() => (visible = false)} show-icon>值映射用于将来源向量转换为目标值。</Notice>
28
+ * <Notice closable onClose={() => (visible = false)} icon>值映射用于将来源向量转换为目标值。</Notice>
28
29
  *
29
30
  * @example 带标题与操作
30
- * <Notice tone="warning" show-icon message="尚未完成实名认证" description="使用该服务前须完成认证"
31
+ * <Notice tone="warning" icon message="尚未完成实名认证" description="使用该服务前须完成认证"
31
32
  * action="立即认证" :on-action="goAuth" />
32
33
  */
33
34
  export declare const Notice: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
@@ -46,9 +47,15 @@ export declare const Notice: import("vue").DefineComponent<import("vue").Extract
46
47
  type: StringConstructor;
47
48
  default: undefined;
48
49
  };
49
- /** 是否显示语义图标 */
50
- showIcon: {
51
- type: BooleanConstructor;
50
+ /**
51
+ * 前置图标:缺省 `false` 不出图标;`true` 按 `tone` 映射;也可直接给字形名。
52
+ *
53
+ * 与 `Toast.icon` / `Notification.icon` **同名同型**(0.6.x 本件叫 `showIcon` 且只收布尔,
54
+ * 三件三个名字三种默认 —— 已统一)。默认值仍与 `Toast` 不同:`Toast` 是「浮出即走」的
55
+ * 消息条,图标是它的主要语义承载;本件是嵌在页面里的说明条,页面里别处往往已经有图标,故缺省不出。
56
+ */
57
+ icon: {
58
+ type: PropType<boolean | IconName>;
52
59
  default: boolean;
53
60
  };
54
61
  /** 是否渲染右上关闭按钮(规范:仅通知类信息可关闭) */
@@ -92,9 +99,15 @@ export declare const Notice: import("vue").DefineComponent<import("vue").Extract
92
99
  type: StringConstructor;
93
100
  default: undefined;
94
101
  };
95
- /** 是否显示语义图标 */
96
- showIcon: {
97
- type: BooleanConstructor;
102
+ /**
103
+ * 前置图标:缺省 `false` 不出图标;`true` 按 `tone` 映射;也可直接给字形名。
104
+ *
105
+ * 与 `Toast.icon` / `Notification.icon` **同名同型**(0.6.x 本件叫 `showIcon` 且只收布尔,
106
+ * 三件三个名字三种默认 —— 已统一)。默认值仍与 `Toast` 不同:`Toast` 是「浮出即走」的
107
+ * 消息条,图标是它的主要语义承载;本件是嵌在页面里的说明条,页面里别处往往已经有图标,故缺省不出。
108
+ */
109
+ icon: {
110
+ type: PropType<boolean | IconName>;
98
111
  default: boolean;
99
112
  };
100
113
  /** 是否渲染右上关闭按钮(规范:仅通知类信息可关闭) */
@@ -123,14 +136,14 @@ export declare const Notice: import("vue").DefineComponent<import("vue").Extract
123
136
  default: undefined;
124
137
  };
125
138
  }>> & Readonly<{}>, {
139
+ icon: boolean | "search" | "link" | "filter" | "copy" | "help" | "table" | "menu" | "delete" | "image" | "close" | "key" | "page-title" | "loading" | "info" | "alert" | "chevron-left" | "chevron-right" | "chevron-down" | "chevron-up" | "check" | "user" | "download" | "back" | "folder" | "folder-open" | "file" | "file-code" | "file-json" | "file-text" | "terminal" | "shield" | "tool" | "plus" | "notification" | "settings" | "logout" | "home" | "workbench" | "apps" | "favorite" | "favorite-filled" | "drag-handle" | "edit" | "refresh" | "upload" | "save" | "more" | "preview" | "external-link" | "minus" | "plus-circle" | "close-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "ai" | "shield-check" | "shield-alert" | "history";
126
140
  onClose: () => void;
127
141
  message: string;
128
- tone: NoticeTone;
129
142
  closable: boolean;
143
+ tone: NoticeTone;
130
144
  description: string;
131
- showIcon: boolean;
132
- closeText: string;
133
145
  action: string;
146
+ closeText: string;
134
147
  onAction: () => void;
135
148
  }, SlotsType<{
136
149
  default?: () => VNodeChild;