@shwfed/config 2.3.26 → 2.3.28

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 (84) hide show
  1. package/dist/mcp.mjs +1211 -701
  2. package/dist/module.json +1 -1
  3. package/dist/preview/assets/{config-BkimX91E.js → config--PcXQV_r.js} +1 -1
  4. package/dist/preview/assets/{config-CO2iovZD.js → config-5KVDXgUF.js} +1 -1
  5. package/dist/preview/assets/{config-u1rl9w2L.js → config-B5avpKJE.js} +1 -1
  6. package/dist/preview/assets/{config-DgZ4NYoA.js → config-CJHPt8Gx.js} +1 -1
  7. package/dist/preview/assets/{config-ypYLVfRE.js → config-CNo3isHa.js} +1 -1
  8. package/dist/preview/assets/{config-Cm9t0CvW.js → config-CQHS6cZe.js} +1 -1
  9. package/dist/preview/assets/{config-DPFHMkHc.js → config-D0_1yZdF.js} +1 -1
  10. package/dist/preview/assets/{config-Dzqe6v-x.js → config-DDfTl9Cs.js} +1 -1
  11. package/dist/preview/assets/{config-BATy87wV.js → config-fvkC2rB8.js} +1 -1
  12. package/dist/preview/assets/{definition.vue_vue_type_script_setup_true_lang-CliXxe84.js → definition.vue_vue_type_script_setup_true_lang-RM-qDh0R.js} +1 -1
  13. package/dist/preview/assets/index-DNd8J9Zv.js +643 -0
  14. package/dist/preview/assets/index-DrIMqXAa.js +1 -0
  15. package/dist/preview/assets/index-a2QwAots.css +1 -0
  16. package/dist/preview/assets/{runtime-Dtc1ETUF.js → runtime-BGTWf-O7.js} +1 -1
  17. package/dist/preview/assets/{runtime-B_FMZ5eD.js → runtime-BPjZQmcY.js} +1 -1
  18. package/dist/preview/assets/{runtime-BTROwcw4.js → runtime-Bq3fmxeF.js} +1 -1
  19. package/dist/preview/assets/{runtime-Dsx8Y56q.js → runtime-CCbyrqQT.js} +1 -1
  20. package/dist/preview/assets/{runtime-T_tUqLxO.js → runtime-C_XX6a0C.js} +1 -1
  21. package/dist/preview/assets/{runtime-BR6-W3u_.js → runtime-CtqwtTE_.js} +1 -1
  22. package/dist/preview/assets/{runtime-D1xLbTQ9.js → runtime-DcrzodsN.js} +1 -1
  23. package/dist/preview/assets/{runtime-CTpsTb-X.js → runtime-Dr_10emf.js} +1 -1
  24. package/dist/preview/assets/{runtime-Cj0kLSqP.js → runtime-Dy4ZmQ-n.js} +1 -1
  25. package/dist/preview/index.html +2 -2
  26. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.tabs/config.d.vue.ts +2 -0
  27. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.tabs/config.vue +57 -3
  28. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.tabs/config.vue.d.ts +2 -0
  29. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.tabs/runtime.d.vue.ts +2 -0
  30. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.tabs/runtime.vue +1 -0
  31. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.tabs/runtime.vue.d.ts +2 -0
  32. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.tabs/schema.d.ts +2 -0
  33. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.tabs/schema.js +4 -0
  34. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.d.vue.ts +4 -4
  35. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.vue.d.ts +4 -4
  36. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/config.d.vue.ts +127 -0
  37. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/config.vue +593 -0
  38. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/config.vue.d.ts +127 -0
  39. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/runtime.d.vue.ts +8 -0
  40. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/runtime.vue +465 -0
  41. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/runtime.vue.d.ts +8 -0
  42. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/schema.d.ts +95 -0
  43. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/schema.js +112 -0
  44. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/config.d.vue.ts +125 -0
  45. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/config.vue +525 -0
  46. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/config.vue.d.ts +125 -0
  47. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/runtime.d.vue.ts +8 -0
  48. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/runtime.vue +460 -0
  49. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/runtime.vue.d.ts +8 -0
  50. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/schema.d.ts +92 -0
  51. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/schema.js +104 -0
  52. package/dist/runtime/components/form/fields/2026-05-26/tree-combobox-shared.d.ts +35 -0
  53. package/dist/runtime/components/form/fields/2026-05-26/tree-combobox-shared.js +31 -0
  54. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi/runtime.vue +36 -13
  55. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi/runtime.vue +36 -12
  56. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/runtime.vue +0 -1
  57. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/config.d.vue.ts +131 -0
  58. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/config.vue +607 -0
  59. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/config.vue.d.ts +131 -0
  60. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/runtime.d.vue.ts +9 -0
  61. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/runtime.vue +447 -0
  62. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/runtime.vue.d.ts +9 -0
  63. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/schema.d.ts +90 -0
  64. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/schema.js +143 -0
  65. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/config.d.vue.ts +129 -0
  66. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/config.vue +538 -0
  67. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/config.vue.d.ts +129 -0
  68. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/runtime.d.vue.ts +9 -0
  69. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/runtime.vue +429 -0
  70. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/runtime.vue.d.ts +9 -0
  71. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/schema.d.ts +87 -0
  72. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/schema.js +135 -0
  73. package/dist/runtime/components/table/columns/2026-05-27/tree-combobox-shared.d.ts +35 -0
  74. package/dist/runtime/components/table/columns/2026-05-27/tree-combobox-shared.js +31 -0
  75. package/dist/runtime/components/table/config.vue +29 -0
  76. package/dist/runtime/components/ui/command/CommandItem.vue +12 -4
  77. package/dist/runtime/components/ui/tree/Tree.d.vue.ts +2 -0
  78. package/dist/runtime/components/ui/tree/Tree.vue +7 -2
  79. package/dist/runtime/components/ui/tree/Tree.vue.d.ts +2 -0
  80. package/dist/runtime/components/ui/tree/TreeNode.vue +16 -26
  81. package/package.json +1 -1
  82. package/dist/preview/assets/index-6rM4rqXR.js +0 -1
  83. package/dist/preview/assets/index-BCE-G4Ha.css +0 -1
  84. package/dist/preview/assets/index-wBVA0mNO.js +0 -643
