@manohub/ui 0.10.5 → 1.0.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 (86) hide show
  1. package/README.md +155 -155
  2. package/dist/components/form/index.js +8 -1
  3. package/dist/components/input/bordered.d.ts +15 -0
  4. package/dist/components/input/bordered.js +8 -0
  5. package/dist/components/input/index.d.ts +82 -31
  6. package/dist/components/input/index.js +16 -6
  7. package/dist/components/input/number-input.d.ts +239 -0
  8. package/dist/components/input/number-input.js +240 -0
  9. package/dist/components/select/index.d.ts +19 -0
  10. package/dist/components/select/index.js +10 -0
  11. package/dist/components/select/select-tree.d.ts +11 -0
  12. package/dist/components/select/select-tree.js +6 -0
  13. package/dist/components/select/select-trigger.d.ts +17 -0
  14. package/dist/components/select/select-trigger.js +9 -0
  15. package/dist/components/table/index.d.ts +85 -10
  16. package/dist/components/table/index.js +38 -9
  17. package/dist/index.d.ts +2 -2
  18. package/dist/index.js +2 -0
  19. package/dist/styles/components/avatar.css +131 -131
  20. package/dist/styles/components/avatar.tokens.css +24 -24
  21. package/dist/styles/components/badge.css +266 -266
  22. package/dist/styles/components/badge.tokens.css +24 -24
  23. package/dist/styles/components/button.css +460 -460
  24. package/dist/styles/components/capsule.css +128 -128
  25. package/dist/styles/components/capsule.tokens.css +27 -27
  26. package/dist/styles/components/card.css +198 -198
  27. package/dist/styles/components/checkbox.css +145 -145
  28. package/dist/styles/components/checkbox.tokens.css +26 -26
  29. package/dist/styles/components/code-block.css +216 -216
  30. package/dist/styles/components/code-block.tokens.css +40 -40
  31. package/dist/styles/components/collapse.css +62 -62
  32. package/dist/styles/components/collapse.tokens.css +20 -20
  33. package/dist/styles/components/dialog.css +158 -158
  34. package/dist/styles/components/dialog.tokens.css +24 -24
  35. package/dist/styles/components/divider.css +75 -75
  36. package/dist/styles/components/divider.tokens.css +22 -22
  37. package/dist/styles/components/drawer.css +143 -143
  38. package/dist/styles/components/drawer.tokens.css +22 -22
  39. package/dist/styles/components/filter.css +29 -29
  40. package/dist/styles/components/form.css +456 -425
  41. package/dist/styles/components/form.tokens.css +19 -15
  42. package/dist/styles/components/input.css +659 -538
  43. package/dist/styles/components/input.tokens.css +43 -43
  44. package/dist/styles/components/layout.css +200 -200
  45. package/dist/styles/components/list-view.css +244 -244
  46. package/dist/styles/components/loading.css +76 -76
  47. package/dist/styles/components/loading.tokens.css +23 -23
  48. package/dist/styles/components/nav.css +48 -48
  49. package/dist/styles/components/notice.css +153 -153
  50. package/dist/styles/components/notice.tokens.css +17 -17
  51. package/dist/styles/components/notification.css +159 -159
  52. package/dist/styles/components/notification.tokens.css +37 -37
  53. package/dist/styles/components/page.css +473 -473
  54. package/dist/styles/components/pagination.css +303 -303
  55. package/dist/styles/components/pagination.tokens.css +32 -32
  56. package/dist/styles/components/panel.css +77 -77
  57. package/dist/styles/components/query-state.css +88 -88
  58. package/dist/styles/components/radio.css +271 -271
  59. package/dist/styles/components/radio.tokens.css +26 -26
  60. package/dist/styles/components/search.css +34 -34
  61. package/dist/styles/components/select.css +326 -326
  62. package/dist/styles/components/select.tokens.css +44 -44
  63. package/dist/styles/components/skeleton.css +60 -60
  64. package/dist/styles/components/skeleton.tokens.css +27 -27
  65. package/dist/styles/components/steps.css +205 -205
  66. package/dist/styles/components/steps.tokens.css +44 -44
  67. package/dist/styles/components/switch.css +165 -165
  68. package/dist/styles/components/switch.tokens.css +26 -26
  69. package/dist/styles/components/tabbar.css +235 -235
  70. package/dist/styles/components/tabbar.tokens.css +30 -30
  71. package/dist/styles/components/table.css +510 -504
  72. package/dist/styles/components/table.tokens.css +44 -44
  73. package/dist/styles/components/tag.css +127 -127
  74. package/dist/styles/components/tag.tokens.css +24 -24
  75. package/dist/styles/components/toast.css +185 -185
  76. package/dist/styles/components/toast.tokens.css +26 -26
  77. package/dist/styles/components/tooltip.css +89 -89
  78. package/dist/styles/components/tooltip.tokens.css +25 -25
  79. package/dist/styles/components/tree.css +173 -173
  80. package/dist/styles/components/upload.css +151 -151
  81. package/dist/styles/components/upload.tokens.css +27 -27
  82. package/dist/styles/index.css +153 -153
  83. package/dist/styles/operations/collapse.css +84 -84
  84. package/dist/styles/operations/popup.css +193 -193
  85. package/dist/styles/operations/tabs.css +82 -82
  86. package/package.json +62 -62
