@veltra/desktop 1.0.13 → 1.0.14

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 (180) hide show
  1. package/dist/components/action/action-group.js +110 -3
  2. package/dist/components/action/action-group.js.map +1 -1
  3. package/dist/components/action/action-group.vue.d.ts +16 -3
  4. package/dist/components/action/action.js +26 -13
  5. package/dist/components/action/action.js.map +1 -1
  6. package/dist/components/action/action.vue.d.ts +2 -2
  7. package/dist/components/action/style.js +2 -1
  8. package/dist/components/action/style2.css +35 -7
  9. package/dist/components/auto-complete/auto-complete.vue.d.ts +2 -2
  10. package/dist/components/batch-edit/batch-edit-form.js +106 -42
  11. package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
  12. package/dist/components/batch-edit/batch-edit-list.js +84 -47
  13. package/dist/components/batch-edit/batch-edit-list.js.map +1 -1
  14. package/dist/components/batch-edit/batch-edit.js +42 -10
  15. package/dist/components/batch-edit/batch-edit.js.map +1 -1
  16. package/dist/components/batch-edit/style.js +2 -4
  17. package/dist/components/batch-edit/style2.css +202 -30
  18. package/dist/components/batch-edit/use-edit.js +45 -9
  19. package/dist/components/batch-edit/use-edit.js.map +1 -1
  20. package/dist/components/cascade/cascade.js +3 -1
  21. package/dist/components/cascade/cascade.js.map +1 -1
  22. package/dist/components/cascade/cascade.vue.d.ts +2 -2
  23. package/dist/components/checkbox/checkbox-button.vue.d.ts +1 -1
  24. package/dist/components/checkbox-group/checkbox-group.vue.d.ts +2 -2
  25. package/dist/components/code-editor/code-editor.js +145 -49
  26. package/dist/components/code-editor/code-editor.js.map +1 -1
  27. package/dist/components/code-editor/code-editor.vue.d.ts +2 -0
  28. package/dist/components/code-editor/style2.css +87 -19
  29. package/dist/components/date-panel/date-panel.vue.d.ts +1 -1
  30. package/dist/components/date-picker/date-picker.vue.d.ts +2 -2
  31. package/dist/components/date-range-picker/date-range-picker.vue.d.ts +2 -2
  32. package/dist/components/dialog/dialog.js +6 -2
  33. package/dist/components/dialog/dialog.js.map +1 -1
  34. package/dist/components/dialog/style2.css +2 -3
  35. package/dist/components/expression-editor/components/path-preview.js +27 -0
  36. package/dist/components/expression-editor/components/path-preview.js.map +1 -0
  37. package/dist/components/expression-editor/components/variable-picker.js +199 -153
  38. package/dist/components/expression-editor/components/variable-picker.js.map +1 -1
  39. package/dist/components/expression-editor/core/chip.js +54 -0
  40. package/dist/components/expression-editor/core/chip.js.map +1 -0
  41. package/dist/components/expression-editor/core/editor.js +424 -0
  42. package/dist/components/expression-editor/core/editor.js.map +1 -0
  43. package/dist/components/expression-editor/core/mention.js +91 -0
  44. package/dist/components/expression-editor/core/mention.js.map +1 -0
  45. package/dist/components/expression-editor/core/model.js +64 -0
  46. package/dist/components/expression-editor/core/model.js.map +1 -0
  47. package/dist/components/expression-editor/di.js +4 -10
  48. package/dist/components/expression-editor/di.js.map +1 -1
  49. package/dist/components/expression-editor/expression-editor.js +168 -114
  50. package/dist/components/expression-editor/expression-editor.js.map +1 -1
  51. package/dist/components/expression-editor/expression-editor.vue.d.ts +2 -1
  52. package/dist/components/expression-editor/style.js +0 -2
  53. package/dist/components/expression-editor/style2.css +145 -219
  54. package/dist/components/index.js +54 -54
  55. package/dist/components/input/input.vue.d.ts +2 -2
  56. package/dist/components/layout/layout.js +12 -11
  57. package/dist/components/layout/layout.js.map +1 -1
  58. package/dist/components/multi-select/multi-select.vue.d.ts +3 -3
  59. package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +3 -3
  60. package/dist/components/notification/notification.vue.d.ts +1 -1
  61. package/dist/components/number/number.vue.d.ts +1 -1
  62. package/dist/components/number-input/number-input.js +4 -4
  63. package/dist/components/number-input/number-input.js.map +1 -1
  64. package/dist/components/number-input/number-input.vue.d.ts +2 -2
  65. package/dist/components/number-range-input/number-range-input.vue.d.ts +1 -1
  66. package/dist/components/password-input/password-input.vue.d.ts +1 -1
  67. package/dist/components/pop-confirm/pop-confirm.vue.d.ts +1 -1
  68. package/dist/components/radio-group/radio-group.vue.d.ts +2 -2
  69. package/dist/components/rich-text-editor/rich-text-editor.js +1 -1
  70. package/dist/components/rich-text-editor/rich-text-editor.vue.d.ts +1 -1
  71. package/dist/components/rich-text-editor/toolbar.js +2 -2
  72. package/dist/components/select/select.vue.d.ts +2 -2
  73. package/dist/components/steps/steps.vue.d.ts +1 -1
  74. package/dist/components/table/use-table.js +16 -0
  75. package/dist/components/table/use-table.js.map +1 -1
  76. package/dist/components/tabs/tabs-horizontal.vue.d.ts +1 -1
  77. package/dist/components/tabs/tabs-vertical.vue.d.ts +1 -1
  78. package/dist/components/tabs/tabs.vue.d.ts +1 -1
  79. package/dist/components/textarea/textarea.vue.d.ts +2 -2
  80. package/dist/components/tip/tip.vue.d.ts +1 -1
  81. package/dist/components/tree/style2.css +18 -12
  82. package/dist/components/tree/tree-node.js +7 -4
  83. package/dist/components/tree/tree-node.js.map +1 -1
  84. package/dist/components/tree-select/tree-select.vue.d.ts +3 -3
  85. package/dist/index.d.ts +3 -3
  86. package/dist/index.js +83 -83
  87. package/dist/style.js +3 -3
  88. package/dist/types/action.d.ts +38 -4
  89. package/dist/types/cascade.d.ts +2 -3
  90. package/dist/types/code-editor.d.ts +9 -2
  91. package/dist/types/expression-editor.d.ts +9 -1
  92. package/dist/types/index.d.ts +2 -2
  93. package/package.json +11 -12
  94. package/src/components/action/action-group.vue +126 -56
  95. package/src/components/action/action.vue +35 -12
  96. package/src/components/action/style.scss +46 -10
  97. package/src/components/action/style.ts +2 -1
  98. package/src/components/batch-edit/batch-edit-form.vue +121 -45
  99. package/src/components/batch-edit/batch-edit-list.vue +56 -39
  100. package/src/components/batch-edit/batch-edit.vue +57 -6
  101. package/src/components/batch-edit/style.scss +251 -37
  102. package/src/components/batch-edit/style.ts +5 -8
  103. package/src/components/batch-edit/use-edit.ts +58 -11
  104. package/src/components/cascade/cascade.vue +3 -1
  105. package/src/components/code-editor/code-editor.vue +198 -63
  106. package/src/components/code-editor/style.scss +110 -12
  107. package/src/components/dialog/dialog.vue +6 -2
  108. package/src/components/dialog/style.scss +4 -4
  109. package/src/components/expression-editor/__test__/chip.test.ts +86 -0
  110. package/src/components/expression-editor/__test__/mention.test.ts +122 -0
  111. package/src/components/expression-editor/__test__/model.test.ts +127 -0
  112. package/src/components/expression-editor/components/path-preview.vue +32 -0
  113. package/src/components/expression-editor/components/variable-picker.vue +224 -219
  114. package/src/components/expression-editor/core/chip.ts +101 -0
  115. package/src/components/expression-editor/core/editor.ts +513 -0
  116. package/src/components/expression-editor/core/mention.ts +121 -0
  117. package/src/components/expression-editor/core/model.ts +109 -0
  118. package/src/components/expression-editor/di.ts +4 -32
  119. package/src/components/expression-editor/expression-editor.vue +184 -151
  120. package/src/components/expression-editor/style.scss +148 -220
  121. package/src/components/expression-editor/style.ts +0 -2
  122. package/src/components/layout/layout.vue +17 -19
  123. package/src/components/number-input/number-input.vue +4 -4
  124. package/src/components/table/use-table.ts +16 -0
  125. package/src/components/tree/style.scss +30 -33
  126. package/src/components/tree/tree-node.vue +4 -2
  127. package/src/types/action.ts +42 -4
  128. package/src/types/cascade.ts +4 -3
  129. package/src/types/code-editor.ts +9 -2
  130. package/src/types/expression-editor.ts +9 -0
  131. package/dist/components/action/action-group.vue_vue_type_script_setup_true_lang.js +0 -65
  132. package/dist/components/action/action-group.vue_vue_type_script_setup_true_lang.js.map +0 -1
  133. package/dist/components/expression-editor/constants.js +0 -9
  134. package/dist/components/expression-editor/constants.js.map +0 -1
  135. package/dist/components/expression-editor/internal/editor-runtime/create-runtime.js +0 -47
  136. package/dist/components/expression-editor/internal/editor-runtime/create-runtime.js.map +0 -1
  137. package/dist/components/expression-editor/internal/editor-runtime/model-sync.js +0 -49
  138. package/dist/components/expression-editor/internal/editor-runtime/model-sync.js.map +0 -1
  139. package/dist/components/expression-editor/internal/features/commands/register-command-packs.js +0 -215
  140. package/dist/components/expression-editor/internal/features/commands/register-command-packs.js.map +0 -1
  141. package/dist/components/expression-editor/internal/features/drag-drop/drag-drop-service.js +0 -33
  142. package/dist/components/expression-editor/internal/features/drag-drop/drag-drop-service.js.map +0 -1
  143. package/dist/components/expression-editor/internal/features/insertion/insertion-service.js +0 -33
  144. package/dist/components/expression-editor/internal/features/insertion/insertion-service.js.map +0 -1
  145. package/dist/components/expression-editor/nodes/variable-node.js +0 -94
  146. package/dist/components/expression-editor/nodes/variable-node.js.map +0 -1
  147. package/dist/components/expression-editor/parser.js +0 -32
  148. package/dist/components/expression-editor/parser.js.map +0 -1
  149. package/dist/components/expression-editor/plain-text.js +0 -19
  150. package/dist/components/expression-editor/plain-text.js.map +0 -1
  151. package/dist/components/expression-editor/use-context.js +0 -69
  152. package/dist/components/expression-editor/use-context.js.map +0 -1
  153. package/dist/components/expression-editor/use-decorators.js +0 -27
  154. package/dist/components/expression-editor/use-decorators.js.map +0 -1
  155. package/dist/components/expression-editor/use-expression-drag-drop.js +0 -275
  156. package/dist/components/expression-editor/use-expression-drag-drop.js.map +0 -1
  157. package/src/components/batch-edit/batch-edit-new.vue +0 -168
  158. package/src/components/batch-edit/style-new.scss +0 -35
  159. package/src/components/batch-edit/use-edit-new.ts +0 -68
  160. package/src/components/batch-edit/use-tip.ts +0 -47
  161. package/src/components/expression-editor/__test__/architecture-boundaries.test.ts +0 -103
  162. package/src/components/expression-editor/__test__/architecture-compatibility.test.ts +0 -52
  163. package/src/components/expression-editor/__test__/drag-drop.test.ts +0 -171
  164. package/src/components/expression-editor/__test__/parser.test.ts +0 -62
  165. package/src/components/expression-editor/constants.ts +0 -6
  166. package/src/components/expression-editor/internal/contracts/editor-runtime.ts +0 -11
  167. package/src/components/expression-editor/internal/editor-runtime/create-runtime.ts +0 -64
  168. package/src/components/expression-editor/internal/editor-runtime/index.ts +0 -1
  169. package/src/components/expression-editor/internal/editor-runtime/model-sync.ts +0 -68
  170. package/src/components/expression-editor/internal/features/commands/register-command-packs.ts +0 -517
  171. package/src/components/expression-editor/internal/features/drag-drop/drag-drop-service.ts +0 -51
  172. package/src/components/expression-editor/internal/features/insertion/insertion-service.ts +0 -56
  173. package/src/components/expression-editor/nodes/variable-node.tsx +0 -118
  174. package/src/components/expression-editor/parser.ts +0 -46
  175. package/src/components/expression-editor/plain-text.ts +0 -25
  176. package/src/components/expression-editor/plan.md +0 -22
  177. package/src/components/expression-editor/use-context.ts +0 -134
  178. package/src/components/expression-editor/use-decorators.tsx +0 -29
  179. package/src/components/expression-editor/use-editor.ts +0 -12
  180. package/src/components/expression-editor/use-expression-drag-drop.ts +0 -396
