@manohub/ui 1.0.0 → 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.
- package/dist/components/input/bordered.d.ts +15 -0
- package/dist/components/input/bordered.js +8 -0
- package/dist/components/input/index.d.ts +82 -31
- package/dist/components/input/index.js +16 -6
- package/dist/components/input/number-input.d.ts +239 -0
- package/dist/components/input/number-input.js +240 -0
- package/dist/components/select/index.d.ts +19 -0
- package/dist/components/select/index.js +10 -0
- package/dist/components/select/select-tree.d.ts +11 -0
- package/dist/components/select/select-tree.js +6 -0
- package/dist/components/select/select-trigger.d.ts +17 -0
- package/dist/components/select/select-trigger.js +9 -0
- package/dist/components/table/index.d.ts +85 -10
- package/dist/components/table/index.js +38 -9
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -0
- package/dist/styles/components/form.css +14 -0
- package/dist/styles/components/form.tokens.css +4 -0
- package/dist/styles/components/input.css +159 -38
- package/dist/styles/components/table.css +6 -0
- package/package.json +2 -2
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `bordered` 三档 → 控件类名(**唯一来源**)。
|
|
3
|
+
*
|
|
4
|
+
* 输入族三个件(`Input` / `Textarea` / `NumberInput`)共用同一份面与同一个 prop,判定表抄三份必然漂,
|
|
5
|
+
* 故收在这里。类名口径:prop 是**肯定式**(`bordered`)、类名是**否定式**(`--borderless`)——
|
|
6
|
+
* 那一对的反差是库内既定口径(见 `docs/guide/naming-and-defaults.md` §2.1);
|
|
7
|
+
* `'focus'` 档的类名 `--border-on-focus` 是这套口径下的新成员:它说的就是「聚焦时才有框」。
|
|
8
|
+
*
|
|
9
|
+
* | `bordered` | 类名 | 常态 | 悬停 | 聚焦 |
|
|
10
|
+
* | --- | --- | --- | --- | --- |
|
|
11
|
+
* | `true`(缺省) | (无) | 有框 | 框变色 | 框变色 + 主色环 |
|
|
12
|
+
* | `'focus'` | `.mh-input--border-on-focus` | 无框无底 | 复用有框档那句 | 显框 + 主色环(复用) |
|
|
13
|
+
* | `false` | `.mh-input--borderless` | 无框无底 | 无 | 无(本档效果只有一种) |
|
|
14
|
+
*/
|
|
15
|
+
export declare const borderedClassOf: (bordered: boolean | "focus" | undefined) => string;
|
|
@@ -109,11 +109,19 @@ export declare const Input: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
109
109
|
default: boolean;
|
|
110
110
|
};
|
|
111
111
|
/**
|
|
112
|
-
*
|
|
113
|
-
*
|
|
112
|
+
* 有无边框,三档(判定表见 `./bordered.ts`,输入族三件共用):
|
|
113
|
+
*
|
|
114
|
+
* - `true`(缺省)**常有框**;
|
|
115
|
+
* - `false` **无框** —— 常态、悬停、聚焦都不出现(本档的效果只有一种);
|
|
116
|
+
* - `'focus'` **聚焦(与悬停)才显出框** —— 行内编辑那档:常态看着像「值」,点进去才亮框;
|
|
117
|
+
* 悬停 / 聚焦的表现**复用有框档那两条**,不另写一套。
|
|
118
|
+
*
|
|
119
|
+
* 配 `readonly` 即**只读值档**(摘要 / 详情里回显业务值的推荐写法,也是 `Form.Item` 的
|
|
120
|
+
* `readonly` 行配的那一档):几何与可编辑输入框完全一致,但不给任何「可编辑」线索。
|
|
121
|
+
* 只读值档请写 `readonly` + `bordered={false}`;`readonly` + `'focus'` 会被中和(兜底,不推荐)。
|
|
114
122
|
*/
|
|
115
123
|
bordered: {
|
|
116
|
-
type:
|
|
124
|
+
type: PropType<boolean | "focus">;
|
|
117
125
|
default: boolean;
|
|
118
126
|
};
|
|
119
127
|
maxlength: {
|
|
@@ -228,11 +236,19 @@ export declare const Input: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
228
236
|
default: boolean;
|
|
229
237
|
};
|
|
230
238
|
/**
|
|
231
|
-
*
|
|
232
|
-
*
|
|
239
|
+
* 有无边框,三档(判定表见 `./bordered.ts`,输入族三件共用):
|
|
240
|
+
*
|
|
241
|
+
* - `true`(缺省)**常有框**;
|
|
242
|
+
* - `false` **无框** —— 常态、悬停、聚焦都不出现(本档的效果只有一种);
|
|
243
|
+
* - `'focus'` **聚焦(与悬停)才显出框** —— 行内编辑那档:常态看着像「值」,点进去才亮框;
|
|
244
|
+
* 悬停 / 聚焦的表现**复用有框档那两条**,不另写一套。
|
|
245
|
+
*
|
|
246
|
+
* 配 `readonly` 即**只读值档**(摘要 / 详情里回显业务值的推荐写法,也是 `Form.Item` 的
|
|
247
|
+
* `readonly` 行配的那一档):几何与可编辑输入框完全一致,但不给任何「可编辑」线索。
|
|
248
|
+
* 只读值档请写 `readonly` + `bordered={false}`;`readonly` + `'focus'` 会被中和(兜底,不推荐)。
|
|
233
249
|
*/
|
|
234
250
|
bordered: {
|
|
235
|
-
type:
|
|
251
|
+
type: PropType<boolean | "focus">;
|
|
236
252
|
default: boolean;
|
|
237
253
|
};
|
|
238
254
|
maxlength: {
|
|
@@ -289,7 +305,7 @@ export declare const Input: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
289
305
|
type: string;
|
|
290
306
|
onChange: (v: string) => void;
|
|
291
307
|
invalid: boolean;
|
|
292
|
-
bordered: boolean;
|
|
308
|
+
bordered: boolean | "focus";
|
|
293
309
|
defaultValue: string;
|
|
294
310
|
placeholder: string;
|
|
295
311
|
autofocus: boolean;
|
|
@@ -297,10 +313,10 @@ export declare const Input: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
297
313
|
status: InputStatus;
|
|
298
314
|
as: "button" | "input";
|
|
299
315
|
readonly: boolean;
|
|
316
|
+
onEnter: (v: string) => void;
|
|
300
317
|
clearable: boolean;
|
|
301
318
|
maxlength: number;
|
|
302
319
|
showCount: boolean;
|
|
303
|
-
onEnter: (v: string) => void;
|
|
304
320
|
controlClass: string;
|
|
305
321
|
controlAttrs: Record<string, unknown>;
|
|
306
322
|
hasValue: boolean;
|
|
@@ -328,8 +344,8 @@ export interface TextareaProps {
|
|
|
328
344
|
invalid?: boolean;
|
|
329
345
|
/** 校验状态(`invalid` 的显式写法) */
|
|
330
346
|
status?: InputStatus;
|
|
331
|
-
/**
|
|
332
|
-
bordered?: boolean;
|
|
347
|
+
/** 是否带边框(三档口径见 `Input` 的同名 prop:`true` / `false` / `'focus'`) */
|
|
348
|
+
bordered?: boolean | 'focus';
|
|
333
349
|
maxlength?: number;
|
|
334
350
|
/** 右下角字数统计(须给 `maxlength` 才渲染) */
|
|
335
351
|
showCount?: boolean;
|
|
@@ -388,8 +404,9 @@ export declare const Textarea: import("vue").DefineComponent<import("vue").Extra
|
|
|
388
404
|
type: PropType<InputStatus>;
|
|
389
405
|
default: undefined;
|
|
390
406
|
};
|
|
407
|
+
/** 是否带边框(三档口径见 `Input` 的同名 prop:`true` 常有框 / `false` 无框 / `'focus'` 聚焦才显框) */
|
|
391
408
|
bordered: {
|
|
392
|
-
type:
|
|
409
|
+
type: PropType<boolean | "focus">;
|
|
393
410
|
default: boolean;
|
|
394
411
|
};
|
|
395
412
|
maxlength: {
|
|
@@ -453,8 +470,9 @@ export declare const Textarea: import("vue").DefineComponent<import("vue").Extra
|
|
|
453
470
|
type: PropType<InputStatus>;
|
|
454
471
|
default: undefined;
|
|
455
472
|
};
|
|
473
|
+
/** 是否带边框(三档口径见 `Input` 的同名 prop:`true` 常有框 / `false` 无框 / `'focus'` 聚焦才显框) */
|
|
456
474
|
bordered: {
|
|
457
|
-
type:
|
|
475
|
+
type: PropType<boolean | "focus">;
|
|
458
476
|
default: boolean;
|
|
459
477
|
};
|
|
460
478
|
maxlength: {
|
|
@@ -481,7 +499,7 @@ export declare const Textarea: import("vue").DefineComponent<import("vue").Extra
|
|
|
481
499
|
disabled: boolean;
|
|
482
500
|
onChange: (v: string) => void;
|
|
483
501
|
invalid: boolean;
|
|
484
|
-
bordered: boolean;
|
|
502
|
+
bordered: boolean | "focus";
|
|
485
503
|
defaultValue: string;
|
|
486
504
|
placeholder: string;
|
|
487
505
|
rows: number;
|
|
@@ -558,11 +576,19 @@ export declare const InputCompound: {
|
|
|
558
576
|
default: boolean;
|
|
559
577
|
};
|
|
560
578
|
/**
|
|
561
|
-
*
|
|
562
|
-
*
|
|
579
|
+
* 有无边框,三档(判定表见 `./bordered.ts`,输入族三件共用):
|
|
580
|
+
*
|
|
581
|
+
* - `true`(缺省)**常有框**;
|
|
582
|
+
* - `false` **无框** —— 常态、悬停、聚焦都不出现(本档的效果只有一种);
|
|
583
|
+
* - `'focus'` **聚焦(与悬停)才显出框** —— 行内编辑那档:常态看着像「值」,点进去才亮框;
|
|
584
|
+
* 悬停 / 聚焦的表现**复用有框档那两条**,不另写一套。
|
|
585
|
+
*
|
|
586
|
+
* 配 `readonly` 即**只读值档**(摘要 / 详情里回显业务值的推荐写法,也是 `Form.Item` 的
|
|
587
|
+
* `readonly` 行配的那一档):几何与可编辑输入框完全一致,但不给任何「可编辑」线索。
|
|
588
|
+
* 只读值档请写 `readonly` + `bordered={false}`;`readonly` + `'focus'` 会被中和(兜底,不推荐)。
|
|
563
589
|
*/
|
|
564
590
|
bordered: {
|
|
565
|
-
type:
|
|
591
|
+
type: PropType<boolean | "focus">;
|
|
566
592
|
default: boolean;
|
|
567
593
|
};
|
|
568
594
|
maxlength: {
|
|
@@ -621,7 +647,7 @@ export declare const InputCompound: {
|
|
|
621
647
|
type: string;
|
|
622
648
|
onChange: (v: string) => void;
|
|
623
649
|
invalid: boolean;
|
|
624
|
-
bordered: boolean;
|
|
650
|
+
bordered: boolean | "focus";
|
|
625
651
|
defaultValue: string;
|
|
626
652
|
placeholder: string;
|
|
627
653
|
autofocus: boolean;
|
|
@@ -629,10 +655,10 @@ export declare const InputCompound: {
|
|
|
629
655
|
status: InputStatus;
|
|
630
656
|
as: "button" | "input";
|
|
631
657
|
readonly: boolean;
|
|
658
|
+
onEnter: (v: string) => void;
|
|
632
659
|
clearable: boolean;
|
|
633
660
|
maxlength: number;
|
|
634
661
|
showCount: boolean;
|
|
635
|
-
onEnter: (v: string) => void;
|
|
636
662
|
controlClass: string;
|
|
637
663
|
controlAttrs: Record<string, unknown>;
|
|
638
664
|
hasValue: boolean;
|
|
@@ -711,11 +737,19 @@ export declare const InputCompound: {
|
|
|
711
737
|
default: boolean;
|
|
712
738
|
};
|
|
713
739
|
/**
|
|
714
|
-
*
|
|
715
|
-
*
|
|
740
|
+
* 有无边框,三档(判定表见 `./bordered.ts`,输入族三件共用):
|
|
741
|
+
*
|
|
742
|
+
* - `true`(缺省)**常有框**;
|
|
743
|
+
* - `false` **无框** —— 常态、悬停、聚焦都不出现(本档的效果只有一种);
|
|
744
|
+
* - `'focus'` **聚焦(与悬停)才显出框** —— 行内编辑那档:常态看着像「值」,点进去才亮框;
|
|
745
|
+
* 悬停 / 聚焦的表现**复用有框档那两条**,不另写一套。
|
|
746
|
+
*
|
|
747
|
+
* 配 `readonly` 即**只读值档**(摘要 / 详情里回显业务值的推荐写法,也是 `Form.Item` 的
|
|
748
|
+
* `readonly` 行配的那一档):几何与可编辑输入框完全一致,但不给任何「可编辑」线索。
|
|
749
|
+
* 只读值档请写 `readonly` + `bordered={false}`;`readonly` + `'focus'` 会被中和(兜底,不推荐)。
|
|
716
750
|
*/
|
|
717
751
|
bordered: {
|
|
718
|
-
type:
|
|
752
|
+
type: PropType<boolean | "focus">;
|
|
719
753
|
default: boolean;
|
|
720
754
|
};
|
|
721
755
|
maxlength: {
|
|
@@ -772,7 +806,7 @@ export declare const InputCompound: {
|
|
|
772
806
|
type: string;
|
|
773
807
|
onChange: (v: string) => void;
|
|
774
808
|
invalid: boolean;
|
|
775
|
-
bordered: boolean;
|
|
809
|
+
bordered: boolean | "focus";
|
|
776
810
|
defaultValue: string;
|
|
777
811
|
placeholder: string;
|
|
778
812
|
autofocus: boolean;
|
|
@@ -780,10 +814,10 @@ export declare const InputCompound: {
|
|
|
780
814
|
status: InputStatus;
|
|
781
815
|
as: "button" | "input";
|
|
782
816
|
readonly: boolean;
|
|
817
|
+
onEnter: (v: string) => void;
|
|
783
818
|
clearable: boolean;
|
|
784
819
|
maxlength: number;
|
|
785
820
|
showCount: boolean;
|
|
786
|
-
onEnter: (v: string) => void;
|
|
787
821
|
controlClass: string;
|
|
788
822
|
controlAttrs: Record<string, unknown>;
|
|
789
823
|
hasValue: boolean;
|
|
@@ -855,11 +889,19 @@ export declare const InputCompound: {
|
|
|
855
889
|
default: boolean;
|
|
856
890
|
};
|
|
857
891
|
/**
|
|
858
|
-
*
|
|
859
|
-
*
|
|
892
|
+
* 有无边框,三档(判定表见 `./bordered.ts`,输入族三件共用):
|
|
893
|
+
*
|
|
894
|
+
* - `true`(缺省)**常有框**;
|
|
895
|
+
* - `false` **无框** —— 常态、悬停、聚焦都不出现(本档的效果只有一种);
|
|
896
|
+
* - `'focus'` **聚焦(与悬停)才显出框** —— 行内编辑那档:常态看着像「值」,点进去才亮框;
|
|
897
|
+
* 悬停 / 聚焦的表现**复用有框档那两条**,不另写一套。
|
|
898
|
+
*
|
|
899
|
+
* 配 `readonly` 即**只读值档**(摘要 / 详情里回显业务值的推荐写法,也是 `Form.Item` 的
|
|
900
|
+
* `readonly` 行配的那一档):几何与可编辑输入框完全一致,但不给任何「可编辑」线索。
|
|
901
|
+
* 只读值档请写 `readonly` + `bordered={false}`;`readonly` + `'focus'` 会被中和(兜底,不推荐)。
|
|
860
902
|
*/
|
|
861
903
|
bordered: {
|
|
862
|
-
type:
|
|
904
|
+
type: PropType<boolean | "focus">;
|
|
863
905
|
default: boolean;
|
|
864
906
|
};
|
|
865
907
|
maxlength: {
|
|
@@ -918,7 +960,7 @@ export declare const InputCompound: {
|
|
|
918
960
|
type: string;
|
|
919
961
|
onChange: (v: string) => void;
|
|
920
962
|
invalid: boolean;
|
|
921
|
-
bordered: boolean;
|
|
963
|
+
bordered: boolean | "focus";
|
|
922
964
|
defaultValue: string;
|
|
923
965
|
placeholder: string;
|
|
924
966
|
autofocus: boolean;
|
|
@@ -926,10 +968,10 @@ export declare const InputCompound: {
|
|
|
926
968
|
status: InputStatus;
|
|
927
969
|
as: "button" | "input";
|
|
928
970
|
readonly: boolean;
|
|
971
|
+
onEnter: (v: string) => void;
|
|
929
972
|
clearable: boolean;
|
|
930
973
|
maxlength: number;
|
|
931
974
|
showCount: boolean;
|
|
932
|
-
onEnter: (v: string) => void;
|
|
933
975
|
controlClass: string;
|
|
934
976
|
controlAttrs: Record<string, unknown>;
|
|
935
977
|
hasValue: boolean;
|
|
@@ -980,8 +1022,9 @@ export declare const InputCompound: {
|
|
|
980
1022
|
type: PropType<InputStatus>;
|
|
981
1023
|
default: undefined;
|
|
982
1024
|
};
|
|
1025
|
+
/** 是否带边框(三档口径见 `Input` 的同名 prop:`true` 常有框 / `false` 无框 / `'focus'` 聚焦才显框) */
|
|
983
1026
|
bordered: {
|
|
984
|
-
type:
|
|
1027
|
+
type: PropType<boolean | "focus">;
|
|
985
1028
|
default: boolean;
|
|
986
1029
|
};
|
|
987
1030
|
maxlength: {
|
|
@@ -1045,8 +1088,9 @@ export declare const InputCompound: {
|
|
|
1045
1088
|
type: PropType<InputStatus>;
|
|
1046
1089
|
default: undefined;
|
|
1047
1090
|
};
|
|
1091
|
+
/** 是否带边框(三档口径见 `Input` 的同名 prop:`true` 常有框 / `false` 无框 / `'focus'` 聚焦才显框) */
|
|
1048
1092
|
bordered: {
|
|
1049
|
-
type:
|
|
1093
|
+
type: PropType<boolean | "focus">;
|
|
1050
1094
|
default: boolean;
|
|
1051
1095
|
};
|
|
1052
1096
|
maxlength: {
|
|
@@ -1073,7 +1117,7 @@ export declare const InputCompound: {
|
|
|
1073
1117
|
disabled: boolean;
|
|
1074
1118
|
onChange: (v: string) => void;
|
|
1075
1119
|
invalid: boolean;
|
|
1076
|
-
bordered: boolean;
|
|
1120
|
+
bordered: boolean | "focus";
|
|
1077
1121
|
defaultValue: string;
|
|
1078
1122
|
placeholder: string;
|
|
1079
1123
|
rows: number;
|
|
@@ -1102,3 +1146,10 @@ export declare const InputCompound: {
|
|
|
1102
1146
|
}>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
1103
1147
|
};
|
|
1104
1148
|
export type InputCompoundType = typeof InputCompound;
|
|
1149
|
+
/**
|
|
1150
|
+
* 数字输入与 `Input` **同族**(同一个表壳 / 内距 / 状态协议,同一份面 `input.css`),
|
|
1151
|
+
* 故与 `Textarea` 同款处置:**平级导出、共用本目录**(`AGENTS.md` 硬约束 1)。
|
|
1152
|
+
* 它**不是** `Input` 的点号成员 —— 成员位留给「同一件自己的形态」(`.Textarea` / `.Display`),
|
|
1153
|
+
* 而数字输入是另一件(值模型 `number | null` vs `string`)。
|
|
1154
|
+
*/
|
|
1155
|
+
export { NumberInput, type NumberInputProps } from './number-input';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineComponent, ref, computed, createVNode, mergeProps, createTextVNode } from "vue";
|
|
2
2
|
import { Icon } from "@manohub/icon";
|
|
3
|
+
import { borderedClassOf } from "./bordered.js";
|
|
3
4
|
const Input = /* @__PURE__ */ defineComponent({
|
|
4
5
|
name: "Input",
|
|
5
6
|
inheritAttrs: false,
|
|
@@ -67,11 +68,19 @@ const Input = /* @__PURE__ */ defineComponent({
|
|
|
67
68
|
default: false
|
|
68
69
|
},
|
|
69
70
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
71
|
+
* 有无边框,三档(判定表见 `./bordered.ts`,输入族三件共用):
|
|
72
|
+
*
|
|
73
|
+
* - `true`(缺省)**常有框**;
|
|
74
|
+
* - `false` **无框** —— 常态、悬停、聚焦都不出现(本档的效果只有一种);
|
|
75
|
+
* - `'focus'` **聚焦(与悬停)才显出框** —— 行内编辑那档:常态看着像「值」,点进去才亮框;
|
|
76
|
+
* 悬停 / 聚焦的表现**复用有框档那两条**,不另写一套。
|
|
77
|
+
*
|
|
78
|
+
* 配 `readonly` 即**只读值档**(摘要 / 详情里回显业务值的推荐写法,也是 `Form.Item` 的
|
|
79
|
+
* `readonly` 行配的那一档):几何与可编辑输入框完全一致,但不给任何「可编辑」线索。
|
|
80
|
+
* 只读值档请写 `readonly` + `bordered={false}`;`readonly` + `'focus'` 会被中和(兜底,不推荐)。
|
|
72
81
|
*/
|
|
73
82
|
bordered: {
|
|
74
|
-
type: Boolean,
|
|
83
|
+
type: [Boolean, String],
|
|
75
84
|
default: true
|
|
76
85
|
},
|
|
77
86
|
maxlength: {
|
|
@@ -174,7 +183,7 @@ const Input = /* @__PURE__ */ defineComponent({
|
|
|
174
183
|
};
|
|
175
184
|
const inputType = computed(() => props.type === "password" && revealed.value ? "text" : props.type);
|
|
176
185
|
const isTrigger = computed(() => props.as === "button");
|
|
177
|
-
const controlClasses = computed(() => ["mh-input", isTrigger.value ? "mh-input--trigger" : "", props.size === "md" ? "" : `mh-input--${props.size}`, props.bordered
|
|
186
|
+
const controlClasses = computed(() => ["mh-input", isTrigger.value ? "mh-input--trigger" : "", props.size === "md" ? "" : `mh-input--${props.size}`, borderedClassOf(props.bordered), visualStatus.value ? `is-${visualStatus.value}` : "", props.disabled ? "is-disabled" : "", props.controlClass].filter(Boolean).join(" "));
|
|
178
187
|
const showClear = computed(() => props.clearable && (props.hasValue ?? !!current.value));
|
|
179
188
|
const showCounter = computed(() => !isTrigger.value && props.showCount && props.maxlength !== void 0);
|
|
180
189
|
const showPlaceholder = computed(() => isTrigger.value && props.hasValue === false && !!props.placeholder);
|
|
@@ -283,8 +292,9 @@ const Textarea = /* @__PURE__ */ defineComponent({
|
|
|
283
292
|
type: String,
|
|
284
293
|
default: void 0
|
|
285
294
|
},
|
|
295
|
+
/** 是否带边框(三档口径见 `Input` 的同名 prop:`true` 常有框 / `false` 无框 / `'focus'` 聚焦才显框) */
|
|
286
296
|
bordered: {
|
|
287
|
-
type: Boolean,
|
|
297
|
+
type: [Boolean, String],
|
|
288
298
|
default: true
|
|
289
299
|
},
|
|
290
300
|
maxlength: {
|
|
@@ -344,7 +354,7 @@ const Textarea = /* @__PURE__ */ defineComponent({
|
|
|
344
354
|
"class": ["mh-input__wrap", attrs.class].filter(Boolean).join(" "),
|
|
345
355
|
"style": attrs.style
|
|
346
356
|
}, [createVNode("textarea", mergeProps(forwardAttrs.value, {
|
|
347
|
-
"class": ["mh-input", "mh-input--textarea", props.size === "md" ? "" : `mh-input--${props.size}`, props.bordered
|
|
357
|
+
"class": ["mh-input", "mh-input--textarea", props.size === "md" ? "" : `mh-input--${props.size}`, borderedClassOf(props.bordered), visualStatus.value ? `is-${visualStatus.value}` : "", props.disabled ? "is-disabled" : ""].filter(Boolean).join(" "),
|
|
348
358
|
"rows": autoRows.value,
|
|
349
359
|
"value": current.value,
|
|
350
360
|
"placeholder": props.placeholder,
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { type PropType, type SlotsType, type VNodeChild } from 'vue';
|
|
2
|
+
import type { ControlSize } from '../control-size';
|
|
3
|
+
import type { InputStatus } from './index';
|
|
4
|
+
/**
|
|
5
|
+
* 数字输入(**自绘**)。
|
|
6
|
+
*
|
|
7
|
+
* 与 `Input` **同族同面**(同一个表壳 / 内距 / 状态协议,样式归 `styles/components/input.css`),
|
|
8
|
+
* 按 `AGENTS.md` 硬约束 1 的「同族两件可并排平级导出、共用同一目录与同一份面」处置
|
|
9
|
+
* —— 与 `Input` / `Textarea` 的关系同款,故不另开组件目录、不新增面文件。
|
|
10
|
+
*
|
|
11
|
+
* 为什么单列一个件而不是加进 `Input`:`Input` 的 `modelValue` 是 **string**,且已串起
|
|
12
|
+
* 「密码可见切换 / 清除位 / 字数统计 / 触发器形态」一条链;把数值语义(`min` / `max` / `step` /
|
|
13
|
+
* `precision` / 钳制 / 舍入 / 步进按钮)塞进去会污染统一词表(`AGENTS.md` 硬约束 8)。
|
|
14
|
+
* 本件也**不接** `Input` 的 `as="button"` 触发器形态 —— 那是复合件(`Select` 一族)的口子。
|
|
15
|
+
*
|
|
16
|
+
* 统一词表(与 `Checkbox` / `Switch` / `Input` 同款):`modelValue` / `onChange` / `disabled` / `size`;
|
|
17
|
+
* 值变更时 `emit('update:modelValue')` 与 `onChange` **双走**。
|
|
18
|
+
*
|
|
19
|
+
* ## 值域口径(三条,都是「原生数字框最被讨厌的点」的反面)
|
|
20
|
+
*
|
|
21
|
+
* 1. **空值是 `null`,不是 `0`**:留空与「填了 0」是两件事,前者不提交、后者要提交。
|
|
22
|
+
* 2. **输入中途不钳制**:`-` / `1.` / 空串这些中间态一律原样留着(打一半就被改掉会打断输入);
|
|
23
|
+
* 钳制与舍入发生在**归一时刻** —— `blur` / `Enter` / 步进按钮 / `min`·`max`·`precision` 变化。
|
|
24
|
+
* 3. **非法输入回滚**:解析不出来(如 `1a`)就退回上一个合法值,**不静默变 0**。
|
|
25
|
+
*
|
|
26
|
+
* 属性落点与 `Input` 完全同款:`class` / `style` → 表壳 `.mh-input__wrap`;其余 attrs 一律透传到
|
|
27
|
+
* 控件(`id` / `name` / `aria-*` / `data-*` / 原生事件),见 `forwardAttrs`。
|
|
28
|
+
*
|
|
29
|
+
* @example 受控 + 区间
|
|
30
|
+
* <NumberInput modelValue={timeout} min={0} max={43200} onChange={setTimeout} />
|
|
31
|
+
*
|
|
32
|
+
* @example 表格内 / 行内编辑档(无框)
|
|
33
|
+
* <NumberInput modelValue={row.value} bordered={false} precision={0} onChange={set} />
|
|
34
|
+
*
|
|
35
|
+
* @example 带单位后缀
|
|
36
|
+
* <NumberInput modelValue={size} min={1}>
|
|
37
|
+
* {{ suffix: () => 'MB' }}
|
|
38
|
+
* </NumberInput>
|
|
39
|
+
*/
|
|
40
|
+
export interface NumberInputProps {
|
|
41
|
+
/** 受控值(空值为 `null`,不是 `0`) */
|
|
42
|
+
modelValue?: number | null;
|
|
43
|
+
/** 非受控初值(缺省 `null`) */
|
|
44
|
+
defaultValue?: number | null;
|
|
45
|
+
/** 下界(含):归一时刻钳住 */
|
|
46
|
+
min?: number;
|
|
47
|
+
/** 上界(含):归一时刻钳住 */
|
|
48
|
+
max?: number;
|
|
49
|
+
/** 步进量(缺省 1);同时决定 `precision` 的缺省推断(整数步长 → 0 位小数) */
|
|
50
|
+
step?: number;
|
|
51
|
+
/** 小数位;显式给出时优先于按 `step` 推断 */
|
|
52
|
+
precision?: number;
|
|
53
|
+
placeholder?: string;
|
|
54
|
+
/** 尺寸档(与全库 `ControlSize` 同表:24 / 28 / 32) */
|
|
55
|
+
size?: ControlSize;
|
|
56
|
+
disabled?: boolean;
|
|
57
|
+
/** 只读(口径同 `Input`:值可选中复制,但不能改;步进按钮一并收掉) */
|
|
58
|
+
readonly?: boolean;
|
|
59
|
+
/** 校验态(下发 `aria-invalid`,样式走协议不看 data-*);等价于 `status="error"` */
|
|
60
|
+
invalid?: boolean;
|
|
61
|
+
/** 校验状态(`invalid` 的显式写法;两者同时给以 `status` 为准) */
|
|
62
|
+
status?: InputStatus;
|
|
63
|
+
/** 是否带边框(三档口径见 `Input` 的同名 prop:`true` / `false` / `'focus'`) */
|
|
64
|
+
bordered?: boolean | 'focus';
|
|
65
|
+
/** 是否渲染右端步进按钮(缺省 true;`readonly` / `disabled` 时自动不渲染) */
|
|
66
|
+
controls?: boolean;
|
|
67
|
+
/** 失焦时钳到 `[min, max]` 并按 `precision` 舍入(缺省 true) */
|
|
68
|
+
clampOnBlur?: boolean;
|
|
69
|
+
/** 值变更回调(模型与 `emit` 双走) */
|
|
70
|
+
onChange?: (v: number | null) => void;
|
|
71
|
+
/** 回车回调(回车会先做一次归一) */
|
|
72
|
+
onEnter?: (v: number | null) => void;
|
|
73
|
+
}
|
|
74
|
+
export declare const NumberInput: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
75
|
+
modelValue: {
|
|
76
|
+
type: PropType<number | null>;
|
|
77
|
+
default: undefined;
|
|
78
|
+
};
|
|
79
|
+
defaultValue: {
|
|
80
|
+
type: PropType<number | null>;
|
|
81
|
+
default: null;
|
|
82
|
+
};
|
|
83
|
+
min: {
|
|
84
|
+
type: NumberConstructor;
|
|
85
|
+
default: undefined;
|
|
86
|
+
};
|
|
87
|
+
max: {
|
|
88
|
+
type: NumberConstructor;
|
|
89
|
+
default: undefined;
|
|
90
|
+
};
|
|
91
|
+
step: {
|
|
92
|
+
type: NumberConstructor;
|
|
93
|
+
default: undefined;
|
|
94
|
+
};
|
|
95
|
+
precision: {
|
|
96
|
+
type: NumberConstructor;
|
|
97
|
+
default: undefined;
|
|
98
|
+
};
|
|
99
|
+
placeholder: {
|
|
100
|
+
type: StringConstructor;
|
|
101
|
+
default: undefined;
|
|
102
|
+
};
|
|
103
|
+
size: {
|
|
104
|
+
type: PropType<ControlSize>;
|
|
105
|
+
default: string;
|
|
106
|
+
};
|
|
107
|
+
disabled: {
|
|
108
|
+
type: BooleanConstructor;
|
|
109
|
+
default: boolean;
|
|
110
|
+
};
|
|
111
|
+
readonly: {
|
|
112
|
+
type: BooleanConstructor;
|
|
113
|
+
default: boolean;
|
|
114
|
+
};
|
|
115
|
+
invalid: {
|
|
116
|
+
type: BooleanConstructor;
|
|
117
|
+
default: boolean;
|
|
118
|
+
};
|
|
119
|
+
status: {
|
|
120
|
+
type: PropType<InputStatus>;
|
|
121
|
+
default: undefined;
|
|
122
|
+
};
|
|
123
|
+
/** 是否带边框(三档口径见 `Input` 的同名 prop:`true` 常有框 / `false` 无框 / `'focus'` 聚焦才显框) */
|
|
124
|
+
bordered: {
|
|
125
|
+
type: PropType<boolean | "focus">;
|
|
126
|
+
default: boolean;
|
|
127
|
+
};
|
|
128
|
+
controls: {
|
|
129
|
+
type: BooleanConstructor;
|
|
130
|
+
default: boolean;
|
|
131
|
+
};
|
|
132
|
+
clampOnBlur: {
|
|
133
|
+
type: BooleanConstructor;
|
|
134
|
+
default: boolean;
|
|
135
|
+
};
|
|
136
|
+
onChange: {
|
|
137
|
+
type: PropType<(v: number | null) => void>;
|
|
138
|
+
default: undefined;
|
|
139
|
+
};
|
|
140
|
+
onEnter: {
|
|
141
|
+
type: PropType<(v: number | null) => void>;
|
|
142
|
+
default: undefined;
|
|
143
|
+
};
|
|
144
|
+
}>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
145
|
+
'update:modelValue': (v: number | null) => true;
|
|
146
|
+
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
147
|
+
modelValue: {
|
|
148
|
+
type: PropType<number | null>;
|
|
149
|
+
default: undefined;
|
|
150
|
+
};
|
|
151
|
+
defaultValue: {
|
|
152
|
+
type: PropType<number | null>;
|
|
153
|
+
default: null;
|
|
154
|
+
};
|
|
155
|
+
min: {
|
|
156
|
+
type: NumberConstructor;
|
|
157
|
+
default: undefined;
|
|
158
|
+
};
|
|
159
|
+
max: {
|
|
160
|
+
type: NumberConstructor;
|
|
161
|
+
default: undefined;
|
|
162
|
+
};
|
|
163
|
+
step: {
|
|
164
|
+
type: NumberConstructor;
|
|
165
|
+
default: undefined;
|
|
166
|
+
};
|
|
167
|
+
precision: {
|
|
168
|
+
type: NumberConstructor;
|
|
169
|
+
default: undefined;
|
|
170
|
+
};
|
|
171
|
+
placeholder: {
|
|
172
|
+
type: StringConstructor;
|
|
173
|
+
default: undefined;
|
|
174
|
+
};
|
|
175
|
+
size: {
|
|
176
|
+
type: PropType<ControlSize>;
|
|
177
|
+
default: string;
|
|
178
|
+
};
|
|
179
|
+
disabled: {
|
|
180
|
+
type: BooleanConstructor;
|
|
181
|
+
default: boolean;
|
|
182
|
+
};
|
|
183
|
+
readonly: {
|
|
184
|
+
type: BooleanConstructor;
|
|
185
|
+
default: boolean;
|
|
186
|
+
};
|
|
187
|
+
invalid: {
|
|
188
|
+
type: BooleanConstructor;
|
|
189
|
+
default: boolean;
|
|
190
|
+
};
|
|
191
|
+
status: {
|
|
192
|
+
type: PropType<InputStatus>;
|
|
193
|
+
default: undefined;
|
|
194
|
+
};
|
|
195
|
+
/** 是否带边框(三档口径见 `Input` 的同名 prop:`true` 常有框 / `false` 无框 / `'focus'` 聚焦才显框) */
|
|
196
|
+
bordered: {
|
|
197
|
+
type: PropType<boolean | "focus">;
|
|
198
|
+
default: boolean;
|
|
199
|
+
};
|
|
200
|
+
controls: {
|
|
201
|
+
type: BooleanConstructor;
|
|
202
|
+
default: boolean;
|
|
203
|
+
};
|
|
204
|
+
clampOnBlur: {
|
|
205
|
+
type: BooleanConstructor;
|
|
206
|
+
default: boolean;
|
|
207
|
+
};
|
|
208
|
+
onChange: {
|
|
209
|
+
type: PropType<(v: number | null) => void>;
|
|
210
|
+
default: undefined;
|
|
211
|
+
};
|
|
212
|
+
onEnter: {
|
|
213
|
+
type: PropType<(v: number | null) => void>;
|
|
214
|
+
default: undefined;
|
|
215
|
+
};
|
|
216
|
+
}>> & Readonly<{
|
|
217
|
+
"onUpdate:modelValue"?: ((v: number | null) => any) | undefined;
|
|
218
|
+
}>, {
|
|
219
|
+
size: ControlSize;
|
|
220
|
+
disabled: boolean;
|
|
221
|
+
min: number;
|
|
222
|
+
max: number;
|
|
223
|
+
onChange: (v: number | null) => void;
|
|
224
|
+
invalid: boolean;
|
|
225
|
+
bordered: boolean | "focus";
|
|
226
|
+
defaultValue: number | null;
|
|
227
|
+
placeholder: string;
|
|
228
|
+
modelValue: number | null;
|
|
229
|
+
status: InputStatus;
|
|
230
|
+
step: number;
|
|
231
|
+
precision: number;
|
|
232
|
+
readonly: boolean;
|
|
233
|
+
controls: boolean;
|
|
234
|
+
clampOnBlur: boolean;
|
|
235
|
+
onEnter: (v: number | null) => void;
|
|
236
|
+
}, SlotsType<{
|
|
237
|
+
prefix?: () => VNodeChild;
|
|
238
|
+
suffix?: () => VNodeChild;
|
|
239
|
+
}>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|