@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,103 +0,0 @@
1
- /**
2
- * ARCH-01: Capability boundary and key wiring regression gate.
3
- * Verifies sync/insertion/drag-drop/rendering have independent entry points
4
- * and runtime -> command packs -> mutation services wiring is intact.
5
- * Failure maps to roadmap acceptance criteria.
6
- */
7
- import { describe, expect, it, vi } from 'vitest'
8
-
9
- vi.mock('../../tag', () => ({ UTag: () => null }))
10
- import { createEditor } from 'lexical'
11
- import { ref, shallowRef } from 'vue'
12
-
13
- import type { ExpressionEditorRuntime } from '../internal/contracts/editor-runtime'
14
- import { createExpressionEditorRuntime } from '../internal/editor-runtime'
15
- import { registerCommandPacks } from '../internal/features/commands/register-command-packs'
16
- import {
17
- moveVariableByDirection,
18
- reorderVariable
19
- } from '../internal/features/drag-drop/drag-drop-service'
20
- import { insertVariableAtTrigger } from '../internal/features/insertion/insertion-service'
21
- import { VariableNode } from '../nodes/variable-node'
22
-
23
- describe('ARCH-01: sync boundary', () => {
24
- it('createExpressionEditorRuntime returns runtime with editor, mutations, syncFromModelValue', () => {
25
- const container = shallowRef<HTMLElement | null>(null)
26
- const props = { modelValue: '', variables: [] }
27
- const emit = () => {}
28
- const cls = { b: 'expression-editor', e: (s: string) => `expression-editor__${s}` } as const
29
-
30
- const runtime = createExpressionEditorRuntime({
31
- disabled: ref(false),
32
- readonly: ref(false),
33
- props,
34
- cls,
35
- emit,
36
- container
37
- })
38
-
39
- expect(runtime).toHaveProperty('editor')
40
- expect(runtime).toHaveProperty('mutations')
41
- expect(runtime).toHaveProperty('syncFromModelValue')
42
- expect(typeof runtime.syncFromModelValue).toBe('function')
43
- expect(runtime.mutations).toHaveProperty('runUpdate')
44
- expect(typeof runtime.mutations.runUpdate).toBe('function')
45
- })
46
-
47
- it('EditorMutationGateway.runUpdate executes updater inside editor.update', () => {
48
- const container = shallowRef<HTMLElement | null>(null)
49
- const props = { modelValue: '', variables: [] }
50
- const emit = () => {}
51
- const cls = { b: 'expression-editor', e: (s: string) => `expression-editor__${s}` } as const
52
-
53
- const runtime = createExpressionEditorRuntime({
54
- disabled: ref(false),
55
- readonly: ref(false),
56
- props,
57
- cls,
58
- emit,
59
- container
60
- }) as ExpressionEditorRuntime
61
-
62
- let executed = false
63
- runtime.mutations.runUpdate(() => {
64
- executed = true
65
- })
66
- expect(executed).toBe(true)
67
- })
68
- })
69
-
70
- describe('ARCH-01: insertion boundary', () => {
71
- it('insertVariableAtTrigger is callable and returns boolean', () => {
72
- const editor = createEditor({ namespace: 'Test', nodes: [VariableNode], onError: () => {} })
73
- const result = insertVariableAtTrigger(editor, {
74
- nodeKey: 'nonexistent',
75
- charPosition: 0,
76
- variable: { value: 'x', label: 'X' }
77
- })
78
- expect(typeof result).toBe('boolean')
79
- })
80
- })
81
-
82
- describe('ARCH-01: drag-drop boundary', () => {
83
- it('reorderVariable is callable and returns boolean', () => {
84
- const editor = createEditor({ namespace: 'Test', nodes: [VariableNode], onError: () => {} })
85
- const result = reorderVariable(editor, { payloadText: null, scopeId: 'test', targetSlot: 0 })
86
- expect(typeof result).toBe('boolean')
87
- })
88
-
89
- it('moveVariableByDirection is callable and returns boolean', () => {
90
- const editor = createEditor({ namespace: 'Test', nodes: [VariableNode], onError: () => {} })
91
- const result = moveVariableByDirection(editor, 'nonexistent-key', -1, false)
92
- expect(typeof result).toBe('boolean')
93
- })
94
- })
95
-
96
- describe('ARCH-01: command packs boundary', () => {
97
- it('registerCommandPacks returns cleanup function', () => {
98
- const editor = createEditor({ namespace: 'Test', nodes: [VariableNode], onError: () => {} })
99
- const cleanup = registerCommandPacks(editor)
100
- expect(typeof cleanup).toBe('function')
101
- cleanup()
102
- })
103
- })
@@ -1,52 +0,0 @@
1
- /**
2
- * ARCH-02: Public API compatibility gate.
3
- * Locks export surface, props, and emits so future changes cannot break consumers.
4
- * Failure here maps directly to roadmap acceptance criteria.
5
- */
6
- import { describe, expect, it, vi } from 'vitest'
7
-
8
- import type { ExpressionEditorEmits, ExpressionEditorProps, VariableItem } from '../../../types'
9
-
10
- vi.mock('../expression-editor.vue', () => ({ default: { name: 'ExpressionEditor' } }))
11
-
12
- import { UExpressionEditor } from '../index'
13
-
14
- describe('ARCH-02: UExpressionEditor public API compatibility', () => {
15
- it('UExpressionEditor is importable and is a Vue component', () => {
16
- expect(UExpressionEditor).toBeDefined()
17
- expect(typeof UExpressionEditor).toBe('object')
18
- expect(UExpressionEditor).toHaveProperty('name', 'ExpressionEditor')
19
- })
20
-
21
- it('ExpressionEditorProps has required keys: modelValue, placeholder, variables', () => {
22
- const requiredKeys: (keyof ExpressionEditorProps)[] = ['modelValue', 'placeholder', 'variables']
23
- const props: ExpressionEditorProps = { modelValue: '', placeholder: 'test', variables: [] }
24
- for (const key of requiredKeys) {
25
- expect(key in props || typeof (props as Record<string, unknown>)[key] !== 'undefined').toBe(
26
- true
27
- )
28
- }
29
- })
30
-
31
- it('ExpressionEditorProps modelValue accepts string', () => {
32
- const props: ExpressionEditorProps = { modelValue: 'hello{foo}' }
33
- expect(props.modelValue).toBe('hello{foo}')
34
- })
35
-
36
- it('ExpressionEditorProps variables accepts VariableItem[]', () => {
37
- const items: VariableItem[] = [
38
- { label: 'Foo', value: 'foo' },
39
- { label: 'Bar', value: 'bar', type: 'string' }
40
- ]
41
- const props: ExpressionEditorProps = { variables: items }
42
- expect(props.variables).toEqual(items)
43
- })
44
-
45
- it('update:modelValue emit signature: (e, value: string) => void', () => {
46
- const emit: ExpressionEditorEmits = (e: 'update:modelValue', value: string) => {
47
- expect(e).toBe('update:modelValue')
48
- expect(typeof value).toBe('string')
49
- }
50
- emit('update:modelValue', 'new value')
51
- })
52
- })
@@ -1,171 +0,0 @@
1
- import { $createParagraphNode, $getRoot, createEditor, type LexicalEditor } from 'lexical'
2
- import { vi } from 'vitest'
3
-
4
- import { VariableNode } from '../nodes/variable-node'
5
-
6
- vi.mock('../../tag', () => ({ UTag: () => null }))
7
-
8
- import { parseContent } from '../parser'
9
- import {
10
- applyDropReorder,
11
- collectVariableNodeDescriptors,
12
- createInternalDragPayload,
13
- moveVariableByDirection,
14
- reorderVariableNode
15
- } from '../use-expression-drag-drop'
16
-
17
- function createTestEditor(content: string): LexicalEditor {
18
- const editor = createEditor({
19
- namespace: 'ExpressionEditorDragDropTest',
20
- nodes: [VariableNode],
21
- onError: () => {}
22
- })
23
-
24
- editor.update(
25
- () => {
26
- const root = $getRoot()
27
- root.clear()
28
- const paragraph = $createParagraphNode()
29
- paragraph.append(...parseContent(content))
30
- root.append(paragraph)
31
- },
32
- { discrete: true }
33
- )
34
-
35
- return editor
36
- }
37
-
38
- function getEditorText(editor: LexicalEditor): string {
39
- let text = ''
40
- editor.getEditorState().read(() => {
41
- text = $getRoot().getTextContent()
42
- })
43
- return text
44
- }
45
-
46
- function stripVariableTokens(content: string): string {
47
- return content.replace(/\{[^}]+\}/g, '')
48
- }
49
-
50
- function getVariableOrder(editor: LexicalEditor): string[] {
51
- return collectVariableNodeDescriptors(editor).map((item) => item.variable)
52
- }
53
-
54
- function getVariableKey(editor: LexicalEditor, variable: string): string {
55
- const descriptor = collectVariableNodeDescriptors(editor).find(
56
- (item) => item.variable === variable
57
- )
58
- if (!descriptor) {
59
- throw new Error(`Cannot find variable: ${variable}`)
60
- }
61
- return descriptor.key
62
- }
63
-
64
- describe('expression drag drop (ARCH-01 drag-drop boundary)', () => {
65
- it('reorders variable sequence correctly', () => {
66
- const editor = createTestEditor('A {first} + {second} + {third}')
67
- const secondKey = getVariableKey(editor, 'second')
68
-
69
- let moved = false
70
- editor.update(
71
- () => {
72
- moved = reorderVariableNode(secondKey, 0, false)
73
- },
74
- { discrete: true }
75
- )
76
-
77
- expect(moved).toBe(true)
78
- expect(getVariableOrder(editor)).toEqual(['second', 'first', 'third'])
79
- })
80
-
81
- it('keeps plain text and whitespace unchanged while reordering variables', () => {
82
- const editor = createTestEditor('left {alpha}\t+\n{beta} right')
83
- const before = getEditorText(editor)
84
- const betaKey = getVariableKey(editor, 'beta')
85
-
86
- editor.update(
87
- () => {
88
- reorderVariableNode(betaKey, 0, false)
89
- },
90
- { discrete: true }
91
- )
92
-
93
- const after = getEditorText(editor)
94
- expect(stripVariableTokens(after)).toBe(stripVariableTokens(before))
95
- expect(getVariableOrder(editor)).toEqual(['beta', 'alpha'])
96
- })
97
-
98
- it('ignores invalid or external payload without changing content', () => {
99
- const editor = createTestEditor('x {foo} y {bar}')
100
- const initial = getEditorText(editor)
101
-
102
- let moved = true
103
- editor.update(
104
- () => {
105
- moved = applyDropReorder({
106
- payloadText: '{"action":"move-variable","scopeId":"scope-a"}',
107
- scopeId: 'scope-a',
108
- targetSlot: 0,
109
- focusMovedNode: false
110
- })
111
- },
112
- { discrete: true }
113
- )
114
-
115
- expect(moved).toBe(false)
116
- expect(getEditorText(editor)).toBe(initial)
117
- })
118
-
119
- it('returns false when moveVariableByDirection is called with non-existent key (refactor behavior)', () => {
120
- const editor = createTestEditor('{a} {b}')
121
- let moved = false
122
- editor.update(
123
- () => {
124
- moved = moveVariableByDirection('non-existent-key', -1, false)
125
- },
126
- { discrete: true }
127
- )
128
- expect(moved).toBe(false)
129
- expect(getVariableOrder(editor)).toEqual(['a', 'b'])
130
- })
131
-
132
- it('uses the same reorder behavior for fallback move and drop payload', () => {
133
- const input = 'start {a} middle {b} end {c}'
134
- const fallbackEditor = createTestEditor(input)
135
- const dropEditor = createTestEditor(input)
136
-
137
- const fallbackKey = getVariableKey(fallbackEditor, 'b')
138
- const dropKey = getVariableKey(dropEditor, 'b')
139
-
140
- let fallbackMoved = false
141
- fallbackEditor.update(
142
- () => {
143
- fallbackMoved = moveVariableByDirection(fallbackKey, -1, false)
144
- },
145
- { discrete: true }
146
- )
147
-
148
- let dropMoved = false
149
- dropEditor.update(
150
- () => {
151
- const payload = createInternalDragPayload({
152
- action: 'move-variable',
153
- sourceKey: dropKey,
154
- scopeId: 'scope-04-test'
155
- })
156
- dropMoved = applyDropReorder({
157
- payloadText: payload,
158
- scopeId: 'scope-04-test',
159
- targetSlot: 0,
160
- focusMovedNode: false
161
- })
162
- },
163
- { discrete: true }
164
- )
165
-
166
- expect(fallbackMoved).toBe(true)
167
- expect(dropMoved).toBe(true)
168
- expect(getEditorText(dropEditor)).toBe(getEditorText(fallbackEditor))
169
- expect(getVariableOrder(dropEditor)).toEqual(getVariableOrder(fallbackEditor))
170
- })
171
- })
@@ -1,62 +0,0 @@
1
- import { createEditor } from 'lexical'
2
- import type { LexicalNode } from 'lexical'
3
- import { vi } from 'vitest'
4
-
5
- import { VariableNode } from '../nodes/variable-node'
6
-
7
- vi.mock('../../tag', () => ({ UTag: () => null }))
8
-
9
- import { parseContent } from '../parser'
10
-
11
- function serializeNodes(nodes: LexicalNode[]): string {
12
- return nodes.map((n) => n.getTextContent()).join('')
13
- }
14
-
15
- function parseAndSerialize(content: string): string {
16
- const editor = createEditor({ namespace: 'Test', nodes: [VariableNode], onError: () => {} })
17
- let serialized = ''
18
- editor.update(
19
- () => {
20
- const nodes = parseContent(content)
21
- serialized = serializeNodes(nodes)
22
- },
23
- { discrete: true }
24
- )
25
- return serialized
26
- }
27
-
28
- describe('parseContent (ARCH-01 parse boundary)', () => {
29
- it('round-trips hello{foo}world (trailing text preserved)', () => {
30
- const input = 'hello{foo}world'
31
- expect(parseAndSerialize(input)).toBe(input)
32
- })
33
-
34
- it('round-trips {a} (single variable)', () => {
35
- const input = '{a}'
36
- expect(parseAndSerialize(input)).toBe(input)
37
- })
38
-
39
- it('round-trips hello (no variables)', () => {
40
- const input = 'hello'
41
- expect(parseAndSerialize(input)).toBe(input)
42
- })
43
-
44
- it('round-trips {a}{b} (adjacent variables)', () => {
45
- const input = '{a}{b}'
46
- expect(parseAndSerialize(input)).toBe(input)
47
- })
48
-
49
- it('round-trips prefix{a}suffix', () => {
50
- const input = 'prefix{a}suffix'
51
- expect(parseAndSerialize(input)).toBe(input)
52
- })
53
-
54
- it('round-trips empty string (refactor behavior consistency)', () => {
55
- expect(parseAndSerialize('')).toBe('')
56
- })
57
-
58
- it('preserves text with unclosed brace as plain text (no variable match)', () => {
59
- const input = 'hello{unclosed'
60
- expect(parseAndSerialize(input)).toBe(input)
61
- })
62
- })
@@ -1,6 +0,0 @@
1
- export const CONTEXT_TRIGGER_CHAR = '@'
2
-
3
- export const EXPRESSION_VARIABLE_DRAG_TYPE = 'application/x-ultra-expression-variable'
4
- export const EXPRESSION_VARIABLE_DRAG_MARKER_ATTR = 'data-ultra-expression-variable-node'
5
- export const EXPRESSION_VARIABLE_DRAG_KEY_ATTR = 'data-ultra-expression-variable-key'
6
- export const EXPRESSION_DROP_SCOPE_ATTR = 'data-ultra-expression-drop-scope'
@@ -1,11 +0,0 @@
1
- import type { LexicalEditor } from 'lexical'
2
-
3
- export interface EditorMutationGateway {
4
- runUpdate(updater: () => void): void
5
- }
6
-
7
- export interface ExpressionEditorRuntime {
8
- editor: LexicalEditor
9
- mutations: EditorMutationGateway
10
- syncFromModelValue(): void
11
- }
@@ -1,64 +0,0 @@
1
- import type { BEM } from '@veltra/utils'
2
- import { createEditor } from 'lexical'
3
- import { watchEffect, computed, type Ref, type ShallowRef } from 'vue'
4
-
5
- import type { ExpressionEditorEmits, ExpressionEditorProps } from '../../../../types'
6
- import { createVariableMap } from '../../di'
7
- import { VariableNode } from '../../nodes/variable-node'
8
- import type { EditorMutationGateway, ExpressionEditorRuntime } from '../contracts/editor-runtime'
9
- import { createModelSync } from './model-sync'
10
-
11
- export interface CreateExpressionEditorRuntimeOptions {
12
- disabled: Ref<boolean>
13
- readonly: Ref<boolean>
14
- props: ExpressionEditorProps
15
- cls: BEM<'expression-editor'>
16
- emit: ExpressionEditorEmits
17
- container: ShallowRef<HTMLElement | null>
18
- }
19
-
20
- function createDefaultMutationGateway(
21
- editor: ExpressionEditorRuntime['editor']
22
- ): EditorMutationGateway {
23
- return {
24
- runUpdate(updater) {
25
- editor.update(() => {
26
- updater()
27
- })
28
- }
29
- }
30
- }
31
-
32
- function resolveEditable(disabled: Ref<boolean>, readonly: Ref<boolean>) {
33
- return !disabled.value && !readonly.value
34
- }
35
-
36
- export function createExpressionEditorRuntime(
37
- options: CreateExpressionEditorRuntimeOptions
38
- ): ExpressionEditorRuntime {
39
- const { disabled, readonly, container, props, emit, cls } = options
40
- const editor = createEditor({
41
- namespace: 'ExpressionEditor',
42
- nodes: [VariableNode],
43
- onError: console.error,
44
- editable: resolveEditable(disabled, readonly),
45
- theme: { paragraph: cls.e('paragraph') }
46
- })
47
-
48
- watchEffect(() => {
49
- editor.setEditable(resolveEditable(disabled, readonly))
50
- })
51
-
52
- watchEffect(() => {
53
- container.value && editor.setRootElement(container.value)
54
- })
55
-
56
- const variableMap = computed(() => createVariableMap(props.variables))
57
- const sync = createModelSync({ editor, props, emit, variableMap })
58
-
59
- return {
60
- editor,
61
- mutations: createDefaultMutationGateway(editor),
62
- syncFromModelValue: sync.syncFromModelValue
63
- }
64
- }
@@ -1 +0,0 @@
1
- export { createExpressionEditorRuntime } from './create-runtime'
@@ -1,68 +0,0 @@
1
- import { $createParagraphNode, $getRoot, SKIP_DOM_SELECTION_TAG, type LexicalEditor } from 'lexical'
2
- import { nextTick, watchEffect, type ComputedRef } from 'vue'
3
-
4
- import type { ExpressionEditorEmits, ExpressionEditorProps, VariableItem } from '../../../../types'
5
- import { parseContent } from '../../parser'
6
-
7
- interface CreateModelSyncOptions {
8
- editor: LexicalEditor
9
- props: ExpressionEditorProps
10
- emit: ExpressionEditorEmits
11
- variableMap: ComputedRef<Map<string, VariableItem>>
12
- }
13
-
14
- export function createModelSync(options: CreateModelSyncOptions) {
15
- const { editor, props, emit, variableMap } = options
16
-
17
- let changeByUser = false
18
- let changeByModel = false
19
- let lastEmittedValue: string | null = null
20
-
21
- function syncFromModelValue() {
22
- changeByModel = true
23
- const { modelValue } = props
24
- if (!modelValue) return
25
-
26
- editor.update(
27
- () => {
28
- const root = $getRoot()
29
- root.clear()
30
- const paragraph = $createParagraphNode()
31
- const nodes = parseContent(modelValue, variableMap.value)
32
- paragraph.append(...nodes)
33
- root.append(paragraph)
34
- },
35
- { tag: SKIP_DOM_SELECTION_TAG }
36
- )
37
-
38
- nextTick(() => {
39
- changeByModel = false
40
- })
41
- }
42
-
43
- editor.registerTextContentListener((text) => {
44
- if (changeByModel) return
45
-
46
- emit('update:modelValue', text)
47
- lastEmittedValue = text
48
- changeByUser = true
49
- nextTick(() => {
50
- if (lastEmittedValue === props.modelValue) {
51
- changeByUser = false
52
- } else {
53
- setTimeout(() => {
54
- changeByUser = false
55
- }, 0)
56
- }
57
- })
58
- })
59
-
60
- watchEffect(() => {
61
- if (changeByUser) return
62
- const current = editor.getEditorState().read(() => $getRoot().getTextContent())
63
- if (props.modelValue === current) return
64
- syncFromModelValue()
65
- })
66
-
67
- return { syncFromModelValue }
68
- }