@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
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { defineComponent, createVNode, mergeProps, ref, computed, onBeforeUnmount, isVNode } from "vue";
|
|
2
|
+
import { Icon } from "@manohub/icon";
|
|
3
|
+
function _isSlot(s) {
|
|
4
|
+
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !isVNode(s);
|
|
5
|
+
}
|
|
6
|
+
const CodeView = /* @__PURE__ */ defineComponent({
|
|
7
|
+
name: "CodeView",
|
|
8
|
+
inheritAttrs: false,
|
|
9
|
+
props: {
|
|
10
|
+
code: {
|
|
11
|
+
type: String,
|
|
12
|
+
default: ""
|
|
13
|
+
},
|
|
14
|
+
inline: {
|
|
15
|
+
type: Boolean,
|
|
16
|
+
default: false
|
|
17
|
+
},
|
|
18
|
+
plain: {
|
|
19
|
+
type: Boolean,
|
|
20
|
+
default: false
|
|
21
|
+
},
|
|
22
|
+
language: {
|
|
23
|
+
type: String,
|
|
24
|
+
default: ""
|
|
25
|
+
},
|
|
26
|
+
copyable: {
|
|
27
|
+
type: Boolean,
|
|
28
|
+
default: false
|
|
29
|
+
},
|
|
30
|
+
maxHeight: {
|
|
31
|
+
type: [String, Number],
|
|
32
|
+
default: void 0
|
|
33
|
+
},
|
|
34
|
+
wrap: {
|
|
35
|
+
type: Boolean,
|
|
36
|
+
default: false
|
|
37
|
+
},
|
|
38
|
+
onCopy: {
|
|
39
|
+
type: Function,
|
|
40
|
+
default: void 0
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
slots: Object,
|
|
44
|
+
setup(props, {
|
|
45
|
+
slots,
|
|
46
|
+
attrs
|
|
47
|
+
}) {
|
|
48
|
+
const copied = ref(false);
|
|
49
|
+
let timer;
|
|
50
|
+
onBeforeUnmount(() => {
|
|
51
|
+
if (timer) clearTimeout(timer);
|
|
52
|
+
});
|
|
53
|
+
const copy = async () => {
|
|
54
|
+
const text = props.code;
|
|
55
|
+
let ok = false;
|
|
56
|
+
try {
|
|
57
|
+
if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
|
|
58
|
+
await navigator.clipboard.writeText(text);
|
|
59
|
+
ok = true;
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
ok = false;
|
|
63
|
+
}
|
|
64
|
+
if (!ok) {
|
|
65
|
+
console.warn("[ui] CodeBlock.View:当前环境无法写入剪贴板,复制未生效");
|
|
66
|
+
}
|
|
67
|
+
copied.value = ok;
|
|
68
|
+
if (ok) {
|
|
69
|
+
if (timer) clearTimeout(timer);
|
|
70
|
+
timer = setTimeout(() => copied.value = false, 1500);
|
|
71
|
+
}
|
|
72
|
+
props.onCopy?.(ok);
|
|
73
|
+
};
|
|
74
|
+
return () => {
|
|
75
|
+
const extra = attrs.class;
|
|
76
|
+
const style = attrs.style;
|
|
77
|
+
const content = slots.default ? slots.default() : props.code;
|
|
78
|
+
if (props.inline) {
|
|
79
|
+
return createVNode("code", {
|
|
80
|
+
"class": ["mh-code-block", "mh-code-block--inline", props.plain ? "mh-code-block--plain" : "", extra].filter(Boolean).join(" "),
|
|
81
|
+
"style": style
|
|
82
|
+
}, [content]);
|
|
83
|
+
}
|
|
84
|
+
const copyLabel = copied.value ? "已复制" : "复制代码";
|
|
85
|
+
const limited = props.maxHeight === void 0 ? void 0 : {
|
|
86
|
+
maxHeight: typeof props.maxHeight === "number" ? `${props.maxHeight}px` : props.maxHeight,
|
|
87
|
+
overflow: "auto"
|
|
88
|
+
};
|
|
89
|
+
return createVNode("div", {
|
|
90
|
+
"class": ["mh-code-block", props.wrap ? "mh-code-block--wrap" : "", extra].filter(Boolean).join(" "),
|
|
91
|
+
"style": style
|
|
92
|
+
}, [createVNode("pre", {
|
|
93
|
+
"class": "mh-code-block__view",
|
|
94
|
+
"style": limited
|
|
95
|
+
}, [content]), props.language ? createVNode("span", {
|
|
96
|
+
"class": "mh-code-block__lang"
|
|
97
|
+
}, [props.language]) : null, props.copyable ? createVNode("button", {
|
|
98
|
+
"type": "button",
|
|
99
|
+
"class": ["mh-button", "mh-button--icon", "mh-code-block__copy", copied.value ? "is-copied" : ""].filter(Boolean).join(" "),
|
|
100
|
+
"data-state": copied.value ? "copied" : "idle",
|
|
101
|
+
"aria-label": copyLabel,
|
|
102
|
+
"title": copyLabel,
|
|
103
|
+
"onClick": copy
|
|
104
|
+
}, [createVNode(Icon, {
|
|
105
|
+
"name": copied.value ? "check" : "copy",
|
|
106
|
+
"class": "mh-button__icon"
|
|
107
|
+
}, null)]) : null]);
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
const CodeEditor = /* @__PURE__ */ defineComponent({
|
|
112
|
+
name: "CodeEditor",
|
|
113
|
+
inheritAttrs: false,
|
|
114
|
+
props: {
|
|
115
|
+
modelValue: {
|
|
116
|
+
type: String,
|
|
117
|
+
default: void 0
|
|
118
|
+
},
|
|
119
|
+
defaultValue: {
|
|
120
|
+
type: String,
|
|
121
|
+
default: ""
|
|
122
|
+
},
|
|
123
|
+
placeholder: {
|
|
124
|
+
type: String,
|
|
125
|
+
default: void 0
|
|
126
|
+
},
|
|
127
|
+
rows: {
|
|
128
|
+
type: Number,
|
|
129
|
+
default: void 0
|
|
130
|
+
},
|
|
131
|
+
autoSize: {
|
|
132
|
+
type: [Boolean, Object],
|
|
133
|
+
default: true
|
|
134
|
+
},
|
|
135
|
+
maxHeight: {
|
|
136
|
+
type: [String, Number],
|
|
137
|
+
default: void 0
|
|
138
|
+
},
|
|
139
|
+
readonly: {
|
|
140
|
+
type: Boolean,
|
|
141
|
+
default: false
|
|
142
|
+
},
|
|
143
|
+
disabled: {
|
|
144
|
+
type: Boolean,
|
|
145
|
+
default: false
|
|
146
|
+
},
|
|
147
|
+
language: {
|
|
148
|
+
type: String,
|
|
149
|
+
default: ""
|
|
150
|
+
},
|
|
151
|
+
onChange: {
|
|
152
|
+
type: Function,
|
|
153
|
+
default: void 0
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
emits: {
|
|
157
|
+
"update:modelValue": (v) => true
|
|
158
|
+
},
|
|
159
|
+
setup(props, {
|
|
160
|
+
emit,
|
|
161
|
+
attrs
|
|
162
|
+
}) {
|
|
163
|
+
const inner = ref(props.defaultValue);
|
|
164
|
+
const current = computed(() => props.modelValue ?? inner.value);
|
|
165
|
+
const visibleRows = computed(() => {
|
|
166
|
+
if (props.autoSize === false) return props.rows ?? 4;
|
|
167
|
+
const option = typeof props.autoSize === "object" ? props.autoSize : {};
|
|
168
|
+
const min = option.minRows ?? 3;
|
|
169
|
+
const max = option.maxRows ?? 12;
|
|
170
|
+
const lines = (current.value ?? "").split("\n").length;
|
|
171
|
+
return Math.min(Math.max(lines, min), max);
|
|
172
|
+
});
|
|
173
|
+
const areaStyle = computed(() => props.maxHeight === void 0 ? void 0 : {
|
|
174
|
+
maxHeight: typeof props.maxHeight === "number" ? `${props.maxHeight}px` : props.maxHeight,
|
|
175
|
+
overflow: "auto"
|
|
176
|
+
});
|
|
177
|
+
const onInput = (event) => {
|
|
178
|
+
const el = event.target;
|
|
179
|
+
const value = el.value;
|
|
180
|
+
if (props.modelValue === void 0) inner.value = value;
|
|
181
|
+
emit("update:modelValue", value);
|
|
182
|
+
props.onChange?.(value);
|
|
183
|
+
if (props.modelValue !== void 0 && props.modelValue !== value) el.value = props.modelValue;
|
|
184
|
+
};
|
|
185
|
+
return () => createVNode("div", {
|
|
186
|
+
"class": ["mh-code-block", "mh-code-block--editable", attrs.class].filter(Boolean).join(" "),
|
|
187
|
+
"style": attrs.style
|
|
188
|
+
}, [createVNode("textarea", {
|
|
189
|
+
"class": "mh-code-block__editor",
|
|
190
|
+
"rows": visibleRows.value,
|
|
191
|
+
"value": current.value,
|
|
192
|
+
"placeholder": props.placeholder,
|
|
193
|
+
"readonly": props.readonly,
|
|
194
|
+
"disabled": props.disabled,
|
|
195
|
+
"style": areaStyle.value,
|
|
196
|
+
"spellcheck": false,
|
|
197
|
+
"autocapitalize": "off",
|
|
198
|
+
"autocomplete": "off",
|
|
199
|
+
"onInput": onInput
|
|
200
|
+
}, null), props.language ? createVNode("span", {
|
|
201
|
+
"class": "mh-code-block__lang"
|
|
202
|
+
}, [props.language]) : null]);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
const CodeBlockBase = /* @__PURE__ */ defineComponent({
|
|
206
|
+
name: "CodeBlock",
|
|
207
|
+
inheritAttrs: false,
|
|
208
|
+
props: {
|
|
209
|
+
editable: {
|
|
210
|
+
type: Boolean,
|
|
211
|
+
default: false
|
|
212
|
+
},
|
|
213
|
+
/* —— 只读档(`editable` 为假时生效) —— */
|
|
214
|
+
code: {
|
|
215
|
+
type: String,
|
|
216
|
+
default: ""
|
|
217
|
+
},
|
|
218
|
+
inline: {
|
|
219
|
+
type: Boolean,
|
|
220
|
+
default: false
|
|
221
|
+
},
|
|
222
|
+
plain: {
|
|
223
|
+
type: Boolean,
|
|
224
|
+
default: false
|
|
225
|
+
},
|
|
226
|
+
copyable: {
|
|
227
|
+
type: Boolean,
|
|
228
|
+
default: false
|
|
229
|
+
},
|
|
230
|
+
wrap: {
|
|
231
|
+
type: Boolean,
|
|
232
|
+
default: false
|
|
233
|
+
},
|
|
234
|
+
onCopy: {
|
|
235
|
+
type: Function,
|
|
236
|
+
default: void 0
|
|
237
|
+
},
|
|
238
|
+
/* —— 编辑档(`editable` 为真时生效) —— */
|
|
239
|
+
modelValue: {
|
|
240
|
+
type: String,
|
|
241
|
+
default: void 0
|
|
242
|
+
},
|
|
243
|
+
defaultValue: {
|
|
244
|
+
type: String,
|
|
245
|
+
default: ""
|
|
246
|
+
},
|
|
247
|
+
placeholder: {
|
|
248
|
+
type: String,
|
|
249
|
+
default: void 0
|
|
250
|
+
},
|
|
251
|
+
rows: {
|
|
252
|
+
type: Number,
|
|
253
|
+
default: void 0
|
|
254
|
+
},
|
|
255
|
+
autoSize: {
|
|
256
|
+
type: [Boolean, Object],
|
|
257
|
+
default: true
|
|
258
|
+
},
|
|
259
|
+
readonly: {
|
|
260
|
+
type: Boolean,
|
|
261
|
+
default: false
|
|
262
|
+
},
|
|
263
|
+
disabled: {
|
|
264
|
+
type: Boolean,
|
|
265
|
+
default: false
|
|
266
|
+
},
|
|
267
|
+
onChange: {
|
|
268
|
+
type: Function,
|
|
269
|
+
default: void 0
|
|
270
|
+
},
|
|
271
|
+
/* —— 两档共用 —— */
|
|
272
|
+
language: {
|
|
273
|
+
type: String,
|
|
274
|
+
default: ""
|
|
275
|
+
},
|
|
276
|
+
maxHeight: {
|
|
277
|
+
type: [String, Number],
|
|
278
|
+
default: void 0
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
emits: {
|
|
282
|
+
"update:modelValue": (v) => true
|
|
283
|
+
},
|
|
284
|
+
slots: Object,
|
|
285
|
+
setup(props, {
|
|
286
|
+
emit,
|
|
287
|
+
slots,
|
|
288
|
+
attrs
|
|
289
|
+
}) {
|
|
290
|
+
return () => {
|
|
291
|
+
let _slot;
|
|
292
|
+
const shared = {
|
|
293
|
+
language: props.language,
|
|
294
|
+
maxHeight: props.maxHeight,
|
|
295
|
+
class: attrs.class,
|
|
296
|
+
style: attrs.style
|
|
297
|
+
};
|
|
298
|
+
if (props.editable) {
|
|
299
|
+
return createVNode(CodeEditor, mergeProps(shared, {
|
|
300
|
+
"modelValue": props.modelValue,
|
|
301
|
+
"defaultValue": props.defaultValue,
|
|
302
|
+
"placeholder": props.placeholder,
|
|
303
|
+
"rows": props.rows,
|
|
304
|
+
"autoSize": props.autoSize,
|
|
305
|
+
"readonly": props.readonly,
|
|
306
|
+
"disabled": props.disabled,
|
|
307
|
+
"onChange": props.onChange,
|
|
308
|
+
"onUpdate:modelValue": (v) => emit("update:modelValue", v)
|
|
309
|
+
}), null);
|
|
310
|
+
}
|
|
311
|
+
const view = {
|
|
312
|
+
...shared,
|
|
313
|
+
code: props.code,
|
|
314
|
+
inline: props.inline,
|
|
315
|
+
plain: props.plain,
|
|
316
|
+
copyable: props.copyable,
|
|
317
|
+
wrap: props.wrap,
|
|
318
|
+
onCopy: props.onCopy
|
|
319
|
+
};
|
|
320
|
+
const body = slots.default;
|
|
321
|
+
return body ? createVNode(CodeView, view, _isSlot(_slot = body()) ? _slot : {
|
|
322
|
+
default: () => [_slot]
|
|
323
|
+
}) : createVNode(CodeView, view, null);
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
const CodeBlock = Object.assign(CodeBlockBase, {
|
|
328
|
+
View: CodeView,
|
|
329
|
+
Editor: CodeEditor
|
|
330
|
+
});
|
|
331
|
+
export {
|
|
332
|
+
CodeBlock,
|
|
333
|
+
CodeEditor,
|
|
334
|
+
CodeView
|
|
335
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type PropType, type SlotsType, type VNodeChild } from 'vue';
|
|
2
2
|
export type DialogWidth = 'md' | 'lg';
|
|
3
|
-
/**
|
|
3
|
+
/** 语义档:决定标题左侧图标的图形与颜色(缺省不渲染图标) */
|
|
4
4
|
export type DialogTone = 'info' | 'success' | 'warning' | 'error';
|
|
5
5
|
/**
|
|
6
6
|
* 对话框(**自绘**;模态语义与遮罩全由原生 `<dialog>` 给)。
|
|
@@ -50,7 +50,7 @@ export declare const Dialog: import("vue").DefineComponent<import("vue").Extract
|
|
|
50
50
|
/**
|
|
51
51
|
* 语义档(缺省不渲染图标):`warning` / `error` 用于「这一步有风险」的确认 ——
|
|
52
52
|
* 服务层的 `confirm()` / `alert()` 就是靠它把「删除确认」与「保存成功」区分开的。
|
|
53
|
-
*
|
|
53
|
+
* 它**只加一个带圈语义图标与配色**,不改标题文案、不动底栏按钮的语义(危险色仍由 `okDanger` 定)。
|
|
54
54
|
*/
|
|
55
55
|
tone: {
|
|
56
56
|
type: PropType<DialogTone>;
|
|
@@ -157,7 +157,7 @@ export declare const Dialog: import("vue").DefineComponent<import("vue").Extract
|
|
|
157
157
|
/**
|
|
158
158
|
* 语义档(缺省不渲染图标):`warning` / `error` 用于「这一步有风险」的确认 ——
|
|
159
159
|
* 服务层的 `confirm()` / `alert()` 就是靠它把「删除确认」与「保存成功」区分开的。
|
|
160
|
-
*
|
|
160
|
+
* 它**只加一个带圈语义图标与配色**,不改标题文案、不动底栏按钮的语义(危险色仍由 `okDanger` 定)。
|
|
161
161
|
*/
|
|
162
162
|
tone: {
|
|
163
163
|
type: PropType<DialogTone>;
|
|
@@ -2,10 +2,10 @@ import { defineComponent, ref, watch, onMounted, onBeforeUnmount, computed, crea
|
|
|
2
2
|
import { Icon } from "@manohub/icon";
|
|
3
3
|
import { Button } from "../button/index.js";
|
|
4
4
|
const TONE_ICON = {
|
|
5
|
-
info: "info",
|
|
6
|
-
success: "check",
|
|
7
|
-
warning: "alert",
|
|
8
|
-
error: "close"
|
|
5
|
+
info: "info-circle",
|
|
6
|
+
success: "check-circle",
|
|
7
|
+
warning: "alert-circle",
|
|
8
|
+
error: "close-circle"
|
|
9
9
|
};
|
|
10
10
|
const Dialog = /* @__PURE__ */ defineComponent({
|
|
11
11
|
name: "Dialog",
|
|
@@ -24,7 +24,7 @@ const Dialog = /* @__PURE__ */ defineComponent({
|
|
|
24
24
|
/**
|
|
25
25
|
* 语义档(缺省不渲染图标):`warning` / `error` 用于「这一步有风险」的确认 ——
|
|
26
26
|
* 服务层的 `confirm()` / `alert()` 就是靠它把「删除确认」与「保存成功」区分开的。
|
|
27
|
-
*
|
|
27
|
+
* 它**只加一个带圈语义图标与配色**,不改标题文案、不动底栏按钮的语义(危险色仍由 `okDanger` 定)。
|
|
28
28
|
*/
|
|
29
29
|
tone: {
|
|
30
30
|
type: String,
|
|
@@ -41,7 +41,12 @@ export interface FilterProps {
|
|
|
41
41
|
title?: string;
|
|
42
42
|
/** 标题下的说明小字(透传给 `Form.Header`) */
|
|
43
43
|
description?: string;
|
|
44
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* label 列宽(px),透传给 `Form`。
|
|
46
|
+
*
|
|
47
|
+
* **缺省不设**:不传即与 `Form` 一致(取令牌 `--ui-form-label-width`,120)。
|
|
48
|
+
* 想收窄(筛选条的标签多为四字)就显式传,例如 `labelWidth={68}`。
|
|
49
|
+
*/
|
|
45
50
|
labelWidth?: number;
|
|
46
51
|
/** 受控条件快照(`条件名 → 值`);不传即非受控(由 `defaultValue` 起) */
|
|
47
52
|
modelValue?: FilterValues;
|
|
@@ -79,7 +84,8 @@ export interface FilterItemProps {
|
|
|
79
84
|
* 增量只有一处 —— **读写的值都是归一后的**(`'all'` / 空数组 / 空值 → 空串),
|
|
80
85
|
* 于是消费方直接把 `value` 绑给控件,不必自己处理哨兵。
|
|
81
86
|
*
|
|
82
|
-
*
|
|
87
|
+
* 字段宽**自适应**:字段区是 `Form` 的多列动态档(`Filter` 传 `columns="auto"`),
|
|
88
|
+
* 故本件只输出 `Form.Item` 自己的类 —— 列宽由那条网格轨道算,换行下来的字段与上一行逐列对齐。
|
|
83
89
|
*
|
|
84
90
|
* @example
|
|
85
91
|
* <Filter.Item code="status" label="授权状态">
|
|
@@ -2,8 +2,6 @@ import { defineComponent, createVNode, ref, h, Fragment } from "vue";
|
|
|
2
2
|
import { Button } from "../button/index.js";
|
|
3
3
|
import { FormItem, Form } from "../form/index.js";
|
|
4
4
|
const FILTER_ALL = "all";
|
|
5
|
-
const FILTER_LABEL_WIDTH = 68;
|
|
6
|
-
const FILTER_GAP = 16;
|
|
7
5
|
function normalizeFilterValue(value) {
|
|
8
6
|
if (Array.isArray(value)) {
|
|
9
7
|
const kept = value.map((item) => normalizeFilterValue(item)).filter((item) => item !== "");
|
|
@@ -96,7 +94,7 @@ const FilterRoot = /* @__PURE__ */ defineComponent({
|
|
|
96
94
|
emit("update:modelValue", next);
|
|
97
95
|
props.onReset?.(next);
|
|
98
96
|
};
|
|
99
|
-
const
|
|
97
|
+
const onFormKeydown = (event) => {
|
|
100
98
|
if (event.key !== "Enter" || event.isComposing) return;
|
|
101
99
|
const target = event.target;
|
|
102
100
|
if (target?.tagName !== "INPUT" || target.closest("[popover]")) return;
|
|
@@ -118,30 +116,23 @@ const FilterRoot = /* @__PURE__ */ defineComponent({
|
|
|
118
116
|
"ref": formRef,
|
|
119
117
|
"class": ["mh-filter__form", attrs.class].filter(Boolean).join(" "),
|
|
120
118
|
"style": attrs.style,
|
|
121
|
-
"labelWidth": props.labelWidth
|
|
122
|
-
"
|
|
119
|
+
"labelWidth": props.labelWidth,
|
|
120
|
+
"columns": "auto",
|
|
121
|
+
"onKeydown": onFormKeydown,
|
|
123
122
|
"modelValue": props.modelValue,
|
|
124
123
|
"defaultValue": props.defaultValue,
|
|
125
124
|
"onChange": onFormChange
|
|
126
125
|
}, {
|
|
127
|
-
default: () =>
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
h(Form.Header, {
|
|
126
|
+
default: () => {
|
|
127
|
+
const raw = slots.default?.();
|
|
128
|
+
const fields = Array.isArray(raw) ? raw : raw == null ? [] : [raw];
|
|
129
|
+
return [h(Form.Header, {
|
|
132
130
|
title: props.title,
|
|
133
131
|
description: props.description
|
|
134
132
|
}, {
|
|
135
133
|
extra: renderActions
|
|
136
|
-
}),
|
|
137
|
-
|
|
138
|
-
h("div", {
|
|
139
|
-
class: "mh-filter__fields",
|
|
140
|
-
onKeydown: onFieldsKeydown
|
|
141
|
-
}, {
|
|
142
|
-
default: () => slots.default?.()
|
|
143
|
-
})
|
|
144
|
-
]
|
|
134
|
+
}), ...fields];
|
|
135
|
+
}
|
|
145
136
|
});
|
|
146
137
|
}
|
|
147
138
|
});
|
|
@@ -181,7 +172,7 @@ const FilterItem = /* @__PURE__ */ defineComponent({
|
|
|
181
172
|
"required": props.required,
|
|
182
173
|
"error": props.error,
|
|
183
174
|
"hint": props.hint,
|
|
184
|
-
"class":
|
|
175
|
+
"class": attrs.class,
|
|
185
176
|
"style": attrs.style
|
|
186
177
|
}, {
|
|
187
178
|
default: (scope) => slots.default?.({
|
|
@@ -99,6 +99,18 @@ export interface FormProps {
|
|
|
99
99
|
defaultValue?: FormValues;
|
|
100
100
|
/** 值变更(快照含**全部已登记字段**,未设值的字段为 `undefined`) */
|
|
101
101
|
onChange?: (values: FormValues) => void;
|
|
102
|
+
/**
|
|
103
|
+
* 根节点的键盘事件(**转发到表单根**)。
|
|
104
|
+
*
|
|
105
|
+
* 本件是 `inheritAttrs: false`,根节点只显式绑 `class` / `style` —— 不声明的监听器会被**静默丢掉**
|
|
106
|
+
* (与该文件里已修过的「消费方 style 被静默丢弃」同款前科)。而根节点就是「全部字段行的容器」,
|
|
107
|
+
* 故它是「字段区层面的委托」的落点:本包 `Filter` 的「字段区回车 = 查询」就搭在这条通道上
|
|
108
|
+
* (构造 `Filter` 时因此不必再套一层只为挂事件的壳 —— 那会改变 `class` / `style` 的落点)。
|
|
109
|
+
*
|
|
110
|
+
* **有意只开这一条**:其它监听器(如 `onClick`)不转发;要把某一条也接进来,先当一次公开行为变更裁决。
|
|
111
|
+
* 要不要拦、拦哪些按键(本包 `Filter` 收窄到「`<input>` 上的回车」)由调用方自己判断,本件只转发。
|
|
112
|
+
*/
|
|
113
|
+
onKeydown?: (event: KeyboardEvent) => void;
|
|
102
114
|
}
|
|
103
115
|
export interface FormItemProps {
|
|
104
116
|
/**
|
|
@@ -193,6 +205,15 @@ export interface FormItemProps {
|
|
|
193
205
|
* `{ y, x }` 上下 / 左右分别给,缺省 0(贴容器边)。页面里的表单在 `Panel.Body` 里、内距由那块给;
|
|
194
206
|
* **弹窗 / 抽屉里没有别的容器**给内距,就用表单自带的 `padding={{ y: 16, x: 20 }}`。
|
|
195
207
|
*
|
|
208
|
+
* ## 键盘事件(`onKeydown` 转发到根节点)
|
|
209
|
+
*
|
|
210
|
+
* `onKeydown` 是本件的**声明式入口**(缺省不绑):传进来的处理器绑在根节点上 ——
|
|
211
|
+
* 本件是 `inheritAttrs: false`,根节点只显式绑 `class` / `style`,不声明的监听器会被静默丢掉。
|
|
212
|
+
* 根节点即「全部字段行的容器」,因此它是「字段区层面的委托」的落点:本包 `Filter` 的
|
|
213
|
+
* 「字段区回车 = 查询」就搭在这里,构造 `Filter` 时**不必**再套一层只为挂事件的壳
|
|
214
|
+
* (那会改变 `class` / `style` 的落点)。要不要拦、拦哪些按键由调用方自己判断,本件只转发。
|
|
215
|
+
* **有意只开这一条**:其它监听器不转发,扩张要先当一次公开行为变更裁决。
|
|
216
|
+
*
|
|
196
217
|
* ## 只读值(摘要 / 详情)
|
|
197
218
|
*
|
|
198
219
|
* 「向导最后一步的确认摘要」「详情弹窗」不需要另起一套描述列表件 —— 只用表单行本身,
|
|
@@ -455,6 +476,11 @@ export declare const Form: {
|
|
|
455
476
|
type: PropType<(values: FormValues) => void>;
|
|
456
477
|
default: undefined;
|
|
457
478
|
};
|
|
479
|
+
/** 根节点的键盘事件(转发到表单根;缺省不绑)—— 用途与边界见 `FormProps` 的同名注释 */
|
|
480
|
+
onKeydown: {
|
|
481
|
+
type: PropType<(event: KeyboardEvent) => void>;
|
|
482
|
+
default: undefined;
|
|
483
|
+
};
|
|
458
484
|
}>> & Readonly<{
|
|
459
485
|
"onUpdate:modelValue"?: ((values: FormValues) => any) | undefined;
|
|
460
486
|
}>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
@@ -463,6 +489,7 @@ export declare const Form: {
|
|
|
463
489
|
padding: Padding;
|
|
464
490
|
layout: "horizontal" | "vertical";
|
|
465
491
|
onChange: (values: FormValues) => void;
|
|
492
|
+
onKeydown: (event: KeyboardEvent) => void;
|
|
466
493
|
defaultValue: FormValues;
|
|
467
494
|
gap: number;
|
|
468
495
|
columns: FormColumns;
|
|
@@ -544,12 +571,18 @@ export declare const Form: {
|
|
|
544
571
|
type: PropType<(values: FormValues) => void>;
|
|
545
572
|
default: undefined;
|
|
546
573
|
};
|
|
574
|
+
/** 根节点的键盘事件(转发到表单根;缺省不绑)—— 用途与边界见 `FormProps` 的同名注释 */
|
|
575
|
+
onKeydown: {
|
|
576
|
+
type: PropType<(event: KeyboardEvent) => void>;
|
|
577
|
+
default: undefined;
|
|
578
|
+
};
|
|
547
579
|
}>> & Readonly<{
|
|
548
580
|
"onUpdate:modelValue"?: ((values: FormValues) => any) | undefined;
|
|
549
581
|
}>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, {
|
|
550
582
|
padding: Padding;
|
|
551
583
|
layout: "horizontal" | "vertical";
|
|
552
584
|
onChange: (values: FormValues) => void;
|
|
585
|
+
onKeydown: (event: KeyboardEvent) => void;
|
|
553
586
|
defaultValue: FormValues;
|
|
554
587
|
gap: number;
|
|
555
588
|
columns: FormColumns;
|
|
@@ -626,6 +659,11 @@ export declare const Form: {
|
|
|
626
659
|
type: PropType<(values: FormValues) => void>;
|
|
627
660
|
default: undefined;
|
|
628
661
|
};
|
|
662
|
+
/** 根节点的键盘事件(转发到表单根;缺省不绑)—— 用途与边界见 `FormProps` 的同名注释 */
|
|
663
|
+
onKeydown: {
|
|
664
|
+
type: PropType<(event: KeyboardEvent) => void>;
|
|
665
|
+
default: undefined;
|
|
666
|
+
};
|
|
629
667
|
}>> & Readonly<{
|
|
630
668
|
"onUpdate:modelValue"?: ((values: FormValues) => any) | undefined;
|
|
631
669
|
}>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
@@ -634,6 +672,7 @@ export declare const Form: {
|
|
|
634
672
|
padding: Padding;
|
|
635
673
|
layout: "horizontal" | "vertical";
|
|
636
674
|
onChange: (values: FormValues) => void;
|
|
675
|
+
onKeydown: (event: KeyboardEvent) => void;
|
|
637
676
|
defaultValue: FormValues;
|
|
638
677
|
gap: number;
|
|
639
678
|
columns: FormColumns;
|
|
@@ -236,6 +236,11 @@ const FormRoot = /* @__PURE__ */ defineComponent({
|
|
|
236
236
|
onChange: {
|
|
237
237
|
type: Function,
|
|
238
238
|
default: void 0
|
|
239
|
+
},
|
|
240
|
+
/** 根节点的键盘事件(转发到表单根;缺省不绑)—— 用途与边界见 `FormProps` 的同名注释 */
|
|
241
|
+
onKeydown: {
|
|
242
|
+
type: Function,
|
|
243
|
+
default: void 0
|
|
239
244
|
}
|
|
240
245
|
},
|
|
241
246
|
emits: {
|
|
@@ -313,6 +318,7 @@ const FormRoot = /* @__PURE__ */ defineComponent({
|
|
|
313
318
|
} = splitFormHeader(list);
|
|
314
319
|
return createVNode("div", {
|
|
315
320
|
"class": ["mh-form", columnsClass(), props.layout === "vertical" ? "mh-form--vertical" : "", attrs.class].filter(Boolean).join(" "),
|
|
321
|
+
"onKeydown": props.onKeydown,
|
|
316
322
|
"style": [
|
|
317
323
|
mergePartStyle(attrs.style, props.padding),
|
|
318
324
|
/* 行距同时下发实体 `gap` 与变量:多列的轨道下限公式要用**同一个**行距值算 ——
|