@manohub/ui 0.8.2 → 0.10.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.
- package/README.md +14 -8
- package/dist/components/button/index.d.ts +8 -8
- package/dist/components/checkbox/index.js +5 -1
- package/dist/components/code-block/index.d.ts +776 -0
- package/dist/components/code-block/index.js +335 -0
- package/dist/components/dialog/index.d.ts +3 -3
- package/dist/components/dialog/index.js +5 -5
- package/dist/components/filter/index.d.ts +8 -2
- package/dist/components/filter/index.js +11 -20
- package/dist/components/form/index.d.ts +39 -0
- package/dist/components/form/index.js +6 -0
- package/dist/components/input/index.d.ts +48 -7
- package/dist/components/input/index.js +23 -3
- package/dist/components/notice/index.d.ts +1 -1
- package/dist/components/notice/index.js +4 -4
- package/dist/components/notification/index.d.ts +1 -1
- package/dist/components/notification/index.js +5 -5
- package/dist/components/radio/index.js +29 -3
- package/dist/components/search/index.js +37 -35
- package/dist/components/select/index.js +1 -3
- package/dist/components/select/select-trigger.d.ts +4 -2
- package/dist/components/select/select-trigger.js +9 -4
- package/dist/components/table/index.d.ts +19 -8
- package/dist/components/table/index.js +3 -3
- package/dist/components/tag/index.d.ts +1 -1
- package/dist/components/text/index.d.ts +4 -3
- package/dist/components/toast/index.d.ts +4 -4
- package/dist/components/toast/index.js +16 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +2 -4
- package/dist/services/dialog.d.ts +1 -1
- package/dist/styles/components/avatar.css +4 -1
- package/dist/styles/components/button.css +2 -0
- package/dist/styles/components/code-block.css +216 -0
- package/dist/styles/components/code-block.tokens.css +40 -0
- package/dist/styles/components/dialog.css +3 -3
- package/dist/styles/components/filter.css +22 -34
- package/dist/styles/components/input.css +24 -0
- package/dist/styles/components/select.css +3 -4
- package/dist/styles/components/table.css +33 -22
- package/dist/styles/components/table.tokens.css +6 -6
- package/dist/styles/components/text.css +10 -0
- package/dist/styles/components/toast.css +35 -6
- package/dist/styles/components/upload.css +1 -0
- package/dist/styles/index.css +7 -8
- package/dist/styles/reset.css +52 -167
- package/package.json +2 -2
- package/dist/components/code/index.d.ts +0 -134
- package/dist/components/code/index.js +0 -117
- package/dist/components/code-editor/index.d.ts +0 -163
- package/dist/components/code-editor/index.js +0 -98
- package/dist/styles/components/code-editor.css +0 -91
- package/dist/styles/components/code-editor.tokens.css +0 -24
- package/dist/styles/components/code.css +0 -153
- package/dist/styles/components/code.tokens.css +0 -29
- package/dist/styles/components/filter.tokens.css +0 -14
|
@@ -35,8 +35,9 @@ export interface TextareaAutoSize {
|
|
|
35
35
|
* <Textarea modelValue={note} autoSize={{ minRows: 2, maxRows: 6 }} maxlength={500} showCount onChange={setNote} />
|
|
36
36
|
*
|
|
37
37
|
* @example 触发器形态(复合件用:控件换成 `<button>`,表壳 / 清除位 / 右侧图标位全部复用)
|
|
38
|
-
* <Input as="button" clearable hasValue={!!value} controlClass="my-picker"
|
|
39
|
-
* {{
|
|
38
|
+
* <Input as="button" clearable hasValue={!!value} placeholder="请选择" controlClass="my-picker"
|
|
39
|
+
* controlAttrs={{ popovertarget: id }}>
|
|
40
|
+
* {{ default: () => value, suffix: () => <Icon name="chevron-down" /> }}
|
|
40
41
|
* </Input>
|
|
41
42
|
*/
|
|
42
43
|
export declare const Input: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
@@ -50,6 +51,13 @@ export declare const Input: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
50
51
|
type: StringConstructor;
|
|
51
52
|
default: string;
|
|
52
53
|
};
|
|
54
|
+
/**
|
|
55
|
+
* 占位文案。两种形态都消费它:
|
|
56
|
+
* - 缺省(`as="input"`)走原生 `::placeholder` 伪元素;
|
|
57
|
+
* - 触发器形态(`as="button"`)**没有 `::placeholder` 可用**,改由一个 span 承载
|
|
58
|
+
* (`.mh-input__placeholder`)—— 当且仅当 `hasValue === false` 且本 prop 有值时渲染它,
|
|
59
|
+
* 并**取代** `default` 插槽(见上面触发器一节)。没传 `hasValue` 的调用方行为不变。
|
|
60
|
+
*/
|
|
53
61
|
placeholder: {
|
|
54
62
|
type: StringConstructor;
|
|
55
63
|
default: undefined;
|
|
@@ -142,7 +150,8 @@ export declare const Input: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
142
150
|
type: PropType<Record<string, unknown>>;
|
|
143
151
|
default: undefined;
|
|
144
152
|
};
|
|
145
|
-
/**
|
|
153
|
+
/** 显式覆盖清除位显隐;不给时仍按「有内容」判定(多选类复合件没有单值可判)。
|
|
154
|
+
* 同时是触发器形态「显示值还是显示占位」的判据(仅当它为 `false` 且传了 `placeholder` 时接管) */
|
|
146
155
|
hasValue: {
|
|
147
156
|
type: BooleanConstructor;
|
|
148
157
|
default: undefined;
|
|
@@ -160,6 +169,13 @@ export declare const Input: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
160
169
|
type: StringConstructor;
|
|
161
170
|
default: string;
|
|
162
171
|
};
|
|
172
|
+
/**
|
|
173
|
+
* 占位文案。两种形态都消费它:
|
|
174
|
+
* - 缺省(`as="input"`)走原生 `::placeholder` 伪元素;
|
|
175
|
+
* - 触发器形态(`as="button"`)**没有 `::placeholder` 可用**,改由一个 span 承载
|
|
176
|
+
* (`.mh-input__placeholder`)—— 当且仅当 `hasValue === false` 且本 prop 有值时渲染它,
|
|
177
|
+
* 并**取代** `default` 插槽(见上面触发器一节)。没传 `hasValue` 的调用方行为不变。
|
|
178
|
+
*/
|
|
163
179
|
placeholder: {
|
|
164
180
|
type: StringConstructor;
|
|
165
181
|
default: undefined;
|
|
@@ -252,7 +268,8 @@ export declare const Input: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
252
268
|
type: PropType<Record<string, unknown>>;
|
|
253
269
|
default: undefined;
|
|
254
270
|
};
|
|
255
|
-
/**
|
|
271
|
+
/** 显式覆盖清除位显隐;不给时仍按「有内容」判定(多选类复合件没有单值可判)。
|
|
272
|
+
* 同时是触发器形态「显示值还是显示占位」的判据(仅当它为 `false` 且传了 `placeholder` 时接管) */
|
|
256
273
|
hasValue: {
|
|
257
274
|
type: BooleanConstructor;
|
|
258
275
|
default: undefined;
|
|
@@ -478,6 +495,13 @@ export declare const InputCompound: {
|
|
|
478
495
|
type: StringConstructor;
|
|
479
496
|
default: string;
|
|
480
497
|
};
|
|
498
|
+
/**
|
|
499
|
+
* 占位文案。两种形态都消费它:
|
|
500
|
+
* - 缺省(`as="input"`)走原生 `::placeholder` 伪元素;
|
|
501
|
+
* - 触发器形态(`as="button"`)**没有 `::placeholder` 可用**,改由一个 span 承载
|
|
502
|
+
* (`.mh-input__placeholder`)—— 当且仅当 `hasValue === false` 且本 prop 有值时渲染它,
|
|
503
|
+
* 并**取代** `default` 插槽(见上面触发器一节)。没传 `hasValue` 的调用方行为不变。
|
|
504
|
+
*/
|
|
481
505
|
placeholder: {
|
|
482
506
|
type: StringConstructor;
|
|
483
507
|
default: undefined;
|
|
@@ -570,7 +594,8 @@ export declare const InputCompound: {
|
|
|
570
594
|
type: PropType<Record<string, unknown>>;
|
|
571
595
|
default: undefined;
|
|
572
596
|
};
|
|
573
|
-
/**
|
|
597
|
+
/** 显式覆盖清除位显隐;不给时仍按「有内容」判定(多选类复合件没有单值可判)。
|
|
598
|
+
* 同时是触发器形态「显示值还是显示占位」的判据(仅当它为 `false` 且传了 `placeholder` 时接管) */
|
|
574
599
|
hasValue: {
|
|
575
600
|
type: BooleanConstructor;
|
|
576
601
|
default: undefined;
|
|
@@ -622,6 +647,13 @@ export declare const InputCompound: {
|
|
|
622
647
|
type: StringConstructor;
|
|
623
648
|
default: string;
|
|
624
649
|
};
|
|
650
|
+
/**
|
|
651
|
+
* 占位文案。两种形态都消费它:
|
|
652
|
+
* - 缺省(`as="input"`)走原生 `::placeholder` 伪元素;
|
|
653
|
+
* - 触发器形态(`as="button"`)**没有 `::placeholder` 可用**,改由一个 span 承载
|
|
654
|
+
* (`.mh-input__placeholder`)—— 当且仅当 `hasValue === false` 且本 prop 有值时渲染它,
|
|
655
|
+
* 并**取代** `default` 插槽(见上面触发器一节)。没传 `hasValue` 的调用方行为不变。
|
|
656
|
+
*/
|
|
625
657
|
placeholder: {
|
|
626
658
|
type: StringConstructor;
|
|
627
659
|
default: undefined;
|
|
@@ -714,7 +746,8 @@ export declare const InputCompound: {
|
|
|
714
746
|
type: PropType<Record<string, unknown>>;
|
|
715
747
|
default: undefined;
|
|
716
748
|
};
|
|
717
|
-
/**
|
|
749
|
+
/** 显式覆盖清除位显隐;不给时仍按「有内容」判定(多选类复合件没有单值可判)。
|
|
750
|
+
* 同时是触发器形态「显示值还是显示占位」的判据(仅当它为 `false` 且传了 `placeholder` 时接管) */
|
|
718
751
|
hasValue: {
|
|
719
752
|
type: BooleanConstructor;
|
|
720
753
|
default: undefined;
|
|
@@ -757,6 +790,13 @@ export declare const InputCompound: {
|
|
|
757
790
|
type: StringConstructor;
|
|
758
791
|
default: string;
|
|
759
792
|
};
|
|
793
|
+
/**
|
|
794
|
+
* 占位文案。两种形态都消费它:
|
|
795
|
+
* - 缺省(`as="input"`)走原生 `::placeholder` 伪元素;
|
|
796
|
+
* - 触发器形态(`as="button"`)**没有 `::placeholder` 可用**,改由一个 span 承载
|
|
797
|
+
* (`.mh-input__placeholder`)—— 当且仅当 `hasValue === false` 且本 prop 有值时渲染它,
|
|
798
|
+
* 并**取代** `default` 插槽(见上面触发器一节)。没传 `hasValue` 的调用方行为不变。
|
|
799
|
+
*/
|
|
760
800
|
placeholder: {
|
|
761
801
|
type: StringConstructor;
|
|
762
802
|
default: undefined;
|
|
@@ -849,7 +889,8 @@ export declare const InputCompound: {
|
|
|
849
889
|
type: PropType<Record<string, unknown>>;
|
|
850
890
|
default: undefined;
|
|
851
891
|
};
|
|
852
|
-
/**
|
|
892
|
+
/** 显式覆盖清除位显隐;不给时仍按「有内容」判定(多选类复合件没有单值可判)。
|
|
893
|
+
* 同时是触发器形态「显示值还是显示占位」的判据(仅当它为 `false` 且传了 `placeholder` 时接管) */
|
|
853
894
|
hasValue: {
|
|
854
895
|
type: BooleanConstructor;
|
|
855
896
|
default: undefined;
|
|
@@ -14,6 +14,13 @@ const Input = /* @__PURE__ */ defineComponent({
|
|
|
14
14
|
type: String,
|
|
15
15
|
default: ""
|
|
16
16
|
},
|
|
17
|
+
/**
|
|
18
|
+
* 占位文案。两种形态都消费它:
|
|
19
|
+
* - 缺省(`as="input"`)走原生 `::placeholder` 伪元素;
|
|
20
|
+
* - 触发器形态(`as="button"`)**没有 `::placeholder` 可用**,改由一个 span 承载
|
|
21
|
+
* (`.mh-input__placeholder`)—— 当且仅当 `hasValue === false` 且本 prop 有值时渲染它,
|
|
22
|
+
* 并**取代** `default` 插槽(见上面触发器一节)。没传 `hasValue` 的调用方行为不变。
|
|
23
|
+
*/
|
|
17
24
|
placeholder: {
|
|
18
25
|
type: String,
|
|
19
26
|
default: void 0
|
|
@@ -95,7 +102,13 @@ const Input = /* @__PURE__ */ defineComponent({
|
|
|
95
102
|
* 整件的**表壳、附加位与状态规则一并复用**,只把「控件元素」从 `<input>` 换成 `<button>`:
|
|
96
103
|
* 于是 `Select` 这类件能拿到输入框的框与内距、内建清除位、右侧图标位与三态反馈,同时保留
|
|
97
104
|
* 原生 `<button>` 才有的语义(如 `popovertarget` 触发 popover —— 该属性只认 button)。
|
|
98
|
-
* 缺省 `as="input"` 的渲染路径除本组 prop 外零变化。
|
|
105
|
+
* 缺省 `as="input"` 的渲染路径除本组 prop 外零变化。
|
|
106
|
+
*
|
|
107
|
+
* **无值时的占位**:`<button>` 没有 `::placeholder` 伪元素可用,故 `placeholder` 在这个形态下
|
|
108
|
+
* 由本件渲染成一个 span(`.mh-input__placeholder`,色档与原生占位一致);判据是
|
|
109
|
+
* `hasValue === false && placeholder` **同时**成立 —— 两者缺一即沿用消费方给的 `default` 插槽。
|
|
110
|
+
* 这样「有值渲染值、无值渲染占位」这件例行事的文案与切换都由输入面统一,复合件不必各画一遍
|
|
111
|
+
* (`Select` 早期为自己的值区单画过一份,见 `select-trigger.tsx`)。 */
|
|
99
112
|
/** 控件元素形态:`input` 文本输入(缺省)/ `button` 触发器 */
|
|
100
113
|
as: {
|
|
101
114
|
type: String,
|
|
@@ -111,7 +124,8 @@ const Input = /* @__PURE__ */ defineComponent({
|
|
|
111
124
|
type: Object,
|
|
112
125
|
default: void 0
|
|
113
126
|
},
|
|
114
|
-
/**
|
|
127
|
+
/** 显式覆盖清除位显隐;不给时仍按「有内容」判定(多选类复合件没有单值可判)。
|
|
128
|
+
* 同时是触发器形态「显示值还是显示占位」的判据(仅当它为 `false` 且传了 `placeholder` 时接管) */
|
|
115
129
|
hasValue: {
|
|
116
130
|
type: Boolean,
|
|
117
131
|
default: void 0
|
|
@@ -149,6 +163,7 @@ const Input = /* @__PURE__ */ defineComponent({
|
|
|
149
163
|
const isTrigger = computed(() => props.as === "button");
|
|
150
164
|
const controlClasses = computed(() => ["mh-input", isTrigger.value ? "mh-input--trigger" : "", props.size === "md" ? "" : `mh-input--${props.size}`, props.bordered ? "" : "mh-input--borderless", visualStatus.value ? `is-${visualStatus.value}` : "", props.disabled ? "is-disabled" : "", props.controlClass].filter(Boolean).join(" "));
|
|
151
165
|
const showClear = computed(() => props.clearable && (props.hasValue ?? !!current.value));
|
|
166
|
+
const showPlaceholder = computed(() => isTrigger.value && props.hasValue === false && !!props.placeholder);
|
|
152
167
|
return () => createVNode("div", {
|
|
153
168
|
"class": ["mh-input__wrap", attrs.class].filter(Boolean).join(" "),
|
|
154
169
|
"style": attrs.style
|
|
@@ -164,7 +179,12 @@ const Input = /* @__PURE__ */ defineComponent({
|
|
|
164
179
|
"class": controlClasses.value,
|
|
165
180
|
"disabled": props.disabled,
|
|
166
181
|
"aria-invalid": isInvalid.value ? "true" : void 0
|
|
167
|
-
}), [
|
|
182
|
+
}), [showPlaceholder.value ? (
|
|
183
|
+
/* 触发器没有 `::placeholder`,占位文案由本件渲染(色见 `.mh-input__placeholder`) */
|
|
184
|
+
createVNode("span", {
|
|
185
|
+
"class": "mh-input__placeholder"
|
|
186
|
+
}, [props.placeholder])
|
|
187
|
+
) : slots.default ? slots.default() : null])
|
|
168
188
|
) : createVNode("input", {
|
|
169
189
|
"class": controlClasses.value,
|
|
170
190
|
"type": inputType.value,
|
|
@@ -136,7 +136,7 @@ export declare const Notice: import("vue").DefineComponent<import("vue").Extract
|
|
|
136
136
|
default: undefined;
|
|
137
137
|
};
|
|
138
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";
|
|
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" | "info-circle" | "check-circle" | "alert-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "ai" | "shield-check" | "shield-alert" | "history";
|
|
140
140
|
onClose: () => void;
|
|
141
141
|
message: string;
|
|
142
142
|
closable: boolean;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { defineComponent, createVNode, Fragment, createTextVNode } from "vue";
|
|
2
2
|
import { Icon } from "@manohub/icon";
|
|
3
3
|
const TONE_ICON = {
|
|
4
|
-
info: "info",
|
|
5
|
-
success: "check",
|
|
6
|
-
warning: "alert",
|
|
7
|
-
error: "close"
|
|
4
|
+
info: "info-circle",
|
|
5
|
+
success: "check-circle",
|
|
6
|
+
warning: "alert-circle",
|
|
7
|
+
error: "close-circle"
|
|
8
8
|
};
|
|
9
9
|
const Notice = /* @__PURE__ */ defineComponent({
|
|
10
10
|
name: "Notice",
|
|
@@ -102,7 +102,7 @@ export declare const Notification: import("vue").DefineComponent<import("vue").E
|
|
|
102
102
|
default: undefined;
|
|
103
103
|
};
|
|
104
104
|
}>> & Readonly<{}>, {
|
|
105
|
-
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";
|
|
105
|
+
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" | "info-circle" | "check-circle" | "alert-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "ai" | "shield-check" | "shield-alert" | "history";
|
|
106
106
|
title: string;
|
|
107
107
|
onClose: () => void;
|
|
108
108
|
closable: boolean;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { defineComponent, onMounted, onBeforeUnmount, createVNode } from "vue";
|
|
2
2
|
import { Icon } from "@manohub/icon";
|
|
3
3
|
const TONE_ICON = {
|
|
4
|
-
info: "info",
|
|
5
|
-
success: "check",
|
|
6
|
-
warning: "alert",
|
|
7
|
-
error: "close",
|
|
8
|
-
submit: "check"
|
|
4
|
+
info: "info-circle",
|
|
5
|
+
success: "check-circle",
|
|
6
|
+
warning: "alert-circle",
|
|
7
|
+
error: "close-circle",
|
|
8
|
+
submit: "check-circle"
|
|
9
9
|
};
|
|
10
10
|
const Notification = /* @__PURE__ */ defineComponent({
|
|
11
11
|
name: "Notification",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineComponent, createVNode, ref, computed } from "vue";
|
|
1
|
+
import { defineComponent, createVNode, ref, nextTick, computed } from "vue";
|
|
2
2
|
const Radio = /* @__PURE__ */ defineComponent({
|
|
3
3
|
name: "Radio",
|
|
4
4
|
inheritAttrs: false,
|
|
@@ -136,7 +136,17 @@ const RadioGroup = /* @__PURE__ */ defineComponent({
|
|
|
136
136
|
props.onChange?.(value);
|
|
137
137
|
}
|
|
138
138
|
);
|
|
139
|
+
const rootRef = ref(null);
|
|
140
|
+
const syncNative = () => {
|
|
141
|
+
const root = rootRef.value;
|
|
142
|
+
if (!root) return;
|
|
143
|
+
root.querySelectorAll(".mh-radio__input").forEach((el) => {
|
|
144
|
+
const want = String(current.value) === el.value;
|
|
145
|
+
if (el.checked !== want) el.checked = want;
|
|
146
|
+
});
|
|
147
|
+
};
|
|
139
148
|
return () => createVNode("div", {
|
|
149
|
+
"ref": rootRef,
|
|
140
150
|
"class": ["mh-radio-group", props.vertical ? "mh-radio-group--vertical" : void 0, attrs.class].filter(Boolean).join(" "),
|
|
141
151
|
"style": attrs.style
|
|
142
152
|
}, [slots.default ? slots.default({
|
|
@@ -150,7 +160,10 @@ const RadioGroup = /* @__PURE__ */ defineComponent({
|
|
|
150
160
|
"checked": option.value === current.value,
|
|
151
161
|
"disabled": props.disabled || option.disabled,
|
|
152
162
|
"size": props.size,
|
|
153
|
-
"onChange":
|
|
163
|
+
"onChange": (value) => {
|
|
164
|
+
select(value);
|
|
165
|
+
void nextTick(syncNative);
|
|
166
|
+
}
|
|
154
167
|
}, null))]);
|
|
155
168
|
}
|
|
156
169
|
});
|
|
@@ -206,7 +219,17 @@ const RadioCard = /* @__PURE__ */ defineComponent({
|
|
|
206
219
|
props.onChange?.(value);
|
|
207
220
|
}
|
|
208
221
|
);
|
|
222
|
+
const rootRef = ref(null);
|
|
223
|
+
const syncNative = () => {
|
|
224
|
+
const root = rootRef.value;
|
|
225
|
+
if (!root) return;
|
|
226
|
+
root.querySelectorAll(".mh-radio-card__input").forEach((el) => {
|
|
227
|
+
const want = current.value === el.value;
|
|
228
|
+
if (el.checked !== want) el.checked = want;
|
|
229
|
+
});
|
|
230
|
+
};
|
|
209
231
|
return () => createVNode("div", {
|
|
232
|
+
"ref": rootRef,
|
|
210
233
|
"class": ["mh-radio-card", props.columns > 1 ? "mh-radio-card--grid" : "", attrs.class].filter(Boolean).join(" "),
|
|
211
234
|
"style": props.columns > 1 ? {
|
|
212
235
|
...attrs.style,
|
|
@@ -228,7 +251,10 @@ const RadioCard = /* @__PURE__ */ defineComponent({
|
|
|
228
251
|
"value": String(item.value),
|
|
229
252
|
"checked": isChecked,
|
|
230
253
|
"disabled": isDisabled,
|
|
231
|
-
"onChange": () =>
|
|
254
|
+
"onChange": () => {
|
|
255
|
+
select(item.value);
|
|
256
|
+
void nextTick(syncNative);
|
|
257
|
+
}
|
|
232
258
|
}, null), createVNode("span", {
|
|
233
259
|
"class": "mh-radio-card__radio",
|
|
234
260
|
"aria-hidden": "true"
|
|
@@ -76,44 +76,46 @@ const Search = /* @__PURE__ */ defineComponent({
|
|
|
76
76
|
const iconAction = computed(() => props.action === "icon");
|
|
77
77
|
const showAction = computed(() => iconAction.value || props.searchText !== void 0);
|
|
78
78
|
const actionLabel = computed(() => props.searchText ?? "搜索");
|
|
79
|
-
return () =>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}, {
|
|
92
|
-
default: () => [iconAction.value ? {} : {
|
|
79
|
+
return () => {
|
|
80
|
+
const field = {
|
|
81
|
+
class: "mh-search__input",
|
|
82
|
+
modelValue: current.value,
|
|
83
|
+
size: props.size,
|
|
84
|
+
disabled: props.disabled,
|
|
85
|
+
placeholder: props.placeholder,
|
|
86
|
+
clearable: props.clearable,
|
|
87
|
+
onChange: commit,
|
|
88
|
+
onEnter: search
|
|
89
|
+
};
|
|
90
|
+
const fieldNode = iconAction.value ? createVNode(Input, field, null) : createVNode(Input, field, {
|
|
93
91
|
prefix: () => createVNode(Icon, {
|
|
94
92
|
"name": "search"
|
|
95
93
|
}, null)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
94
|
+
});
|
|
95
|
+
return createVNode("div", {
|
|
96
|
+
"class": ["mh-search", attrs.class].filter(Boolean).join(" "),
|
|
97
|
+
"style": attrs.style
|
|
98
|
+
}, [fieldNode, showAction.value ? iconAction.value ? createVNode(Button, {
|
|
99
|
+
"class": "mh-search__btn",
|
|
100
|
+
"variant": "primary",
|
|
101
|
+
"size": props.size,
|
|
102
|
+
"icon": "search",
|
|
103
|
+
"title": actionLabel.value,
|
|
104
|
+
"disabled": props.disabled,
|
|
105
|
+
"loading": props.loading,
|
|
106
|
+
"onClick": search
|
|
107
|
+
}, null) : createVNode(Button, {
|
|
108
|
+
"class": "mh-search__btn",
|
|
109
|
+
"variant": "primary",
|
|
110
|
+
"size": props.size,
|
|
111
|
+
"icon": "search",
|
|
112
|
+
"disabled": props.disabled,
|
|
113
|
+
"loading": props.loading,
|
|
114
|
+
"onClick": search
|
|
115
|
+
}, {
|
|
116
|
+
default: () => props.searchText
|
|
117
|
+
}) : null]);
|
|
118
|
+
};
|
|
117
119
|
}
|
|
118
120
|
});
|
|
119
121
|
export {
|
|
@@ -211,9 +211,7 @@ const Select = /* @__PURE__ */ defineComponent({
|
|
|
211
211
|
"class": "mh-select__chip"
|
|
212
212
|
}, [option.label])), foldedCount.value > 0 ? createVNode("span", {
|
|
213
213
|
"class": "mh-select__chip mh-select__chip--fold"
|
|
214
|
-
}, [foldText.value]) : null
|
|
215
|
-
"class": "mh-select__value mh-select__value--placeholder"
|
|
216
|
-
}, [props.placeholder]) : null]) : void 0
|
|
214
|
+
}, [foldText.value]) : null]) : void 0
|
|
217
215
|
}, null), createVNode(SelectPanel, {
|
|
218
216
|
"id": panelId,
|
|
219
217
|
"elementRef": panelRef,
|
|
@@ -35,11 +35,12 @@ export declare const SelectTrigger: import("vue").DefineComponent<import("vue").
|
|
|
35
35
|
type: BooleanConstructor;
|
|
36
36
|
default: boolean;
|
|
37
37
|
};
|
|
38
|
+
/** 无值时的占位文案(**透传给输入面**:`hasValue === false` 时由它渲染并取代 `default` 插槽) */
|
|
38
39
|
placeholder: {
|
|
39
40
|
type: StringConstructor;
|
|
40
41
|
default: string;
|
|
41
42
|
};
|
|
42
|
-
/**
|
|
43
|
+
/** 单选显示文本(只在**有值**时渲染;无值态由输入面的占位承担) */
|
|
43
44
|
label: {
|
|
44
45
|
type: StringConstructor;
|
|
45
46
|
default: undefined;
|
|
@@ -93,11 +94,12 @@ export declare const SelectTrigger: import("vue").DefineComponent<import("vue").
|
|
|
93
94
|
type: BooleanConstructor;
|
|
94
95
|
default: boolean;
|
|
95
96
|
};
|
|
97
|
+
/** 无值时的占位文案(**透传给输入面**:`hasValue === false` 时由它渲染并取代 `default` 插槽) */
|
|
96
98
|
placeholder: {
|
|
97
99
|
type: StringConstructor;
|
|
98
100
|
default: string;
|
|
99
101
|
};
|
|
100
|
-
/**
|
|
102
|
+
/** 单选显示文本(只在**有值**时渲染;无值态由输入面的占位承担) */
|
|
101
103
|
label: {
|
|
102
104
|
type: StringConstructor;
|
|
103
105
|
default: undefined;
|
|
@@ -38,11 +38,12 @@ const SelectTrigger = /* @__PURE__ */ defineComponent({
|
|
|
38
38
|
type: Boolean,
|
|
39
39
|
default: false
|
|
40
40
|
},
|
|
41
|
+
/** 无值时的占位文案(**透传给输入面**:`hasValue === false` 时由它渲染并取代 `default` 插槽) */
|
|
41
42
|
placeholder: {
|
|
42
43
|
type: String,
|
|
43
44
|
default: "请选择"
|
|
44
45
|
},
|
|
45
|
-
/**
|
|
46
|
+
/** 单选显示文本(只在**有值**时渲染;无值态由输入面的占位承担) */
|
|
46
47
|
label: {
|
|
47
48
|
type: String,
|
|
48
49
|
default: void 0
|
|
@@ -72,6 +73,7 @@ const SelectTrigger = /* @__PURE__ */ defineComponent({
|
|
|
72
73
|
"disabled": props.disabled,
|
|
73
74
|
"clearable": props.clearable,
|
|
74
75
|
"hasValue": props.hasValue,
|
|
76
|
+
"placeholder": props.placeholder,
|
|
75
77
|
"class": "mh-popup-anchor mh-select-host",
|
|
76
78
|
"controlClass": controlClass(),
|
|
77
79
|
"controlAttrs": {
|
|
@@ -84,9 +86,12 @@ const SelectTrigger = /* @__PURE__ */ defineComponent({
|
|
|
84
86
|
},
|
|
85
87
|
"onChange": () => props.onClear?.()
|
|
86
88
|
}, {
|
|
87
|
-
default: () => props.renderValue ? props.renderValue() :
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
default: () => props.renderValue ? props.renderValue() : (
|
|
90
|
+
/* 只画**有值**时的那一行;无值态在上面被输入面的占位取代(`default` 不会被调用) */
|
|
91
|
+
createVNode("span", {
|
|
92
|
+
"class": "mh-select__value"
|
|
93
|
+
}, [props.label])
|
|
94
|
+
),
|
|
90
95
|
/* 箭头沿用输入框的右侧图标位(槽内尺寸收敛见 `select.css` 的 `.mh-select-host` 一节);
|
|
91
96
|
展开转向由 `popup.css` 的 `.mh-popup-caret` 承担(含触发器进表壳后的兄弟档) */
|
|
92
97
|
suffix: () => createVNode(Icon, {
|
|
@@ -16,8 +16,19 @@ export interface TableColumn {
|
|
|
16
16
|
*/
|
|
17
17
|
width?: string | number;
|
|
18
18
|
align?: 'left' | 'center' | 'right';
|
|
19
|
-
/**
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* 允许该列**换行**(缺省不换行:`nowrap` + 省略号)。
|
|
21
|
+
*
|
|
22
|
+
* <p>缺省不换行是刻意的:换行只会把行高顶高(`td` 的 `height` 只是**下限**),
|
|
23
|
+
* 而且必然伴随从字符间断字(实测序号列窄到装不下两位数时,`10` 被拆成 `1` / `0` 两行、
|
|
24
|
+
* 行高 30 → 49)。真要换行的列(描述 / 备注 / 多行摘要)显式打开它。</p>
|
|
25
|
+
*
|
|
26
|
+
* <p><b>只影响 `layout="fixed"`</b>:`auto` 档列宽由内容计算,表体本来就换行
|
|
27
|
+
* (不换行会让长文本列不再收敛、表格更容易撑破容器),故本档给不给都一样。</p>
|
|
28
|
+
*
|
|
29
|
+
* <p>只作用于表体 `td`;表头始终 `nowrap`(表头字短,换行只会让表头行变高)。</p>
|
|
30
|
+
*/
|
|
31
|
+
wrap?: boolean;
|
|
21
32
|
/**
|
|
22
33
|
* 列下限(px):防止窄容器把该列压没。**给了才下发 `min-width`** ——
|
|
23
34
|
* ⚠️ 它**不是硬下限**:实测(Chrome)`<col>` 上的 `min-width` 会被当成**分配权重**参与按比例
|
|
@@ -72,13 +83,13 @@ export interface TablePagination {
|
|
|
72
83
|
* 组件自己切片会让「服务端分页」与「客户端分页」两套口径藏在同一个 prop 里;
|
|
73
84
|
* - **错误态**:归 `QueryState`(表格只管列数据)。
|
|
74
85
|
*
|
|
75
|
-
* @example 基本列表(表默认满宽;列宽给权重 + `fixed`
|
|
86
|
+
* @example 基本列表(表默认满宽;列宽给权重 + `fixed` 才严格按比例)
|
|
76
87
|
* <Table
|
|
77
88
|
* layout="fixed" striped row-key="id" :data="rows"
|
|
78
89
|
* :columns="[
|
|
79
90
|
* { key: 'name', title: '名称', width: 3 },
|
|
80
91
|
* { key: 'amount', title: '金额', width: 1, align: 'right' },
|
|
81
|
-
* { key: 'description', title: '描述', width: 4,
|
|
92
|
+
* { key: 'description', title: '描述', width: 4, wrap: true },
|
|
82
93
|
* ]"
|
|
83
94
|
* :pagination="{ total: 120, current: page, onChange: (p) => (page = p) }"
|
|
84
95
|
* />
|
|
@@ -164,8 +175,8 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
164
175
|
* - `auto`(缺省)—— 列宽随内容自适应。`column.width` 是**建议值**,
|
|
165
176
|
* 长文本(尤其中文长串 / 无空格串)会顶破列宽把表格撑得比容器还宽 ⇒ 包裹层出横向滚动条。
|
|
166
177
|
* - `fixed` —— `table-layout: fixed`:列宽受声明约束、**不再被内容撑破**,
|
|
167
|
-
* 于是百分比 / 数字权重可以「吃满容器 +
|
|
168
|
-
*
|
|
178
|
+
* 于是百分比 / 数字权重可以「吃满容器 + 严格按比例」。表体**默认不换行**(`nowrap` + 省略号),
|
|
179
|
+
* 要换行的列显式 `wrap: true`。
|
|
169
180
|
*/
|
|
170
181
|
layout: {
|
|
171
182
|
type: PropType<"auto" | "fixed">;
|
|
@@ -311,8 +322,8 @@ export declare const Table: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
311
322
|
* - `auto`(缺省)—— 列宽随内容自适应。`column.width` 是**建议值**,
|
|
312
323
|
* 长文本(尤其中文长串 / 无空格串)会顶破列宽把表格撑得比容器还宽 ⇒ 包裹层出横向滚动条。
|
|
313
324
|
* - `fixed` —— `table-layout: fixed`:列宽受声明约束、**不再被内容撑破**,
|
|
314
|
-
* 于是百分比 / 数字权重可以「吃满容器 +
|
|
315
|
-
*
|
|
325
|
+
* 于是百分比 / 数字权重可以「吃满容器 + 严格按比例」。表体**默认不换行**(`nowrap` + 省略号),
|
|
326
|
+
* 要换行的列显式 `wrap: true`。
|
|
316
327
|
*/
|
|
317
328
|
layout: {
|
|
318
329
|
type: PropType<"auto" | "fixed">;
|
|
@@ -68,8 +68,8 @@ const Table = /* @__PURE__ */ defineComponent({
|
|
|
68
68
|
* - `auto`(缺省)—— 列宽随内容自适应。`column.width` 是**建议值**,
|
|
69
69
|
* 长文本(尤其中文长串 / 无空格串)会顶破列宽把表格撑得比容器还宽 ⇒ 包裹层出横向滚动条。
|
|
70
70
|
* - `fixed` —— `table-layout: fixed`:列宽受声明约束、**不再被内容撑破**,
|
|
71
|
-
* 于是百分比 / 数字权重可以「吃满容器 +
|
|
72
|
-
*
|
|
71
|
+
* 于是百分比 / 数字权重可以「吃满容器 + 严格按比例」。表体**默认不换行**(`nowrap` + 省略号),
|
|
72
|
+
* 要换行的列显式 `wrap: true`。
|
|
73
73
|
*/
|
|
74
74
|
layout: {
|
|
75
75
|
type: String,
|
|
@@ -177,7 +177,7 @@ const Table = /* @__PURE__ */ defineComponent({
|
|
|
177
177
|
const leadColumns = computed(() => (hasSelectColumn.value ? 1 : 0) + (props.expandable ? 1 : 0));
|
|
178
178
|
const columnCount = computed(() => leadColumns.value + props.columns.length);
|
|
179
179
|
const isEmpty = computed(() => props.data.length === 0);
|
|
180
|
-
const cellClass = (column) => [column.align === "center" ? "mh-table__cell-center" : "", column.align === "right" ? "mh-table__cell-amount" : "", column.
|
|
180
|
+
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);
|
|
181
181
|
const colStyles = computed(() => {
|
|
182
182
|
const weightSum = props.columns.reduce((sum, item) => typeof item.width === "number" ? sum + item.width : sum, 0);
|
|
183
183
|
return props.columns.map((column) => {
|
|
@@ -185,7 +185,7 @@ export declare const Tag: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
185
185
|
}>> & Readonly<{}>, {
|
|
186
186
|
color: string;
|
|
187
187
|
size: ControlSize;
|
|
188
|
-
icon: "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";
|
|
188
|
+
icon: "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" | "info-circle" | "check-circle" | "alert-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "ai" | "shield-check" | "shield-alert" | "history";
|
|
189
189
|
disabled: boolean;
|
|
190
190
|
name: string;
|
|
191
191
|
value: string | number;
|
|
@@ -40,9 +40,10 @@ export interface TextProps {
|
|
|
40
40
|
*
|
|
41
41
|
* ## 与 `Title` / 平台默认的关系
|
|
42
42
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
43
|
+
* `as="h2"` 只贡献**语义**,视觉完全由 `size` / `weight` 决定:字号由 `size` 档(缺省 `body`)显式给,
|
|
44
|
+
* 浏览器给 `h1`-`h6` 的那套字阶(`1.5em` + 粗体)由**本件自己的面**归零(`.mh-text:where(h1…h6)`,
|
|
45
|
+
* 只点名标题标签 —— `strong` 的加粗是它唯一的表达,不归零)。元素级基线**不再**代管这条:
|
|
46
|
+
* 它在 Tailwind 的层外,会压住消费方的 `text-*` 工具类(理由见 `styles/reset.css` 文件头)。
|
|
46
47
|
*
|
|
47
48
|
* ## 不做什么
|
|
48
49
|
*
|