@shwfed/config 2.3.28 → 2.4.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.
Files changed (146) hide show
  1. package/dist/mcp.mjs +3128 -1272
  2. package/dist/module.json +1 -1
  3. package/dist/preview/assets/{config-CQHS6cZe.js → config-BcQQl4v6.js} +1 -1
  4. package/dist/preview/assets/{config-fvkC2rB8.js → config-BdFIFUa_.js} +1 -1
  5. package/dist/preview/assets/{config-DDfTl9Cs.js → config-Bi9F-Jdh.js} +1 -1
  6. package/dist/preview/assets/{config-CJHPt8Gx.js → config-Bxkq2ZRm.js} +1 -1
  7. package/dist/preview/assets/{config-D0_1yZdF.js → config-C32yfrlg.js} +1 -1
  8. package/dist/preview/assets/{config--PcXQV_r.js → config-CHHX7vhb.js} +1 -1
  9. package/dist/preview/assets/{config-5KVDXgUF.js → config-CZ0f5xdI.js} +1 -1
  10. package/dist/preview/assets/{config-B5avpKJE.js → config-D9xGgFnF.js} +1 -1
  11. package/dist/preview/assets/{config-CNo3isHa.js → config-Ddh8pxIi.js} +1 -1
  12. package/dist/preview/assets/{definition.vue_vue_type_script_setup_true_lang-RM-qDh0R.js → definition.vue_vue_type_script_setup_true_lang-C_cjxvm1.js} +1 -1
  13. package/dist/preview/assets/{index-a2QwAots.css → index-BqOX70Hd.css} +1 -1
  14. package/dist/preview/assets/index-D-VR1i8D.js +659 -0
  15. package/dist/preview/assets/index-ihZGlPdX.js +1 -0
  16. package/dist/preview/assets/{runtime-BPjZQmcY.js → runtime-Bn8mqeDH.js} +1 -1
  17. package/dist/preview/assets/{runtime-DcrzodsN.js → runtime-Cc_Wk3o-.js} +1 -1
  18. package/dist/preview/assets/{runtime-BGTWf-O7.js → runtime-CttAjIgg.js} +1 -1
  19. package/dist/preview/assets/{runtime-Dy4ZmQ-n.js → runtime-Cx4f2UTl.js} +1 -1
  20. package/dist/preview/assets/{runtime-CCbyrqQT.js → runtime-D1dESjXR.js} +1 -1
  21. package/dist/preview/assets/{runtime-C_XX6a0C.js → runtime-DIEP1Xbh.js} +1 -1
  22. package/dist/preview/assets/{runtime-CtqwtTE_.js → runtime-DKceWuBx.js} +1 -1
  23. package/dist/preview/assets/{runtime-Dr_10emf.js → runtime-Dhid9O5c.js} +1 -1
  24. package/dist/preview/assets/{runtime-Bq3fmxeF.js → runtime-YMiqi6WY.js} +1 -1
  25. package/dist/preview/index.html +2 -2
  26. package/dist/runtime/components/block-layout-editor/index.d.vue.ts +10 -2
  27. package/dist/runtime/components/block-layout-editor/index.vue +44 -8
  28. package/dist/runtime/components/block-layout-editor/index.vue.d.ts +10 -2
  29. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.form/config.d.vue.ts +2 -0
  30. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.form/config.vue.d.ts +2 -0
  31. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.form/runtime.d.vue.ts +2 -0
  32. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.form/runtime.vue.d.ts +2 -0
  33. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.form/schema.d.ts +2 -0
  34. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/config.d.vue.ts +2 -0
  35. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/config.vue.d.ts +2 -0
  36. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/runtime.d.vue.ts +2 -0
  37. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/runtime.vue.d.ts +2 -0
  38. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/schema.d.ts +3 -0
  39. package/dist/runtime/components/config/config.vue +35 -0
  40. package/dist/runtime/components/config/use-editor.d.ts +11 -1
  41. package/dist/runtime/components/config/use-editor.js +27 -1
  42. package/dist/runtime/components/form/config.vue +32 -0
  43. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/config.d.vue.ts +163 -0
  44. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/config.vue +745 -0
  45. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/config.vue.d.ts +163 -0
  46. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/runtime.d.vue.ts +8 -0
  47. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/runtime.vue +383 -0
  48. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/runtime.vue.d.ts +8 -0
  49. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/schema.d.ts +264 -0
  50. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/schema.js +183 -0
  51. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/config.d.vue.ts +163 -0
  52. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/config.vue +745 -0
  53. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/config.vue.d.ts +163 -0
  54. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/runtime.d.vue.ts +8 -0
  55. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/runtime.vue +402 -0
  56. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/runtime.vue.d.ts +8 -0
  57. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/schema.d.ts +264 -0
  58. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/schema.js +209 -0
  59. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/config.d.vue.ts +129 -0
  60. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/config.vue +618 -0
  61. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/config.vue.d.ts +129 -0
  62. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/runtime.d.vue.ts +8 -0
  63. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/runtime.vue +501 -0
  64. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/runtime.vue.d.ts +8 -0
  65. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/schema.d.ts +99 -0
  66. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/schema.js +133 -0
  67. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/config.d.vue.ts +127 -0
  68. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/config.vue +550 -0
  69. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/config.vue.d.ts +127 -0
  70. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/runtime.d.vue.ts +8 -0
  71. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/runtime.vue +496 -0
  72. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/runtime.vue.d.ts +8 -0
  73. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/schema.d.ts +96 -0
  74. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/schema.js +125 -0
  75. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/config.d.vue.ts +133 -0
  76. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/config.vue +605 -0
  77. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/config.vue.d.ts +133 -0
  78. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/runtime.d.vue.ts +8 -0
  79. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/runtime.vue +401 -0
  80. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/runtime.vue.d.ts +8 -0
  81. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/schema.d.ts +102 -0
  82. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/schema.js +142 -0
  83. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/config.d.vue.ts +131 -0
  84. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/config.vue +560 -0
  85. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/config.vue.d.ts +131 -0
  86. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/runtime.d.vue.ts +8 -0
  87. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/runtime.vue +395 -0
  88. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/runtime.vue.d.ts +8 -0
  89. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/schema.d.ts +96 -0
  90. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/schema.js +118 -0
  91. package/dist/runtime/components/form/fields/2026-05-28/tree-combobox-shared.d.ts +35 -0
  92. package/dist/runtime/components/form/fields/2026-05-28/tree-combobox-shared.js +31 -0
  93. package/dist/runtime/components/form/index.vue +7 -5
  94. package/dist/runtime/components/form/schema.d.ts +4 -0
  95. package/dist/runtime/components/form/schema.js +4 -0
  96. package/dist/runtime/components/form/unit-config.vue +45 -1
  97. package/dist/runtime/components/table/columns/2026-04-14/com.shwfed.table.column.select/config.vue +0 -22
  98. package/dist/runtime/components/table/columns/2026-04-14/com.shwfed.table.column.select/header.vue +3 -15
  99. package/dist/runtime/components/table/columns/2026-04-14/com.shwfed.table.column.select/schema.d.ts +0 -1
  100. package/dist/runtime/components/table/columns/2026-04-14/com.shwfed.table.column.select/schema.js +0 -4
  101. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/config.d.vue.ts +183 -0
  102. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/config.vue +931 -0
  103. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/config.vue.d.ts +183 -0
  104. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/runtime.d.vue.ts +9 -0
  105. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/runtime.vue +463 -0
  106. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/runtime.vue.d.ts +9 -0
  107. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/schema.d.ts +283 -0
  108. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/schema.js +275 -0
  109. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/config.d.vue.ts +183 -0
  110. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/config.vue +931 -0
  111. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/config.vue.d.ts +183 -0
  112. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/runtime.d.vue.ts +9 -0
  113. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/runtime.vue +414 -0
  114. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/runtime.vue.d.ts +9 -0
  115. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/schema.d.ts +283 -0
  116. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/schema.js +275 -0
  117. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/config.d.vue.ts +133 -0
  118. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/config.vue +632 -0
  119. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/config.vue.d.ts +133 -0
  120. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/runtime.d.vue.ts +9 -0
  121. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/runtime.vue +461 -0
  122. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/runtime.vue.d.ts +9 -0
  123. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/schema.d.ts +93 -0
  124. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/schema.js +161 -0
  125. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/config.d.vue.ts +131 -0
  126. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/config.vue +563 -0
  127. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/config.vue.d.ts +131 -0
  128. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/runtime.d.vue.ts +9 -0
  129. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/runtime.vue +443 -0
  130. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/runtime.vue.d.ts +9 -0
  131. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/schema.d.ts +90 -0
  132. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/schema.js +153 -0
  133. package/dist/runtime/components/table/columns/2026-05-28/tree-combobox-shared.d.ts +35 -0
  134. package/dist/runtime/components/table/columns/2026-05-28/tree-combobox-shared.js +31 -0
  135. package/dist/runtime/components/table/config.vue +55 -82
  136. package/dist/runtime/components/table/schema.d.ts +4 -0
  137. package/dist/runtime/components/ui/command/CommandItem.d.vue.ts +7 -0
  138. package/dist/runtime/components/ui/command/CommandItem.vue +13 -4
  139. package/dist/runtime/components/ui/command/CommandItem.vue.d.ts +7 -0
  140. package/dist/runtime/share/clipboard.d.ts +26 -0
  141. package/dist/runtime/share/clipboard.js +82 -0
  142. package/dist/runtime/share/layout.d.ts +4 -0
  143. package/dist/runtime/share/layout.js +35 -0
  144. package/package.json +1 -1
  145. package/dist/preview/assets/index-DNd8J9Zv.js +0 -643
  146. package/dist/preview/assets/index-DrIMqXAa.js +0 -1