@@ -0,0 +1,460 @@
1
+ <script setup>
2
+ import { Icon } from "@iconify/vue";
3
+ import { Effect, Fiber, Option } from "effect";
4
+ import { Fetch } from "fx-fetch";
5
+ import { computed, ref, shallowRef, watch } from "vue";
6
+ import { useI18n } from "vue-i18n";
7
+ import { cel as _rawCel } from "../../../../../utils/cel";
8
+ import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
9
+ import { getLocalizedText } from "../../../../../share/locale";
10
+ import { Field, FieldLabel } from "../../../../ui/field";
11
+ import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "../../../../ui/input-group";
12
+ import { Markdown } from "../../../../ui/markdown";
13
+ import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../../../../ui/popover";
14
+ import { Skeleton } from "../../../../ui/skeleton";
15
+ import { Tree as UiTree } from "../../../../ui/tree";
16
+ import { interpolateMarkdown } from "../../../../table/utils/runtime";
17
+ import { DEFAULT_FIELD_ORIENTATION } from "../../../utils/common";
18
+ import { useFormReadonly } from "../../../utils/readonly";
19
+ import { useFormState } from "../../../utils/state";
20
+ import {
21
+ findWrappedPath,
22
+ getWrappedChildren,
23
+ wrapStructuralAll
24
+ } from "../tree-combobox-shared";
25
+ defineOptions({ name: "ShwfedTreeComboboxSingleFieldRuntime" });
26
+ const props = defineProps({
27
+ fieldId: { type: String, required: true },
28
+ config: { type: null, required: true }
29
+ });
30
+ const { locale, t } = useI18n({
31
+ inheritLocale: true,
32
+ messages: {
33
+ zh: {
34
+ "tree-combobox-single-placeholder": "\u8BF7\u9009\u62E9",
35
+ "tree-combobox-single-search-placeholder": "\u641C\u7D22\u2026",
36
+ "tree-combobox-single-search-clear": "\u6E05\u9664\u641C\u7D22",
37
+ "tree-combobox-single-empty": "\u65E0\u53EF\u9009\u9879",
38
+ "tree-combobox-single-load-error": "\u52A0\u8F7D\u5931\u8D25",
39
+ "tree-combobox-single-retry": "\u91CD\u8BD5",
40
+ "tree-combobox-single-readonly-empty": "\u2014"
41
+ },
42
+ en: {
43
+ "tree-combobox-single-placeholder": "Select\u2026",
44
+ "tree-combobox-single-search-placeholder": "Search\u2026",
45
+ "tree-combobox-single-search-clear": "Clear search",
46
+ "tree-combobox-single-empty": "No options",
47
+ "tree-combobox-single-load-error": "Failed to load",
48
+ "tree-combobox-single-retry": "Retry",
49
+ "tree-combobox-single-readonly-empty": "\u2014"
50
+ },
51
+ ja: {
52
+ "tree-combobox-single-placeholder": "\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044",
53
+ "tree-combobox-single-search-placeholder": "\u691C\u7D22\u2026",
54
+ "tree-combobox-single-search-clear": "\u691C\u7D22\u3092\u30AF\u30EA\u30A2",
55
+ "tree-combobox-single-empty": "\u9078\u629E\u80A2\u306A\u3057",
56
+ "tree-combobox-single-load-error": "\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
57
+ "tree-combobox-single-retry": "\u518D\u8A66\u884C",
58
+ "tree-combobox-single-readonly-empty": "\u2014"
59
+ }
60
+ }
61
+ });
62
+ const { state, getAt, setAt } = useFormState();
63
+ const inherited = injectCELContext();
64
+ const $cel = (expression, context) => _rawCel(expression, { ...celBindings(inherited), ...context });
65
+ const labelText = computed(() => getLocalizedText(props.config.label, locale.value));
66
+ const tooltipText = computed(
67
+ () => props.config.tooltip ? getLocalizedText(props.config.tooltip, locale.value) : void 0
68
+ );
69
+ const placeholderText = computed(
70
+ () => props.config.placeholder ? getLocalizedText(props.config.placeholder, locale.value) : t("tree-combobox-single-placeholder")
71
+ );
72
+ function evalBool(expression, label) {
73
+ if (!expression) return false;
74
+ try {
75
+ return Effect.runSync($cel(expression, { form: state.value ?? {} }));
76
+ } catch (err) {
77
+ console.error(`[shwfed-form] failed to evaluate ${label} for ${props.fieldId}:`, err);
78
+ return false;
79
+ }
80
+ }
81
+ const isDisabled = computed(() => evalBool(props.config.disabled, "disabled"));
82
+ const formReadonly = useFormReadonly();
83
+ const isReadonly = computed(
84
+ () => props.config.readonly != null ? evalBool(props.config.readonly, "readonly") : formReadonly.value
85
+ );
86
+ const effectiveReadonly = computed(() => isReadonly.value || props.config.derived?.mode === "formula");
87
+ const uncontrolled = ref(void 0);
88
+ const model = computed({
89
+ get: () => {
90
+ const path = props.config.binding;
91
+ const raw = path == null ? uncontrolled.value : getAt(path);
92
+ if (raw == null) return void 0;
93
+ return String(raw);
94
+ },
95
+ set: (next) => {
96
+ const v = next == null ? void 0 : String(next);
97
+ const path = props.config.binding;
98
+ if (path == null) {
99
+ uncontrolled.value = v;
100
+ return;
101
+ }
102
+ setAt(path, v);
103
+ }
104
+ });
105
+ function nodeCtx(raw) {
106
+ return { form: state.value ?? {}, node: raw };
107
+ }
108
+ function nodeKey(raw) {
109
+ try {
110
+ return String(Effect.runSync($cel(props.config.nodeKey, nodeCtx(raw))));
111
+ } catch (err) {
112
+ console.error(`[shwfed-form] failed to evaluate nodeKey for ${props.fieldId}:`, err);
113
+ return "";
114
+ }
115
+ }
116
+ function nodeChildrenList(raw) {
117
+ let v;
118
+ try {
119
+ v = Effect.runSync($cel(props.config.nodeChildren, nodeCtx(raw)));
120
+ } catch (err) {
121
+ console.error(`[shwfed-form] failed to evaluate nodeChildren for ${props.fieldId}:`, err);
122
+ return void 0;
123
+ }
124
+ if (v == null) return void 0;
125
+ if (!Array.isArray(v)) return void 0;
126
+ return v;
127
+ }
128
+ function safeInterpolate(tpl, raw) {
129
+ try {
130
+ return interpolateMarkdown(tpl, $cel, nodeCtx(raw));
131
+ } catch (err) {
132
+ console.error(`[shwfed-form] failed to interpolate node text for ${props.fieldId}:`, err);
133
+ return tpl;
134
+ }
135
+ }
136
+ function wrappedLabelText(w) {
137
+ const tpl = getLocalizedText(props.config.nodeLabel, locale.value) ?? "";
138
+ return tpl ? safeInterpolate(tpl, w.raw) : "";
139
+ }
140
+ function wrappedTooltipText(w) {
141
+ if (!props.config.nodeTooltip) return void 0;
142
+ const tpl = getLocalizedText(props.config.nodeTooltip, locale.value);
143
+ return tpl ? safeInterpolate(tpl, w.raw) : void 0;
144
+ }
145
+ function wrappedSelectable(w, _depth) {
146
+ if (isDisabled.value) return false;
147
+ const expr = props.config.nodeSelectable;
148
+ if (!expr) return true;
149
+ try {
150
+ return Effect.runSync($cel(expr, nodeCtx(w.raw)));
151
+ } catch {
152
+ return false;
153
+ }
154
+ }
155
+ const rawRoots = shallowRef([]);
156
+ const loading = ref(false);
157
+ const fetchError = ref(null);
158
+ async function fetchTree() {
159
+ const dataSource = props.config.dataSource;
160
+ if (!dataSource) {
161
+ rawRoots.value = [];
162
+ return;
163
+ }
164
+ const effect = Effect.gen(function* () {
165
+ let jsonOpt = Option.none();
166
+ if (dataSource.request) {
167
+ const builder = yield* $cel(dataSource.request, {
168
+ form: state.value ?? {}
169
+ });
170
+ const response = yield* builder.json();
171
+ jsonOpt = Option.some(response);
172
+ }
173
+ const dataRaw = yield* $cel(dataSource.data, {
174
+ form: state.value ?? {},
175
+ json: jsonOpt
176
+ });
177
+ return Array.isArray(dataRaw) ? dataRaw : [];
178
+ });
179
+ const program = Effect.gen(function* () {
180
+ const showMaskFiber = yield* Effect.fork(
181
+ Effect.sync(() => {
182
+ loading.value = true;
183
+ }).pipe(Effect.delay("30 millis"))
184
+ );
185
+ return yield* Effect.ensuring(effect, Fiber.interrupt(showMaskFiber));
186
+ }).pipe(
187
+ Effect.ensuring(Effect.sync(() => {
188
+ loading.value = false;
189
+ }))
190
+ );
191
+ try {
192
+ const result = await Effect.runPromise(Effect.provide(program, Fetch.layer));
193
+ rawRoots.value = result;
194
+ fetchError.value = null;
195
+ } catch (e) {
196
+ console.warn("[shwfed-form] tree-combobox dataSource fetch failed", e);
197
+ fetchError.value = e;
198
+ }
199
+ }
200
+ watch(
201
+ () => [props.config.dataSource?.request, props.config.dataSource?.data],
202
+ () => {
203
+ void fetchTree();
204
+ },
205
+ { immediate: true }
206
+ );
207
+ const roots = computed(
208
+ () => wrapStructuralAll(rawRoots.value, {
209
+ nodeKey,
210
+ nodeChildren: nodeChildrenList
211
+ })
212
+ );
213
+ const triggerLabel = computed(() => {
214
+ const k = model.value;
215
+ if (!k) return "";
216
+ const path = findWrappedPath(roots.value, k);
217
+ if (!path || path.length === 0) return "";
218
+ const leaf = path[path.length - 1];
219
+ return wrappedLabelText(leaf);
220
+ });
221
+ const initialExpanded = computed(() => {
222
+ if (!props.config.expandAll) return [];
223
+ const out = [];
224
+ const stack = [...roots.value];
225
+ while (stack.length) {
226
+ const n = stack.pop();
227
+ if (n.kind === "branch") {
228
+ out.push(n.key);
229
+ stack.push(...n.children);
230
+ }
231
+ }
232
+ return out;
233
+ });
234
+ const filterQuery = ref("");
235
+ function filterPredicate(w, query) {
236
+ const q = query.trim().toLowerCase();
237
+ if (!q) return true;
238
+ return wrappedLabelText(w).trim().toLowerCase().includes(q);
239
+ }
240
+ const open = ref(false);
241
+ function handleUpdate(next) {
242
+ const k = typeof next === "string" ? next : void 0;
243
+ model.value = k;
244
+ if (k) open.value = false;
245
+ }
246
+ const showClear = computed(
247
+ () => !isDisabled.value && !loading.value && !!model.value
248
+ );
249
+ function handleClear() {
250
+ model.value = void 0;
251
+ open.value = false;
252
+ }
253
+ const hoveredKey = ref(null);
254
+ watch(open, (isOpen) => {
255
+ if (!isOpen) hoveredKey.value = null;
256
+ });
257
+ function collectTooltipNodes(out, siblings) {
258
+ for (const n of siblings) {
259
+ if (wrappedTooltipText(n)) out.push(n.key);
260
+ if (n.kind === "branch") collectTooltipNodes(out, n.children);
261
+ }
262
+ }
263
+ const anyHasTooltip = computed(() => {
264
+ if (!props.config.nodeTooltip) return false;
265
+ const out = [];
266
+ collectTooltipNodes(out, roots.value);
267
+ return out.length > 0;
268
+ });
269
+ const hoveredTooltip = computed(() => {
270
+ const k = hoveredKey.value;
271
+ if (!k) return void 0;
272
+ const path = findWrappedPath(roots.value, k);
273
+ if (!path || path.length === 0) return void 0;
274
+ return wrappedTooltipText(path[path.length - 1]);
275
+ });
276
+ </script>
277
+
278
+ <template>
279
+ <Field
280
+ :orientation="config.orientation ?? DEFAULT_FIELD_ORIENTATION"
281
+ :data-disabled="isDisabled || void 0"
282
+ >
283
+ <FieldLabel
284
+ v-if="labelText"
285
+ :for="fieldId"
286
+ class="text-xs text-zinc-500"
287
+ >
288
+ <template
289
+ v-if="tooltipText"
290
+ #tooltip
291
+ >
292
+ <Markdown
293
+ :source="tooltipText"
294
+ class="prose prose-xs prose-zinc"
295
+ />
296
+ </template>
297
+ {{ labelText }}
298
+ </FieldLabel>
299
+
300
+ <div
301
+ v-if="effectiveReadonly"
302
+ class="min-h-9 py-1.5 text-sm text-zinc-700"
303
+ >
304
+ {{ triggerLabel || t("tree-combobox-single-readonly-empty") }}
305
+ </div>
306
+
307
+ <Popover
308
+ v-else
309
+ v-model:open="open"
310
+ >
311
+ <PopoverAnchor as-child>
312
+ <InputGroup
313
+ class="group/tree-combobox-single"
314
+ :data-disabled="isDisabled ? 'true' : void 0"
315
+ >
316
+ <PopoverTrigger as-child>
317
+ <InputGroupInput
318
+ :id="fieldId"
319
+ :model-value="triggerLabel"
320
+ :disabled="isDisabled"
321
+ :placeholder="placeholderText"
322
+ class="cursor-pointer text-left"
323
+ readonly
324
+ />
325
+ </PopoverTrigger>
326
+ <InputGroupAddon
327
+ v-if="loading"
328
+ align="inline-end"
329
+ data-slot="tree-combobox-single-loading"
330
+ class="text-zinc-400"
331
+ >
332
+ <Icon
333
+ icon="fluent:spinner-ios-20-regular"
334
+ class="animate-spin"
335
+ />
336
+ </InputGroupAddon>
337
+ <InputGroupAddon
338
+ v-else-if="showClear"
339
+ align="inline-end"
340
+ class="[@media(hover:hover)]:opacity-0 transition-opacity group-hover/tree-combobox-single:opacity-100 focus-within:opacity-100"
341
+ >
342
+ <InputGroupButton
343
+ size="icon-xs"
344
+ data-slot="tree-combobox-single-clear"
345
+ class="text-zinc-500 hover:text-zinc-700"
346
+ tabindex="-1"
347
+ @mousedown.prevent
348
+ @click.stop="handleClear"
349
+ >
350
+ <Icon icon="fluent:dismiss-20-regular" />
351
+ </InputGroupButton>
352
+ </InputGroupAddon>
353
+ </InputGroup>
354
+ </PopoverAnchor>
355
+ <PopoverContent
356
+ class="p-0"
357
+ :style="{ width: 'var(--reka-popover-trigger-width)' }"
358
+ >
359
+ <div
360
+ data-slot="tree-combobox-single-search"
361
+ class="flex h-9 items-center gap-2 border-b border-zinc-200 px-3"
362
+ >
363
+ <Icon
364
+ icon="fluent:search-20-filled"
365
+ class="size-3.5 shrink-0 opacity-50"
366
+ />
367
+ <input
368
+ v-model="filterQuery"
369
+ :disabled="isDisabled"
370
+ :placeholder="t('tree-combobox-single-search-placeholder')"
371
+ class="flex h-9 w-full bg-transparent text-sm outline-hidden placeholder:text-zinc-500 disabled:cursor-not-allowed disabled:opacity-50"
372
+ >
373
+ </div>
374
+ <div class="flex flex-col p-1">
375
+ <div
376
+ v-if="fetchError && roots.length === 0"
377
+ class="min-h-9 px-2 py-1.5 text-sm text-red-500"
378
+ >
379
+ {{ t("tree-combobox-single-load-error") }}
380
+ </div>
381
+ <div
382
+ v-else-if="loading && roots.length === 0"
383
+ class="flex flex-col gap-1.5 px-2 py-1"
384
+ aria-busy="true"
385
+ >
386
+ <Skeleton class="h-5 w-2/3" />
387
+ <Skeleton class="h-5 w-1/2" />
388
+ <Skeleton class="h-5 w-3/5" />
389
+ </div>
390
+
391
+ <UiTree
392
+ v-else
393
+ :roots="roots"
394
+ :get-key="(w) => w.key"
395
+ :get-children="getWrappedChildren"
396
+ selection-mode="single"
397
+ :model-value="model"
398
+ :selectable="wrappedSelectable"
399
+ :filter-predicate="filterPredicate"
400
+ :filter-query="filterQuery"
401
+ :initial-expanded="initialExpanded"
402
+ :show-focused-row="false"
403
+ :class="isDisabled ? 'pointer-events-none opacity-60' : void 0"
404
+ class="max-h-72 overflow-y-auto"
405
+ @update:model-value="handleUpdate"
406
+ >
407
+ <template #node="{ node, selected }">
408
+ <span
409
+ class="flex flex-1 min-w-0 items-center justify-between gap-2"
410
+ @mouseenter="hoveredKey = node.key"
411
+ @focusin="hoveredKey = node.key"
412
+ >
413
+ <Markdown
414
+ :source="wrappedLabelText(node)"
415
+ class="prose prose-sm prose-zinc text-zinc-700 min-w-0"
416
+ />
417
+ <Icon
418
+ v-if="selected"
419
+ icon="fluent:checkmark-20-regular"
420
+ class="size-3 shrink-0 text-zinc-700"
421
+ />
422
+ </span>
423
+ </template>
424
+
425
+ <template #empty>
426
+ <div class="min-h-9 px-2 py-1.5 text-sm text-zinc-400">
427
+ {{ t("tree-combobox-single-empty") }}
428
+ </div>
429
+ </template>
430
+
431
+ <template #error="{ error, retry }">
432
+ <span class="inline-flex items-center gap-1 text-xs text-red-500">
433
+ {{ t("tree-combobox-single-load-error") }}
434
+ <button
435
+ type="button"
436
+ class="underline hover:text-red-600"
437
+ @click.stop="retry"
438
+ >
439
+ {{ t("tree-combobox-single-retry") }}
440
+ </button>
441
+ <span class="sr-only">{{ String(error) }}</span>
442
+ </span>
443
+ </template>
444
+ </UiTree>
445
+ </div>
446
+ <div
447
+ v-if="anyHasTooltip && hoveredTooltip"
448
+ data-slot="tree-combobox-single-tooltip"
449
+ class="border-t border-zinc-200 px-3 py-2"
450
+ >
451
+ <Markdown
452
+ :source="hoveredTooltip"
453
+ block
454
+ class="prose prose-sm prose-zinc"
455
+ />
456
+ </div>
457
+ </PopoverContent>
458
+ </Popover>
459
+ </Field>
460
+ </template>
@@ -0,0 +1,8 @@
1
+ import type { Value } from './schema.js';
2
+ type __VLS_Props = {
3
+ fieldId: string;
4
+ config: Value;
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
@@ -0,0 +1,92 @@
1
+ import { Schema } from 'effect';
2
+ import type { Environment } from '../../../../../vendor/cel-js/lib/index.js';
3
+ export declare const type: "com.shwfed.form.field.tree.combobox.single";
4
+ export declare const compatibilityDate: "2026-05-26";
5
+ export declare const metadata: {
6
+ readonly name: "下拉树(单选)";
7
+ readonly icon: "fluent:tree-evergreen-20-regular";
8
+ readonly w: {
9
+ readonly initial: 8;
10
+ readonly min: 4;
11
+ readonly max: number;
12
+ };
13
+ readonly h: {
14
+ readonly initial: 2;
15
+ readonly min: 2;
16
+ readonly max: 2;
17
+ };
18
+ };
19
+ export declare function schema(configure: (env: Environment) => void): Schema.Struct<{
20
+ label: Schema.optional<Schema.TupleType<readonly [Schema.Struct<{
21
+ locale: Schema.Literal<["zh"]>;
22
+ message: Schema.SchemaClass<string, string, never>;
23
+ }>], [Schema.Struct<{
24
+ locale: Schema.Literal<["ja", "en", "ko"]>;
25
+ message: Schema.SchemaClass<string, string, never>;
26
+ }>]>>;
27
+ placeholder: Schema.optional<Schema.TupleType<readonly [Schema.Struct<{
28
+ locale: Schema.Literal<["zh"]>;
29
+ message: Schema.SchemaClass<string, string, never>;
30
+ }>], [Schema.Struct<{
31
+ locale: Schema.Literal<["ja", "en", "ko"]>;
32
+ message: Schema.SchemaClass<string, string, never>;
33
+ }>]>>;
34
+ tooltip: Schema.optional<Schema.TupleType<readonly [Schema.Struct<{
35
+ locale: Schema.Literal<["zh"]>;
36
+ message: Schema.SchemaClass<string, string, never>;
37
+ }>], [Schema.Struct<{
38
+ locale: Schema.Literal<["ja", "en", "ko"]>;
39
+ message: Schema.SchemaClass<string, string, never>;
40
+ }>]>>;
41
+ orientation: Schema.optional<Schema.Literal<["vertical", "floating"]>>;
42
+ binding: Schema.optional<Schema.refine<string, typeof Schema.String>>;
43
+ disabled: Schema.optional<Schema.Schema<string, string, never>>;
44
+ readonly: Schema.optional<Schema.Schema<string, string, never>>;
45
+ derived: Schema.optional<Schema.Struct<{
46
+ mode: Schema.Literal<["formula", "prefill"]>;
47
+ expression: Schema.Schema<string, string, never>;
48
+ }>>;
49
+ dataSource: Schema.Struct<{
50
+ request: Schema.optional<Schema.Schema<string, string, never>>;
51
+ data: Schema.Schema<string, string, never>;
52
+ }>;
53
+ nodeKey: Schema.Schema<string, string, never>;
54
+ nodeChildren: Schema.Schema<string, string, never>;
55
+ nodeLabel: Schema.refine<readonly [{
56
+ readonly locale: "zh";
57
+ readonly message: string;
58
+ }, ...{
59
+ readonly locale: "en" | "ja" | "ko";
60
+ readonly message: string;
61
+ }[]], Schema.TupleType<readonly [Schema.Struct<{
62
+ locale: Schema.Literal<["zh"]>;
63
+ message: Schema.SchemaClass<string, string, never>;
64
+ }>], [Schema.Struct<{
65
+ locale: Schema.Literal<["ja", "en", "ko"]>;
66
+ message: Schema.SchemaClass<string, string, never>;
67
+ }>]>>;
68
+ nodeTooltip: Schema.optional<Schema.refine<readonly [{
69
+ readonly locale: "zh";
70
+ readonly message: string;
71
+ }, ...{
72
+ readonly locale: "en" | "ja" | "ko";
73
+ readonly message: string;
74
+ }[]], Schema.TupleType<readonly [Schema.Struct<{
75
+ locale: Schema.Literal<["zh"]>;
76
+ message: Schema.SchemaClass<string, string, never>;
77
+ }>], [Schema.Struct<{
78
+ locale: Schema.Literal<["ja", "en", "ko"]>;
79
+ message: Schema.SchemaClass<string, string, never>;
80
+ }>]>>>;
81
+ nodeSelectable: Schema.optional<Schema.Schema<string, string, never>>;
82
+ expandAll: Schema.optionalWith<typeof Schema.Boolean, {
83
+ default: () => false;
84
+ }>;
85
+ id: Schema.refine<string, typeof Schema.String>;
86
+ displayName: Schema.optional<Schema.SchemaClass<string, string, never>>;
87
+ hidden: Schema.optional<Schema.Schema<string, string, never>>;
88
+ type: Schema.Literal<["com.shwfed.form.field.tree.combobox.single"]>;
89
+ compatibilityDate: Schema.Literal<["2026-05-26"]>;
90
+ }>;
91
+ export type Value = Schema.Schema.Type<ReturnType<typeof schema>>;
92
+ export declare function defaults(): Partial<Value>;
@@ -0,0 +1,104 @@
1
+ import { Schema } from "effect";
2
+ import { Expression, LocaleMarkdown } from "../../../../../share/expression.js";
3
+ import { Locale } from "../../../../../share/locale.js";
4
+ import { DataSource } from "../../../../table/schema.js";
5
+ import { commonFieldFields, derivedField, FieldOrientationSchema } from "../../../utils/common.js";
6
+ export const type = "com.shwfed.form.field.tree.combobox.single";
7
+ export const compatibilityDate = "2026-05-26";
8
+ export const metadata = {
9
+ name: "\u4E0B\u62C9\u6811\uFF08\u5355\u9009\uFF09",
10
+ icon: "fluent:tree-evergreen-20-regular",
11
+ w: { initial: 8, min: 4, max: Infinity },
12
+ h: { initial: 2, min: 2, max: 2 }
13
+ };
14
+ const NODE_VAR = {
15
+ type: "dyn",
16
+ label: "\u5F53\u524D\u8282\u70B9",
17
+ description: "`\u6570\u636E\u6E90` \u8FD4\u56DE\u7684\u8282\u70B9\uFF1B\u7531\u6811\u9010\u5C42\u5411\u4E0B\u8BFB\u53D6"
18
+ };
19
+ const isListLike = (t) => t === "dyn" || t.startsWith("list") || t.startsWith("optional");
20
+ const isKeyType = (t) => t === "string" || t === "number" || t === "dyn";
21
+ function withNode(configure) {
22
+ return (env) => {
23
+ configure(env);
24
+ env.registerVariable("node", NODE_VAR.type, { description: NODE_VAR.description });
25
+ };
26
+ }
27
+ export function schema(configure) {
28
+ const CelBool = Expression({ configure, resultType: "bool" });
29
+ const CelNodeKey = Expression({ configure: withNode(configure), resultType: isKeyType });
30
+ const CelNodeChildren = Expression({ configure: withNode(configure), resultType: isListLike });
31
+ const CelNodeBool = Expression({ configure: withNode(configure), resultType: "bool" });
32
+ const NodeLocaleMd = LocaleMarkdown({ configure: withNode(configure) });
33
+ return Schema.Struct({
34
+ type: Schema.Literal(type),
35
+ compatibilityDate: Schema.Literal(compatibilityDate),
36
+ ...commonFieldFields(configure),
37
+ label: Schema.optional(Locale.annotations({
38
+ title: "\u6807\u7B7E",
39
+ description: "\u5B57\u6BB5\u524D\u5C55\u793A\u7684\u6587\u672C\uFF1B\u7559\u7A7A\u5219\u4E0D\u6E32\u67D3\u6807\u7B7E"
40
+ })),
41
+ placeholder: Schema.optional(Locale.annotations({
42
+ title: "\u5360\u4F4D\u7B26",
43
+ description: "\u672A\u9009\u4E2D\u4EFB\u4F55\u9009\u9879\u65F6\u89E6\u53D1\u5668\u4E2D\u7684\u5360\u4F4D\u6587\u672C"
44
+ })),
45
+ tooltip: Schema.optional(Locale.annotations({
46
+ title: "\u63D0\u793A",
47
+ description: "\u9F20\u6807\u60AC\u505C\u5728\u6807\u7B7E\u4E0A\u65F6\u5C55\u793A\u7684\u8BF4\u660E"
48
+ })),
49
+ orientation: Schema.optional(FieldOrientationSchema),
50
+ binding: Schema.optional(Schema.String.pipe(Schema.minLength(1)).annotations({
51
+ title: "\u7ED1\u5B9A\u8DEF\u5F84",
52
+ description: "\u5199\u5165\u8868\u5355\u72B6\u6001\u7684 `dot-prop` \u8DEF\u5F84\uFF1B\u7559\u7A7A\u5219\u4E3A\u975E\u53D7\u63A7\u5B57\u6BB5"
53
+ })),
54
+ disabled: Schema.optional(CelBool.annotations({
55
+ title: "\u7981\u7528\u6761\u4EF6",
56
+ description: "\u8FD4\u56DE `true` \u65F6\u4ECD\u6E32\u67D3\u4F46\u4E0D\u53EF\u9009\u62E9"
57
+ })),
58
+ readonly: Schema.optional(CelBool.annotations({
59
+ title: "\u53EA\u8BFB\u6761\u4EF6",
60
+ description: "\u8FD4\u56DE `true` \u65F6\u4EC5\u4EE5\u7EAF\u6587\u672C\u5C55\u793A\u5F53\u524D\u5DF2\u9009\u9879\u7684\u6807\u7B7E"
61
+ })),
62
+ derived: derivedField(configure, isKeyType),
63
+ dataSource: DataSource(configure).annotations({
64
+ title: "\u6570\u636E\u6E90",
65
+ description: "\u8FD4\u56DE\u5B8C\u6574\u6811\uFF08\u6839\u8282\u70B9\u5217\u8868\uFF09\u7684\u6570\u636E\u6E90\uFF1B\u901A\u8FC7 `\u8282\u70B9\u5B50\u7EA7` \u8868\u8FBE\u5F0F\u9010\u5C42\u5411\u4E0B\u8BFB\u53D6"
66
+ }),
67
+ nodeKey: CelNodeKey.annotations({
68
+ title: "\u8282\u70B9 ID",
69
+ description: "\u4E3A\u6BCF\u4E2A\u8282\u70B9\u8BA1\u7B97\u7A33\u5B9A\u552F\u4E00 ID \u7684 CEL \u8868\u8FBE\u5F0F\uFF0C\u53EF\u8BBF\u95EE `node`\uFF1B\u8FD0\u884C\u65F6\u4EE5\u5B57\u7B26\u4E32\u5F62\u5F0F\u5B58\u50A8"
70
+ }),
71
+ nodeChildren: CelNodeChildren.annotations({
72
+ title: "\u8282\u70B9\u5B50\u7EA7",
73
+ description: "\u8FD4\u56DE\u5F53\u524D\u8282\u70B9\u5B50\u7EA7\u5217\u8868\u7684 CEL \u8868\u8FBE\u5F0F\uFF1B\u8FD4\u56DE `none`/`null` \u6216\u7A7A\u6570\u7EC4\u65F6\u8BE5\u8282\u70B9\u89C6\u4E3A\u53F6\u5B50\uFF08\u7EC8\u7AEF\u8282\u70B9\uFF09"
74
+ }),
75
+ nodeLabel: NodeLocaleMd.annotations({
76
+ title: "\u8282\u70B9\u6807\u7B7E",
77
+ description: "\u8282\u70B9\u5C55\u793A\u7684\u672C\u5730\u5316\u6587\u672C\uFF0C\u652F\u6301 Markdown \u4E0E `{{ node.foo }}` / `{{ form.foo }}` \u63D2\u503C"
78
+ }),
79
+ nodeTooltip: Schema.optional(NodeLocaleMd.annotations({
80
+ title: "\u8282\u70B9\u63D0\u793A",
81
+ description: "\u9F20\u6807\u60AC\u505C\u5728\u8282\u70B9\u4E0A\u65F6\u5C55\u793A\u7684\u672C\u5730\u5316\u63D0\u793A"
82
+ })),
83
+ nodeSelectable: Schema.optional(CelNodeBool.annotations({
84
+ title: "\u8282\u70B9\u53EF\u9009\u6761\u4EF6",
85
+ description: "\u8FD4\u56DE `true` \u8868\u793A\u8BE5\u8282\u70B9\u53EF\u88AB\u9009\u4E2D\uFF1B\u9ED8\u8BA4\u5168\u90E8\u53EF\u9009"
86
+ })),
87
+ expandAll: Schema.optionalWith(Schema.Boolean, { default: () => false }).annotations({
88
+ title: "\u9ED8\u8BA4\u5168\u90E8\u5C55\u5F00",
89
+ description: "\u5F00\u542F\u540E\u6302\u8F7D\u65F6\u5C55\u5F00\u6240\u6709\u975E\u53F6\u5B50\u8282\u70B9"
90
+ })
91
+ }).annotations({
92
+ title: "TreeComboboxSingleField",
93
+ description: "\u57FA\u4E8E\u6811\u5F62\u6570\u636E\u7684\u4E0B\u62C9\u5355\u9009\u8F93\u5165"
94
+ });
95
+ }
96
+ export function defaults() {
97
+ return {
98
+ dataSource: { data: "[]" },
99
+ nodeKey: "string(node.id)",
100
+ nodeChildren: "has(node.children) ? node.children : null",
101
+ nodeLabel: [{ locale: "zh", message: "{{ node.label }}" }],
102
+ expandAll: false
103
+ };
104
+ }