@shwfed/config 2.8.0 → 2.9.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/dist/mcp.mjs +61 -10
- package/dist/module.json +1 -1
- package/dist/preview/assets/{badge-BI1mdo92.js → badge-Ddz0ExD-.js} +1 -1
- package/dist/preview/assets/{config-XgVqueyq.js → config---5_lEKG.js} +1 -1
- package/dist/preview/assets/{config-OrJljNWU.js → config-5qIYVWZh.js} +1 -1
- package/dist/preview/assets/config-B8zbFg3y.js +1 -0
- package/dist/preview/assets/{config-DqUnpWZk.js → config-Bn619USg.js} +1 -1
- package/dist/preview/assets/{config-DuzQXHvg.js → config-CUeBTyLb.js} +1 -1
- package/dist/preview/assets/config-DN_3WauN.js +1 -0
- package/dist/preview/assets/config-U-3fWb-2.js +1 -0
- package/dist/preview/assets/config-q5VV9rp7.js +1 -0
- package/dist/preview/assets/config-vePqHFvZ.js +1 -0
- package/dist/preview/assets/{definition.vue_vue_type_script_setup_true_lang-lEhYVEcN.js → definition.vue_vue_type_script_setup_true_lang-fQa65UMX.js} +1 -1
- package/dist/preview/assets/index-BKaqQGb-.js +688 -0
- package/dist/preview/assets/index-Bj8xIK5h.js +1 -0
- package/dist/preview/assets/index-BlHAyQdm.css +1 -0
- package/dist/preview/assets/{index-BvLLQuQr.js → index-CzWhSvDG.js} +1 -1
- package/dist/preview/assets/{item-DMtXi_cx.js → item-DHarupON.js} +1 -1
- package/dist/preview/assets/{runtime-CA58Mif7.js → runtime-560tuaHv.js} +1 -1
- package/dist/preview/assets/{runtime-CjJBU_e1.js → runtime-C2rQ3L3-.js} +1 -1
- package/dist/preview/assets/{runtime-DeUmGsM_.js → runtime-CKghL8I_.js} +1 -1
- package/dist/preview/assets/runtime-CMsaNery.js +1 -0
- package/dist/preview/assets/runtime-CMuCGJZm.js +1 -0
- package/dist/preview/assets/{runtime-wVZ1xP8L.js → runtime-DOM_La4X.js} +1 -1
- package/dist/preview/assets/{runtime-BUPuX-Gq.js → runtime-DQHb9t0r.js} +1 -1
- package/dist/preview/assets/{runtime-DnXoWy2A.js → runtime-Dgl3wVfD.js} +1 -1
- package/dist/preview/assets/{runtime-CWqQzWuc.js → runtime-aLgWVLET.js} +1 -1
- package/dist/preview/index.html +2 -2
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/config.d.vue.ts +8 -0
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/config.vue +28 -0
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/config.vue.d.ts +8 -0
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/runtime.vue +17 -17
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/schema.d.ts +4 -0
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/schema.js +8 -0
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json.confirm/config.d.vue.ts +8 -0
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json.confirm/config.vue +25 -0
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json.confirm/config.vue.d.ts +8 -0
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json.confirm/runtime.vue +2 -7
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json.confirm/schema.d.ts +4 -0
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json.confirm/schema.js +8 -0
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/runtime.vue +13 -2
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/schema.d.ts +1 -0
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/schema.js +4 -1
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/runtime.vue +10 -2
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/schema.d.ts +1 -0
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/schema.js +4 -1
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/runtime.vue +16 -0
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/schema.d.ts +1 -0
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/schema.js +4 -1
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/runtime.vue +13 -5
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/schema.d.ts +1 -0
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/schema.js +4 -1
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/runtime.vue +25 -5
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/schema.d.ts +1 -0
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/schema.js +4 -1
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/runtime.vue +18 -8
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/schema.d.ts +1 -0
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/schema.js +4 -1
- package/dist/runtime/components/form/index.vue +11 -3
- package/dist/runtime/components/form/schema.d.ts +4 -0
- package/dist/runtime/components/form/schema.js +1 -0
- package/dist/runtime/components/form/unit-config.vue +6 -1
- package/dist/runtime/components/form/utils/form-vars.js +2 -0
- package/dist/runtime/components/form/utils/resolve.d.ts +10 -0
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/runtime.vue +13 -2
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/schema.d.ts +1 -0
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/schema.js +4 -1
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/runtime.vue +10 -2
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/schema.d.ts +1 -0
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/schema.js +4 -1
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/runtime.vue +16 -0
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/schema.d.ts +1 -0
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/schema.js +3 -1
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/runtime.vue +13 -5
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/schema.d.ts +1 -0
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/schema.js +3 -1
- package/dist/runtime/components/table/config.vue +5 -1
- package/dist/runtime/components/table/row-provider.vue +8 -0
- package/dist/runtime/components/table/utils/resolve.d.ts +7 -0
- package/dist/runtime/components/table/utils/shared.js +4 -0
- package/dist/runtime/components/ui/expression-editor/CodeMirrorInput.d.vue.ts +1 -0
- package/dist/runtime/components/ui/expression-editor/CodeMirrorInput.vue +9 -1
- package/dist/runtime/components/ui/expression-editor/CodeMirrorInput.vue.d.ts +1 -0
- package/dist/runtime/components/ui/expression-editor/ExpressionEditor.d.vue.ts +2 -2
- package/dist/runtime/components/ui/expression-editor/ExpressionEditor.vue +33 -4
- package/dist/runtime/components/ui/expression-editor/ExpressionEditor.vue.d.ts +2 -2
- package/dist/runtime/components/ui/expression-editor/picker-entries.d.ts +3 -2
- package/dist/runtime/components/ui/expression-editor/picker-entries.js +14 -3
- package/dist/runtime/components/ui/expression-editor/selection-chip-extension.d.ts +4 -0
- package/dist/runtime/components/ui/expression-editor/selection-chip-extension.js +119 -0
- package/dist/runtime/components/ui/expression-editor/selection-refs.d.ts +8 -0
- package/dist/runtime/components/ui/expression-editor/selection-refs.js +29 -0
- package/dist/runtime/share/event-bus.d.ts +12 -12
- package/dist/runtime/utils/cel-context.d.ts +22 -0
- package/dist/runtime/utils/cel-context.js +8 -0
- package/dist/runtime/utils/selections-registry.d.ts +77 -0
- package/dist/runtime/utils/selections-registry.js +49 -0
- package/package.json +1 -1
- package/dist/preview/assets/config-BNF2r9jW.js +0 -1
- package/dist/preview/assets/config-BxuGYvER.js +0 -1
- package/dist/preview/assets/config-Cy5w3JWQ.js +0 -1
- package/dist/preview/assets/config-Du5SuNSb.js +0 -1
- package/dist/preview/assets/config-ggyCcWNZ.js +0 -1
- package/dist/preview/assets/index-DsMR5NfK.css +0 -1
- package/dist/preview/assets/index-Yv78vz4W.js +0 -680
- package/dist/preview/assets/index-yrBKwEfk.js +0 -1
- package/dist/preview/assets/runtime-2S3Yr051.js +0 -1
- package/dist/preview/assets/runtime-C4jFTZ4Z.js +0 -1
- package/dist/runtime/share/form-validate.d.ts +0 -18
- package/dist/runtime/share/form-validate.js +0 -8
package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/schema.js
CHANGED
|
@@ -9,7 +9,10 @@ export const metadata = {
|
|
|
9
9
|
name: "\u6811\uFF08\u5355\u9009\uFF09",
|
|
10
10
|
icon: "fluent:tree-evergreen-20-regular",
|
|
11
11
|
w: { initial: 8, min: 4, max: Infinity },
|
|
12
|
-
h: { initial: 8, min: 4, max: Infinity, grow: true }
|
|
12
|
+
h: { initial: 8, min: 4, max: Infinity, grow: true },
|
|
13
|
+
// Publishes its resolved node (the backend record) to the `selections`
|
|
14
|
+
// registry (runtime.vue), readable via `selections["<id>"]`.
|
|
15
|
+
selection: true
|
|
13
16
|
};
|
|
14
17
|
export function schema(configure) {
|
|
15
18
|
const CelBool = Expression({ configure, resultType: "bool" });
|
|
@@ -15,10 +15,10 @@ import { provideCommitBus } from "./utils/commit-bus";
|
|
|
15
15
|
import { provideDerivedQuiescence, useDerived } from "./utils/derived";
|
|
16
16
|
import { useFormHistory } from "./utils/history";
|
|
17
17
|
import { evaluateInitial } from "./utils/initial";
|
|
18
|
-
import { provideFormValidate } from "../../share/form-validate";
|
|
19
18
|
import { provideEventTarget } from "../../share/event-bus";
|
|
20
19
|
import { provideFormReadonly } from "./utils/readonly";
|
|
21
20
|
import { provideFormState } from "./utils/state";
|
|
21
|
+
import { provideSelectionsRegistry } from "../../utils/selections-registry";
|
|
22
22
|
import { provideValidation } from "./utils/validation";
|
|
23
23
|
defineOptions({ name: "ShwfedForm" });
|
|
24
24
|
const state = defineModel({ type: Object, ...{ default: () => ({}) } });
|
|
@@ -29,13 +29,15 @@ const props = defineProps({
|
|
|
29
29
|
const configure = props.configure ?? (() => {
|
|
30
30
|
});
|
|
31
31
|
void configure;
|
|
32
|
+
const selections = provideSelectionsRegistry();
|
|
32
33
|
provideCELContext(buildFormRuntimeScope({
|
|
33
34
|
form: () => state.value ?? {},
|
|
34
35
|
now: () => new TZDate(),
|
|
35
36
|
// `formHistory` is created further down; these thunks are stored now and
|
|
36
37
|
// only called at eval time (long after setup), so reading it here is safe.
|
|
37
38
|
undoable: () => formHistory.canUndo.value,
|
|
38
|
-
redoable: () => formHistory.canRedo.value
|
|
39
|
+
redoable: () => formHistory.canRedo.value,
|
|
40
|
+
selections: () => selections.entries.value
|
|
39
41
|
}));
|
|
40
42
|
const inherited = injectCELContext();
|
|
41
43
|
const $cel = (expression, context) => _rawCel(expression, { ...celBindings(inherited), ...context });
|
|
@@ -81,10 +83,16 @@ const validation = provideValidation({
|
|
|
81
83
|
seeded,
|
|
82
84
|
settled: quiescence.settled
|
|
83
85
|
});
|
|
84
|
-
provideFormValidate(validation.validate);
|
|
85
86
|
const formHistory = useFormHistory(state, { quiescence, seeded, dirty: formState.dirty });
|
|
87
|
+
class FormInvalid {
|
|
88
|
+
_tag = "FormInvalid";
|
|
89
|
+
}
|
|
86
90
|
const formInstanceId = config.value?.id ?? crypto.randomUUID();
|
|
87
91
|
provideEventTarget(formInstanceId, {
|
|
92
|
+
"validate": () => Effect.gen(function* () {
|
|
93
|
+
const valid = yield* Effect.promise(() => validation.validate());
|
|
94
|
+
if (!valid) yield* Effect.die(new FormInvalid());
|
|
95
|
+
}),
|
|
88
96
|
"undo": () => Effect.sync(formHistory.undo),
|
|
89
97
|
"redo": () => Effect.sync(formHistory.redo),
|
|
90
98
|
"reset-to-initial": () => Effect.sync(formHistory.reset)
|
|
@@ -11,6 +11,10 @@ export declare const metadata: {
|
|
|
11
11
|
readonly name: "表单";
|
|
12
12
|
readonly icon: "fluent:form-20-regular";
|
|
13
13
|
readonly operations: readonly [{
|
|
14
|
+
readonly id: "validate";
|
|
15
|
+
readonly name: "校验";
|
|
16
|
+
readonly icon: "fluent:checkmark-circle-20-regular";
|
|
17
|
+
}, {
|
|
14
18
|
readonly id: "undo";
|
|
15
19
|
readonly name: "撤销";
|
|
16
20
|
readonly icon: "fluent:arrow-undo-20-regular";
|
|
@@ -20,6 +20,7 @@ export const metadata = {
|
|
|
20
20
|
name: "\u8868\u5355",
|
|
21
21
|
icon: "fluent:form-20-regular",
|
|
22
22
|
operations: [
|
|
23
|
+
{ id: "validate", name: "\u6821\u9A8C", icon: "fluent:checkmark-circle-20-regular" },
|
|
23
24
|
{ id: "undo", name: "\u64A4\u9500", icon: "fluent:arrow-undo-20-regular" },
|
|
24
25
|
{ id: "redo", name: "\u91CD\u505A", icon: "fluent:arrow-redo-20-regular" },
|
|
25
26
|
{ id: "reset-to-initial", name: "\u91CD\u7F6E\u4E3A\u521D\u59CB\u503C", icon: "fluent:arrow-reset-20-regular" }
|
|
@@ -7,7 +7,8 @@ import { toast } from "vue-sonner";
|
|
|
7
7
|
import {
|
|
8
8
|
celBindings,
|
|
9
9
|
injectCELContext,
|
|
10
|
-
provideCELContext
|
|
10
|
+
provideCELContext,
|
|
11
|
+
provideSelectionRoster
|
|
11
12
|
} from "../../utils/cel-context";
|
|
12
13
|
import { findFreePlacement, normalizeLayoutSet, placeGroupAt } from "../../share/layout";
|
|
13
14
|
import { readClip, reidFragment, writeClip } from "../../share/clipboard";
|
|
@@ -45,6 +46,10 @@ const breadcrumbExt = inject(BREADCRUMB_EXTENSION_KEY, null);
|
|
|
45
46
|
const fullPane = ref(false);
|
|
46
47
|
provide(FORM_FIELD_LAYOUT_KEY, { fullPane });
|
|
47
48
|
provideCELContext(props.fieldCelScope ?? {});
|
|
49
|
+
const selectionRoster = computed(
|
|
50
|
+
() => unit.value.fields.filter((f) => findField(f.type, f.compatibilityDate)?.metadata?.selection).map((f) => ({ id: f.id, name: fieldLabel(f) }))
|
|
51
|
+
);
|
|
52
|
+
provideSelectionRoster(selectionRoster);
|
|
48
53
|
const takeover = inject(SIDEBAR_TAKEOVER_KEY, null);
|
|
49
54
|
const takeoverTarget = computed(() => takeover?.target.value ?? null);
|
|
50
55
|
const activeFieldId = computed(() => {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { SELECTIONS_VAR } from "../../../utils/cel-context.js";
|
|
1
2
|
export function registerFormVariablesIfAbsent(env) {
|
|
2
3
|
const declared = new Set(env.getDefinitions().variables.map((v) => v.name));
|
|
3
4
|
if (!declared.has("now")) env.registerVariable("now", "Date", { label: "\u5F53\u524D\u65F6\u95F4", description: "\u5F53\u524D\u65E5\u671F/\u65F6\u95F4" });
|
|
4
5
|
if (!declared.has("form")) env.registerVariable("form", "dyn", { label: "\u8868\u5355\u503C", description: "\u5F53\u524D\u8868\u5355\u72B6\u6001" });
|
|
5
6
|
if (!declared.has("undoable")) env.registerVariable("undoable", "bool", { label: "\u53EF\u64A4\u9500", description: "\u5F53\u524D\u662F\u5426\u6709\u53EF\u64A4\u9500\u7684\u4FEE\u6539" });
|
|
6
7
|
if (!declared.has("redoable")) env.registerVariable("redoable", "bool", { label: "\u53EF\u91CD\u505A", description: "\u5F53\u524D\u662F\u5426\u6709\u53EF\u91CD\u505A\u7684\u4FEE\u6539" });
|
|
8
|
+
if (!declared.has(SELECTIONS_VAR)) env.registerVariable(SELECTIONS_VAR, "dyn", { label: "\u9009\u4E2D\u9879", description: "\u5404\u9009\u62E9\u5B57\u6BB5\u5F53\u524D\u9009\u4E2D\u9879\u7684\u5B8C\u6574\u5BF9\u8C61\uFF08\u6309\u5B57\u6BB5\u6807\u8BC6\uFF09" });
|
|
7
9
|
}
|
|
@@ -65,6 +65,16 @@ export type FieldMetadata = Readonly<{
|
|
|
65
65
|
* fullscreen. See `BlockLayoutEditor`'s inline-config pane.
|
|
66
66
|
*/
|
|
67
67
|
inlineConfig?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Whether this field is *selection-like* — it publishes its currently-resolved
|
|
70
|
+
* full option to the `selections` registry at runtime (see
|
|
71
|
+
* `utils/selections-registry`), keyed by its uuid. The form's unit-config reads
|
|
72
|
+
* this to build the selection roster the ExpressionEditor advertises: a sibling
|
|
73
|
+
* expression reaches the chosen record via `selections["<id>"].code`, and the
|
|
74
|
+
* editor renders that uuid as this field's name. Set it together with the
|
|
75
|
+
* runtime publish so the picker never advertises a field that writes nothing.
|
|
76
|
+
*/
|
|
77
|
+
selection?: boolean;
|
|
68
78
|
}>;
|
|
69
79
|
/**
|
|
70
80
|
* Optional creation-time defaults factory. Returns a partial config that
|
|
@@ -9,6 +9,7 @@ import { useI18n } from "vue-i18n";
|
|
|
9
9
|
import { asRequest, fetchJsonOption } from "../../../../../share/request";
|
|
10
10
|
import { cel as _rawCel } from "../../../../../utils/cel";
|
|
11
11
|
import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
|
|
12
|
+
import { publishSelection } from "../../../../../utils/selections-registry";
|
|
12
13
|
import { getLocalizedText } from "../../../../../share/locale";
|
|
13
14
|
import { dispatchTriggers, useEventChannel } from "../../../../../share/event-bus";
|
|
14
15
|
import {
|
|
@@ -97,7 +98,8 @@ const staticEntries = computed(() => {
|
|
|
97
98
|
value: item.value.value,
|
|
98
99
|
label: labelTpl ? safeInterpolate(labelTpl, {}) : "",
|
|
99
100
|
tooltip: tooltipTpl ? safeInterpolate(tooltipTpl, {}) : void 0,
|
|
100
|
-
keywords: (item.keywords ?? []).join(" ")
|
|
101
|
+
keywords: (item.keywords ?? []).join(" "),
|
|
102
|
+
raw: item
|
|
101
103
|
};
|
|
102
104
|
});
|
|
103
105
|
});
|
|
@@ -205,7 +207,8 @@ const remoteEntries = computed(() => {
|
|
|
205
207
|
key: String(idx),
|
|
206
208
|
label: labelOf(option),
|
|
207
209
|
value: valueOf(option),
|
|
208
|
-
keywords: keywordsOf(option)
|
|
210
|
+
keywords: keywordsOf(option),
|
|
211
|
+
raw: option
|
|
209
212
|
}));
|
|
210
213
|
});
|
|
211
214
|
const entries = computed(
|
|
@@ -244,6 +247,14 @@ const selectedKeySet = computed(() => new Set(selectedKeys.value));
|
|
|
244
247
|
const selectedEntries = computed(
|
|
245
248
|
() => selectedKeys.value.map((k) => entries.value.find((e) => e.key === k)).filter((e) => !!e)
|
|
246
249
|
);
|
|
250
|
+
publishSelection(
|
|
251
|
+
props.column.id,
|
|
252
|
+
() => selectedEntries.value.length > 0 ? selectedEntries.value : void 0,
|
|
253
|
+
{
|
|
254
|
+
identity: (list) => list.map((e) => e.key).join(" "),
|
|
255
|
+
raw: (list) => list.map((e) => e.raw)
|
|
256
|
+
}
|
|
257
|
+
);
|
|
247
258
|
const triggerLabel = computed(() => {
|
|
248
259
|
const arr = selectedEntries.value;
|
|
249
260
|
if (arr.length === 0) return "";
|
|
@@ -7,6 +7,7 @@ export declare const compatibilityDate: "2026-05-28";
|
|
|
7
7
|
export declare const metadata: {
|
|
8
8
|
readonly name: "多选";
|
|
9
9
|
readonly icon: "fluent:chevron-down-20-regular";
|
|
10
|
+
readonly selection: true;
|
|
10
11
|
};
|
|
11
12
|
export declare function itemSchema(configure: (env: Environment) => void): Schema.Struct<{
|
|
12
13
|
id: Schema.refine<string, typeof Schema.String>;
|
|
@@ -15,7 +15,10 @@ export const type = "com.shwfed.table.column.combobox-multi";
|
|
|
15
15
|
export const compatibilityDate = "2026-05-28";
|
|
16
16
|
export const metadata = {
|
|
17
17
|
name: "\u591A\u9009",
|
|
18
|
-
icon: "fluent:chevron-down-20-regular"
|
|
18
|
+
icon: "fluent:chevron-down-20-regular",
|
|
19
|
+
// Publishes its resolved options (array) to the per-row `selections` registry
|
|
20
|
+
// (runtime.vue), readable via `selections["<id>"]`.
|
|
21
|
+
selection: true
|
|
19
22
|
};
|
|
20
23
|
const isListType = (actual) => actual === "dyn" || actual.startsWith("list");
|
|
21
24
|
const isKeywordsType = (actual) => actual === "dyn" || actual.startsWith("list") || actual.startsWith("optional");
|
|
@@ -9,6 +9,7 @@ import { useI18n } from "vue-i18n";
|
|
|
9
9
|
import { asRequest, fetchJsonOption } from "../../../../../share/request";
|
|
10
10
|
import { cel as _rawCel } from "../../../../../utils/cel";
|
|
11
11
|
import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
|
|
12
|
+
import { publishSelection } from "../../../../../utils/selections-registry";
|
|
12
13
|
import { getLocalizedText } from "../../../../../share/locale";
|
|
13
14
|
import { dispatchTriggers, useEventChannel } from "../../../../../share/event-bus";
|
|
14
15
|
import {
|
|
@@ -97,7 +98,8 @@ const staticEntries = computed(() => {
|
|
|
97
98
|
value: item.value.value,
|
|
98
99
|
label: labelTpl ? safeInterpolate(labelTpl, {}) : "",
|
|
99
100
|
tooltip: tooltipTpl ? safeInterpolate(tooltipTpl, {}) : void 0,
|
|
100
|
-
keywords: (item.keywords ?? []).join(" ")
|
|
101
|
+
keywords: (item.keywords ?? []).join(" "),
|
|
102
|
+
raw: item
|
|
101
103
|
};
|
|
102
104
|
});
|
|
103
105
|
});
|
|
@@ -205,7 +207,8 @@ const remoteEntries = computed(() => {
|
|
|
205
207
|
key: String(idx),
|
|
206
208
|
label: labelOf(option),
|
|
207
209
|
value: valueOf(option),
|
|
208
|
-
keywords: keywordsOf(option)
|
|
210
|
+
keywords: keywordsOf(option),
|
|
211
|
+
raw: option
|
|
209
212
|
}));
|
|
210
213
|
});
|
|
211
214
|
const entries = computed(
|
|
@@ -232,6 +235,11 @@ const selectedEntry = computed(
|
|
|
232
235
|
);
|
|
233
236
|
const selectedKey = computed(() => selectedEntry.value?.key);
|
|
234
237
|
const selectedLabel = computed(() => selectedEntry.value?.label ?? "");
|
|
238
|
+
publishSelection(
|
|
239
|
+
props.column.id,
|
|
240
|
+
() => selectedEntry.value,
|
|
241
|
+
{ identity: (entry) => entry.key, raw: (entry) => entry.raw }
|
|
242
|
+
);
|
|
235
243
|
const open = ref(false);
|
|
236
244
|
const isDisabled = computed(
|
|
237
245
|
() => !isInteractive.value || isDisabledByConfig.value || pending.value
|
|
@@ -7,6 +7,7 @@ export declare const compatibilityDate: "2026-05-28";
|
|
|
7
7
|
export declare const metadata: {
|
|
8
8
|
readonly name: "单选";
|
|
9
9
|
readonly icon: "fluent:chevron-down-20-regular";
|
|
10
|
+
readonly selection: true;
|
|
10
11
|
};
|
|
11
12
|
export declare function itemSchema(configure: (env: Environment) => void): Schema.Struct<{
|
|
12
13
|
id: Schema.refine<string, typeof Schema.String>;
|
|
@@ -15,7 +15,10 @@ export const type = "com.shwfed.table.column.combobox-single";
|
|
|
15
15
|
export const compatibilityDate = "2026-05-28";
|
|
16
16
|
export const metadata = {
|
|
17
17
|
name: "\u5355\u9009",
|
|
18
|
-
icon: "fluent:chevron-down-20-regular"
|
|
18
|
+
icon: "fluent:chevron-down-20-regular",
|
|
19
|
+
// Publishes its resolved option (the source record) to the per-row
|
|
20
|
+
// `selections` registry (runtime.vue), readable via `selections["<id>"]`.
|
|
21
|
+
selection: true
|
|
19
22
|
};
|
|
20
23
|
const isListType = (actual) => actual === "dyn" || actual.startsWith("list");
|
|
21
24
|
const isKeywordsType = (actual) => actual === "dyn" || actual.startsWith("list") || actual.startsWith("optional");
|
|
@@ -5,6 +5,7 @@ import { computed, ref, shallowRef, watch } from "vue";
|
|
|
5
5
|
import { useI18n } from "vue-i18n";
|
|
6
6
|
import { cel as _rawCel } from "../../../../../utils/cel";
|
|
7
7
|
import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
|
|
8
|
+
import { publishSelection } from "../../../../../utils/selections-registry";
|
|
8
9
|
import { getLocalizedText } from "../../../../../share/locale";
|
|
9
10
|
import { fetchJsonOption } from "../../../../../share/request";
|
|
10
11
|
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "../../../../ui/input-group";
|
|
@@ -203,6 +204,21 @@ const roots = computed(
|
|
|
203
204
|
nodeChildren: nodeChildrenList
|
|
204
205
|
})
|
|
205
206
|
);
|
|
207
|
+
const selectedLeaves = computed(
|
|
208
|
+
() => committedKeys.value.map((k) => {
|
|
209
|
+
const path = findWrappedPath(roots.value, k);
|
|
210
|
+
if (!path || path.length === 0) return void 0;
|
|
211
|
+
return path[path.length - 1];
|
|
212
|
+
}).filter((node) => node !== void 0)
|
|
213
|
+
);
|
|
214
|
+
publishSelection(
|
|
215
|
+
props.column.id,
|
|
216
|
+
() => selectedLeaves.value.length > 0 ? selectedLeaves.value : void 0,
|
|
217
|
+
{
|
|
218
|
+
identity: (list) => list.map((w) => w.key).join(" "),
|
|
219
|
+
raw: (list) => list.map((w) => w.raw)
|
|
220
|
+
}
|
|
221
|
+
);
|
|
206
222
|
const pendingKeys = ref(null);
|
|
207
223
|
const open = ref(false);
|
|
208
224
|
watch(open, (next, prev) => {
|
|
@@ -7,6 +7,7 @@ export declare const compatibilityDate: "2026-05-28";
|
|
|
7
7
|
export declare const metadata: {
|
|
8
8
|
readonly name: "下拉树(多选)";
|
|
9
9
|
readonly icon: "fluent:tree-evergreen-20-regular";
|
|
10
|
+
readonly selection: true;
|
|
10
11
|
};
|
|
11
12
|
export declare function schema(configure: (env: Environment) => void): Schema.Struct<{
|
|
12
13
|
placeholder: Schema.optional<Schema.TupleType<readonly [Schema.Struct<{
|
|
@@ -13,7 +13,9 @@ export const type = "com.shwfed.table.column.tree-combobox-multi";
|
|
|
13
13
|
export const compatibilityDate = "2026-05-28";
|
|
14
14
|
export const metadata = {
|
|
15
15
|
name: "\u4E0B\u62C9\u6811\uFF08\u591A\u9009\uFF09",
|
|
16
|
-
icon: "fluent:tree-evergreen-20-regular"
|
|
16
|
+
icon: "fluent:tree-evergreen-20-regular",
|
|
17
|
+
// Publishes its resolved nodes (array) to the per-row `selections` registry (runtime.vue), readable via `selections["<id>"]`.
|
|
18
|
+
selection: true
|
|
17
19
|
};
|
|
18
20
|
const isListLike = (t) => t === "dyn" || t.startsWith("list") || t.startsWith("optional");
|
|
19
21
|
const isKeyType = (t) => t === "string" || t === "number" || t === "dyn";
|
|
@@ -5,6 +5,7 @@ import { computed, ref, shallowRef, watch } from "vue";
|
|
|
5
5
|
import { useI18n } from "vue-i18n";
|
|
6
6
|
import { cel as _rawCel } from "../../../../../utils/cel";
|
|
7
7
|
import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
|
|
8
|
+
import { publishSelection } from "../../../../../utils/selections-registry";
|
|
8
9
|
import { getLocalizedText } from "../../../../../share/locale";
|
|
9
10
|
import { fetchJsonOption } from "../../../../../share/request";
|
|
10
11
|
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "../../../../ui/input-group";
|
|
@@ -206,14 +207,21 @@ const roots = computed(
|
|
|
206
207
|
nodeChildren: nodeChildrenList
|
|
207
208
|
})
|
|
208
209
|
);
|
|
209
|
-
const
|
|
210
|
+
const selectedWrapped = computed(() => {
|
|
210
211
|
const k = model.value;
|
|
211
|
-
if (!k) return
|
|
212
|
+
if (!k) return void 0;
|
|
212
213
|
const path = findWrappedPath(roots.value, k);
|
|
213
|
-
if (!path || path.length === 0) return
|
|
214
|
-
|
|
215
|
-
return wrappedLabelText(leaf);
|
|
214
|
+
if (!path || path.length === 0) return void 0;
|
|
215
|
+
return path[path.length - 1];
|
|
216
216
|
});
|
|
217
|
+
const triggerLabel = computed(
|
|
218
|
+
() => selectedWrapped.value ? wrappedLabelText(selectedWrapped.value) : ""
|
|
219
|
+
);
|
|
220
|
+
publishSelection(
|
|
221
|
+
props.column.id,
|
|
222
|
+
() => selectedWrapped.value,
|
|
223
|
+
{ identity: (w) => w.key, raw: (w) => w.raw }
|
|
224
|
+
);
|
|
217
225
|
const initialExpanded = computed(() => {
|
|
218
226
|
if (!props.column.expandAll) return [];
|
|
219
227
|
const out = [];
|
|
@@ -7,6 +7,7 @@ export declare const compatibilityDate: "2026-05-28";
|
|
|
7
7
|
export declare const metadata: {
|
|
8
8
|
readonly name: "下拉树(单选)";
|
|
9
9
|
readonly icon: "fluent:tree-evergreen-20-regular";
|
|
10
|
+
readonly selection: true;
|
|
10
11
|
};
|
|
11
12
|
export declare function schema(configure: (env: Environment) => void): Schema.Struct<{
|
|
12
13
|
placeholder: Schema.optional<Schema.TupleType<readonly [Schema.Struct<{
|
|
@@ -13,7 +13,9 @@ export const type = "com.shwfed.table.column.tree-combobox-single";
|
|
|
13
13
|
export const compatibilityDate = "2026-05-28";
|
|
14
14
|
export const metadata = {
|
|
15
15
|
name: "\u4E0B\u62C9\u6811\uFF08\u5355\u9009\uFF09",
|
|
16
|
-
icon: "fluent:tree-evergreen-20-regular"
|
|
16
|
+
icon: "fluent:tree-evergreen-20-regular",
|
|
17
|
+
// Publishes its resolved node (backend record) to the per-row `selections` registry (runtime.vue), readable via `selections["<id>"]`.
|
|
18
|
+
selection: true
|
|
17
19
|
};
|
|
18
20
|
const isListLike = (t) => t === "dyn" || t.startsWith("list") || t.startsWith("optional");
|
|
19
21
|
const isKeyType = (t) => t === "string" || t === "number" || t === "dyn";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed, defineComponent, inject, onBeforeUnmount, provide, ref, watch } from "vue";
|
|
3
|
-
import { provideCELContext, provideScopeAncestor } from "../../utils/cel-context";
|
|
3
|
+
import { provideCELContext, provideScopeAncestor, provideSelectionRoster } from "../../utils/cel-context";
|
|
4
4
|
import { BREADCRUMB_EXTENSION_KEY } from "../config/breadcrumb-extension";
|
|
5
5
|
import { TABLE_COLUMN_LAYOUT_KEY } from "./column-layout";
|
|
6
6
|
import { Icon } from "@iconify/vue";
|
|
@@ -310,6 +310,10 @@ const selectedColumnEntry = computed(() => {
|
|
|
310
310
|
if (!c) return void 0;
|
|
311
311
|
return findColumnEntry(c.type, c.compatibilityDate);
|
|
312
312
|
});
|
|
313
|
+
const selectionRoster = computed(
|
|
314
|
+
() => editingColumns.value.filter((c) => findColumnEntry(c.type, c.compatibilityDate)?.metadata?.selection).map((c) => ({ id: c.id, name: columnLabel(c) }))
|
|
315
|
+
);
|
|
316
|
+
provideSelectionRoster(selectionRoster);
|
|
313
317
|
const pinnedLeftIds = computed(() => {
|
|
314
318
|
const ids = editingGeneralConfig.value.initialState?.columnPinning?.left;
|
|
315
319
|
return new Set(Array.isArray(ids) ? ids : []);
|
|
@@ -3,6 +3,7 @@ import { Effect } from "effect";
|
|
|
3
3
|
import { customRef } from "vue";
|
|
4
4
|
import { cel as _rawCel } from "../../utils/cel";
|
|
5
5
|
import { celBindings, injectCELContext, provideCELContext, provideScopeAddress } from "../../utils/cel-context";
|
|
6
|
+
import { provideSelectionsRegistry } from "../../utils/selections-registry";
|
|
6
7
|
import { useDerived, useDerivedQuiescence } from "../form/utils/derived";
|
|
7
8
|
import { provideFormState } from "../form/utils/state";
|
|
8
9
|
defineOptions({ name: "ShwfedTableRowProvider" });
|
|
@@ -24,6 +25,7 @@ const rowRef = customRef((track, trigger) => ({
|
|
|
24
25
|
trigger();
|
|
25
26
|
}
|
|
26
27
|
}));
|
|
28
|
+
const selections = provideSelectionsRegistry();
|
|
27
29
|
provideCELContext({
|
|
28
30
|
row: {
|
|
29
31
|
type: "dyn",
|
|
@@ -36,6 +38,12 @@ provideCELContext({
|
|
|
36
38
|
label: "\u884C\u5E8F\u53F7",
|
|
37
39
|
description: "\u5F53\u524D\u884C\u5728\u6240\u6709\u6570\u636E\u4E2D\u7684\u5E8F\u53F7\uFF0C\u4ECE `0` \u5F00\u59CB\u3002",
|
|
38
40
|
value: () => props.displayIndex
|
|
41
|
+
},
|
|
42
|
+
selections: {
|
|
43
|
+
type: "dyn",
|
|
44
|
+
label: "\u9009\u4E2D\u9879",
|
|
45
|
+
description: "\u672C\u884C\u5404\u9009\u62E9\u5217\u5F53\u524D\u9009\u4E2D\u9879\u7684\u5B8C\u6574\u5BF9\u8C61\uFF08\u6309\u5217\u6807\u8BC6\uFF09\u3002",
|
|
46
|
+
value: () => selections.entries.value
|
|
39
47
|
}
|
|
40
48
|
});
|
|
41
49
|
if (props.scopeId) {
|
|
@@ -9,6 +9,13 @@ type SchemaFactory = (configure: (env: Environment) => void) => AnySchema;
|
|
|
9
9
|
export type ColumnMetadata = Readonly<{
|
|
10
10
|
name: string;
|
|
11
11
|
icon: string;
|
|
12
|
+
/**
|
|
13
|
+
* True when this column publishes its resolved option to the per-row
|
|
14
|
+
* `selections` registry (its runtime keyed by `column.id`). Set it together
|
|
15
|
+
* with the runtime publish so the expression editor never advertises a column
|
|
16
|
+
* that writes nothing. Mirrors `FieldMetadata.selection` on the form host.
|
|
17
|
+
*/
|
|
18
|
+
selection?: boolean;
|
|
12
19
|
}>;
|
|
13
20
|
export type ColumnDefDeps = Readonly<{
|
|
14
21
|
getLocaleText: (value: LocaleValue | undefined) => string | undefined;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
2
|
import { Icon } from "@iconify/vue";
|
|
3
3
|
import { h } from "vue";
|
|
4
|
+
import { SELECTIONS_VAR } from "../../../utils/cel-context.js";
|
|
4
5
|
import { Expression, LocaleMarkdown } from "../../../share/expression.js";
|
|
5
6
|
import { Locale } from "../../../share/locale.js";
|
|
6
7
|
import { md } from "../../../share/markdown.js";
|
|
@@ -97,6 +98,9 @@ export function registerRowVariablesIfAbsent(env) {
|
|
|
97
98
|
if (!declared.has("index")) {
|
|
98
99
|
env.registerVariable("index", "number", { label: "\u884C\u5E8F\u53F7", description: "\u884C\u7D22\u5F15" });
|
|
99
100
|
}
|
|
101
|
+
if (!declared.has(SELECTIONS_VAR)) {
|
|
102
|
+
env.registerVariable(SELECTIONS_VAR, "dyn", { label: "\u9009\u4E2D\u9879", description: "\u672C\u884C\u5404\u9009\u62E9\u5217\u5F53\u524D\u9009\u4E2D\u9879\u7684\u5B8C\u6574\u5BF9\u8C61\uFF08\u6309\u5217\u6807\u8BC6\uFF09" });
|
|
103
|
+
}
|
|
100
104
|
}
|
|
101
105
|
function configureWithRow(configure) {
|
|
102
106
|
return (env) => {
|
|
@@ -6,6 +6,7 @@ import { onBeforeUnmount, onMounted, useTemplateRef, watch } from "vue";
|
|
|
6
6
|
import { cn } from "../../../utils/cn";
|
|
7
7
|
import { celHighlighting } from "./cel-language";
|
|
8
8
|
import { scopeChips, scopeLookupFacet } from "./chip-extension";
|
|
9
|
+
import { selectionChips, selectionLookupFacet } from "./selection-chip-extension";
|
|
9
10
|
defineOptions({ name: "UiCodeMirrorInput" });
|
|
10
11
|
const props = defineProps({
|
|
11
12
|
class: { type: [Boolean, null, String, Object, Array], required: false, skipCheck: true },
|
|
@@ -13,12 +14,14 @@ const props = defineProps({
|
|
|
13
14
|
modelValue: { type: String, required: false },
|
|
14
15
|
multiline: { type: Boolean, required: false },
|
|
15
16
|
placeholder: { type: String, required: false },
|
|
16
|
-
scopeLookup: { type: Map, required: true }
|
|
17
|
+
scopeLookup: { type: Map, required: true },
|
|
18
|
+
selectionLookup: { type: Map, required: true }
|
|
17
19
|
});
|
|
18
20
|
const emits = defineEmits(["update:modelValue"]);
|
|
19
21
|
const host = useTemplateRef("host");
|
|
20
22
|
let view = null;
|
|
21
23
|
const lookupCompartment = new Compartment();
|
|
24
|
+
const selectionLookupCompartment = new Compartment();
|
|
22
25
|
const modeCompartment = new Compartment();
|
|
23
26
|
let applyingExternal = false;
|
|
24
27
|
const editorTheme = EditorView.theme({
|
|
@@ -73,6 +76,7 @@ function makeState(doc) {
|
|
|
73
76
|
keymap.of([...defaultKeymap, ...historyKeymap]),
|
|
74
77
|
cmPlaceholder(props.placeholder ?? ""),
|
|
75
78
|
lookupCompartment.of(scopeLookupFacet.of(props.scopeLookup)),
|
|
79
|
+
selectionLookupCompartment.of(selectionLookupFacet.of(props.selectionLookup)),
|
|
76
80
|
modeCompartment.of(modeExtension(!!props.multiline)),
|
|
77
81
|
editorTheme,
|
|
78
82
|
// CEL syntax colours sit *under* the chips: the chip plugin's
|
|
@@ -80,6 +84,7 @@ function makeState(doc) {
|
|
|
80
84
|
// marks here only show through on ordinary expression text.
|
|
81
85
|
celHighlighting(),
|
|
82
86
|
scopeChips(),
|
|
87
|
+
selectionChips(),
|
|
83
88
|
EditorView.contentAttributes.of({ "aria-label": props.placeholder ?? "Expression" }),
|
|
84
89
|
EditorView.updateListener.of((update) => {
|
|
85
90
|
if (!update.docChanged || applyingExternal) return;
|
|
@@ -110,6 +115,9 @@ watch(() => props.modelValue, (next) => {
|
|
|
110
115
|
watch(() => props.scopeLookup, (lookup) => {
|
|
111
116
|
view?.dispatch({ effects: lookupCompartment.reconfigure(scopeLookupFacet.of(lookup)) });
|
|
112
117
|
});
|
|
118
|
+
watch(() => props.selectionLookup, (lookup) => {
|
|
119
|
+
view?.dispatch({ effects: selectionLookupCompartment.reconfigure(selectionLookupFacet.of(lookup)) });
|
|
120
|
+
});
|
|
113
121
|
watch(() => props.multiline, (multiline) => {
|
|
114
122
|
view?.dispatch({ effects: modeCompartment.reconfigure(modeExtension(!!multiline)) });
|
|
115
123
|
});
|
|
@@ -14,11 +14,11 @@ type __VLS_Props = {
|
|
|
14
14
|
extraVars?: Record<string, VarSpec>;
|
|
15
15
|
unlistedVarsAreDyn?: boolean;
|
|
16
16
|
};
|
|
17
|
-
declare var __VLS_13: {},
|
|
17
|
+
declare var __VLS_13: {}, __VLS_150: {};
|
|
18
18
|
type __VLS_Slots = {} & {
|
|
19
19
|
leading?: (props: typeof __VLS_13) => any;
|
|
20
20
|
} & {
|
|
21
|
-
trailing?: (props: typeof
|
|
21
|
+
trailing?: (props: typeof __VLS_150) => any;
|
|
22
22
|
};
|
|
23
23
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
24
24
|
"update:modelValue": (payload: string) => any;
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
import { Icon } from "@iconify/vue";
|
|
3
3
|
import { computed, ref, useSlots, useTemplateRef, watch } from "vue";
|
|
4
4
|
import { buildCheckEnvironment, evaluateExpression } from "../../../share/expression";
|
|
5
|
-
import { injectCELContext, useScopeAncestry } from "../../../utils/cel-context";
|
|
5
|
+
import { injectCELContext, useScopeAncestry, useSelectionRoster } from "../../../utils/cel-context";
|
|
6
6
|
import { Markdown } from "../markdown";
|
|
7
7
|
import CodeMirrorInput from "./CodeMirrorInput.vue";
|
|
8
8
|
import { buildScopeLookup } from "./scope-refs";
|
|
9
|
-
import {
|
|
9
|
+
import { buildSelectionLookup } from "./selection-refs";
|
|
10
|
+
import { buildScopeEntries, buildSelectionEntries, buildVarEntries } from "./picker-entries";
|
|
10
11
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "../command";
|
|
11
12
|
import { InputGroup, InputGroupAddon, InputGroupButton } from "../input-group";
|
|
12
13
|
import { Popover, PopoverContent, PopoverTrigger } from "../popover";
|
|
@@ -24,10 +25,13 @@ const props = defineProps({
|
|
|
24
25
|
const emits = defineEmits(["update:modelValue"]);
|
|
25
26
|
const celContext = injectCELContext();
|
|
26
27
|
const scopeAncestry = useScopeAncestry();
|
|
28
|
+
const selectionRoster = useSelectionRoster();
|
|
27
29
|
const varEntries = computed(() => buildVarEntries(celContext, props.extraVars));
|
|
28
30
|
const scopeEntries = computed(() => buildScopeEntries(scopeAncestry.value.slice(1)));
|
|
31
|
+
const selectionEntries = computed(() => buildSelectionEntries(selectionRoster.value));
|
|
29
32
|
const scopeLookup = computed(() => buildScopeLookup(scopeAncestry.value));
|
|
30
|
-
const
|
|
33
|
+
const selectionLookup = computed(() => buildSelectionLookup(selectionRoster.value));
|
|
34
|
+
const hasVars = computed(() => varEntries.value.length > 0 || scopeEntries.value.length > 0 || selectionEntries.value.length > 0);
|
|
31
35
|
const checkEnvironment = computed(() => {
|
|
32
36
|
const vars = /* @__PURE__ */ new Map();
|
|
33
37
|
for (const [name, entry] of Object.entries(celContext)) vars.set(name, entry.type);
|
|
@@ -46,6 +50,7 @@ const open = ref(false);
|
|
|
46
50
|
const entries = ref([]);
|
|
47
51
|
const shownVars = computed(() => entries.value.filter((e) => e.group === "var"));
|
|
48
52
|
const shownScopes = computed(() => entries.value.filter((e) => e.group === "scope"));
|
|
53
|
+
const shownSelections = computed(() => entries.value.filter((e) => e.group === "selection"));
|
|
49
54
|
const hoveredName = ref(null);
|
|
50
55
|
const editorRef = useTemplateRef("editor");
|
|
51
56
|
function insertVariable(text) {
|
|
@@ -54,7 +59,7 @@ function insertVariable(text) {
|
|
|
54
59
|
}
|
|
55
60
|
watch(open, (v) => {
|
|
56
61
|
if (v) {
|
|
57
|
-
entries.value = [...varEntries.value, ...scopeEntries.value];
|
|
62
|
+
entries.value = [...varEntries.value, ...selectionEntries.value, ...scopeEntries.value];
|
|
58
63
|
hoveredName.value = entries.value[0]?.id ?? null;
|
|
59
64
|
}
|
|
60
65
|
});
|
|
@@ -91,6 +96,7 @@ const addonAlign = computed(
|
|
|
91
96
|
:placeholder="props.placeholder"
|
|
92
97
|
:multiline="props.multiline"
|
|
93
98
|
:scope-lookup="scopeLookup"
|
|
99
|
+
:selection-lookup="selectionLookup"
|
|
94
100
|
:class="props.class"
|
|
95
101
|
@update:model-value="(v) => emits('update:modelValue', v)"
|
|
96
102
|
/>
|
|
@@ -141,6 +147,29 @@ const addonAlign = computed(
|
|
|
141
147
|
</span>
|
|
142
148
|
</CommandItem>
|
|
143
149
|
</CommandGroup>
|
|
150
|
+
<CommandGroup
|
|
151
|
+
v-if="shownSelections.length > 0"
|
|
152
|
+
heading="选中项"
|
|
153
|
+
>
|
|
154
|
+
<CommandItem
|
|
155
|
+
v-for="entry in shownSelections"
|
|
156
|
+
:key="entry.id"
|
|
157
|
+
:value="`${entry.display} ${entry.id}`"
|
|
158
|
+
class="cursor-pointer gap-2"
|
|
159
|
+
@select="insertVariable(entry.insert)"
|
|
160
|
+
@mouseenter="hoveredName = entry.id"
|
|
161
|
+
@focus="hoveredName = entry.id"
|
|
162
|
+
>
|
|
163
|
+
<Icon
|
|
164
|
+
icon="fluent:cursor-click-20-regular"
|
|
165
|
+
class="size-3.5 shrink-0 text-teal-500"
|
|
166
|
+
/>
|
|
167
|
+
<span class="flex-1 truncate text-xs text-zinc-700">{{ entry.display }}</span>
|
|
168
|
+
<span class="rounded bg-teal-100 px-1.5 py-0.5 font-mono text-[10px] leading-none text-teal-700 select-none">
|
|
169
|
+
{{ entry.type }}
|
|
170
|
+
</span>
|
|
171
|
+
</CommandItem>
|
|
172
|
+
</CommandGroup>
|
|
144
173
|
<CommandGroup
|
|
145
174
|
v-if="shownScopes.length > 0"
|
|
146
175
|
heading="跨层引用"
|
|
@@ -14,11 +14,11 @@ type __VLS_Props = {
|
|
|
14
14
|
extraVars?: Record<string, VarSpec>;
|
|
15
15
|
unlistedVarsAreDyn?: boolean;
|
|
16
16
|
};
|
|
17
|
-
declare var __VLS_13: {},
|
|
17
|
+
declare var __VLS_13: {}, __VLS_150: {};
|
|
18
18
|
type __VLS_Slots = {} & {
|
|
19
19
|
leading?: (props: typeof __VLS_13) => any;
|
|
20
20
|
} & {
|
|
21
|
-
trailing?: (props: typeof
|
|
21
|
+
trailing?: (props: typeof __VLS_150) => any;
|
|
22
22
|
};
|
|
23
23
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
24
24
|
"update:modelValue": (payload: string) => any;
|