@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.
- package/dist/components/action/action-group.js +110 -3
- package/dist/components/action/action-group.js.map +1 -1
- package/dist/components/action/action-group.vue.d.ts +16 -3
- package/dist/components/action/action.js +26 -13
- package/dist/components/action/action.js.map +1 -1
- package/dist/components/action/action.vue.d.ts +2 -2
- package/dist/components/action/style.js +2 -1
- package/dist/components/action/style2.css +35 -7
- package/dist/components/auto-complete/auto-complete.vue.d.ts +2 -2
- package/dist/components/batch-edit/batch-edit-form.js +106 -42
- package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
- package/dist/components/batch-edit/batch-edit-list.js +84 -47
- package/dist/components/batch-edit/batch-edit-list.js.map +1 -1
- package/dist/components/batch-edit/batch-edit.js +42 -10
- package/dist/components/batch-edit/batch-edit.js.map +1 -1
- package/dist/components/batch-edit/style.js +2 -4
- package/dist/components/batch-edit/style2.css +202 -30
- package/dist/components/batch-edit/use-edit.js +45 -9
- package/dist/components/batch-edit/use-edit.js.map +1 -1
- package/dist/components/cascade/cascade.js +3 -1
- package/dist/components/cascade/cascade.js.map +1 -1
- package/dist/components/cascade/cascade.vue.d.ts +2 -2
- package/dist/components/checkbox/checkbox-button.vue.d.ts +1 -1
- package/dist/components/checkbox-group/checkbox-group.vue.d.ts +2 -2
- package/dist/components/code-editor/code-editor.js +145 -49
- package/dist/components/code-editor/code-editor.js.map +1 -1
- package/dist/components/code-editor/code-editor.vue.d.ts +2 -0
- package/dist/components/code-editor/style2.css +87 -19
- package/dist/components/date-panel/date-panel.vue.d.ts +1 -1
- package/dist/components/date-picker/date-picker.vue.d.ts +2 -2
- package/dist/components/date-range-picker/date-range-picker.vue.d.ts +2 -2
- package/dist/components/dialog/dialog.js +6 -2
- package/dist/components/dialog/dialog.js.map +1 -1
- package/dist/components/dialog/style2.css +2 -3
- package/dist/components/expression-editor/components/path-preview.js +27 -0
- package/dist/components/expression-editor/components/path-preview.js.map +1 -0
- package/dist/components/expression-editor/components/variable-picker.js +199 -153
- package/dist/components/expression-editor/components/variable-picker.js.map +1 -1
- package/dist/components/expression-editor/core/chip.js +54 -0
- package/dist/components/expression-editor/core/chip.js.map +1 -0
- package/dist/components/expression-editor/core/editor.js +424 -0
- package/dist/components/expression-editor/core/editor.js.map +1 -0
- package/dist/components/expression-editor/core/mention.js +91 -0
- package/dist/components/expression-editor/core/mention.js.map +1 -0
- package/dist/components/expression-editor/core/model.js +64 -0
- package/dist/components/expression-editor/core/model.js.map +1 -0
- package/dist/components/expression-editor/di.js +4 -10
- package/dist/components/expression-editor/di.js.map +1 -1
- package/dist/components/expression-editor/expression-editor.js +168 -114
- package/dist/components/expression-editor/expression-editor.js.map +1 -1
- package/dist/components/expression-editor/expression-editor.vue.d.ts +2 -1
- package/dist/components/expression-editor/style.js +0 -2
- package/dist/components/expression-editor/style2.css +145 -219
- package/dist/components/index.js +54 -54
- package/dist/components/input/input.vue.d.ts +2 -2
- package/dist/components/layout/layout.js +12 -11
- package/dist/components/layout/layout.js.map +1 -1
- package/dist/components/multi-select/multi-select.vue.d.ts +3 -3
- package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +3 -3
- package/dist/components/notification/notification.vue.d.ts +1 -1
- package/dist/components/number/number.vue.d.ts +1 -1
- package/dist/components/number-input/number-input.js +4 -4
- package/dist/components/number-input/number-input.js.map +1 -1
- package/dist/components/number-input/number-input.vue.d.ts +2 -2
- package/dist/components/number-range-input/number-range-input.vue.d.ts +1 -1
- package/dist/components/password-input/password-input.vue.d.ts +1 -1
- package/dist/components/pop-confirm/pop-confirm.vue.d.ts +1 -1
- package/dist/components/radio-group/radio-group.vue.d.ts +2 -2
- package/dist/components/rich-text-editor/rich-text-editor.js +1 -1
- package/dist/components/rich-text-editor/rich-text-editor.vue.d.ts +1 -1
- package/dist/components/rich-text-editor/toolbar.js +2 -2
- package/dist/components/select/select.vue.d.ts +2 -2
- package/dist/components/steps/steps.vue.d.ts +1 -1
- package/dist/components/table/use-table.js +16 -0
- package/dist/components/table/use-table.js.map +1 -1
- package/dist/components/tabs/tabs-horizontal.vue.d.ts +1 -1
- package/dist/components/tabs/tabs-vertical.vue.d.ts +1 -1
- package/dist/components/tabs/tabs.vue.d.ts +1 -1
- package/dist/components/textarea/textarea.vue.d.ts +2 -2
- package/dist/components/tip/tip.vue.d.ts +1 -1
- package/dist/components/tree/style2.css +18 -12
- package/dist/components/tree/tree-node.js +7 -4
- package/dist/components/tree/tree-node.js.map +1 -1
- package/dist/components/tree-select/tree-select.vue.d.ts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +83 -83
- package/dist/style.js +3 -3
- package/dist/types/action.d.ts +38 -4
- package/dist/types/cascade.d.ts +2 -3
- package/dist/types/code-editor.d.ts +9 -2
- package/dist/types/expression-editor.d.ts +9 -1
- package/dist/types/index.d.ts +2 -2
- package/package.json +11 -12
- package/src/components/action/action-group.vue +126 -56
- package/src/components/action/action.vue +35 -12
- package/src/components/action/style.scss +46 -10
- package/src/components/action/style.ts +2 -1
- package/src/components/batch-edit/batch-edit-form.vue +121 -45
- package/src/components/batch-edit/batch-edit-list.vue +56 -39
- package/src/components/batch-edit/batch-edit.vue +57 -6
- package/src/components/batch-edit/style.scss +251 -37
- package/src/components/batch-edit/style.ts +5 -8
- package/src/components/batch-edit/use-edit.ts +58 -11
- package/src/components/cascade/cascade.vue +3 -1
- package/src/components/code-editor/code-editor.vue +198 -63
- package/src/components/code-editor/style.scss +110 -12
- package/src/components/dialog/dialog.vue +6 -2
- package/src/components/dialog/style.scss +4 -4
- package/src/components/expression-editor/__test__/chip.test.ts +86 -0
- package/src/components/expression-editor/__test__/mention.test.ts +122 -0
- package/src/components/expression-editor/__test__/model.test.ts +127 -0
- package/src/components/expression-editor/components/path-preview.vue +32 -0
- package/src/components/expression-editor/components/variable-picker.vue +224 -219
- package/src/components/expression-editor/core/chip.ts +101 -0
- package/src/components/expression-editor/core/editor.ts +513 -0
- package/src/components/expression-editor/core/mention.ts +121 -0
- package/src/components/expression-editor/core/model.ts +109 -0
- package/src/components/expression-editor/di.ts +4 -32
- package/src/components/expression-editor/expression-editor.vue +184 -151
- package/src/components/expression-editor/style.scss +148 -220
- package/src/components/expression-editor/style.ts +0 -2
- package/src/components/layout/layout.vue +17 -19
- package/src/components/number-input/number-input.vue +4 -4
- package/src/components/table/use-table.ts +16 -0
- package/src/components/tree/style.scss +30 -33
- package/src/components/tree/tree-node.vue +4 -2
- package/src/types/action.ts +42 -4
- package/src/types/cascade.ts +4 -3
- package/src/types/code-editor.ts +9 -2
- package/src/types/expression-editor.ts +9 -0
- package/dist/components/action/action-group.vue_vue_type_script_setup_true_lang.js +0 -65
- package/dist/components/action/action-group.vue_vue_type_script_setup_true_lang.js.map +0 -1
- package/dist/components/expression-editor/constants.js +0 -9
- package/dist/components/expression-editor/constants.js.map +0 -1
- package/dist/components/expression-editor/internal/editor-runtime/create-runtime.js +0 -47
- package/dist/components/expression-editor/internal/editor-runtime/create-runtime.js.map +0 -1
- package/dist/components/expression-editor/internal/editor-runtime/model-sync.js +0 -49
- package/dist/components/expression-editor/internal/editor-runtime/model-sync.js.map +0 -1
- package/dist/components/expression-editor/internal/features/commands/register-command-packs.js +0 -215
- package/dist/components/expression-editor/internal/features/commands/register-command-packs.js.map +0 -1
- package/dist/components/expression-editor/internal/features/drag-drop/drag-drop-service.js +0 -33
- package/dist/components/expression-editor/internal/features/drag-drop/drag-drop-service.js.map +0 -1
- package/dist/components/expression-editor/internal/features/insertion/insertion-service.js +0 -33
- package/dist/components/expression-editor/internal/features/insertion/insertion-service.js.map +0 -1
- package/dist/components/expression-editor/nodes/variable-node.js +0 -94
- package/dist/components/expression-editor/nodes/variable-node.js.map +0 -1
- package/dist/components/expression-editor/parser.js +0 -32
- package/dist/components/expression-editor/parser.js.map +0 -1
- package/dist/components/expression-editor/plain-text.js +0 -19
- package/dist/components/expression-editor/plain-text.js.map +0 -1
- package/dist/components/expression-editor/use-context.js +0 -69
- package/dist/components/expression-editor/use-context.js.map +0 -1
- package/dist/components/expression-editor/use-decorators.js +0 -27
- package/dist/components/expression-editor/use-decorators.js.map +0 -1
- package/dist/components/expression-editor/use-expression-drag-drop.js +0 -275
- package/dist/components/expression-editor/use-expression-drag-drop.js.map +0 -1
- package/src/components/batch-edit/batch-edit-new.vue +0 -168
- package/src/components/batch-edit/style-new.scss +0 -35
- package/src/components/batch-edit/use-edit-new.ts +0 -68
- package/src/components/batch-edit/use-tip.ts +0 -47
- package/src/components/expression-editor/__test__/architecture-boundaries.test.ts +0 -103
- package/src/components/expression-editor/__test__/architecture-compatibility.test.ts +0 -52
- package/src/components/expression-editor/__test__/drag-drop.test.ts +0 -171
- package/src/components/expression-editor/__test__/parser.test.ts +0 -62
- package/src/components/expression-editor/constants.ts +0 -6
- package/src/components/expression-editor/internal/contracts/editor-runtime.ts +0 -11
- package/src/components/expression-editor/internal/editor-runtime/create-runtime.ts +0 -64
- package/src/components/expression-editor/internal/editor-runtime/index.ts +0 -1
- package/src/components/expression-editor/internal/editor-runtime/model-sync.ts +0 -68
- package/src/components/expression-editor/internal/features/commands/register-command-packs.ts +0 -517
- package/src/components/expression-editor/internal/features/drag-drop/drag-drop-service.ts +0 -51
- package/src/components/expression-editor/internal/features/insertion/insertion-service.ts +0 -56
- package/src/components/expression-editor/nodes/variable-node.tsx +0 -118
- package/src/components/expression-editor/parser.ts +0 -46
- package/src/components/expression-editor/plain-text.ts +0 -25
- package/src/components/expression-editor/plan.md +0 -22
- package/src/components/expression-editor/use-context.ts +0 -134
- package/src/components/expression-editor/use-decorators.tsx +0 -29
- package/src/components/expression-editor/use-editor.ts +0 -12
- 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
|
-
}
|