@@ -21,6 +21,14 @@ export declare const SelectTrigger: import("vue").DefineComponent<import("vue").
21
21
  type: BooleanConstructor;
22
22
  default: boolean;
23
23
  };
24
+ /**
25
+ * 有无边框(**直接透传给输入面**,三档口径与 `Input` 的同名 prop 完全一致):
26
+ * `true` 常有框 / `false` 无框(任何状态都不显)/ `'focus'` 聚焦(与悬停)才显框。
27
+ */
28
+ bordered: {
29
+ type: PropType<boolean | "focus">;
30
+ default: boolean;
31
+ };
24
32
  clearable: {
25
33
  type: BooleanConstructor;
26
34
  default: boolean;
@@ -90,6 +98,14 @@ export declare const SelectTrigger: import("vue").DefineComponent<import("vue").
90
98
  type: BooleanConstructor;
91
99
  default: boolean;
92
100
  };
101
+ /**
102
+ * 有无边框(**直接透传给输入面**,三档口径与 `Input` 的同名 prop 完全一致):
103
+ * `true` 常有框 / `false` 无框(任何状态都不显)/ `'focus'` 聚焦(与悬停)才显框。
104
+ */
105
+ bordered: {
106
+ type: PropType<boolean | "focus">;
107
+ default: boolean;
108
+ };
93
109
  clearable: {
94
110
  type: BooleanConstructor;
95
111
  default: boolean;
@@ -145,6 +161,7 @@ export declare const SelectTrigger: import("vue").DefineComponent<import("vue").
145
161
  disabled: boolean;
146
162
  label: string;
147
163
  onKeydown: (event: KeyboardEvent) => void;
164
+ bordered: boolean | "focus";
148
165
  placeholder: string;
149
166
  status: InputStatus;
150
167
  clearable: boolean;
@@ -24,6 +24,14 @@ const SelectTrigger = /* @__PURE__ */ defineComponent({
24
24
  type: Boolean,
25
25
  default: false
26
26
  },
27
+ /**
28
+ * 有无边框(**直接透传给输入面**,三档口径与 `Input` 的同名 prop 完全一致):
29
+ * `true` 常有框 / `false` 无框(任何状态都不显)/ `'focus'` 聚焦(与悬停)才显框。
30
+ */
31
+ bordered: {
32
+ type: [Boolean, String],
33
+ default: true
34
+ },
27
35
  clearable: {
28
36
  type: Boolean,
29
37
  default: false
@@ -81,6 +89,7 @@ const SelectTrigger = /* @__PURE__ */ defineComponent({
81
89
  "size": props.size,
82
90
  "status": props.status,
83
91
  "disabled": props.disabled,
92
+ "bordered": props.bordered,
84
93
  "clearable": props.clearable,
85
94
  "hasValue": props.hasValue,
86
95
  "placeholder": props.placeholder,
@@ -50,6 +50,36 @@ export interface TableRowProps {
50
50
  class?: string;
51
51
  onClick?: (row: TableRow, index: number, event: MouseEvent) => void;
52
52
  }
53
+ /**
54
+ * `#cell` 插槽的作用域 —— **单元格编辑走这条**。
55
+ *
56
+ * 表格**不替调用方渲染控件**:编辑格要摆什么(`Input` / `Select` / `NumberInput`、外层要不要套
57
+ * `Form.Item` 拿 label 位与错误文案位、只读态摆什么)全由调用方在插槽里决定。口径与 `Form.Item`
58
+ * 同款 —— 它的默认插槽也是「你自己放控件」;骨架层因此不必猜每种业务格子的排版,
59
+ * 也不会把「哪一格长什么样」的开关堆成一张越来越长的 prop 表。
60
+ *
61
+ * **回写是受控的**:`setValue(next)` 只把「这一格变成了什么」上报出去
62
+ * (= 发一次 `onCellChange(row, column.key, next, index)`)。本件**从不改 `data`** ——
63
+ * 新数组与「这次改动该不该被接受」都由调用方决定,与行选中同一套受控口径。
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
+ */
74
+ export interface TableCellSlotScope {
75
+ row: TableRow;
76
+ column: TableColumn;
77
+ /** 该格当前值(`row[column.key]` 的原值;表格不改写它,也不做任何格式化) */
78
+ value: unknown;
79
+ index: number;
80
+ /** 上报该格的新值(= 发一次 `onCellChange`);调用方没接 `onCellChange` 时是空操作 */
81
+ setValue: (next: unknown) => void;
82
+ }
53
83
  /**
54
84
  * 行级可勾选判定(`selectable` 的函数形态):返回 `false` 的行渲染**禁用态**勾选框,
55
85
  * 且不进表头全选的增删范围。签名与 `onRow` / `rowClass` 一致(都给 `index`)。
@@ -150,6 +180,17 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
150
180
  type: BooleanConstructor;
151
181
  default: boolean;
152
182
  };
183
+ /**
184
+ * 单元格值变更 —— 由 `#cell` 插槽里的 `setValue` 触发,是**唯一的回写通道**。
185
+ *
186
+ * 本件**不改 `data`**(与本仓表格一贯的克制口径一致:全受控、只发事件、不排序、不切片);
187
+ * 要不要接受、以及新数组怎么产生,都由调用方决定。
188
+ * 没接这个回调时 `setValue` 是空操作(插槽里的控件照旧可绑,不会报错)。
189
+ */
190
+ onCellChange: {
191
+ type: PropType<(row: TableRow, key: string, value: unknown, index: number) => void>;
192
+ default: undefined;
193
+ };
153
194
  /** 尺寸档:`sm` 紧凑(表格嵌在卡片里)/ `md` 标准 / `lg` 宽松(详情页) */
154
195
  size: {
155
196
  type: PropType<ControlSize>;
@@ -160,7 +201,18 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
160
201
  type: BooleanConstructor;
161
202
  default: boolean;
162
203
  };
163
- borderless: {
204
+ /**
205
+ * 有无外框(缺省**有**框):去外框写 `:bordered="false"`。
206
+ *
207
+ * **极性口径**:本库的「有无外框」一律用**肯定式** `bordered`(`Input` / `Textarea` /
208
+ * `NumberInput` / `Nav` 同款,见 `docs/guide/naming-and-defaults.md` §2.1)。本件原名
209
+ * `borderless`(否定式、默认 `false`),2026-10 按同名同义统一改成 `bordered` —— 默认行为不变
210
+ * (都是「缺省有框」),只是名字的极性换到与其余件一致,调用方不必再记「哪件用否定式」。
211
+ *
212
+ * 类名仍是 `.mh-table--borderless`:面层词根**统一为否定式**(输入族关框时也输出它),
213
+ * 与 prop 的极性相反 —— 两套各自内部一致,`Input` 的文档页记着同一处口径。
214
+ */
215
+ bordered: {
164
216
  type: BooleanConstructor;
165
217
  default: boolean;
166
218
  };
@@ -297,6 +349,17 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
297
349
  type: BooleanConstructor;
298
350
  default: boolean;
299
351
  };
352
+ /**
353
+ * 单元格值变更 —— 由 `#cell` 插槽里的 `setValue` 触发,是**唯一的回写通道**。
354
+ *
355
+ * 本件**不改 `data`**(与本仓表格一贯的克制口径一致:全受控、只发事件、不排序、不切片);
356
+ * 要不要接受、以及新数组怎么产生,都由调用方决定。
357
+ * 没接这个回调时 `setValue` 是空操作(插槽里的控件照旧可绑,不会报错)。
358
+ */
359
+ onCellChange: {
360
+ type: PropType<(row: TableRow, key: string, value: unknown, index: number) => void>;
361
+ default: undefined;
362
+ };
300
363
  /** 尺寸档:`sm` 紧凑(表格嵌在卡片里)/ `md` 标准 / `lg` 宽松(详情页) */
301
364
  size: {
302
365
  type: PropType<ControlSize>;
@@ -307,7 +370,18 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
307
370
  type: BooleanConstructor;
308
371
  default: boolean;
309
372
  };
310
- borderless: {
373
+ /**
374
+ * 有无外框(缺省**有**框):去外框写 `:bordered="false"`。
375
+ *
376
+ * **极性口径**:本库的「有无外框」一律用**肯定式** `bordered`(`Input` / `Textarea` /
377
+ * `NumberInput` / `Nav` 同款,见 `docs/guide/naming-and-defaults.md` §2.1)。本件原名
378
+ * `borderless`(否定式、默认 `false`),2026-10 按同名同义统一改成 `bordered` —— 默认行为不变
379
+ * (都是「缺省有框」),只是名字的极性换到与其余件一致,调用方不必再记「哪件用否定式」。
380
+ *
381
+ * 类名仍是 `.mh-table--borderless`:面层词根**统一为否定式**(输入族关框时也输出它),
382
+ * 与 prop 的极性相反 —— 两套各自内部一致,`Input` 的文档页记着同一处口径。
383
+ */
384
+ bordered: {
311
385
  type: BooleanConstructor;
312
386
  default: boolean;
313
387
  };
@@ -414,11 +488,12 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
414
488
  expandedKeys: (string | number)[];
415
489
  defaultExpandedKeys: (string | number)[];
416
490
  onExpandChange: (keys: Array<string | number>) => void;
491
+ bordered: boolean;
417
492
  modelValue: (string | number)[];
418
493
  emptyText: string;
419
494
  selectable: boolean | TableRowSelectable;
420
495
  striped: boolean;
421
- borderless: boolean;
496
+ onCellChange: (row: TableRow, key: string, value: unknown, index: number) => void;
422
497
  stickyHead: boolean;
423
498
  stickyCol: boolean;
424
499
  showHeader: boolean;
@@ -429,13 +504,13 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
429
504
  expandable: (row: TableRow, index: number) => VNodeChild;
430
505
  pagination: false | TablePagination;
431
506
  }, SlotsType<{
432
- /** 单元格:`{ row, column, value, index }`(不给则直接输出原值) */
433
- cell?: (context: {
434
- row: TableRow;
435
- column: TableColumn;
436
- value: unknown;
437
- index: number;
438
- }) => VNodeChild;
507
+ /**
508
+ * 单元格:`{ row, column, value, index, setValue }`(不给则直接输出原值)。
509
+ *
510
+ * **编辑格也走这里**(见 `TableCellSlotScope` 的说明):本件不替调用方渲染控件,
511
+ * 只给值、给位置、给一个受控的回写口 `setValue`。
512
+ */
513
+ cell?: (context: TableCellSlotScope) => VNodeChild;
439
514
  /** 行尾操作区:`{ row, index }`(面里用 `align: 'right'` 的列承载) */
440
515
  actions?: (context: {
441
516
  row: TableRow;
@@ -43,6 +43,17 @@ const Table = /* @__PURE__ */ defineComponent({
43
43
  type: Boolean,
44
44
  default: false
45
45
  },
46
+ /**
47
+ * 单元格值变更 —— 由 `#cell` 插槽里的 `setValue` 触发,是**唯一的回写通道**。
48
+ *
49
+ * 本件**不改 `data`**(与本仓表格一贯的克制口径一致:全受控、只发事件、不排序、不切片);
50
+ * 要不要接受、以及新数组怎么产生,都由调用方决定。
51
+ * 没接这个回调时 `setValue` 是空操作(插槽里的控件照旧可绑,不会报错)。
52
+ */
53
+ onCellChange: {
54
+ type: Function,
55
+ default: void 0
56
+ },
46
57
  /** 尺寸档:`sm` 紧凑(表格嵌在卡片里)/ `md` 标准 / `lg` 宽松(详情页) */
47
58
  size: {
48
59
  type: String,
@@ -53,9 +64,20 @@ const Table = /* @__PURE__ */ defineComponent({
53
64
  type: Boolean,
54
65
  default: false
55
66
  },
56
- borderless: {
67
+ /**
68
+ * 有无外框(缺省**有**框):去外框写 `:bordered="false"`。
69
+ *
70
+ * **极性口径**:本库的「有无外框」一律用**肯定式** `bordered`(`Input` / `Textarea` /
71
+ * `NumberInput` / `Nav` 同款,见 `docs/guide/naming-and-defaults.md` §2.1)。本件原名
72
+ * `borderless`(否定式、默认 `false`),2026-10 按同名同义统一改成 `bordered` —— 默认行为不变
73
+ * (都是「缺省有框」),只是名字的极性换到与其余件一致,调用方不必再记「哪件用否定式」。
74
+ *
75
+ * 类名仍是 `.mh-table--borderless`:面层词根**统一为否定式**(输入族关框时也输出它),
76
+ * 与 prop 的极性相反 —— 两套各自内部一致,`Input` 的文档页记着同一处口径。
77
+ */
78
+ bordered: {
57
79
  type: Boolean,
58
- default: false
80
+ default: true
59
81
  },
60
82
  /** 外框交给包裹层(满高表格用) */
61
83
  fill: {
@@ -178,6 +200,9 @@ const Table = /* @__PURE__ */ defineComponent({
178
200
  const columnCount = computed(() => leadColumns.value + props.columns.length);
179
201
  const isEmpty = computed(() => props.data.length === 0);
180
202
  const cellClass = (column) => [column.align === "center" ? "mh-table__cell-center" : "", column.align === "right" ? "mh-table__cell-amount" : "", column.wrap ? "mh-table__cell-wrap" : ""].filter(Boolean);
203
+ const cellSetValue = (row, column, index) => (next) => {
204
+ props.onCellChange?.(row, column.key, next, index);
205
+ };
181
206
  const colStyles = computed(() => {
182
207
  const weightSum = props.columns.reduce((sum, item) => typeof item.width === "number" ? sum + item.width : sum, 0);
183
208
  return props.columns.map((column) => {
@@ -221,7 +246,7 @@ const Table = /* @__PURE__ */ defineComponent({
221
246
  };
222
247
  const sortGlyph = (key) => props.sortKey === key && props.sortOrder === "asc" ? "chevron-up" : "chevron-down";
223
248
  return () => {
224
- 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.layout === "fixed" ? "mh-table--fixed" : "", props.stickyHead ? "mh-table--sticky-head" : "", props.stickyCol ? "mh-table--sticky-col" : "", attrs.class].filter(Boolean).join(" ");
249
+ const tableClass = ["mh-table", resolvedSize.value === "sm" ? "mh-table--xs" : "", resolvedSize.value === "lg" ? "mh-table--lg" : "", props.bordered ? "" : "mh-table--borderless", props.fill ? "mh-table--fill" : "", props.layout === "fixed" ? "mh-table--fixed" : "", props.stickyHead ? "mh-table--sticky-head" : "", props.stickyCol ? "mh-table--sticky-col" : "", attrs.class].filter(Boolean).join(" ");
225
250
  const pager = typeof props.pagination === "object" ? props.pagination : null;
226
251
  return createVNode("div", {
227
252
  "class": "mh-table-wrapper",
@@ -303,12 +328,16 @@ const Table = /* @__PURE__ */ defineComponent({
303
328
  ) : null, props.columns.map((column) => createVNode("td", {
304
329
  "key": column.key,
305
330
  "class": cellClass(column).join(" ")
306
- }, [slots.cell ? slots.cell({
307
- row,
308
- column,
309
- value: row[column.key],
310
- index
311
- }) : slots.actions && column.align === "right" ? slots.actions({
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({
312
341
  row,
313
342
  index
314
343
  }) : String(row[column.key] ?? "")]))]), isExpanded ? createVNode("tr", {
package/dist/index.d.ts CHANGED
@@ -32,7 +32,7 @@ export { Tree, type TreeNode } from './components/tree';
32
32
  export { ListView, type ListViewProps, type ListViewStatus, type ListViewStatusTone, type ListViewCardItemProps, type ListViewCompound, } from './components/list-view';
33
33
  export { Badge, type BadgeTone, type BadgeShape, type BadgeSize, type BadgeDot, type BadgeStatus, } from './components/badge';
34
34
  export { Button, type ButtonVariant, type ButtonCompound, type ButtonCompoundType, } from './components/button';
35
- export { Input, Textarea, type TextareaProps, type InputCompound, type InputCompoundType, } from './components/input';
35
+ export { Input, Textarea, NumberInput, type TextareaProps, type NumberInputProps, type InputCompound, type InputCompoundType, } from './components/input';
36
36
  export { Search, type SearchProps } from './components/search';
37
37
  export { Select, SelectTree, type SelectOption, type SelectValue } from './components/select';
38
38
  export { Switch } from './components/switch';
@@ -45,7 +45,7 @@ export { Notification, type NotificationTone, } from './components/notification'
45
45
  export { Dialog, type DialogWidth } from './components/dialog';
46
46
  export { Drawer, type DrawerSide } from './components/drawer';
47
47
  export { Tooltip, type TooltipSide, type TooltipAlign, } from './components/tooltip';
48
- export { Table, type TableColumn, type TableRow, type TableRowSelectable, type TableSortOrder, } from './components/table';
48
+ export { Table, type TableColumn, type TableCellSlotScope, type TableRow, type TableRowSelectable, type TableSortOrder, } from './components/table';
49
49
  export { Pagination, type PaginationPageItem } from './components/pagination';
50
50
  export { TabBar, type TabBarOption, type TabBarValue } from './components/tabbar';
51
51
  export { Steps, type CanJump, type StepsItem, type StepsVariant, type StepsCompound, type StepsCompoundType, } from './components/steps';
package/dist/index.js CHANGED
@@ -38,6 +38,7 @@ import { Upload, formatFileSize } from "./components/upload/index.js";
38
38
  import { QueryState } from "./components/query-state/index.js";
39
39
  import { Loading } from "./components/loading/index.js";
40
40
  import { mergePartStyle, partPaddingStyle } from "./components/part-padding.js";
41
+ import { NumberInput } from "./components/input/number-input.js";
41
42
  import { SelectTree } from "./components/select/select-tree.js";
42
43
  import { alert, closeAllDialogs, confirm } from "./services/dialog.js";
43
44
  import { clearToasts, toast } from "./services/toast.js";
@@ -66,6 +67,7 @@ export {
66
67
  Nav,
67
68
  Notice,
68
69
  Notification,
70
+ NumberInput,
69
71
  Page,
70
72
  Pagination,
71
73
  Panel,
@@ -1,131 +1,131 @@
1
- /**
2
- * Avatar —— 头像(四档尺寸 / 文字 / 图标 / 占位 / 方角 / 带框 / 计数 / 头像组 / 角标)。
3
- *
4
- * 出处:`@aihub/theme` 的 `playground/components/avatar.css` 与 `src/components/avatar.css`
5
- * (实测四档 24 / 36 / 60 / 80;字母底色取主色;角标高 20 白描边)。
6
- *
7
- * 两条来自规范的硬结论,改前先读:
8
- * 1. **圆形裁切归图片自身,容器不裁**:角上的角标(`__badge`)与徽章(`__chip`)是绝对定位件,
9
- * 容器若带 `overflow: hidden`,会沿圆弧把它们各切掉一半(实测反馈)。故容器 `overflow: visible`,
10
- * 图片用 `border-radius: inherit` 跟着形态自裁。
11
- * 2. **头像组靠负边距堆叠**(`.mh-avatar-group`),每个头像带 2px 的底描边把相邻项隔开。
12
- */
13
- .mh-avatar {
14
- display: inline-flex;
15
- align-items: center;
16
- justify-content: center;
17
- position: relative;
18
- flex-shrink: 0;
19
- overflow: visible; /* 见文件头第 1 条:裁切归图片 */
20
- border-radius: var(--ui-radius-full);
21
- background: var(--ui-base-400); /* Ne04 占位底 */
22
- color: var(--ui-base-100); /* 占位前景 */
23
- }
24
-
25
- /* 图片:撑满 + 跟随形态自裁(否则去掉容器 overflow 后长宽不符的图会外溢)。
26
- `display: block` 必须自己写:元素级基线不再把 `img` 转块级(那条会压消费方的 `h-*` / `hidden`),
27
- 否则行内基线间隙会把圆形头像顶偏。 */
28
- .mh-avatar > img {
29
- display: block;
30
- width: 100%;
31
- height: 100%;
32
- border-radius: inherit;
33
- object-fit: cover;
34
- }
35
-
36
- /* ===== 尺寸四档 ===== */
37
- .mh-avatar--sm {
38
- width: var(--ui-avatar-size-sm);
39
- height: var(--ui-avatar-size-sm);
40
- font-size: var(--ui-font-caption);
41
- }
42
- .mh-avatar--md {
43
- width: var(--ui-avatar-size-md);
44
- height: var(--ui-avatar-size-md);
45
- font-size: var(--ui-font-caption);
46
- }
47
- .mh-avatar--lg {
48
- width: var(--ui-avatar-size-lg);
49
- height: var(--ui-avatar-size-lg);
50
- font-size: var(--ui-font-title);
51
- }
52
- .mh-avatar--xl {
53
- width: var(--ui-avatar-size-xl);
54
- height: var(--ui-avatar-size-xl);
55
- font-size: var(--ui-font-display);
56
- }
57
-
58
- /* ===== 内容形态 ===== */
59
- /* 文字头像:底取主色(业务要按人名哈希换色时给 `.mh-avatar--letter` 覆盖 background 即可) */
60
- .mh-avatar--letter {
61
- background: var(--ui-primary);
62
- }
63
- /* 图标头像:图标由 @manohub/icon 渲染,这里只给尺寸档 */
64
- .mh-avatar--icon {
65
- color: var(--ui-base-100);
66
- }
67
- /* 占位:虚线框 + 说明字(虚线线色取线型档,口径「实线 base-300 / 虚线 base-400」) */
68
- .mh-avatar--placeholder {
69
- border: 1px dashed var(--ui-line-dashed);
70
- background: var(--ui-base-100);
71
- color: var(--ui-base-content-subtle);
72
- font-size: var(--ui-font-caption);
73
- }
74
- /* 方角(商业图像):圆角矩形 */
75
- .mh-avatar--square {
76
- border-radius: var(--ui-radius-control);
77
- }
78
- /* 带框:靠阴影画出 2px 底环(不占布局,避免与角标抢位) */
79
- .mh-avatar--framed {
80
- box-shadow: 0 0 0 2px var(--ui-base-100), var(--ui-shadow-card);
81
- }
82
- /* 计数档(头像组末位的「+N」) */
83
- .mh-avatar--count {
84
- background: var(--ui-base-200);
85
- color: var(--ui-base-content-muted);
86
- font-size: var(--ui-font-caption);
87
- }
88
-
89
- /* ===== 角上外挂件(见文件头第 1 条:容器不裁,故它们不会被切)===== */
90
- .mh-avatar__badge {
91
- position: absolute;
92
- top: 0;
93
- right: 0;
94
- display: flex;
95
- align-items: center;
96
- justify-content: center;
97
- min-width: var(--ui-avatar-badge-size);
98
- height: var(--ui-avatar-badge-size);
99
- padding: 0 var(--ui-space-1);
100
- border-radius: var(--ui-radius-full);
101
- background: var(--ui-error); /* 红底(规范 Badge 专页实测) */
102
- border: 2px solid var(--ui-base-100); /* 白描边 */
103
- color: var(--ui-error-content);
104
- font-size: var(--ui-font-caption);
105
- }
106
- .mh-avatar__chip {
107
- position: absolute;
108
- right: -2px;
109
- bottom: -2px;
110
- display: flex;
111
- align-items: center;
112
- justify-content: center;
113
- width: 24px;
114
- height: 24px;
115
- border-radius: var(--ui-radius-full);
116
- background: var(--ui-primary);
117
- border: 2px solid var(--ui-base-100);
118
- cursor: pointer;
119
- }
120
-
121
- /* ===== 头像组:负边距堆叠,靠 2px 底描边分隔 ===== */
122
- .mh-avatar-group {
123
- display: inline-flex;
124
- align-items: center;
125
- }
126
- .mh-avatar-group .mh-avatar {
127
- border: 2px solid var(--ui-base-100);
128
- }
129
- .mh-avatar-group .mh-avatar + .mh-avatar {
130
- margin-left: calc(-1 * var(--ui-avatar-gap));
131
- }
1
+ /**
2
+ * Avatar —— 头像(四档尺寸 / 文字 / 图标 / 占位 / 方角 / 带框 / 计数 / 头像组 / 角标)。
3
+ *
4
+ * 出处:`@aihub/theme` 的 `playground/components/avatar.css` 与 `src/components/avatar.css`
5
+ * (实测四档 24 / 36 / 60 / 80;字母底色取主色;角标高 20 白描边)。
6
+ *
7
+ * 两条来自规范的硬结论,改前先读:
8
+ * 1. **圆形裁切归图片自身,容器不裁**:角上的角标(`__badge`)与徽章(`__chip`)是绝对定位件,
9
+ * 容器若带 `overflow: hidden`,会沿圆弧把它们各切掉一半(实测反馈)。故容器 `overflow: visible`,
10
+ * 图片用 `border-radius: inherit` 跟着形态自裁。
11
+ * 2. **头像组靠负边距堆叠**(`.mh-avatar-group`),每个头像带 2px 的底描边把相邻项隔开。
12
+ */
13
+ .mh-avatar {
14
+ display: inline-flex;
15
+ align-items: center;
16
+ justify-content: center;
17
+ position: relative;
18
+ flex-shrink: 0;
19
+ overflow: visible; /* 见文件头第 1 条:裁切归图片 */
20
+ border-radius: var(--ui-radius-full);
21
+ background: var(--ui-base-400); /* Ne04 占位底 */
22
+ color: var(--ui-base-100); /* 占位前景 */
23
+ }
24
+
25
+ /* 图片:撑满 + 跟随形态自裁(否则去掉容器 overflow 后长宽不符的图会外溢)。
26
+ `display: block` 必须自己写:元素级基线不再把 `img` 转块级(那条会压消费方的 `h-*` / `hidden`),
27
+ 否则行内基线间隙会把圆形头像顶偏。 */
28
+ .mh-avatar > img {
29
+ display: block;
30
+ width: 100%;
31
+ height: 100%;
32
+ border-radius: inherit;
33
+ object-fit: cover;
34
+ }
35
+
36
+ /* ===== 尺寸四档 ===== */
37
+ .mh-avatar--sm {
38
+ width: var(--ui-avatar-size-sm);
39
+ height: var(--ui-avatar-size-sm);
40
+ font-size: var(--ui-font-caption);
41
+ }
42
+ .mh-avatar--md {
43
+ width: var(--ui-avatar-size-md);
44
+ height: var(--ui-avatar-size-md);
45
+ font-size: var(--ui-font-caption);
46
+ }
47
+ .mh-avatar--lg {
48
+ width: var(--ui-avatar-size-lg);
49
+ height: var(--ui-avatar-size-lg);
50
+ font-size: var(--ui-font-title);
51
+ }
52
+ .mh-avatar--xl {
53
+ width: var(--ui-avatar-size-xl);
54
+ height: var(--ui-avatar-size-xl);
55
+ font-size: var(--ui-font-display);
56
+ }
57
+
58
+ /* ===== 内容形态 ===== */
59
+ /* 文字头像:底取主色(业务要按人名哈希换色时给 `.mh-avatar--letter` 覆盖 background 即可) */
60
+ .mh-avatar--letter {
61
+ background: var(--ui-primary);
62
+ }
63
+ /* 图标头像:图标由 @manohub/icon 渲染,这里只给尺寸档 */
64
+ .mh-avatar--icon {
65
+ color: var(--ui-base-100);
66
+ }
67
+ /* 占位:虚线框 + 说明字(虚线线色取线型档,口径「实线 base-300 / 虚线 base-400」) */
68
+ .mh-avatar--placeholder {
69
+ border: 1px dashed var(--ui-line-dashed);
70
+ background: var(--ui-base-100);
71
+ color: var(--ui-base-content-subtle);
72
+ font-size: var(--ui-font-caption);
73
+ }
74
+ /* 方角(商业图像):圆角矩形 */
75
+ .mh-avatar--square {
76
+ border-radius: var(--ui-radius-control);
77
+ }
78
+ /* 带框:靠阴影画出 2px 底环(不占布局,避免与角标抢位) */
79
+ .mh-avatar--framed {
80
+ box-shadow: 0 0 0 2px var(--ui-base-100), var(--ui-shadow-card);
81
+ }
82
+ /* 计数档(头像组末位的「+N」) */
83
+ .mh-avatar--count {
84
+ background: var(--ui-base-200);
85
+ color: var(--ui-base-content-muted);
86
+ font-size: var(--ui-font-caption);
87
+ }
88
+
89
+ /* ===== 角上外挂件(见文件头第 1 条:容器不裁,故它们不会被切)===== */
90
+ .mh-avatar__badge {
91
+ position: absolute;
92
+ top: 0;
93
+ right: 0;
94
+ display: flex;
95
+ align-items: center;
96
+ justify-content: center;
97
+ min-width: var(--ui-avatar-badge-size);
98
+ height: var(--ui-avatar-badge-size);
99
+ padding: 0 var(--ui-space-1);
100
+ border-radius: var(--ui-radius-full);
101
+ background: var(--ui-error); /* 红底(规范 Badge 专页实测) */
102
+ border: 2px solid var(--ui-base-100); /* 白描边 */
103
+ color: var(--ui-error-content);
104
+ font-size: var(--ui-font-caption);
105
+ }
106
+ .mh-avatar__chip {
107
+ position: absolute;
108
+ right: -2px;
109
+ bottom: -2px;
110
+ display: flex;
111
+ align-items: center;
112
+ justify-content: center;
113
+ width: 24px;
114
+ height: 24px;
115
+ border-radius: var(--ui-radius-full);
116
+ background: var(--ui-primary);
117
+ border: 2px solid var(--ui-base-100);
118
+ cursor: pointer;
119
+ }
120
+
121
+ /* ===== 头像组:负边距堆叠,靠 2px 底描边分隔 ===== */
122
+ .mh-avatar-group {
123
+ display: inline-flex;
124
+ align-items: center;
125
+ }
126
+ .mh-avatar-group .mh-avatar {
127
+ border: 2px solid var(--ui-base-100);
128
+ }
129
+ .mh-avatar-group .mh-avatar + .mh-avatar {
130
+ margin-left: calc(-1 * var(--ui-avatar-gap));
131
+ }
@@ -1,24 +1,24 @@
1
- /**
2
- * avatar —— 单件令牌(**基础值**)。
3
- *
4
- * 本件自己的几何 / 尺寸 / 色彩槽位;只服务本件,故不随主题进 `@manohub/theme`。
5
- *
6
- * ## 抽出说明
7
- * 本文件从面文件里抽出(原先混写在 `avatar.css` 顶部):这些是**基础值**,锚在
8
- * `[data-manohub-ui]` —— 跨包唯一作用域锚,由入口层无条件写在应用容器上,因此**任何落在
9
- * 容器里的分件都取得到值**,不再依赖「声明在某个组件根类上」这条脆弱假设
10
- * (历史症状:跨件消费的 `--ui-*-group-*` 取不到值,组内间距变 0)。
11
- *
12
- * ⚠️ `.mh-<件>--<档>` 这类**档位改写**留在面文件的修饰符块里 —— 它们靠「同一元素上两个
13
- * 选择器改写同一个令牌」生效,搬到本文件会让档位失效。
14
- * ⚠️ 新增组件要登记两处:本文件 + `src/styles/index.css`(见其文件头「五处齐备」)。
15
- */
16
- [data-manohub-ui] {
17
- /* 单件令牌(只服务本件;跨件令牌才进 theme/) */
18
- --ui-avatar-size-sm: 24px;
19
- --ui-avatar-size-md: 36px;
20
- --ui-avatar-size-lg: 60px;
21
- --ui-avatar-size-xl: 80px;
22
- --ui-avatar-badge-size: 20px; /* 角标高 20,宽按位数撑开 */
23
- --ui-avatar-gap: 10px; /* 堆叠重叠量(组件可用 gap 覆盖) */
24
- }
1
+ /**
2
+ * avatar —— 单件令牌(**基础值**)。
3
+ *
4
+ * 本件自己的几何 / 尺寸 / 色彩槽位;只服务本件,故不随主题进 `@manohub/theme`。
5
+ *
6
+ * ## 抽出说明
7
+ * 本文件从面文件里抽出(原先混写在 `avatar.css` 顶部):这些是**基础值**,锚在
8
+ * `[data-manohub-ui]` —— 跨包唯一作用域锚,由入口层无条件写在应用容器上,因此**任何落在
9
+ * 容器里的分件都取得到值**,不再依赖「声明在某个组件根类上」这条脆弱假设
10
+ * (历史症状:跨件消费的 `--ui-*-group-*` 取不到值,组内间距变 0)。
11
+ *
12
+ * ⚠️ `.mh-<件>--<档>` 这类**档位改写**留在面文件的修饰符块里 —— 它们靠「同一元素上两个
13
+ * 选择器改写同一个令牌」生效,搬到本文件会让档位失效。
14
+ * ⚠️ 新增组件要登记两处:本文件 + `src/styles/index.css`(见其文件头「五处齐备」)。
15
+ */
16
+ [data-manohub-ui] {
17
+ /* 单件令牌(只服务本件;跨件令牌才进 theme/) */
18
+ --ui-avatar-size-sm: 24px;
19
+ --ui-avatar-size-md: 36px;
20
+ --ui-avatar-size-lg: 60px;
21
+ --ui-avatar-size-xl: 80px;
22
+ --ui-avatar-badge-size: 20px; /* 角标高 20,宽按位数撑开 */
23
+ --ui-avatar-gap: 10px; /* 堆叠重叠量(组件可用 gap 覆盖) */
24
+ }