@antdv-next/x 1.2.1 → 1.2.3-beta.1

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.
@@ -0,0 +1,1144 @@
1
+ import { useSenderContext } from "../context.js";
2
+ import { HistoryValueStore, isSameValue } from "./prosemirror/value.js";
3
+ import { collectDefinitions, createDocument, documentToResult, isEquivalentDocument, senderSchema, stringifyValue } from "./prosemirror/model.js";
4
+ import Skill_default from "./Skill.js";
5
+ import { classNames } from "@v-c/util";
6
+ import { computed, createTextVNode, createVNode, defineComponent, nextTick, onBeforeUnmount, onMounted, ref, render, watch } from "vue";
7
+ import { Dropdown, Input } from "antdv-next";
8
+ import { baseKeymap } from "prosemirror-commands";
9
+ import { closeHistory, history, redo, undo } from "prosemirror-history";
10
+ import { keymap } from "prosemirror-keymap";
11
+ import { Fragment as Fragment$1 } from "prosemirror-model";
12
+ import { EditorState, NodeSelection, TextSelection } from "prosemirror-state";
13
+ import { EditorView } from "prosemirror-view";
14
+ //#region components/sender/components/SlotTextAreaProseMirror.tsx
15
+ var SILENT_META = "senderSilent";
16
+ var InputControl = Input;
17
+ var SlotTextAreaProseMirror_default = /* @__PURE__ */ defineComponent({
18
+ name: "SlotTextArea",
19
+ setup(_, { expose }) {
20
+ const senderCtx = useSenderContext();
21
+ const editableRef = ref();
22
+ const prefixCls = computed(() => senderCtx.value.prefixCls || "antd-sender");
23
+ const definitions = /* @__PURE__ */ new Map();
24
+ const skills = /* @__PURE__ */ new Map();
25
+ const values = new HistoryValueStore();
26
+ const managedNodeViews = /* @__PURE__ */ new Set();
27
+ const cancelCompositionHandlers = /* @__PURE__ */ new Set();
28
+ let editorView = null;
29
+ let restoreControlKey = null;
30
+ let managedHistoryActive = !!(senderCtx.value.skill?.value || senderCtx.value.slotConfig?.some((config) => config.type !== "text"));
31
+ let lastEditOwner = null;
32
+ let closeGroupAfterInput = false;
33
+ let controlledConfigs = senderCtx.value.slotConfig;
34
+ let controlledSkill = senderCtx.value.skill;
35
+ const getAutoSizeStyle = () => {
36
+ const autoSize = senderCtx.value.autoSize;
37
+ if (!autoSize) return {};
38
+ const lineHeight = 22;
39
+ if (autoSize === true) return {
40
+ minHeight: `${lineHeight}px`,
41
+ overflowY: void 0
42
+ };
43
+ return {
44
+ minHeight: autoSize.minRows ? `${autoSize.minRows * lineHeight}px` : void 0,
45
+ maxHeight: autoSize.maxRows ? `${autoSize.maxRows * lineHeight}px` : void 0,
46
+ overflowY: autoSize.maxRows ? "auto" : void 0
47
+ };
48
+ };
49
+ const mergeInputStyle = computed(() => ({
50
+ ...senderCtx.value.styles?.input,
51
+ ...getAutoSizeStyle()
52
+ }));
53
+ const isLocked = () => !!(senderCtx.value.readOnly || senderCtx.value.disabled);
54
+ const flushDom = () => {
55
+ editorView?.domObserver?.flush?.();
56
+ };
57
+ const getValue = () => {
58
+ flushDom();
59
+ if (!editorView) return {
60
+ value: "",
61
+ slotConfig: []
62
+ };
63
+ return documentToResult(editorView.state.doc, values, definitions, skills);
64
+ };
65
+ const triggerValueChange = (event) => {
66
+ const value = getValue();
67
+ senderCtx.value.onChange?.(value.value, event, value.slotConfig, value.skill);
68
+ senderCtx.value.setSubmitDisabled?.(!value.value && value.slotConfig.length === 0 && !value.skill);
69
+ };
70
+ const refreshNodeViews = () => {
71
+ managedNodeViews.forEach((nodeView) => nodeView.refresh());
72
+ };
73
+ const findNodePosition = (key, type) => {
74
+ if (!editorView) return null;
75
+ let result = null;
76
+ editorView.state.doc.descendants((node, pos) => {
77
+ if (result === null && node.attrs.key === key && (!type || node.attrs.type === type)) {
78
+ result = pos;
79
+ return false;
80
+ }
81
+ return result === null;
82
+ });
83
+ return result;
84
+ };
85
+ const restoreSelectedControl = () => {
86
+ if (!editorView) return false;
87
+ const selection = editorView.state.selection;
88
+ const selectedNode = selection instanceof NodeSelection && selection.node.type === senderSchema.nodes.slot && selection.node.attrs.type === "input" ? selection.node : null;
89
+ const key = restoreControlKey ?? selectedNode?.attrs.key;
90
+ if (!key) return false;
91
+ const pos = findNodePosition(key, "input");
92
+ const node = pos === null ? null : editorView.state.doc.nodeAt(pos);
93
+ if (!node) return false;
94
+ let cancelled = false;
95
+ const cancel = () => {
96
+ cancelled = true;
97
+ };
98
+ nextTick(() => {
99
+ if (cancelled) return;
100
+ const input = Array.from(editableRef.value?.querySelectorAll("[data-slot-key]") ?? []).find((element) => element.dataset.slotKey === key)?.querySelector("input");
101
+ if (!input) return;
102
+ input.focus();
103
+ if (typeof node.attrs.selectionStart === "number" && typeof node.attrs.selectionEnd === "number") input.setSelectionRange(Math.min(node.attrs.selectionStart, input.value.length), Math.min(node.attrs.selectionEnd, input.value.length), node.attrs.selectionDirection);
104
+ restoreControlKey = null;
105
+ });
106
+ onBeforeUnmount(cancel);
107
+ return true;
108
+ };
109
+ const syncDocumentEmptyState = () => {
110
+ editorView?.dom.toggleAttribute("data-empty", editorView.state.doc.content.size === 0);
111
+ };
112
+ const dispatchTransaction = (transaction) => {
113
+ if (!editorView) return;
114
+ if (transaction.docChanged && !managedHistoryActive) transaction.setMeta("addToHistory", false);
115
+ const nextState = editorView.state.apply(transaction);
116
+ editorView.updateState(nextState);
117
+ syncDocumentEmptyState();
118
+ if (transaction.docChanged && !transaction.getMeta(SILENT_META)) triggerValueChange(transaction.getMeta("uiEvent"));
119
+ if (transaction.docChanged) refreshNodeViews();
120
+ };
121
+ const dispatchSilent = (transaction) => {
122
+ transaction.setMeta("addToHistory", false);
123
+ transaction.setMeta(SILENT_META, true);
124
+ editorView?.dispatch(transaction);
125
+ };
126
+ const closeManagedGroup = () => {
127
+ if (!editorView || !managedHistoryActive) return;
128
+ dispatchSilent(closeHistory(editorView.state.tr));
129
+ };
130
+ const selectManagedNode = (getPos) => {
131
+ if (!editorView) return;
132
+ const pos = getPos();
133
+ if (pos === null) return;
134
+ const selection = editorView.state.selection;
135
+ if (selection instanceof NodeSelection && selection.from === pos) return;
136
+ const transaction = closeHistory(editorView.state.tr.setSelection(NodeSelection.create(editorView.state.doc, pos)));
137
+ dispatchSilent(transaction);
138
+ };
139
+ const recordControlSelection = (getPos, target, breakGroup) => {
140
+ if (!editorView) return;
141
+ const pos = getPos();
142
+ if (pos === null) return;
143
+ const node = editorView.state.doc.nodeAt(pos);
144
+ if (!node) return;
145
+ const selectionStart = Math.min(target.selectionStart ?? 0, target.value.length);
146
+ const selectionEnd = Math.min(target.selectionEnd ?? selectionStart, target.value.length);
147
+ let transaction = editorView.state.tr.setNodeMarkup(pos, void 0, {
148
+ ...node.attrs,
149
+ selectionStart,
150
+ selectionEnd,
151
+ selectionDirection: target.selectionDirection ?? "none"
152
+ });
153
+ transaction = transaction.setSelection(NodeSelection.create(transaction.doc, pos));
154
+ if (breakGroup) transaction = closeHistory(transaction);
155
+ dispatchSilent(transaction);
156
+ };
157
+ const captureActiveControlSelection = () => {
158
+ const input = document.activeElement;
159
+ if (!(input instanceof HTMLInputElement)) return;
160
+ const key = input.closest("[data-slot-key]")?.dataset.slotKey;
161
+ if (!key) return;
162
+ const pos = findNodePosition(key, "input");
163
+ if (pos === null) return;
164
+ recordControlSelection(() => pos, input, true);
165
+ };
166
+ const updateSlotValue = (getPos, value, event, control, force = false) => {
167
+ if (!editorView || isLocked()) return;
168
+ const pos = getPos();
169
+ if (pos === null) return;
170
+ const node = editorView.state.doc.nodeAt(pos);
171
+ if (!node || !force && values.isSame(node.attrs.valueId, value)) return;
172
+ const attrs = {
173
+ ...node.attrs,
174
+ valueId: values.add(value),
175
+ selectionStart: control?.selectionStart ?? node.attrs.selectionStart,
176
+ selectionEnd: control?.selectionEnd ?? node.attrs.selectionEnd,
177
+ selectionDirection: control?.selectionDirection ?? node.attrs.selectionDirection
178
+ };
179
+ const transaction = editorView.state.tr.setNodeMarkup(pos, void 0, attrs);
180
+ if (control) transaction.setSelection(NodeSelection.create(transaction.doc, pos));
181
+ transaction.setMeta("uiEvent", event);
182
+ managedHistoryActive = true;
183
+ lastEditOwner = "control";
184
+ editorView.dispatch(transaction);
185
+ };
186
+ const runHistory = (command, event, controlKey) => {
187
+ if (!editorView || isLocked() || !managedHistoryActive) return false;
188
+ const previousControlValueId = controlKey ? (() => {
189
+ const pos = findNodePosition(controlKey, "input");
190
+ return pos === null ? void 0 : editorView?.state.doc.nodeAt(pos)?.attrs.valueId;
191
+ })() : void 0;
192
+ const handled = command(editorView.state, editorView.dispatch, editorView);
193
+ event?.preventDefault();
194
+ if (handled) {
195
+ if (controlKey) {
196
+ const pos = findNodePosition(controlKey, "input");
197
+ restoreControlKey = previousControlValueId !== (pos === null ? void 0 : editorView.state.doc.nodeAt(pos)?.attrs.valueId) ? controlKey : null;
198
+ }
199
+ if (!restoreSelectedControl()) {
200
+ restoreControlKey = null;
201
+ editorView.focus();
202
+ }
203
+ }
204
+ return handled || !!event;
205
+ };
206
+ const routePasteEvent = (event) => {
207
+ const files = event.clipboardData?.files;
208
+ if (!event.clipboardData?.getData("text/plain") && files?.length && senderCtx.value.onPasteFile) {
209
+ event.preventDefault();
210
+ senderCtx.value.onPasteFile(files);
211
+ return true;
212
+ }
213
+ return false;
214
+ };
215
+ const getSelectionSlice = () => {
216
+ if (!editorView) return null;
217
+ const { from, to } = editorView.state.selection;
218
+ if (from === to) return null;
219
+ try {
220
+ return editorView.state.doc.slice(from, to);
221
+ } catch {
222
+ return null;
223
+ }
224
+ };
225
+ const sliceToCopyPayload = (slice) => {
226
+ const fragment = slice.content;
227
+ const nodes = [];
228
+ fragment.forEach((node) => nodes.push(node));
229
+ const result = documentToResult(senderSchema.nodes.doc.create(void 0, Fragment$1.from(nodes)), values, definitions, skills);
230
+ return {
231
+ slotConfig: result.slotConfig,
232
+ skill: result.skill,
233
+ value: result.value,
234
+ text: result.value
235
+ };
236
+ };
237
+ const handleCopyOrCut = (event, type) => {
238
+ if (!editorView) return false;
239
+ const slice = getSelectionSlice();
240
+ let payload = null;
241
+ let payloadText = "";
242
+ if (slice) {
243
+ const sliced = sliceToCopyPayload(slice);
244
+ payload = {
245
+ ...sliced,
246
+ value: sliced.text,
247
+ text: sliced.text
248
+ };
249
+ payloadText = payload.text;
250
+ } else {
251
+ payloadText = window.getSelection()?.toString() ?? "";
252
+ payload = {
253
+ slotConfig: [],
254
+ skill: void 0,
255
+ value: payloadText,
256
+ text: payloadText
257
+ };
258
+ }
259
+ const info = {
260
+ value: payload.value,
261
+ slotConfig: payload.slotConfig,
262
+ skill: payload.skill,
263
+ text: payloadText
264
+ };
265
+ (type === "copy" ? senderCtx.value.onCopy : senderCtx.value.onCut)?.(event, info);
266
+ if (event.defaultPrevented) return true;
267
+ if (type === "copy" && !slice && !payloadText) return false;
268
+ try {
269
+ event.clipboardData?.setData("text/plain", payloadText);
270
+ } catch {}
271
+ if (type === "cut" && isLocked()) return true;
272
+ if (type === "cut" && slice) {
273
+ flushDom();
274
+ syncSelectionFromDom();
275
+ const sel = editorView.state.selection;
276
+ const hasRange = sel.from !== sel.to;
277
+ let delFrom = sel.from;
278
+ let delTo = sel.to;
279
+ if (!hasRange) {
280
+ const nativeSel = window.getSelection();
281
+ const range = nativeSel?.rangeCount ? nativeSel.getRangeAt(0) : null;
282
+ if (!!range && !range.collapsed && editorView.dom.contains(range.commonAncestorContainer)) {
283
+ delFrom = 0;
284
+ delTo = editorView.state.doc.content.size;
285
+ } else return false;
286
+ }
287
+ if (delFrom !== delTo) {
288
+ managedHistoryActive = true;
289
+ closeManagedGroup();
290
+ editorView.dispatch(editorView.state.tr.delete(delFrom, delTo));
291
+ closeManagedGroup();
292
+ lastEditOwner = "outer";
293
+ }
294
+ } else if (type === "cut" && !slice) {
295
+ const nativeSel = window.getSelection();
296
+ if (!nativeSel) return false;
297
+ const range = nativeSel.rangeCount ? nativeSel.getRangeAt(0) : null;
298
+ if (!!range && !range.collapsed && editorView.dom.contains(range.commonAncestorContainer) && payloadText) {
299
+ flushDom();
300
+ syncSelectionFromDom();
301
+ managedHistoryActive = true;
302
+ closeManagedGroup();
303
+ editorView.dispatch(editorView.state.tr.delete(0, editorView.state.doc.content.size));
304
+ closeManagedGroup();
305
+ lastEditOwner = "outer";
306
+ }
307
+ }
308
+ return type === "copy";
309
+ };
310
+ const routePasteCallback = (event) => {
311
+ const text = event.clipboardData?.getData("text/plain") ?? "";
312
+ senderCtx.value.onPaste?.(event, {
313
+ text,
314
+ slotConfig: [],
315
+ skill: void 0
316
+ });
317
+ return event.defaultPrevented;
318
+ };
319
+ const createSlotNodeView = (initialNode, _view, getPos) => {
320
+ let node = initialNode;
321
+ let isComposing = false;
322
+ let pendingValue;
323
+ let hasPendingValue = false;
324
+ let receivedBeforeInput = false;
325
+ const dom = document.createElement("span");
326
+ dom.contentEditable = "false";
327
+ const cancelComposition = () => {
328
+ isComposing = false;
329
+ pendingValue = void 0;
330
+ hasPendingValue = false;
331
+ receivedBeforeInput = false;
332
+ };
333
+ cancelCompositionHandlers.add(cancelComposition);
334
+ const resolvePos = () => {
335
+ const pos = getPos();
336
+ return typeof pos === "number" ? pos : null;
337
+ };
338
+ const commitValue = (value, event, control, force = false) => {
339
+ if (isComposing) {
340
+ pendingValue = value;
341
+ hasPendingValue = true;
342
+ return;
343
+ }
344
+ updateSlotValue(resolvePos, value, event, control, force);
345
+ };
346
+ const handleHistoryKey = (event) => {
347
+ if (!(event.ctrlKey || event.metaKey)) return false;
348
+ const key = event.key.toLowerCase();
349
+ if (key !== "z" && key !== "y") return false;
350
+ const command = key === "y" || event.shiftKey ? redo : undo;
351
+ return runHistory(command, event, node.attrs.key);
352
+ };
353
+ const routeControlCopyOrCut = (event, type) => {
354
+ const input = event.target;
355
+ const start = input.selectionStart ?? 0;
356
+ const end = input.selectionEnd ?? start;
357
+ const text = input.value.slice(start, end);
358
+ const info = {
359
+ value: text,
360
+ slotConfig: [],
361
+ skill: void 0,
362
+ text
363
+ };
364
+ (type === "copy" ? senderCtx.value.onCopy : senderCtx.value.onCut)?.(event, info);
365
+ };
366
+ const refresh = () => {
367
+ const config = definitions.get(node.attrs.key);
368
+ if (!config) return;
369
+ dom.dataset.slotKey = node.attrs.key;
370
+ dom.dataset.nodeType = "slot";
371
+ dom.className = `${prefixCls.value}-slot`;
372
+ const rawValue = values.read(node.attrs.valueId);
373
+ let child = null;
374
+ if (config.type === "input") child = createVNode(InputControl, {
375
+ "class": `${prefixCls.value}-slot-input`,
376
+ "placeholder": config.props?.placeholder,
377
+ "value": stringifyValue(rawValue),
378
+ "size": "small",
379
+ "variant": "borderless",
380
+ "readonly": senderCtx.value.readOnly,
381
+ "disabled": senderCtx.value.disabled,
382
+ "onFocus": (event) => {
383
+ const input = event.target;
384
+ selectManagedNode(resolvePos);
385
+ recordControlSelection(resolvePos, input, true);
386
+ },
387
+ "onBeforeinput": (event) => {
388
+ const input = event.target;
389
+ if (event.inputType === "historyUndo" || event.inputType === "historyRedo") {
390
+ runHistory(event.inputType === "historyUndo" ? undo : redo, event, node.attrs.key);
391
+ return;
392
+ }
393
+ receivedBeforeInput = true;
394
+ recordControlSelection(resolvePos, input, false);
395
+ },
396
+ "onSelect": (event) => {
397
+ recordControlSelection(resolvePos, event.target, true);
398
+ },
399
+ "onKeydown": (event) => {
400
+ if (senderCtx.value.onKeyDown?.(event) === false) return;
401
+ if (handleHistoryKey(event)) return;
402
+ if (!event.isComposing && shouldSubmit(event)) {
403
+ event.preventDefault();
404
+ senderCtx.value.triggerSend?.();
405
+ }
406
+ },
407
+ "onKeyup": (event) => {
408
+ senderCtx.value.onKeyUp?.(event);
409
+ },
410
+ "onPaste": (event) => {
411
+ const info = {
412
+ text: event.clipboardData?.getData("text/plain") ?? "",
413
+ slotConfig: [],
414
+ skill: void 0
415
+ };
416
+ senderCtx.value.onPaste?.(event, info);
417
+ if (!event.defaultPrevented) routePasteEvent(event);
418
+ },
419
+ "onCopy": (event) => {
420
+ routeControlCopyOrCut(event, "copy");
421
+ },
422
+ "onCut": (event) => {
423
+ routeControlCopyOrCut(event, "cut");
424
+ },
425
+ "onCompositionstart": () => {
426
+ isComposing = true;
427
+ pendingValue = void 0;
428
+ hasPendingValue = false;
429
+ },
430
+ "onCompositionend": (event) => {
431
+ isComposing = false;
432
+ const input = event.target;
433
+ commitValue(hasPendingValue ? pendingValue : input.value, event, input, false);
434
+ pendingValue = void 0;
435
+ hasPendingValue = false;
436
+ },
437
+ "onChange": (event) => {
438
+ const input = event.target;
439
+ if (!receivedBeforeInput && !isComposing) closeManagedGroup();
440
+ commitValue(input.value, event, input);
441
+ if (!receivedBeforeInput && !isComposing) closeManagedGroup();
442
+ receivedBeforeInput = false;
443
+ }
444
+ }, null);
445
+ else if (config.type === "select") {
446
+ const displayValue = stringifyValue(rawValue);
447
+ child = createVNode(Dropdown, {
448
+ "disabled": isLocked(),
449
+ "trigger": ["click"],
450
+ "menu": {
451
+ items: (config.props?.options ?? []).map((option) => ({
452
+ label: option,
453
+ key: option
454
+ })),
455
+ selectable: true,
456
+ selectedKeys: displayValue ? [displayValue] : [],
457
+ onSelect: ({ key, domEvent }) => {
458
+ commitValue(key, domEvent);
459
+ }
460
+ }
461
+ }, { default: () => [createVNode("span", { "class": classNames([`${prefixCls.value}-slot-select`, { placeholder: !displayValue }]) }, [createVNode("span", {
462
+ "data-placeholder": config.props?.placeholder,
463
+ "class": `${prefixCls.value}-slot-select-value`
464
+ }, [displayValue]), createVNode("span", { "class": `${prefixCls.value}-slot-select-arrow` }, [createTextVNode("▼")])])] });
465
+ } else if (config.type === "tag") child = createVNode("span", { "class": `${prefixCls.value}-slot-tag` }, [config.props?.label ?? config.props?.value ?? ""]);
466
+ else if (config.type === "custom") child = config.customRender?.(rawValue, (nextValue) => commitValue(nextValue, void 0, void 0, true), {
467
+ disabled: senderCtx.value.disabled,
468
+ readOnly: senderCtx.value.readOnly
469
+ }, config);
470
+ render(child, dom);
471
+ };
472
+ dom.addEventListener("compositionstart", () => {
473
+ if (node.attrs.type !== "custom") return;
474
+ if (resolvePos() === null) return;
475
+ isComposing = true;
476
+ pendingValue = void 0;
477
+ hasPendingValue = false;
478
+ });
479
+ dom.addEventListener("compositionend", (event) => {
480
+ if (node.attrs.type !== "custom") return;
481
+ if (resolvePos() === null) {
482
+ isComposing = false;
483
+ pendingValue = void 0;
484
+ hasPendingValue = false;
485
+ return;
486
+ }
487
+ isComposing = false;
488
+ if (hasPendingValue) updateSlotValue(resolvePos, pendingValue, event, void 0, true);
489
+ pendingValue = void 0;
490
+ hasPendingValue = false;
491
+ });
492
+ const nodeView = {
493
+ dom,
494
+ refresh,
495
+ selectNode() {
496
+ dom.classList.add(`${prefixCls.value}-slot-selected`);
497
+ },
498
+ deselectNode() {
499
+ dom.classList.remove(`${prefixCls.value}-slot-selected`);
500
+ },
501
+ update(nextNode) {
502
+ if (nextNode.type !== node.type) return false;
503
+ node = nextNode;
504
+ refresh();
505
+ return true;
506
+ },
507
+ stopEvent: () => true,
508
+ ignoreMutation: () => true,
509
+ destroy() {
510
+ cancelCompositionHandlers.delete(cancelComposition);
511
+ managedNodeViews.delete(nodeView);
512
+ render(null, dom);
513
+ }
514
+ };
515
+ managedNodeViews.add(nodeView);
516
+ refresh();
517
+ return nodeView;
518
+ };
519
+ const createContentNodeView = (initialNode) => {
520
+ let node = initialNode;
521
+ const dom = document.createElement("span");
522
+ const before = document.createElement("span");
523
+ const contentDOM = document.createElement("span");
524
+ const after = document.createElement("span");
525
+ dom.append(before, contentDOM, after);
526
+ const refresh = () => {
527
+ const config = definitions.get(node.attrs.key);
528
+ dom.dataset.contentKey = node.attrs.key;
529
+ before.dataset.slotKey = node.attrs.key;
530
+ before.dataset.nodeType = "nbsp";
531
+ before.className = `${prefixCls.value}-slot-before ${prefixCls.value}-slot-no-width`;
532
+ before.textContent = "\xA0";
533
+ after.dataset.slotKey = node.attrs.key;
534
+ after.dataset.nodeType = "nbsp";
535
+ after.className = `${prefixCls.value}-slot-after ${prefixCls.value}-slot-no-width`;
536
+ after.textContent = "\xA0";
537
+ contentDOM.dataset.slotKey = node.attrs.key;
538
+ contentDOM.dataset.nodeType = "slot";
539
+ contentDOM.className = `${prefixCls.value}-slot-content`;
540
+ contentDOM.dataset.placeholder = config?.type === "content" ? config.props?.placeholder ?? "" : "";
541
+ contentDOM.setAttribute("contenteditable", isLocked() ? "false" : "true");
542
+ };
543
+ const nodeView = {
544
+ dom,
545
+ contentDOM,
546
+ refresh,
547
+ update(nextNode) {
548
+ if (nextNode.type !== node.type) return false;
549
+ node = nextNode;
550
+ refresh();
551
+ return true;
552
+ },
553
+ ignoreMutation(mutation) {
554
+ return !contentDOM.contains(mutation.target);
555
+ },
556
+ destroy() {
557
+ managedNodeViews.delete(nodeView);
558
+ }
559
+ };
560
+ managedNodeViews.add(nodeView);
561
+ refresh();
562
+ return nodeView;
563
+ };
564
+ const createSkillNodeView = (initialNode, _view, getPos) => {
565
+ let node = initialNode;
566
+ const dom = document.createElement("span");
567
+ dom.contentEditable = "false";
568
+ const resolvePos = () => {
569
+ const pos = getPos();
570
+ return typeof pos === "number" ? pos : null;
571
+ };
572
+ const refresh = () => {
573
+ const skill = skills.get(node.attrs.value);
574
+ if (!skill) return;
575
+ dom.dataset.skillKey = node.attrs.value;
576
+ dom.dataset.nodeType = "skill";
577
+ dom.className = `${prefixCls.value}-skill`;
578
+ dom.dataset.placeholder = senderCtx.value.placeholder ?? "";
579
+ render(createVNode(Skill_default, {
580
+ "prefixCls": prefixCls.value,
581
+ "skill": skill,
582
+ "disabled": isLocked(),
583
+ "removeSkill": () => {
584
+ if (!editorView || isLocked()) return;
585
+ const pos = resolvePos();
586
+ if (pos === null) return;
587
+ const currentNode = editorView.state.doc.nodeAt(pos);
588
+ if (!currentNode || currentNode.type !== senderSchema.nodes.skill) return;
589
+ managedHistoryActive = true;
590
+ closeManagedGroup();
591
+ const transaction = editorView.state.tr.delete(pos, pos + currentNode.nodeSize);
592
+ transaction.setSelection(TextSelection.near(transaction.doc.resolve(pos)));
593
+ editorView.focus();
594
+ editorView.dispatch(transaction);
595
+ closeManagedGroup();
596
+ }
597
+ }, null), dom);
598
+ const shouldShowSkillPlaceholder = !getValue().value && getValue().slotConfig.length === 0 && !!senderCtx.value.placeholder && !dom.hasChildNodes();
599
+ dom.classList.toggle(`${prefixCls.value}-skill-empty`, shouldShowSkillPlaceholder);
600
+ };
601
+ const nodeView = {
602
+ dom,
603
+ refresh,
604
+ update(nextNode) {
605
+ if (nextNode.type !== node.type) return false;
606
+ node = nextNode;
607
+ refresh();
608
+ return true;
609
+ },
610
+ stopEvent: () => true,
611
+ ignoreMutation: () => true,
612
+ destroy() {
613
+ managedNodeViews.delete(nodeView);
614
+ render(null, dom);
615
+ }
616
+ };
617
+ managedNodeViews.add(nodeView);
618
+ refresh();
619
+ return nodeView;
620
+ };
621
+ const shouldSubmit = (event) => {
622
+ if (event.key !== "Enter") return false;
623
+ const modifier = event.ctrlKey || event.altKey || event.metaKey;
624
+ const submitType = senderCtx.value.submitType ?? "enter";
625
+ return submitType === "enter" && !event.shiftKey && !modifier || submitType === "shiftEnter" && event.shiftKey && !modifier;
626
+ };
627
+ const normalizeSkillText = () => {
628
+ if (!editorView) return false;
629
+ let changed = false;
630
+ const nativeSelection = window.getSelection();
631
+ const selectedOffset = nativeSelection?.anchorOffset ?? 0;
632
+ let selectedSkill = null;
633
+ editableRef.value?.querySelectorAll("[data-skill-key]").forEach((skillDom) => {
634
+ const textNodes = Array.from(skillDom.childNodes).filter((child) => child.nodeType === Node.TEXT_NODE && child.textContent);
635
+ if (!textNodes.length) return;
636
+ skillDom.classList.remove(`${prefixCls.value}-skill-empty`);
637
+ selectedSkill = {
638
+ value: skillDom.dataset.skillKey ?? "",
639
+ textLength: textNodes.reduce((length, child) => length + (child.textContent?.length ?? 0), 0)
640
+ };
641
+ const reference = skillDom.nextSibling;
642
+ textNodes.forEach((child) => {
643
+ editorView?.dom.insertBefore(child, reference);
644
+ });
645
+ changed = true;
646
+ });
647
+ if (changed) editorView.domObserver?.flush?.();
648
+ if (changed && selectedSkill) {
649
+ const capturedSkill = selectedSkill;
650
+ let selectionPosition = null;
651
+ editorView.state.doc.descendants((node, pos) => {
652
+ if (selectionPosition === null && node.type === senderSchema.nodes.skill && node.attrs.value === capturedSkill.value) {
653
+ selectionPosition = pos + node.nodeSize + capturedSkill.textLength;
654
+ return false;
655
+ }
656
+ return selectionPosition === null;
657
+ });
658
+ if (selectionPosition !== null) {
659
+ dispatchSilent(editorView.state.tr.setSelection(TextSelection.create(editorView.state.doc, selectionPosition)));
660
+ const restoreNativeSelection = () => {
661
+ const textNode = Array.from(editorView?.dom.childNodes ?? []).find((child) => child.nodeType === Node.TEXT_NODE && child.textContent);
662
+ if (!textNode) return;
663
+ const range = document.createRange();
664
+ range.setStart(textNode, Math.min(selectedOffset, textNode.textContent?.length ?? 0));
665
+ range.collapse(true);
666
+ nativeSelection?.removeAllRanges();
667
+ nativeSelection?.addRange(range);
668
+ };
669
+ restoreNativeSelection();
670
+ nextTick(restoreNativeSelection);
671
+ }
672
+ }
673
+ return changed;
674
+ };
675
+ const flushNativeInput = () => {
676
+ normalizeSkillText();
677
+ syncContentDom();
678
+ editorView?.domObserver?.flush?.();
679
+ if (closeGroupAfterInput) {
680
+ closeGroupAfterInput = false;
681
+ closeManagedGroup();
682
+ }
683
+ return true;
684
+ };
685
+ const syncContentDom = () => {
686
+ if (!editorView) return false;
687
+ let transaction = editorView.state.tr;
688
+ const contents = Array.from(editableRef.value?.querySelectorAll(`.${prefixCls.value}-slot-content`) ?? []);
689
+ const updates = [];
690
+ editorView.state.doc.descendants((node, pos) => {
691
+ if (node.type !== senderSchema.nodes.contentSlot) return true;
692
+ const content = contents.find((element) => element.dataset.slotKey === node.attrs.key);
693
+ const value = content?.innerText ?? content?.textContent ?? "";
694
+ const parts = [];
695
+ node.forEach((child) => {
696
+ if (child.isText) parts.push(child.text ?? "");
697
+ else if (child.type === senderSchema.nodes.hardBreak) parts.push("\n");
698
+ });
699
+ if (value !== parts.join("")) {
700
+ const newNodes = [];
701
+ const lines = value.split("\n");
702
+ lines.forEach((line, index) => {
703
+ if (line) newNodes.push(senderSchema.text(line));
704
+ if (index < lines.length - 1) newNodes.push(senderSchema.nodes.hardBreak.create());
705
+ });
706
+ updates.push({
707
+ from: pos + 1,
708
+ to: pos + node.nodeSize - 1,
709
+ nodes: newNodes
710
+ });
711
+ }
712
+ return false;
713
+ });
714
+ updates.sort((left, right) => right.from - left.from).forEach((update) => {
715
+ transaction = transaction.replaceWith(update.from, update.to, update.nodes.length > 0 ? update.nodes : []);
716
+ });
717
+ if (!transaction.docChanged) return false;
718
+ editorView.dispatch(transaction);
719
+ return true;
720
+ };
721
+ const syncSelectionFromDom = () => {
722
+ if (!editorView) return;
723
+ if (document.activeElement instanceof HTMLInputElement && document.activeElement.closest("[data-node-type='slot']")) return;
724
+ const selection = window.getSelection();
725
+ if (!selection?.anchorNode || !selection.focusNode || !editorView.dom.contains(selection.anchorNode) || !editorView.dom.contains(selection.focusNode)) return;
726
+ try {
727
+ const anchor = editorView.posAtDOM(selection.anchorNode, selection.anchorOffset);
728
+ const head = editorView.posAtDOM(selection.focusNode, selection.focusOffset);
729
+ if (anchor !== editorView.state.selection.anchor || head !== editorView.state.selection.head) dispatchSilent(editorView.state.tr.setSelection(TextSelection.create(editorView.state.doc, anchor, head)));
730
+ } catch {
731
+ if (typeof console !== "undefined" && console.warn) console.warn("SlotTextArea: syncSelectionFromDom position calculation failed");
732
+ }
733
+ };
734
+ const handleSyntheticDeletion = (event) => {
735
+ if (!editorView || isLocked()) return false;
736
+ if (event.key !== "Backspace" && event.key !== "Delete") return false;
737
+ if (event.ctrlKey || event.altKey || event.metaKey) return false;
738
+ const nativeRange = window.getSelection()?.rangeCount ? window.getSelection().getRangeAt(0) : null;
739
+ const getContentElement = (container) => {
740
+ return (container.nodeType === Node.ELEMENT_NODE ? container : container.parentElement)?.closest(`.${prefixCls.value}-slot-content`);
741
+ };
742
+ const startContent = nativeRange && getContentElement(nativeRange.startContainer);
743
+ const endContent = nativeRange && getContentElement(nativeRange.endContainer);
744
+ if (nativeRange && !nativeRange.collapsed && startContent && startContent === endContent) {
745
+ const pos = findNodePosition(startContent.dataset.slotKey ?? "");
746
+ if (pos !== null) {
747
+ const contentNode = editorView.state.doc.nodeAt(pos);
748
+ if (contentNode && contentNode.type === senderSchema.nodes.contentSlot) try {
749
+ const from = editorView.posAtDOM(nativeRange.startContainer, nativeRange.startOffset);
750
+ const to = editorView.posAtDOM(nativeRange.endContainer, nativeRange.endOffset);
751
+ const contentFrom = pos + 1;
752
+ const contentTo = pos + contentNode.nodeSize - 1;
753
+ if (contentFrom <= from && from <= to && to <= contentTo) {
754
+ event.preventDefault();
755
+ const transaction = editorView.state.tr.delete(from, to);
756
+ transaction.setSelection(TextSelection.near(transaction.doc.resolve(from)));
757
+ editorView.dispatch(transaction);
758
+ return true;
759
+ }
760
+ } catch {}
761
+ }
762
+ }
763
+ syncSelectionFromDom();
764
+ const { selection } = editorView.state;
765
+ let from = selection.from;
766
+ let to = selection.to;
767
+ if (selection.empty) if (event.key === "Backspace" && from > 0) {
768
+ const before = selection.$from.nodeBefore;
769
+ from -= before?.isText ? 1 : before?.nodeSize ?? 1;
770
+ } else if (event.key === "Delete" && to < editorView.state.doc.content.size) {
771
+ const after = selection.$to.nodeAfter;
772
+ to += after?.isText ? 1 : after?.nodeSize ?? 1;
773
+ } else return false;
774
+ event.preventDefault();
775
+ const transaction = editorView.state.tr.delete(from, to);
776
+ transaction.setSelection(TextSelection.near(transaction.doc.resolve(from)));
777
+ editorView.dispatch(transaction);
778
+ return true;
779
+ };
780
+ const createPlugins = () => [
781
+ history({ newGroupDelay: 500 }),
782
+ keymap({
783
+ "Mod-z": undo,
784
+ "Shift-Mod-z": redo,
785
+ "Mod-y": redo
786
+ }),
787
+ keymap(baseKeymap)
788
+ ];
789
+ const applyControlledState = () => {
790
+ if (!editorView) return;
791
+ const configs = senderCtx.value.slotConfig;
792
+ const skill = senderCtx.value.skill;
793
+ const configsChanged = configs !== controlledConfigs;
794
+ const skillChanged = skill !== controlledSkill;
795
+ if (!configsChanged && !skillChanged) return;
796
+ controlledConfigs = configs;
797
+ controlledSkill = skill;
798
+ if (skill?.value || configs?.some((config) => config.type !== "text")) managedHistoryActive = true;
799
+ if (skill?.value) skills.set(skill.value, skill);
800
+ if (!configsChanged && skillChanged) {
801
+ collectDefinitions(definitions, configs);
802
+ const doc = editorView.state.doc;
803
+ const hasSkill = doc.firstChild?.type === senderSchema.nodes.skill;
804
+ const currentSkillValue = hasSkill ? doc.firstChild.attrs.value : void 0;
805
+ const nextSkillValue = skill?.value;
806
+ const currentSkillProps = hasSkill && currentSkillValue ? skills.get(currentSkillValue) : void 0;
807
+ const skillPropsChanged = currentSkillValue === nextSkillValue && skill && currentSkillProps && !isSameValue(currentSkillProps, skill);
808
+ if (currentSkillValue !== nextSkillValue || skillPropsChanged) {
809
+ let tr = editorView.state.tr;
810
+ if (hasSkill) tr = tr.delete(0, doc.firstChild.nodeSize);
811
+ if (nextSkillValue) {
812
+ const skillNode = senderSchema.nodes.skill.create({ value: nextSkillValue });
813
+ tr = tr.insert(0, skillNode);
814
+ }
815
+ tr.setMeta("addToHistory", false);
816
+ tr.setMeta(SILENT_META, true);
817
+ dispatchTransaction(tr);
818
+ } else refreshNodeViews();
819
+ return;
820
+ }
821
+ const controlledEmpty = !skill?.value && (!configs || configs.length === 0);
822
+ const docEmpty = editorView.state.doc.content.size === 0;
823
+ if (controlledEmpty && docEmpty) {
824
+ collectDefinitions(definitions, configs);
825
+ refreshNodeViews();
826
+ return;
827
+ }
828
+ collectDefinitions(definitions, configs);
829
+ if (isEquivalentDocument(editorView.state.doc, configs, skill, values, definitions)) {
830
+ refreshNodeViews();
831
+ return;
832
+ }
833
+ const state = EditorState.create({
834
+ schema: senderSchema,
835
+ doc: createDocument(configs, skill, values),
836
+ plugins: createPlugins()
837
+ });
838
+ editorView.updateState(state);
839
+ syncDocumentEmptyState();
840
+ nextTick(() => triggerValueChange());
841
+ };
842
+ onMounted(() => {
843
+ const root = editableRef.value;
844
+ if (!root) return;
845
+ const rangePrototype = Range.prototype;
846
+ if (!rangePrototype.getClientRects) rangePrototype.getClientRects = () => [];
847
+ if (!rangePrototype.getBoundingClientRect) rangePrototype.getBoundingClientRect = () => ({
848
+ left: 0,
849
+ right: 0,
850
+ top: 0,
851
+ bottom: 0,
852
+ width: 0,
853
+ height: 0
854
+ });
855
+ collectDefinitions(definitions, senderCtx.value.slotConfig);
856
+ if (senderCtx.value.skill?.value) skills.set(senderCtx.value.skill.value, senderCtx.value.skill);
857
+ const state = EditorState.create({
858
+ schema: senderSchema,
859
+ doc: createDocument(senderCtx.value.slotConfig, senderCtx.value.skill, values),
860
+ plugins: createPlugins()
861
+ });
862
+ editorView = new EditorView({ mount: root }, {
863
+ state,
864
+ dispatchTransaction,
865
+ editable: () => !isLocked(),
866
+ nodeViews: {
867
+ slot: createSlotNodeView,
868
+ contentSlot: createContentNodeView,
869
+ skill: createSkillNodeView
870
+ },
871
+ attributes: {
872
+ role: "textbox",
873
+ tabindex: "0",
874
+ spellcheck: "false"
875
+ },
876
+ handleDOMEvents: {
877
+ focus: (_view, event) => {
878
+ senderCtx.value.onFocus?.(event);
879
+ return false;
880
+ },
881
+ blur: (_view, event) => {
882
+ cancelCompositionHandlers.forEach((cancel) => cancel());
883
+ senderCtx.value.onBlur?.(event);
884
+ return false;
885
+ },
886
+ beforeinput: (_view, rawEvent) => {
887
+ const event = rawEvent;
888
+ if (event.inputType === "historyUndo") {
889
+ if (isLocked() || !managedHistoryActive) return true;
890
+ return runHistory(undo, event);
891
+ }
892
+ if (event.inputType === "historyRedo") {
893
+ if (isLocked() || !managedHistoryActive) return true;
894
+ return runHistory(redo, event);
895
+ }
896
+ if (event.inputType.startsWith("format") || [
897
+ "insertHorizontalRule",
898
+ "insertLink",
899
+ "insertOrderedList",
900
+ "insertUnorderedList"
901
+ ].includes(event.inputType)) {
902
+ event.preventDefault();
903
+ return true;
904
+ }
905
+ if (lastEditOwner === "control") closeManagedGroup();
906
+ if (event.inputType === "insertFromPaste") {
907
+ closeManagedGroup();
908
+ closeGroupAfterInput = true;
909
+ }
910
+ lastEditOwner = "outer";
911
+ syncSelectionFromDom();
912
+ return false;
913
+ },
914
+ input: () => flushNativeInput(),
915
+ keydown: (_view, rawEvent) => {
916
+ const event = rawEvent;
917
+ if (senderCtx.value.onKeyDown?.(event) === false) return true;
918
+ if (event.isComposing) return false;
919
+ const modifier = event.ctrlKey || event.metaKey;
920
+ const key = event.key.toLowerCase();
921
+ if (modifier && (key === "z" || key === "y")) {
922
+ if (isLocked() || !managedHistoryActive) return true;
923
+ return runHistory(key === "y" || event.shiftKey ? redo : undo, event);
924
+ }
925
+ if (handleSyntheticDeletion(event)) return true;
926
+ if (event.key === "Enter" && !shouldSubmit(event) && editorView && !isLocked()) {
927
+ syncSelectionFromDom();
928
+ const { selection } = editorView.state;
929
+ const hardBreak = senderSchema.nodes.hardBreak.create();
930
+ let transaction;
931
+ if (selection instanceof NodeSelection) {
932
+ transaction = editorView.state.tr.insert(selection.to, hardBreak);
933
+ transaction.setSelection(TextSelection.near(transaction.doc.resolve(selection.to + hardBreak.nodeSize)));
934
+ } else transaction = editorView.state.tr.replaceSelectionWith(hardBreak);
935
+ event.preventDefault();
936
+ managedHistoryActive = true;
937
+ editorView.dispatch(transaction);
938
+ return true;
939
+ }
940
+ if (shouldSubmit(event)) {
941
+ event.preventDefault();
942
+ if (!senderCtx.value.disabled) senderCtx.value.triggerSend?.();
943
+ return true;
944
+ }
945
+ return false;
946
+ },
947
+ keyup: (_view, event) => {
948
+ senderCtx.value.onKeyUp?.(event);
949
+ return false;
950
+ },
951
+ copy: (_view, event) => {
952
+ const handled = handleCopyOrCut(event, "copy");
953
+ if (handled) event.preventDefault();
954
+ return handled;
955
+ },
956
+ paste: (_view, event) => {
957
+ const clipboardEvent = event;
958
+ if (routePasteCallback(clipboardEvent)) return true;
959
+ if (isLocked()) {
960
+ clipboardEvent.preventDefault();
961
+ return true;
962
+ }
963
+ const text = clipboardEvent.clipboardData?.getData("text/plain");
964
+ if (routePasteEvent(clipboardEvent)) return true;
965
+ if (text !== void 0) {
966
+ clipboardEvent.preventDefault();
967
+ flushDom();
968
+ syncSelectionFromDom();
969
+ managedHistoryActive = true;
970
+ closeManagedGroup();
971
+ editorView?.dispatch(editorView.state.tr.insertText(text));
972
+ closeManagedGroup();
973
+ lastEditOwner = "outer";
974
+ return true;
975
+ }
976
+ return false;
977
+ },
978
+ cut: (_view, event) => {
979
+ handleCopyOrCut(event, "cut");
980
+ event.preventDefault();
981
+ return true;
982
+ }
983
+ }
984
+ });
985
+ syncDocumentEmptyState();
986
+ triggerValueChange();
987
+ });
988
+ watch(() => [senderCtx.value.slotConfig, senderCtx.value.skill], () => applyControlledState());
989
+ watch(() => [
990
+ senderCtx.value.readOnly,
991
+ senderCtx.value.disabled,
992
+ senderCtx.value.placeholder
993
+ ], () => {
994
+ if (!editorView) return;
995
+ editorView.setProps({ editable: () => !isLocked() });
996
+ refreshNodeViews();
997
+ });
998
+ const createNodes = (configs) => {
999
+ collectDefinitions(definitions, configs);
1000
+ const doc = createDocument(configs, void 0, values);
1001
+ return Array.from({ length: doc.childCount }, (_, index) => doc.child(index));
1002
+ };
1003
+ const insert = (configs, position = "cursor", replaceCharacters, preventScroll) => {
1004
+ if (!editorView || isLocked() || !configs.length) return;
1005
+ const focusedInputKey = document.activeElement instanceof HTMLInputElement ? document.activeElement.closest("[data-slot-key]")?.dataset.slotKey : void 0;
1006
+ captureActiveControlSelection();
1007
+ if (position === "cursor" && replaceCharacters) {
1008
+ const selection = window.getSelection();
1009
+ if (selection?.rangeCount) {
1010
+ const range = selection.getRangeAt(0);
1011
+ if (range.collapsed && range.startContainer.nodeType === Node.TEXT_NODE) {
1012
+ const textBefore = range.startContainer.textContent?.slice(0, range.startOffset) ?? "";
1013
+ const searchLength = Math.min(replaceCharacters.length, textBefore.length);
1014
+ if (textBefore.slice(-searchLength) === replaceCharacters.slice(-searchLength)) {
1015
+ range.setStart(range.startContainer, range.startOffset - searchLength);
1016
+ range.deleteContents();
1017
+ range.collapse(true);
1018
+ selection.removeAllRanges();
1019
+ selection.addRange(range);
1020
+ }
1021
+ }
1022
+ }
1023
+ }
1024
+ flushDom();
1025
+ syncSelectionFromDom();
1026
+ managedHistoryActive = true;
1027
+ closeManagedGroup();
1028
+ let from = editorView.state.selection.from;
1029
+ let to = editorView.state.selection.to;
1030
+ const selectedNode = editorView.state.selection instanceof NodeSelection ? editorView.state.selection.node : null;
1031
+ if (position === "cursor" && focusedInputKey && selectedNode?.type === senderSchema.nodes.slot && selectedNode.attrs.type === "input" && focusedInputKey === selectedNode.attrs.key) from = to = editorView.state.selection.to;
1032
+ if (position === "start") {
1033
+ const first = editorView.state.doc.firstChild;
1034
+ from = to = first?.type === senderSchema.nodes.skill ? first.nodeSize : 0;
1035
+ } else if (position === "end") from = to = editorView.state.doc.content.size;
1036
+ if (replaceCharacters && from === to) {
1037
+ if (editorView.state.doc.textBetween(from, Math.min(editorView.state.doc.content.size, from + replaceCharacters.length)) === replaceCharacters) {
1038
+ from += replaceCharacters.length;
1039
+ to = from;
1040
+ }
1041
+ const start = Math.max(0, from - replaceCharacters.length);
1042
+ if (editorView.state.doc.textBetween(start, from) === replaceCharacters) from = start;
1043
+ else if (editorView.state.doc.textContent.endsWith(replaceCharacters)) {
1044
+ to = editorView.state.doc.content.size;
1045
+ from = to - replaceCharacters.length;
1046
+ }
1047
+ }
1048
+ const nodes = createNodes(configs);
1049
+ if (!nodes.length) return;
1050
+ const transaction = editorView.state.tr.replaceWith(from, to, nodes);
1051
+ transaction.setSelection(TextSelection.near(transaction.doc.resolve(from + nodes.reduce((size, node) => size + node.nodeSize, 0))));
1052
+ editorView.focus();
1053
+ editorView.dispatch(transaction);
1054
+ closeManagedGroup();
1055
+ if (!preventScroll) editableRef.value?.scrollIntoView?.({ block: "nearest" });
1056
+ };
1057
+ const setCursor = (cursor, preventScroll) => {
1058
+ if (!editorView) return;
1059
+ const doc = editorView.state.doc;
1060
+ let selection;
1061
+ if (cursor === "all") {
1062
+ const from = doc.firstChild?.type === senderSchema.nodes.skill ? doc.firstChild.nodeSize : 0;
1063
+ selection = TextSelection.create(doc, from, doc.content.size);
1064
+ } else {
1065
+ const position = cursor === "start" && doc.firstChild?.type === senderSchema.nodes.skill ? doc.firstChild.nodeSize : cursor === "start" ? 0 : doc.content.size;
1066
+ selection = TextSelection.near(doc.resolve(position));
1067
+ }
1068
+ dispatchSilent(editorView.state.tr.setSelection(selection));
1069
+ editorView.focus();
1070
+ if (!preventScroll) editorView.dom.scrollIntoView?.({ block: "nearest" });
1071
+ };
1072
+ const focus = (options) => {
1073
+ if (!editorView) return;
1074
+ const doc = editorView.state.doc;
1075
+ const defaultCursor = doc.content.size === 0 || doc.content.size === doc.firstChild?.nodeSize && doc.firstChild?.type === senderSchema.nodes.skill ? "start" : "end";
1076
+ const cursor = options?.cursor ?? defaultCursor;
1077
+ if (cursor !== "slot") {
1078
+ setCursor(cursor, options?.preventScroll);
1079
+ return;
1080
+ }
1081
+ const key = options?.key;
1082
+ const candidates = Array.from(editableRef.value?.querySelectorAll("[data-slot-key][data-node-type='slot']") ?? []);
1083
+ const dom = key ? candidates.find((element) => element.dataset.slotKey === key) : candidates.find((element) => !!element.querySelector("input") || element.classList.contains(`${prefixCls.value}-slot-content`));
1084
+ const input = dom?.querySelector("input");
1085
+ if (input) input.focus({ preventScroll: options?.preventScroll });
1086
+ else if (dom?.classList.contains(`${prefixCls.value}-slot-content`)) {
1087
+ dom.focus({ preventScroll: options?.preventScroll });
1088
+ const selection = window.getSelection();
1089
+ const range = document.createRange();
1090
+ range.selectNodeContents(dom);
1091
+ range.collapse(true);
1092
+ selection?.removeAllRanges();
1093
+ selection?.addRange(range);
1094
+ syncSelectionFromDom();
1095
+ if (!options?.preventScroll) dom.scrollIntoView?.({ block: "nearest" });
1096
+ } else setCursor(defaultCursor, options?.preventScroll);
1097
+ };
1098
+ const clear = () => {
1099
+ if (!editorView || isLocked()) return;
1100
+ captureActiveControlSelection();
1101
+ flushDom();
1102
+ managedHistoryActive = true;
1103
+ closeManagedGroup();
1104
+ if (editorView.state.doc.content.size === 0) return;
1105
+ const transaction = editorView.state.tr.delete(0, editorView.state.doc.content.size);
1106
+ transaction.setSelection(TextSelection.create(transaction.doc, 0));
1107
+ editorView.dispatch(transaction);
1108
+ closeManagedGroup();
1109
+ };
1110
+ expose({
1111
+ get nativeElement() {
1112
+ return editableRef.value ?? null;
1113
+ },
1114
+ focus,
1115
+ blur() {
1116
+ editorView?.dom.blur();
1117
+ },
1118
+ insert,
1119
+ clear,
1120
+ getValue
1121
+ });
1122
+ onBeforeUnmount(() => {
1123
+ managedNodeViews.forEach((nodeView) => nodeView.destroy?.());
1124
+ managedNodeViews.clear();
1125
+ editorView?.destroy();
1126
+ editorView = null;
1127
+ });
1128
+ return () => {
1129
+ const inputCls = `${prefixCls.value}-input`;
1130
+ return createVNode("div", {
1131
+ "ref": editableRef,
1132
+ "class": classNames([
1133
+ inputCls,
1134
+ `${inputCls}-slot`,
1135
+ senderCtx.value.classNames?.input
1136
+ ]),
1137
+ "style": mergeInputStyle.value,
1138
+ "data-placeholder": senderCtx.value.placeholder
1139
+ }, null);
1140
+ };
1141
+ }
1142
+ });
1143
+ //#endregion
1144
+ export { SlotTextAreaProseMirror_default as default };