@@ -0,0 +1,395 @@
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 { Skeleton } from "../../../../ui/skeleton";
14
+ import { Tree as UiTree } from "../../../../ui/tree";
15
+ import { interpolateMarkdown } from "../../../../table/utils/runtime";
16
+ import { useFormReadonly } from "../../../utils/readonly";
17
+ import { useFormState } from "../../../utils/state";
18
+ defineOptions({ name: "ShwfedTreeSingleFieldRuntime" });
19
+ const props = defineProps({
20
+ fieldId: { type: String, required: true },
21
+ config: { type: null, required: true }
22
+ });
23
+ const { locale, t } = useI18n({
24
+ inheritLocale: true,
25
+ messages: {
26
+ zh: {
27
+ "tree-single-search-label": "\u641C\u7D22",
28
+ "tree-single-search-clear": "\u6E05\u9664\u641C\u7D22",
29
+ "tree-single-load-error": "\u52A0\u8F7D\u5931\u8D25",
30
+ "tree-single-empty": "\u65E0\u53EF\u9009\u9879",
31
+ "tree-single-readonly-empty": "\u2014"
32
+ },
33
+ en: {
34
+ "tree-single-search-label": "Search",
35
+ "tree-single-search-clear": "Clear search",
36
+ "tree-single-load-error": "Failed to load",
37
+ "tree-single-empty": "No options",
38
+ "tree-single-readonly-empty": "\u2014"
39
+ },
40
+ ja: {
41
+ "tree-single-search-label": "\u691C\u7D22",
42
+ "tree-single-search-clear": "\u691C\u7D22\u3092\u30AF\u30EA\u30A2",
43
+ "tree-single-load-error": "\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
44
+ "tree-single-empty": "\u9078\u629E\u80A2\u306A\u3057",
45
+ "tree-single-readonly-empty": "\u2014"
46
+ }
47
+ }
48
+ });
49
+ const { state, getAt, setAt } = useFormState();
50
+ const inherited = injectCELContext();
51
+ const $cel = (expression, context) => _rawCel(expression, { ...celBindings(inherited), ...context });
52
+ const labelText = computed(() => getLocalizedText(props.config.label, locale.value));
53
+ const tooltipText = computed(
54
+ () => props.config.tooltip ? getLocalizedText(props.config.tooltip, locale.value) : void 0
55
+ );
56
+ function evalBool(expression, label) {
57
+ if (!expression) return false;
58
+ try {
59
+ return Effect.runSync($cel(expression, { form: state.value ?? {} }));
60
+ } catch (err) {
61
+ console.error(`[shwfed-form] failed to evaluate ${label} for ${props.fieldId}:`, err);
62
+ return false;
63
+ }
64
+ }
65
+ const isDisabled = computed(() => evalBool(props.config.disabled, "disabled"));
66
+ const formReadonly = useFormReadonly();
67
+ const isReadonly = computed(
68
+ () => props.config.readonly != null ? evalBool(props.config.readonly, "readonly") : formReadonly.value
69
+ );
70
+ const effectiveReadonly = computed(() => isReadonly.value || props.config.derived?.mode === "formula");
71
+ const uncontrolled = ref(void 0);
72
+ const model = computed({
73
+ get: () => {
74
+ const path = props.config.binding;
75
+ const raw = path == null ? uncontrolled.value : getAt(path);
76
+ return raw == null || raw === "" ? void 0 : String(raw);
77
+ },
78
+ set: (next) => {
79
+ const coerced = next == null ? void 0 : String(next);
80
+ const path = props.config.binding;
81
+ if (path == null) {
82
+ uncontrolled.value = coerced;
83
+ return;
84
+ }
85
+ setAt(path, coerced ?? "");
86
+ }
87
+ });
88
+ const roots = ref([]);
89
+ const loading = ref(false);
90
+ const fetchError = ref(null);
91
+ async function fetchTree() {
92
+ const dataSource = props.config.dataSource;
93
+ if (!dataSource) {
94
+ roots.value = [];
95
+ return;
96
+ }
97
+ const effect = Effect.gen(function* () {
98
+ let jsonOpt = Option.none();
99
+ if (dataSource.request) {
100
+ const builder = yield* $cel(dataSource.request, {
101
+ form: state.value ?? {}
102
+ });
103
+ const response = yield* builder.json();
104
+ jsonOpt = Option.some(response);
105
+ }
106
+ const dataRaw = yield* $cel(dataSource.data, {
107
+ form: state.value ?? {},
108
+ json: jsonOpt
109
+ });
110
+ return Array.isArray(dataRaw) ? dataRaw : [];
111
+ });
112
+ const program = Effect.gen(function* () {
113
+ const showMaskFiber = yield* Effect.fork(
114
+ Effect.sync(() => {
115
+ loading.value = true;
116
+ }).pipe(Effect.delay("30 millis"))
117
+ );
118
+ return yield* Effect.ensuring(effect, Fiber.interrupt(showMaskFiber));
119
+ }).pipe(
120
+ Effect.ensuring(Effect.sync(() => {
121
+ loading.value = false;
122
+ }))
123
+ );
124
+ try {
125
+ const result = await Effect.runPromise(Effect.provide(program, Fetch.layer));
126
+ roots.value = result;
127
+ fetchError.value = null;
128
+ } catch (e) {
129
+ console.warn("[shwfed-form] tree dataSource fetch failed", e);
130
+ fetchError.value = e;
131
+ }
132
+ }
133
+ watch(
134
+ () => [props.config.dataSource?.request, props.config.dataSource?.data],
135
+ () => {
136
+ void fetchTree();
137
+ },
138
+ { immediate: true }
139
+ );
140
+ function nodeCtx(node) {
141
+ return { form: state.value ?? {}, node };
142
+ }
143
+ function getKey(node) {
144
+ try {
145
+ const v = Effect.runSync($cel(props.config.nodeKey, nodeCtx(node)));
146
+ return String(v);
147
+ } catch (err) {
148
+ console.error(`[shwfed-form] failed to evaluate nodeKey for ${props.fieldId}:`, err);
149
+ return "";
150
+ }
151
+ }
152
+ function getChildren(node) {
153
+ let raw;
154
+ try {
155
+ raw = Effect.runSync($cel(props.config.nodeChildren, nodeCtx(node)));
156
+ } catch (err) {
157
+ console.error(`[shwfed-form] failed to evaluate nodeChildren for ${props.fieldId}:`, err);
158
+ return void 0;
159
+ }
160
+ if (raw == null) return void 0;
161
+ if (!Array.isArray(raw)) return void 0;
162
+ if (raw.length === 0) return void 0;
163
+ return raw;
164
+ }
165
+ function nodeSelectable(node, _depth) {
166
+ if (isDisabled.value) return false;
167
+ const expr = props.config.nodeSelectable;
168
+ if (!expr) return true;
169
+ try {
170
+ return Effect.runSync($cel(expr, nodeCtx(node)));
171
+ } catch (err) {
172
+ console.error(`[shwfed-form] failed to evaluate nodeSelectable for ${props.fieldId}:`, err);
173
+ return false;
174
+ }
175
+ }
176
+ function safeInterpolate(tpl, node) {
177
+ try {
178
+ return interpolateMarkdown(tpl, $cel, { form: state.value ?? {}, node });
179
+ } catch (err) {
180
+ console.error(`[shwfed-form] failed to interpolate node text for ${props.fieldId}:`, err);
181
+ return tpl;
182
+ }
183
+ }
184
+ function nodeLabelText(node) {
185
+ const tpl = getLocalizedText(props.config.nodeLabel, locale.value) ?? "";
186
+ return tpl ? safeInterpolate(tpl, node) : "";
187
+ }
188
+ function nodeTooltipText(node) {
189
+ if (!props.config.nodeTooltip) return void 0;
190
+ const tpl = getLocalizedText(props.config.nodeTooltip, locale.value);
191
+ if (!tpl) return void 0;
192
+ return safeInterpolate(tpl, node);
193
+ }
194
+ const initialExpanded = computed(() => {
195
+ if (!props.config.expandAll) return [];
196
+ const out = [];
197
+ const stack = [...roots.value];
198
+ while (stack.length) {
199
+ const n = stack.pop();
200
+ const kids = getChildren(n);
201
+ if (kids && kids.length) {
202
+ out.push(getKey(n));
203
+ stack.push(...kids);
204
+ }
205
+ }
206
+ return out;
207
+ });
208
+ const filterQuery = ref("");
209
+ function evalKeywords(node) {
210
+ const expr = props.config.filter?.keywords;
211
+ if (!expr) return [];
212
+ try {
213
+ const raw = Effect.runSync($cel(expr, nodeCtx(node)));
214
+ if (!Array.isArray(raw)) return [];
215
+ return raw.map((v) => String(v));
216
+ } catch {
217
+ return [];
218
+ }
219
+ }
220
+ const searchCorpus = shallowRef(/* @__PURE__ */ new Map());
221
+ watch(
222
+ () => [
223
+ roots.value,
224
+ locale.value,
225
+ props.config.nodeLabel,
226
+ props.config.filter?.keywords
227
+ ],
228
+ () => {
229
+ const map = /* @__PURE__ */ new Map();
230
+ const stack = [...roots.value];
231
+ while (stack.length) {
232
+ const n = stack.pop();
233
+ const label = nodeLabelText(n).trim().toLowerCase();
234
+ const kw = evalKeywords(n).map((k) => k.trim().toLowerCase()).join("\n");
235
+ map.set(getKey(n), kw ? `${label}
236
+ ${kw}` : label);
237
+ const kids = getChildren(n);
238
+ if (kids && kids.length) stack.push(...kids);
239
+ }
240
+ searchCorpus.value = map;
241
+ },
242
+ { immediate: true }
243
+ );
244
+ function filterPredicate(node, query) {
245
+ const q = query.trim().toLowerCase();
246
+ if (!q) return true;
247
+ const hay = searchCorpus.value.get(getKey(node));
248
+ if (hay !== void 0) return hay.includes(q);
249
+ return nodeLabelText(node).trim().toLowerCase().includes(q);
250
+ }
251
+ const filterLabelText = computed(() => {
252
+ const localized = props.config.filter?.label ? getLocalizedText(props.config.filter.label, locale.value) : void 0;
253
+ return localized && localized.length > 0 ? localized : t("tree-single-search-label");
254
+ });
255
+ const readonlyText = computed(() => {
256
+ const selected = model.value;
257
+ const empty = t("tree-single-readonly-empty");
258
+ if (selected == null) return empty;
259
+ const stack = [...roots.value];
260
+ while (stack.length) {
261
+ const n = stack.pop();
262
+ if (getKey(n) === selected) {
263
+ const label = nodeLabelText(n);
264
+ return label.length > 0 ? label : selected;
265
+ }
266
+ const kids = getChildren(n);
267
+ if (kids && kids.length) stack.push(...kids);
268
+ }
269
+ return selected;
270
+ });
271
+ </script>
272
+
273
+ <template>
274
+ <Field
275
+ orientation="vertical"
276
+ :data-disabled="isDisabled || void 0"
277
+ >
278
+ <FieldLabel
279
+ v-if="labelText"
280
+ class="text-xs text-zinc-500"
281
+ >
282
+ <template
283
+ v-if="tooltipText"
284
+ #tooltip
285
+ >
286
+ <Markdown
287
+ :source="tooltipText"
288
+ class="prose prose-xs prose-zinc"
289
+ />
290
+ </template>
291
+ {{ labelText }}
292
+ </FieldLabel>
293
+
294
+ <div
295
+ v-if="effectiveReadonly"
296
+ class="min-h-9 py-1.5 text-sm text-zinc-700"
297
+ >
298
+ {{ readonlyText }}
299
+ </div>
300
+
301
+ <template v-else>
302
+ <Field
303
+ v-if="config.filter?.enabled"
304
+ orientation="floating"
305
+ >
306
+ <FieldLabel>{{ filterLabelText }}</FieldLabel>
307
+ <InputGroup>
308
+ <InputGroupAddon align="inline-start">
309
+ <Icon icon="lucide:search" />
310
+ </InputGroupAddon>
311
+ <InputGroupInput
312
+ v-model="filterQuery"
313
+ :disabled="isDisabled"
314
+ />
315
+ <InputGroupAddon
316
+ v-if="filterQuery.length > 0"
317
+ align="inline-end"
318
+ >
319
+ <InputGroupButton
320
+ size="icon-xs"
321
+ :aria-label="t('tree-single-search-clear')"
322
+ @click="filterQuery = ''"
323
+ >
324
+ <Icon icon="lucide:x" />
325
+ </InputGroupButton>
326
+ </InputGroupAddon>
327
+ </InputGroup>
328
+ </Field>
329
+
330
+ <div
331
+ v-if="fetchError && roots.length === 0"
332
+ class="min-h-9 py-1.5 text-sm text-red-500"
333
+ >
334
+ {{ t("tree-single-load-error") }}
335
+ </div>
336
+ <div
337
+ v-else-if="loading && roots.length === 0"
338
+ class="flex flex-col gap-1.5 py-1"
339
+ aria-busy="true"
340
+ >
341
+ <Skeleton class="h-6 w-2/3" />
342
+ <Skeleton class="h-6 w-1/2" />
343
+ <Skeleton class="h-6 w-3/5" />
344
+ <Skeleton class="h-6 w-2/5" />
345
+ </div>
346
+
347
+ <UiTree
348
+ v-else
349
+ v-model="model"
350
+ :roots="roots"
351
+ :get-key="getKey"
352
+ :get-children="getChildren"
353
+ selection-mode="single"
354
+ :selectable="nodeSelectable"
355
+ :filter-predicate="filterPredicate"
356
+ :filter-query="filterQuery"
357
+ :initial-expanded="initialExpanded"
358
+ :show-focused-row="false"
359
+ :class="isDisabled ? 'pointer-events-none opacity-60' : void 0"
360
+ >
361
+ <template #node="{ node, selected }">
362
+ <span class="flex items-start gap-2">
363
+ <!-- Presentational radio glyph: mirrors the row's selection state
364
+ but never owns it. Row click / keyboard in `<UiTree>` remains
365
+ the single source of truth — this is a visual reflection only. -->
366
+ <Icon
367
+ :icon="selected ? 'fluent:radio-button-20-filled' : 'fluent:radio-button-20-regular'"
368
+ class="pointer-events-none mt-0.5 size-4 shrink-0"
369
+ :class="selected ? 'text-(--primary)' : 'text-zinc-300'"
370
+ aria-hidden="true"
371
+ />
372
+ <span class="flex flex-col gap-0.5">
373
+ <Markdown
374
+ :source="nodeLabelText(node)"
375
+ class="prose prose-sm prose-zinc text-zinc-700"
376
+ />
377
+ <Markdown
378
+ v-if="nodeTooltipText(node)"
379
+ :source="nodeTooltipText(node)"
380
+ block
381
+ class="prose prose-xs prose-zinc text-zinc-400"
382
+ />
383
+ </span>
384
+ </span>
385
+ </template>
386
+
387
+ <template #empty>
388
+ <div class="min-h-9 py-1.5 text-sm text-zinc-400">
389
+ {{ t("tree-single-empty") }}
390
+ </div>
391
+ </template>
392
+ </UiTree>
393
+ </template>
394
+ </Field>
395
+ </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,96 @@
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.single";
4
+ export declare const compatibilityDate: "2026-05-28";
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: 8;
15
+ readonly min: 4;
16
+ readonly max: number;
17
+ readonly grow: true;
18
+ };
19
+ };
20
+ export declare function schema(configure: (env: Environment) => void): Schema.Struct<{
21
+ label: Schema.optional<Schema.TupleType<readonly [Schema.Struct<{
22
+ locale: Schema.Literal<["zh"]>;
23
+ message: Schema.SchemaClass<string, string, never>;
24
+ }>], [Schema.Struct<{
25
+ locale: Schema.Literal<["ja", "en", "ko"]>;
26
+ message: Schema.SchemaClass<string, string, never>;
27
+ }>]>>;
28
+ tooltip: Schema.optional<Schema.TupleType<readonly [Schema.Struct<{
29
+ locale: Schema.Literal<["zh"]>;
30
+ message: Schema.SchemaClass<string, string, never>;
31
+ }>], [Schema.Struct<{
32
+ locale: Schema.Literal<["ja", "en", "ko"]>;
33
+ message: Schema.SchemaClass<string, string, never>;
34
+ }>]>>;
35
+ binding: Schema.optional<Schema.refine<string, typeof Schema.String>>;
36
+ disabled: Schema.optional<Schema.Schema<string, string, never>>;
37
+ readonly: Schema.optional<Schema.Schema<string, string, never>>;
38
+ derived: Schema.optional<Schema.Struct<{
39
+ mode: Schema.Literal<["formula", "prefill"]>;
40
+ expression: Schema.Schema<string, string, never>;
41
+ }>>;
42
+ dataSource: Schema.Struct<{
43
+ request: Schema.optional<Schema.Schema<string, string, never>>;
44
+ data: Schema.Schema<string, string, never>;
45
+ }>;
46
+ nodeKey: Schema.Schema<string, string, never>;
47
+ nodeChildren: Schema.Schema<string, string, never>;
48
+ nodeLabel: Schema.refine<readonly [{
49
+ readonly locale: "zh";
50
+ readonly message: string;
51
+ }, ...{
52
+ readonly locale: "en" | "ja" | "ko";
53
+ readonly message: string;
54
+ }[]], Schema.TupleType<readonly [Schema.Struct<{
55
+ locale: Schema.Literal<["zh"]>;
56
+ message: Schema.SchemaClass<string, string, never>;
57
+ }>], [Schema.Struct<{
58
+ locale: Schema.Literal<["ja", "en", "ko"]>;
59
+ message: Schema.SchemaClass<string, string, never>;
60
+ }>]>>;
61
+ nodeTooltip: Schema.optional<Schema.refine<readonly [{
62
+ readonly locale: "zh";
63
+ readonly message: string;
64
+ }, ...{
65
+ readonly locale: "en" | "ja" | "ko";
66
+ readonly message: string;
67
+ }[]], Schema.TupleType<readonly [Schema.Struct<{
68
+ locale: Schema.Literal<["zh"]>;
69
+ message: Schema.SchemaClass<string, string, never>;
70
+ }>], [Schema.Struct<{
71
+ locale: Schema.Literal<["ja", "en", "ko"]>;
72
+ message: Schema.SchemaClass<string, string, never>;
73
+ }>]>>>;
74
+ nodeSelectable: Schema.optional<Schema.Schema<string, string, never>>;
75
+ expandAll: Schema.optionalWith<typeof Schema.Boolean, {
76
+ default: () => false;
77
+ }>;
78
+ filter: Schema.optional<Schema.Struct<{
79
+ enabled: Schema.SchemaClass<boolean, boolean, never>;
80
+ label: Schema.optional<Schema.TupleType<readonly [Schema.Struct<{
81
+ locale: Schema.Literal<["zh"]>;
82
+ message: Schema.SchemaClass<string, string, never>;
83
+ }>], [Schema.Struct<{
84
+ locale: Schema.Literal<["ja", "en", "ko"]>;
85
+ message: Schema.SchemaClass<string, string, never>;
86
+ }>]>>;
87
+ keywords: Schema.optional<Schema.Schema<string, string, never>>;
88
+ }>>;
89
+ id: Schema.refine<string, typeof Schema.String>;
90
+ displayName: Schema.optional<Schema.SchemaClass<string, string, never>>;
91
+ hidden: Schema.optional<Schema.Schema<string, string, never>>;
92
+ type: Schema.Literal<["com.shwfed.form.field.tree.single"]>;
93
+ compatibilityDate: Schema.Literal<["2026-05-28"]>;
94
+ }>;
95
+ export type Value = Schema.Schema.Type<ReturnType<typeof schema>>;
96
+ export declare function defaults(): Partial<Value>;
@@ -0,0 +1,118 @@
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 } from "../../../utils/common.js";
6
+ export const type = "com.shwfed.form.field.tree.single";
7
+ export const compatibilityDate = "2026-05-28";
8
+ export const metadata = {
9
+ name: "\u6811\uFF08\u5355\u9009\uFF09",
10
+ icon: "fluent:tree-evergreen-20-regular",
11
+ w: { initial: 8, min: 4, max: Infinity },
12
+ h: { initial: 8, min: 4, max: Infinity, grow: true }
13
+ };
14
+ export function schema(configure) {
15
+ const CelBool = Expression({ configure, resultType: "bool" });
16
+ const nodeConfigure = (env) => {
17
+ configure(env);
18
+ env.registerVariable("node", "dyn", { description: "\u5F53\u524D\u8282\u70B9\uFF1B\u7531 `\u6570\u636E` \u8868\u8FBE\u5F0F\u8FD4\u56DE\u7684\u6BCF\u4E00\u9879" });
19
+ };
20
+ const CelNodeKey = Expression({
21
+ configure: nodeConfigure,
22
+ resultType: (t) => t === "string" || t === "number" || t === "dyn"
23
+ });
24
+ const CelNodeChildren = Expression({
25
+ configure: nodeConfigure,
26
+ // Accept lists, optional lists, and `dyn` — CEL infers an empty literal
27
+ // such as `[]` as `list<dyn>`; a configured expression like
28
+ // `has(node.kids) ? node.kids : null` lands on `dyn`. The looser predicate
29
+ // mirrors the table's `data` expression.
30
+ resultType: (t) => t === "dyn" || t.startsWith("list") || t.startsWith("optional")
31
+ });
32
+ const CelNodeBool = Expression({ configure: nodeConfigure, resultType: "bool" });
33
+ const NodeLocaleMd = LocaleMarkdown({ configure: nodeConfigure });
34
+ const CelKeywords = Expression({
35
+ configure: nodeConfigure,
36
+ resultType: (t) => t === "dyn" || t.startsWith("list") || t.startsWith("optional")
37
+ });
38
+ return Schema.Struct({
39
+ type: Schema.Literal(type),
40
+ compatibilityDate: Schema.Literal(compatibilityDate),
41
+ ...commonFieldFields(configure),
42
+ label: Schema.optional(Locale.annotations({
43
+ title: "\u6807\u7B7E",
44
+ description: "\u5B57\u6BB5\u524D\u5C55\u793A\u7684\u6587\u672C\uFF1B\u7559\u7A7A\u5219\u4E0D\u6E32\u67D3\u6807\u7B7E"
45
+ })),
46
+ tooltip: Schema.optional(Locale.annotations({
47
+ title: "\u63D0\u793A",
48
+ description: "\u9F20\u6807\u60AC\u505C\u5728\u6807\u7B7E\u4E0A\u65F6\u5C55\u793A\u7684\u8BF4\u660E"
49
+ })),
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\u5199\u5165\u503C\u4E3A\u6240\u9009\u8282\u70B9 ID \u7684\u5B57\u7B26\u4E32\uFF08\u6807\u91CF\uFF09\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\u6240\u9009\u8282\u70B9\u7684\u6807\u7B7E"
61
+ })),
62
+ derived: derivedField(configure, "dyn"),
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\u6811\u901A\u8FC7 `\u8282\u70B9\u5B50\u7EA7` \u8868\u8FBE\u5F0F\u9010\u5C42\u5411\u4E0B\u8BFB\u53D6\u5B50\u7EA7"
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\u7684\u5B50\u7EA7\u5217\u8868\u7684 CEL \u8868\u8FBE\u5F0F\uFF1B\u8FD4\u56DE `none` / `null` \u89C6\u4E3A\u53F6\u5B50\u8282\u70B9"
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\uFF0C\u652F\u6301 Markdown \u4E0E\u63D2\u503C"
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\u62E9"
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
+ filter: Schema.optional(Schema.Struct({
92
+ enabled: Schema.Boolean.annotations({ title: "\u542F\u7528", description: "\u662F\u5426\u5728\u6811\u4E0A\u65B9\u663E\u793A\u641C\u7D22\u8F93\u5165\u6846" }),
93
+ label: Schema.optional(Locale.annotations({
94
+ title: "\u6807\u7B7E",
95
+ description: "\u641C\u7D22\u8F93\u5165\u6846\u7684\u6D6E\u52A8\u6807\u7B7E\uFF1B\u7559\u7A7A\u5219\u4F7F\u7528\u9ED8\u8BA4\u503C\u300C\u641C\u7D22\u300D"
96
+ })),
97
+ keywords: Schema.optional(CelKeywords.annotations({
98
+ title: "\u989D\u5916\u5173\u952E\u8BCD",
99
+ description: "\u8FD4\u56DE\u5B57\u7B26\u4E32\u5217\u8868\u7684 CEL \u8868\u8FBE\u5F0F\uFF0C\u53EF\u8BBF\u95EE `node`\uFF1B\u5339\u914D\u89C4\u5219\u4E3A\u300C\u8282\u70B9\u6807\u7B7E \u6216 \u4EFB\u4E00\u5173\u952E\u8BCD\u300D\u5305\u542B\u641C\u7D22\u8BCD\uFF08\u4E0D\u533A\u5206\u5927\u5C0F\u5199\uFF09"
100
+ }))
101
+ }).annotations({
102
+ title: "\u8FC7\u6EE4",
103
+ description: "\u5BA2\u6237\u7AEF\u8FC7\u6EE4\uFF1B\u8FC7\u6EE4\u4E0D\u4F1A\u5F71\u54CD\u5DF2\u9009\u4E2D\u7684\u8282\u70B9 ID"
104
+ }))
105
+ }).annotations({
106
+ title: "TreeSingleField",
107
+ description: "\u57FA\u4E8E\u6811\u5F62\u6570\u636E\u7684\u5355\u9009\u8F93\u5165"
108
+ });
109
+ }
110
+ export function defaults() {
111
+ return {
112
+ dataSource: { data: "[]" },
113
+ nodeKey: "string(node.id)",
114
+ nodeChildren: "has(node.children) ? node.children : null",
115
+ nodeLabel: [{ locale: "zh", message: "{{ node.label }}" }],
116
+ expandAll: false
117
+ };
118
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Wrapping + adapter helpers shared by `tree.combobox.single` and
3
+ * `tree.combobox.multi`. The whole tree comes from `dataSource` in one
4
+ * shot, so wrapping is a pure walk over CEL-derived children: each raw
5
+ * node either has children (`branch`) or it doesn't (`terminal`).
6
+ */
7
+ export type WrappedNode = {
8
+ readonly kind: 'branch';
9
+ readonly raw: unknown;
10
+ readonly key: string;
11
+ readonly children: WrappedNode[];
12
+ } | {
13
+ readonly kind: 'terminal';
14
+ readonly raw: unknown;
15
+ readonly key: string;
16
+ };
17
+ export interface WrapStructureContext {
18
+ /** Stringified node id; one per raw node. Reuses `nodeKey` CEL. */
19
+ nodeKey: (raw: unknown) => string;
20
+ /**
21
+ * Normalised children array. `undefined`/`null`/empty all collapse to
22
+ * `undefined` here — the wrapping logic interprets that as
23
+ * "this node has no children" → `terminal`.
24
+ */
25
+ nodeChildren: (raw: unknown) => unknown[] | undefined;
26
+ }
27
+ export declare function wrapStructural(raw: unknown, ctx: WrapStructureContext): WrappedNode;
28
+ export declare function wrapStructuralAll(raws: unknown[], ctx: WrapStructureContext): WrappedNode[];
29
+ /** Synchronous `getChildren` adapter for ui/tree. */
30
+ export declare function getWrappedChildren(w: WrappedNode): WrappedNode[] | undefined;
31
+ /**
32
+ * Find the path from root to a node whose `key` matches. Returns `null`
33
+ * if the key isn't present in `roots`.
34
+ */
35
+ export declare function findWrappedPath(roots: WrappedNode[], key: string): WrappedNode[] | null;
@@ -0,0 +1,31 @@
1
+ export function wrapStructural(raw, ctx) {
2
+ const kids = ctx.nodeChildren(raw);
3
+ if (!kids || kids.length === 0) {
4
+ return { kind: "terminal", raw, key: ctx.nodeKey(raw) };
5
+ }
6
+ return {
7
+ kind: "branch",
8
+ raw,
9
+ key: ctx.nodeKey(raw),
10
+ children: kids.map((c) => wrapStructural(c, ctx))
11
+ };
12
+ }
13
+ export function wrapStructuralAll(raws, ctx) {
14
+ return raws.map((r) => wrapStructural(r, ctx));
15
+ }
16
+ export function getWrappedChildren(w) {
17
+ return w.kind === "branch" ? w.children : void 0;
18
+ }
19
+ export function findWrappedPath(roots, key) {
20
+ const trail = [];
21
+ function walk(siblings) {
22
+ for (const n of siblings) {
23
+ trail.push(n);
24
+ if (n.key === key) return true;
25
+ if (n.kind === "branch" && n.children.length > 0 && walk(n.children)) return true;
26
+ trail.pop();
27
+ }
28
+ return false;
29
+ }
30
+ return walk(roots) ? trail.slice() : null;
31
+ }