@@ -1,24 +1,18 @@
1
1
  //#region src/components/expression-editor/di.ts
2
- /**
3
- * 扁平化变量树,创建 value -> VariableItem 的映射
4
- * @param variables 变量列表(支持树形结构)
5
- * @returns value -> VariableItem 的映射表
6
- */
2
+ /** 扁平化变量树,创建 value -> VariableItem 的映射,用于 DOM → 模型反推时补齐 label/type。 */
7
3
  function createVariableMap(variables) {
8
4
  const map = /* @__PURE__ */ new Map();
9
- function traverse(items, parentPath = []) {
5
+ function traverse(items) {
10
6
  if (!items) return;
11
7
  for (const item of items) {
12
- const currentPath = [...parentPath, item.label];
13
8
  map.set(item.value, item);
14
- if (item.children) traverse(item.children, currentPath);
9
+ if (item.children) traverse(item.children);
15
10
  }
16
11
  }
17
12
  traverse(variables);
18
13
  return map;
19
14
  }
20
- const ExpressionEditorDIKey = Symbol("ExpressionEditorDIKey");
21
15
  //#endregion
22
- export { ExpressionEditorDIKey, createVariableMap };
16
+ export { createVariableMap };
23
17
 
24
18
  //# sourceMappingURL=di.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"di.js","names":[],"sources":["../../../src/components/expression-editor/di.ts"],"sourcesContent":["import type { BEM } from '@veltra/utils'\nimport type { LexicalEditor } from 'lexical'\nimport type { InjectionKey, ComputedRef } from 'vue'\n\nimport type { ExpressionEditorProps, VariableItem } from '../../types'\n\n/**\n * 扁平化变量树,创建 value -> VariableItem 的映射\n * @param variables 变量列表(支持树形结构)\n * @returns value -> VariableItem 的映射表\n */\nexport function createVariableMap(variables?: VariableItem[]): Map<string, VariableItem> {\n const map = new Map<string, VariableItem>()\n\n function traverse(items: VariableItem[] | undefined, parentPath: string[] = []) {\n if (!items) return\n\n for (const item of items) {\n const currentPath = [...parentPath, item.label]\n map.set(item.value, item)\n\n if (item.children) {\n traverse(item.children, currentPath)\n }\n }\n }\n\n traverse(variables)\n return map\n}\n\nexport const ExpressionEditorDIKey: InjectionKey<{\n /** 组件的 BEM 类名 */\n cls: BEM<'expression-editor'>\n /** 组件的 props */\n editorProps: ExpressionEditorProps\n /** 编辑器实例 */\n editor: LexicalEditor\n /** 更新变量节点 */\n updateVariableNode: (oldValue: string, newValue: string, newLabel?: string) => void\n /** 变量映射表 (value -> VariableItem) */\n variableMap: ComputedRef<Map<string, VariableItem>>\n}> = Symbol('ExpressionEditorDIKey')\n"],"mappings":";;;;;;AAWA,SAAgB,kBAAkB,WAAuD;CACvF,MAAM,sBAAM,IAAI,KAA2B;CAE3C,SAAS,SAAS,OAAmC,aAAuB,EAAE,EAAE;AAC9E,MAAI,CAAC,MAAO;AAEZ,OAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,cAAc,CAAC,GAAG,YAAY,KAAK,MAAM;AAC/C,OAAI,IAAI,KAAK,OAAO,KAAK;AAEzB,OAAI,KAAK,SACP,UAAS,KAAK,UAAU,YAAY;;;AAK1C,UAAS,UAAU;AACnB,QAAO;;AAGT,MAAa,wBAWR,OAAO,wBAAwB"}
1
+ {"version":3,"file":"di.js","names":[],"sources":["../../../src/components/expression-editor/di.ts"],"sourcesContent":["import type { VariableItem } from '../../types'\n\n/** 扁平化变量树,创建 value -> VariableItem 的映射,用于 DOM → 模型反推时补齐 label/type。 */\nexport function createVariableMap(variables?: VariableItem[]): Map<string, VariableItem> {\n const map = new Map<string, VariableItem>()\n function traverse(items: VariableItem[] | undefined) {\n if (!items) return\n for (const item of items) {\n map.set(item.value, item)\n if (item.children) traverse(item.children)\n }\n }\n traverse(variables)\n return map\n}\n"],"mappings":";;AAGA,SAAgB,kBAAkB,WAAuD;CACvF,MAAM,sBAAM,IAAI,KAA2B;CAC3C,SAAS,SAAS,OAAmC;AACnD,MAAI,CAAC,MAAO;AACZ,OAAK,MAAM,QAAQ,OAAO;AACxB,OAAI,IAAI,KAAK,OAAO,KAAK;AACzB,OAAI,KAAK,SAAU,UAAS,KAAK,SAAS;;;AAG9C,UAAS,UAAU;AACnB,QAAO"}
@@ -1,21 +1,17 @@
1
- import { ExpressionEditorDIKey, createVariableMap } from "./di.js";
2
1
  import _sfc_main$1 from "./components/variable-picker.js";
3
- import { $isVariableNode } from "./nodes/variable-node.js";
4
- import { createExpressionEditorRuntime } from "./internal/editor-runtime/create-runtime.js";
5
- import { collectVariableNodeDescriptors, supportsNativeDnD } from "./use-expression-drag-drop.js";
6
- import { moveVariableByDirection } from "./internal/features/drag-drop/drag-drop-service.js";
7
- import { insertVariableAtTrigger } from "./internal/features/insertion/insertion-service.js";
8
- import { registerPlainText } from "./plain-text.js";
9
- import { useContext } from "./use-context.js";
10
- import { useDecorators } from "./use-decorators.js";
11
- import { Fragment, computed, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, isRef, normalizeClass, onBeforeUnmount, openBlock, provide, renderList, shallowRef, toDisplayString, unref, useTemplateRef } from "vue";
2
+ import { parse } from "./core/model.js";
3
+ import { createEditor } from "./core/editor.js";
4
+ import { createMention } from "./core/mention.js";
5
+ import { createVariableMap } from "./di.js";
6
+ import { computed, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, nextTick, normalizeClass, onBeforeUnmount, onMounted, openBlock, shallowRef, toDisplayString, unref, useTemplateRef, watch } from "vue";
12
7
  import { bem } from "@veltra/utils";
13
8
  import { useFormComponent, useFormFallbackProps } from "@veltra/compositions";
14
- import { $getRoot } from "lexical";
15
9
  //#region src/components/expression-editor/expression-editor.vue
16
- const _hoisted_1 = ["contenteditable"];
17
- const _hoisted_2 = ["disabled", "onClick"];
18
- const _hoisted_3 = ["disabled", "onClick"];
10
+ const _hoisted_1 = [
11
+ "contenteditable",
12
+ "data-empty",
13
+ "data-placeholder"
14
+ ];
19
15
  const _sfc_main = /* @__PURE__ */ defineComponent({
20
16
  name: "ExpressionEditor",
21
17
  __name: "expression-editor",
@@ -23,6 +19,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
23
19
  modelValue: {},
24
20
  placeholder: { default: "请输入表达式,输入 @ 可插入变量" },
25
21
  variables: {},
22
+ selectableLevels: { default: "leaf" },
26
23
  tips: {},
27
24
  span: {},
28
25
  label: {},
@@ -35,127 +32,184 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
35
32
  setup(__props, { emit: __emit }) {
36
33
  const props = __props;
37
34
  const emit = __emit;
38
- const showPlaceholder = computed(() => !props.modelValue || props.modelValue.trim() === "");
39
35
  const cls = bem("expression-editor");
40
36
  const { formProps } = useFormComponent();
41
37
  const { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props]);
42
- const className = computed(() => {
43
- return [
44
- cls.b,
45
- cls.m(size.value),
46
- bem.is("disabled", disabled.value),
47
- bem.is("readonly", readonly.value)
48
- ];
49
- });
50
- const { editor } = createExpressionEditorRuntime({
51
- disabled,
52
- readonly,
53
- cls,
54
- container: useTemplateRef("container"),
55
- props,
56
- emit
57
- });
58
- const { contextVisible, contextTriggerDom, textNode, charPosition, registerPickerKeyHandler, registerContextCommands } = useContext(editor);
59
- registerPlainText(editor, { getContextCommands: registerContextCommands });
60
- const decorators = useDecorators(editor);
61
- const nativeDnDSupported = supportsNativeDnD();
62
- const fallbackVariables = shallowRef(collectVariableNodeDescriptors(editor));
63
- const showFallbackControls = computed(() => !nativeDnDSupported && fallbackVariables.value.length > 1);
64
- const removeFallbackSync = editor.registerUpdateListener(() => {
65
- fallbackVariables.value = collectVariableNodeDescriptors(editor);
66
- });
67
- onBeforeUnmount(() => {
68
- removeFallbackSync();
69
- });
38
+ const containerRef = useTemplateRef("container");
39
+ const pickerRef = useTemplateRef("pickerRef");
40
+ const className = computed(() => [
41
+ cls.b,
42
+ cls.m(size.value),
43
+ bem.is("disabled", disabled.value),
44
+ bem.is("readonly", readonly.value)
45
+ ]);
70
46
  const variableMap = computed(() => createVariableMap(props.variables));
71
- function Decorators(props) {
72
- return props.decorators;
47
+ const editorRef = shallowRef(null);
48
+ const mention = createMention();
49
+ const currentDoc = shallowRef([]);
50
+ const isEmpty = computed(() => currentDoc.value.length === 0);
51
+ const showPlaceholder = computed(() => isEmpty.value && !disabled.value);
52
+ const pickerMode = shallowRef(null);
53
+ const pickerTriggerDom = shallowRef(void 0);
54
+ const reselectingSegIdx = shallowRef(null);
55
+ const pickerFilter = shallowRef("");
56
+ const pickerVisible = computed(() => pickerMode.value !== null);
57
+ function syncMention() {
58
+ const editor = editorRef.value;
59
+ if (!editor) return;
60
+ if (pickerMode.value === "reselect") return;
61
+ const caret = editor.getCaretOffset();
62
+ const state = mention.update(currentDoc.value, caret);
63
+ if (state) {
64
+ pickerMode.value = "mention";
65
+ pickerFilter.value = state.filter;
66
+ pickerTriggerDom.value = containerRef.value ?? void 0;
67
+ } else if (pickerMode.value === "mention") closePicker();
73
68
  }
74
- function moveVariable(variableKey, direction) {
75
- if (disabled.value || readonly.value) return;
76
- moveVariableByDirection(editor, variableKey, direction, true);
69
+ function closePicker() {
70
+ pickerMode.value = null;
71
+ reselectingSegIdx.value = null;
72
+ pickerFilter.value = "";
77
73
  }
78
- function handleVariableSelect(variable) {
79
- if (disabled.value || readonly.value) return;
80
- const nodeKey = textNode.value?.getKey();
81
- if (!nodeKey) return;
82
- insertVariableAtTrigger(editor, {
83
- nodeKey,
84
- charPosition: charPosition.value,
85
- variable: {
86
- value: variable.value,
87
- label: variable.label,
88
- type: variable.type
74
+ onMounted(() => {
75
+ if (!containerRef.value) return;
76
+ const initialDoc = parse(props.modelValue ?? "", variableMap.value);
77
+ currentDoc.value = initialDoc;
78
+ const editor = createEditor({
79
+ container: containerRef.value,
80
+ cls,
81
+ initialDoc,
82
+ getVariableMap: () => variableMap.value,
83
+ onChange: (doc) => {
84
+ currentDoc.value = doc;
85
+ const value = serializeFromDoc(doc);
86
+ if (value !== (props.modelValue ?? "")) emit("update:modelValue", value);
87
+ syncMention();
88
+ },
89
+ onSelectionChange: () => {
90
+ syncMention();
91
+ },
92
+ onChipReselect: ({ chipEl, segIndex }) => {
93
+ if (disabled.value || readonly.value) return;
94
+ mention.commit();
95
+ pickerMode.value = "reselect";
96
+ pickerFilter.value = "";
97
+ pickerTriggerDom.value = chipEl;
98
+ reselectingSegIdx.value = segIndex;
99
+ },
100
+ onChipRemove: ({ segIndex }) => {
101
+ if (disabled.value || readonly.value) return;
102
+ editor.removeVarAt(segIndex);
89
103
  }
90
104
  });
105
+ editorRef.value = editor;
106
+ });
107
+ onBeforeUnmount(() => {
108
+ editorRef.value?.dispose();
109
+ });
110
+ function serializeFromDoc(doc) {
111
+ let s = "";
112
+ for (const seg of doc) s += seg.kind === "text" ? seg.value : `{${seg.value}}`;
113
+ return s;
91
114
  }
92
- function updateVariableNode(oldValue, newValue, newLabel) {
93
- editor.update(() => {
94
- const root = $getRoot();
95
- const variable = variableMap.value.get(newValue);
96
- const label = newLabel ?? variable?.label ?? newValue;
97
- const type = variable?.type;
98
- function traverse(node) {
99
- if ($isVariableNode(node)) {
100
- if (node.getVariable() === oldValue) node.updateVariable(newValue, label, type);
101
- }
102
- if (typeof node.getChildren === "function") node.getChildren().forEach((child) => traverse(child));
115
+ watch(() => props.modelValue, (v) => {
116
+ const editor = editorRef.value;
117
+ if (!editor) return;
118
+ if (v === editor.getValue()) return;
119
+ editor.setValue(v ?? "");
120
+ });
121
+ watch(variableMap, () => {
122
+ const editor = editorRef.value;
123
+ if (!editor) return;
124
+ editor.setValue(editor.getValue());
125
+ });
126
+ function onKeydown(e) {
127
+ if (disabled.value || readonly.value) return;
128
+ if (pickerMode.value !== null) {
129
+ if (pickerRef.value?.handleKeydown(e)) {
130
+ e.preventDefault();
131
+ return;
103
132
  }
104
- traverse(root);
105
- });
133
+ }
134
+ if (pickerMode.value === "mention") {
135
+ if (e.key === " " || e.key === "ArrowLeft" || e.key === "ArrowRight") {
136
+ mention.dismiss();
137
+ closePicker();
138
+ }
139
+ }
140
+ }
141
+ function onBlur() {
142
+ if (pickerMode.value === "mention") {
143
+ mention.dismiss();
144
+ nextTick(() => closePicker());
145
+ }
146
+ }
147
+ function onPickerSelect(item) {
148
+ const editor = editorRef.value;
149
+ if (!editor) return;
150
+ if (pickerMode.value === "mention") {
151
+ const state = mention.getState();
152
+ if (!state) return;
153
+ const anchor = state.anchorOffset;
154
+ const caret = editor.getCaretOffset() ?? anchor + state.filter.length + 1;
155
+ editor.replaceRangeWithVar(anchor, caret, {
156
+ value: item.value,
157
+ label: item.label,
158
+ ...item.type ? { type: item.type } : {}
159
+ });
160
+ mention.commit();
161
+ } else if (pickerMode.value === "reselect") {
162
+ const idx = reselectingSegIdx.value;
163
+ if (idx !== null) editor.replaceVarAt(idx, {
164
+ value: item.value,
165
+ label: item.label,
166
+ ...item.type ? { type: item.type } : {}
167
+ });
168
+ }
169
+ closePicker();
170
+ }
171
+ function onPickerDismiss() {
172
+ if (pickerMode.value === "mention") mention.dismiss();
173
+ closePicker();
174
+ }
175
+ function onPickerVisibleChange(v) {
176
+ if (!v && pickerMode.value !== null) {
177
+ if (pickerMode.value === "mention") mention.dismiss();
178
+ closePicker();
179
+ }
106
180
  }
107
- provide(ExpressionEditorDIKey, {
108
- cls,
109
- editorProps: props,
110
- editor,
111
- updateVariableNode,
112
- variableMap
113
- });
114
181
  return (_ctx, _cache) => {
115
182
  return openBlock(), createElementBlock("div", { class: normalizeClass(className.value) }, [
116
- createCommentVNode(" 编辑容器 "),
117
183
  createElementVNode("div", {
118
- class: normalizeClass(unref(cls).e("container")),
119
184
  ref: "container",
120
- contenteditable: !unref(readonly) && !unref(disabled)
121
- }, null, 10, _hoisted_1),
122
- showFallbackControls.value ? (openBlock(), createElementBlock("div", {
123
- key: 0,
124
- class: normalizeClass(unref(cls).e("fallback"))
125
- }, [(openBlock(true), createElementBlock(Fragment, null, renderList(fallbackVariables.value, (item, index) => {
126
- return openBlock(), createElementBlock("div", {
127
- key: item.key,
128
- class: normalizeClass(unref(cls).e("fallback-item"))
129
- }, [createElementVNode("span", { class: normalizeClass(unref(cls).e("fallback-label")) }, toDisplayString(item.label || item.variable), 3), createElementVNode("div", { class: normalizeClass(unref(cls).e("fallback-actions")) }, [createElementVNode("button", {
130
- type: "button",
131
- class: normalizeClass(unref(cls).e("fallback-button")),
132
- disabled: unref(disabled) || unref(readonly) || index === 0,
133
- onClick: ($event) => moveVariable(item.key, -1)
134
- }, " 上移 ", 10, _hoisted_2), createElementVNode("button", {
135
- type: "button",
136
- class: normalizeClass(unref(cls).e("fallback-button")),
137
- disabled: unref(disabled) || unref(readonly) || index === fallbackVariables.value.length - 1,
138
- onClick: ($event) => moveVariable(item.key, 1)
139
- }, " 下移 ", 10, _hoisted_3)], 2)], 2);
140
- }), 128))], 2)) : createCommentVNode("v-if", true),
185
+ class: normalizeClass(unref(cls).e("container")),
186
+ contenteditable: !unref(readonly) && !unref(disabled),
187
+ "data-empty": isEmpty.value || void 0,
188
+ "data-placeholder": props.placeholder,
189
+ onKeydown,
190
+ onBlur
191
+ }, null, 42, _hoisted_1),
141
192
  showPlaceholder.value ? (openBlock(), createElementBlock("div", {
142
- key: 1,
193
+ key: 0,
143
194
  class: normalizeClass(unref(cls).e("placeholder"))
144
- }, toDisplayString(__props.placeholder), 3)) : createCommentVNode("v-if", true),
145
- createCommentVNode(" 渲染装饰器节点,内部通过Vue的Teleport组件渲染至节点中 "),
146
- createVNode(Decorators, { decorators: unref(decorators) }, null, 8, ["decorators"]),
147
- createCommentVNode(" 变量选择器 "),
195
+ }, toDisplayString(props.placeholder), 3)) : createCommentVNode("v-if", true),
148
196
  createVNode(_sfc_main$1, {
149
- visible: unref(contextVisible),
150
- "onUpdate:visible": _cache[0] || (_cache[0] = ($event) => isRef(contextVisible) ? contextVisible.value = $event : null),
151
- "trigger-dom": unref(contextTriggerDom),
152
- filterable: true,
153
- "register-picker-key-handler": unref(registerPickerKeyHandler),
154
- onSelect: handleVariableSelect
197
+ ref_key: "pickerRef",
198
+ ref: pickerRef,
199
+ visible: pickerVisible.value,
200
+ "trigger-dom": pickerTriggerDom.value,
201
+ variables: props.variables,
202
+ filter: pickerFilter.value,
203
+ "selectable-levels": props.selectableLevels ?? "leaf",
204
+ onSelect: onPickerSelect,
205
+ onDismiss: onPickerDismiss,
206
+ "onUpdate:visible": onPickerVisibleChange
155
207
  }, null, 8, [
156
208
  "visible",
157
209
  "trigger-dom",
158
- "register-picker-key-handler"
210
+ "variables",
211
+ "filter",
212
+ "selectable-levels"
159
213
  ])
160
214
  ], 2);
161
215
  };
@@ -1 +1 @@
1
- {"version":3,"file":"expression-editor.js","names":[],"sources":["../../../src/components/expression-editor/expression-editor.vue"],"sourcesContent":["<template>\n <div :class=\"className\">\n <!-- 编辑容器 -->\n <div\n :class=\"cls.e('container')\"\n ref=\"container\"\n :contenteditable=\"!readonly && !disabled\"\n ></div>\n\n <div v-if=\"showFallbackControls\" :class=\"cls.e('fallback')\">\n <div\n v-for=\"(item, index) in fallbackVariables\"\n :key=\"item.key\"\n :class=\"cls.e('fallback-item')\"\n >\n <span :class=\"cls.e('fallback-label')\">\n {{ item.label || item.variable }}\n </span>\n <div :class=\"cls.e('fallback-actions')\">\n <button\n type=\"button\"\n :class=\"cls.e('fallback-button')\"\n :disabled=\"disabled || readonly || index === 0\"\n @click=\"moveVariable(item.key, -1)\"\n >\n 上移\n </button>\n <button\n type=\"button\"\n :class=\"cls.e('fallback-button')\"\n :disabled=\"disabled || readonly || index === fallbackVariables.length - 1\"\n @click=\"moveVariable(item.key, 1)\"\n >\n 下移\n </button>\n </div>\n </div>\n </div>\n\n <div :class=\"cls.e('placeholder')\" v-if=\"showPlaceholder\">\n {{ placeholder }}\n </div>\n\n <!-- 渲染装饰器节点,内部通过Vue的Teleport组件渲染至节点中 -->\n <Decorators :decorators=\"decorators\" />\n\n <!-- 变量选择器 -->\n <VariablePicker\n v-model:visible=\"contextVisible\"\n :trigger-dom=\"contextTriggerDom\"\n :filterable=\"true\"\n :register-picker-key-handler=\"registerPickerKeyHandler\"\n @select=\"handleVariableSelect\"\n />\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useFormComponent, useFormFallbackProps } from '@veltra/compositions'\nimport { bem } from '@veltra/utils'\nimport { $getRoot } from 'lexical'\nimport { useTemplateRef, provide, computed, onBeforeUnmount, shallowRef, type VNode } from 'vue'\n\nimport type { ExpressionEditorProps, VariableItem } from '../../types'\nimport VariablePicker from './components/variable-picker.vue'\nimport { ExpressionEditorDIKey, createVariableMap } from './di'\nimport { createExpressionEditorRuntime } from './internal/editor-runtime'\nimport { moveVariableByDirection } from './internal/features/drag-drop/drag-drop-service'\nimport { insertVariableAtTrigger } from './internal/features/insertion/insertion-service'\nimport { $isVariableNode } from './nodes/variable-node'\nimport { registerPlainText } from './plain-text'\nimport { useContext } from './use-context'\nimport { useDecorators } from './use-decorators'\nimport { collectVariableNodeDescriptors, supportsNativeDnD } from './use-expression-drag-drop'\n\ndefineOptions({\n name: 'ExpressionEditor'\n})\n\nconst props = withDefaults(defineProps<ExpressionEditorProps>(), {\n placeholder: '请输入表达式,输入 @ 可插入变量'\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void\n}>()\n\nconst showPlaceholder = computed(() => !props.modelValue || props.modelValue.trim() === '')\n\nconst cls = bem('expression-editor')\n\nconst { formProps } = useFormComponent()\n\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props])\n\nconst className = computed(() => {\n return [\n cls.b,\n cls.m(size.value),\n bem.is('disabled', disabled.value),\n bem.is('readonly', readonly.value)\n ]\n})\n\nconst containerRef = useTemplateRef('container')\n\nconst { editor } = createExpressionEditorRuntime({\n disabled,\n readonly,\n cls,\n container: containerRef,\n props,\n emit\n})\n\nconst {\n contextVisible,\n contextTriggerDom,\n textNode,\n charPosition,\n registerPickerKeyHandler,\n registerContextCommands\n} = useContext(editor)\n\nregisterPlainText(editor, {\n getContextCommands: registerContextCommands\n})\n\nconst decorators = useDecorators(editor)\nconst nativeDnDSupported = supportsNativeDnD()\nconst fallbackVariables = shallowRef(collectVariableNodeDescriptors(editor))\nconst showFallbackControls = computed(\n () => !nativeDnDSupported && fallbackVariables.value.length > 1\n)\n\nconst removeFallbackSync = editor.registerUpdateListener(() => {\n fallbackVariables.value = collectVariableNodeDescriptors(editor)\n})\n\nonBeforeUnmount(() => {\n removeFallbackSync()\n})\n\n// 创建变量映射表\nconst variableMap = computed(() => createVariableMap(props.variables))\n\nfunction Decorators(props: { decorators: VNode[] }) {\n return props.decorators\n}\n\nfunction moveVariable(variableKey: string, direction: -1 | 1) {\n if (disabled.value || readonly.value) return\n\n moveVariableByDirection(editor, variableKey, direction, true)\n}\n\n// 处理变量选择\nfunction handleVariableSelect(variable: VariableItem) {\n if (disabled.value || readonly.value) return\n\n const nodeKey = textNode.value?.getKey()\n if (!nodeKey) return\n\n insertVariableAtTrigger(editor, {\n nodeKey,\n charPosition: charPosition.value,\n variable: {\n value: variable.value,\n label: variable.label,\n type: variable.type\n }\n })\n}\n\n// 更新变量节点的函数\nfunction updateVariableNode(oldValue: string, newValue: string, newLabel?: string) {\n editor.update(() => {\n const root = $getRoot()\n\n // 如果没有提供 label 或 type,从映射表中查找\n const variable = variableMap.value.get(newValue)\n const label = newLabel ?? variable?.label ?? newValue\n const type = variable?.type\n\n // 递归遍历所有节点\n function traverse(node: any) {\n if ($isVariableNode(node)) {\n if (node.getVariable() === oldValue) {\n node.updateVariable(newValue, label, type)\n }\n }\n\n // 如果节点有 getChildren 方法,继续遍历\n if (typeof node.getChildren === 'function') {\n const children = node.getChildren()\n children.forEach((child: any) => traverse(child))\n }\n }\n\n traverse(root)\n })\n}\n\nprovide(ExpressionEditorDIKey, {\n cls,\n editorProps: props,\n editor,\n updateVariableNode,\n variableMap\n})\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"expression-editor.js","names":[],"sources":["../../../src/components/expression-editor/expression-editor.vue"],"sourcesContent":["<template>\n <div :class=\"className\">\n <div\n ref=\"container\"\n :class=\"cls.e('container')\"\n :contenteditable=\"!readonly && !disabled\"\n :data-empty=\"isEmpty || undefined\"\n :data-placeholder=\"props.placeholder\"\n @keydown=\"onKeydown\"\n @blur=\"onBlur\"\n ></div>\n\n <div v-if=\"showPlaceholder\" :class=\"cls.e('placeholder')\">\n {{ props.placeholder }}\n </div>\n\n <VariablePicker\n ref=\"pickerRef\"\n :visible=\"pickerVisible\"\n :trigger-dom=\"pickerTriggerDom\"\n :variables=\"props.variables\"\n :filter=\"pickerFilter\"\n :selectable-levels=\"props.selectableLevels ?? 'leaf'\"\n @select=\"onPickerSelect\"\n @dismiss=\"onPickerDismiss\"\n @update:visible=\"onPickerVisibleChange\"\n />\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useFormComponent, useFormFallbackProps } from '@veltra/compositions'\nimport { bem } from '@veltra/utils'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n shallowRef,\n useTemplateRef,\n watch\n} from 'vue'\n\nimport type { ExpressionEditorProps, VariableItem } from '../../types'\nimport VariablePicker from './components/variable-picker.vue'\nimport { createEditor, type EditorAPI } from './core/editor'\nimport { createMention, type MentionAPI } from './core/mention'\nimport { parse, type Doc } from './core/model'\nimport { createVariableMap } from './di'\n\ndefineOptions({\n name: 'ExpressionEditor'\n})\n\nconst props = withDefaults(defineProps<ExpressionEditorProps>(), {\n placeholder: '请输入表达式,输入 @ 可插入变量',\n selectableLevels: 'leaf'\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void\n}>()\n\nconst cls = bem('expression-editor')\nconst { formProps } = useFormComponent()\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props])\n\nconst containerRef = useTemplateRef<HTMLDivElement>('container')\nconst pickerRef = useTemplateRef<{ handleKeydown: (e: KeyboardEvent) => boolean }>('pickerRef')\n\nconst className = computed(() => [\n cls.b,\n cls.m(size.value),\n bem.is('disabled', disabled.value),\n bem.is('readonly', readonly.value)\n])\n\nconst variableMap = computed(() => createVariableMap(props.variables))\n\nconst editorRef = shallowRef<EditorAPI | null>(null)\nconst mention: MentionAPI = createMention()\n\nconst currentDoc = shallowRef<Doc>([])\nconst isEmpty = computed(() => currentDoc.value.length === 0)\nconst showPlaceholder = computed(() => isEmpty.value && !disabled.value)\n\nconst pickerMode = shallowRef<'mention' | 'reselect' | null>(null)\nconst pickerTriggerDom = shallowRef<HTMLElement | undefined>(undefined)\nconst reselectingSegIdx = shallowRef<number | null>(null)\nconst pickerFilter = shallowRef('')\n\nconst pickerVisible = computed(() => pickerMode.value !== null)\n\nfunction syncMention() {\n const editor = editorRef.value\n if (!editor) return\n if (pickerMode.value === 'reselect') return\n const caret = editor.getCaretOffset()\n const state = mention.update(currentDoc.value, caret)\n if (state) {\n pickerMode.value = 'mention'\n pickerFilter.value = state.filter\n pickerTriggerDom.value = containerRef.value ?? undefined\n } else if (pickerMode.value === 'mention') {\n closePicker()\n }\n}\n\nfunction closePicker() {\n pickerMode.value = null\n reselectingSegIdx.value = null\n pickerFilter.value = ''\n}\n\nonMounted(() => {\n if (!containerRef.value) return\n const initialDoc = parse(props.modelValue ?? '', variableMap.value)\n currentDoc.value = initialDoc\n\n const editor = createEditor({\n container: containerRef.value,\n cls,\n initialDoc,\n getVariableMap: () => variableMap.value,\n onChange: (doc) => {\n currentDoc.value = doc\n const value = serializeFromDoc(doc)\n if (value !== (props.modelValue ?? '')) emit('update:modelValue', value)\n syncMention()\n },\n onSelectionChange: () => {\n syncMention()\n },\n onChipReselect: ({ chipEl, segIndex }) => {\n if (disabled.value || readonly.value) return\n mention.commit()\n pickerMode.value = 'reselect'\n pickerFilter.value = ''\n pickerTriggerDom.value = chipEl\n reselectingSegIdx.value = segIndex\n },\n onChipRemove: ({ segIndex }) => {\n if (disabled.value || readonly.value) return\n editor.removeVarAt(segIndex)\n }\n })\n editorRef.value = editor\n})\n\nonBeforeUnmount(() => {\n editorRef.value?.dispose()\n})\n\nfunction serializeFromDoc(doc: Doc): string {\n let s = ''\n for (const seg of doc) s += seg.kind === 'text' ? seg.value : `{${seg.value}}`\n return s\n}\n\nwatch(\n () => props.modelValue,\n (v) => {\n const editor = editorRef.value\n if (!editor) return\n if (v === editor.getValue()) return\n editor.setValue(v ?? '')\n }\n)\n\nwatch(variableMap, () => {\n // variables 变化:重渲染以刷新 chip label / type\n const editor = editorRef.value\n if (!editor) return\n editor.setValue(editor.getValue())\n})\n\nfunction onKeydown(e: KeyboardEvent) {\n if (disabled.value || readonly.value) return\n // mention / reselect 激活时,优先把箭头键 / Enter / Esc 转给 picker\n if (pickerMode.value !== null) {\n const handledByPicker = pickerRef.value?.handleKeydown(e)\n if (handledByPicker) {\n e.preventDefault()\n return\n }\n }\n\n if (pickerMode.value === 'mention') {\n // 这些键导致 mention 退出(保留 @filter 文本,光标继续移动)\n if (e.key === ' ' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {\n mention.dismiss()\n closePicker()\n }\n }\n}\n\nfunction onBlur() {\n if (pickerMode.value === 'mention') {\n mention.dismiss()\n // 下一帧再关闭,避免和 picker 内 click 冲突\n void nextTick(() => closePicker())\n }\n}\n\nfunction onPickerSelect(item: VariableItem) {\n const editor = editorRef.value\n if (!editor) return\n\n if (pickerMode.value === 'mention') {\n const state = mention.getState()\n if (!state) return\n const anchor = state.anchorOffset\n const caret = editor.getCaretOffset() ?? anchor + state.filter.length + 1\n editor.replaceRangeWithVar(anchor, caret, {\n value: item.value,\n label: item.label,\n ...(item.type ? { type: item.type } : {})\n })\n mention.commit()\n } else if (pickerMode.value === 'reselect') {\n const idx = reselectingSegIdx.value\n if (idx !== null) {\n editor.replaceVarAt(idx, {\n value: item.value,\n label: item.label,\n ...(item.type ? { type: item.type } : {})\n })\n }\n }\n closePicker()\n}\n\nfunction onPickerDismiss() {\n if (pickerMode.value === 'mention') mention.dismiss()\n closePicker()\n}\n\nfunction onPickerVisibleChange(v: boolean) {\n if (!v && pickerMode.value !== null) {\n if (pickerMode.value === 'mention') mention.dismiss()\n closePicker()\n }\n}\n</script>\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { ExpressionEditorProps } from "../../types/expression-editor.js";
1
+ import { ExpressionEditorProps, ExpressionSelectableLevels } from "../../types/expression-editor.js";
2
2
  import * as _$vue from "vue";
3
3
 
4
4
  //#region src/components/expression-editor/expression-editor.vue.d.ts
@@ -8,6 +8,7 @@ declare const __VLS_export: _$vue.DefineComponent<ExpressionEditorProps, {}, {},
8
8
  "onUpdate:modelValue"?: ((value: string) => any) | undefined;
9
9
  }>, {
10
10
  placeholder: string;
11
+ selectableLevels: ExpressionSelectableLevels;
11
12
  }, {}, {}, {}, string, _$vue.ComponentProvideOptions, false, {}, any>;
12
13
  declare const _default: typeof __VLS_export;
13
14
  //#endregion
@@ -1,7 +1,5 @@
1
1
  import "../icon/style.js";
2
2
  import "../tip/style.js";
3
3
  import "../scroll/style.js";
4
- import "../input/style.js";
5
- import "../tag/style.js";
6
4
  import "../empty/style.js";
7
5
  import "./style2.css";