@tiptap/extension-drag-handle 3.20.1 → 3.20.3

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/index.js DELETED
@@ -1,879 +0,0 @@
1
- // src/drag-handle.ts
2
- import { Extension } from "@tiptap/core";
3
-
4
- // src/drag-handle-plugin.ts
5
- import { computePosition } from "@floating-ui/dom";
6
- import { isFirefox } from "@tiptap/core";
7
- import { isChangeOrigin } from "@tiptap/extension-collaboration";
8
- import { Plugin, PluginKey } from "@tiptap/pm/state";
9
- import {
10
- absolutePositionToRelativePosition,
11
- relativePositionToAbsolutePosition,
12
- ySyncPluginKey
13
- } from "@tiptap/y-tiptap";
14
-
15
- // src/helpers/dragHandler.ts
16
- import { getSelectionRanges, NodeRangeSelection } from "@tiptap/extension-node-range";
17
- import { NodeSelection } from "@tiptap/pm/state";
18
-
19
- // src/helpers/cloneElement.ts
20
- function getCSSText(element) {
21
- let value = "";
22
- const style = getComputedStyle(element);
23
- for (let i = 0; i < style.length; i += 1) {
24
- value += `${style[i]}:${style.getPropertyValue(style[i])};`;
25
- }
26
- return value;
27
- }
28
- function cloneElement(node) {
29
- const clonedNode = node.cloneNode(true);
30
- const sourceElements = [node, ...Array.from(node.getElementsByTagName("*"))];
31
- const targetElements = [clonedNode, ...Array.from(clonedNode.getElementsByTagName("*"))];
32
- sourceElements.forEach((sourceElement, index) => {
33
- targetElements[index].style.cssText = getCSSText(sourceElement);
34
- });
35
- return clonedNode;
36
- }
37
-
38
- // src/helpers/defaultRules.ts
39
- var listItemFirstChild = {
40
- id: "listItemFirstChild",
41
- evaluate: ({ parent, isFirst }) => {
42
- if (!isFirst) {
43
- return 0;
44
- }
45
- const listItemTypes = ["listItem", "taskItem"];
46
- if (parent && listItemTypes.includes(parent.type.name)) {
47
- return 1e3;
48
- }
49
- return 0;
50
- }
51
- };
52
- var listWrapperDeprioritize = {
53
- id: "listWrapperDeprioritize",
54
- evaluate: ({ node }) => {
55
- const listItemTypes = ["listItem", "taskItem"];
56
- const firstChild = node.firstChild;
57
- if (firstChild && listItemTypes.includes(firstChild.type.name)) {
58
- return 1e3;
59
- }
60
- return 0;
61
- }
62
- };
63
- var tableStructure = {
64
- id: "tableStructure",
65
- evaluate: ({ node, parent }) => {
66
- const tableStructureTypes = ["tableRow", "tableCell", "tableHeader"];
67
- if (tableStructureTypes.includes(node.type.name)) {
68
- return 1e3;
69
- }
70
- if (parent && parent.type.name === "tableHeader") {
71
- return 1e3;
72
- }
73
- return 0;
74
- }
75
- };
76
- var inlineContent = {
77
- id: "inlineContent",
78
- evaluate: ({ node }) => {
79
- if (node.isInline || node.isText) {
80
- return 1e3;
81
- }
82
- return 0;
83
- }
84
- };
85
- var defaultRules = [
86
- listItemFirstChild,
87
- listWrapperDeprioritize,
88
- tableStructure,
89
- inlineContent
90
- ];
91
-
92
- // src/helpers/edgeDetection.ts
93
- var DEFAULT_EDGE_CONFIG = {
94
- edges: ["left", "top"],
95
- threshold: 12,
96
- strength: 500
97
- };
98
- function normalizeEdgeDetection(input) {
99
- if (input === void 0 || input === "left") {
100
- return { ...DEFAULT_EDGE_CONFIG };
101
- }
102
- if (input === "right") {
103
- return { edges: ["right", "top"], threshold: 12, strength: 500 };
104
- }
105
- if (input === "both") {
106
- return { edges: ["left", "right", "top"], threshold: 12, strength: 500 };
107
- }
108
- if (input === "none") {
109
- return { edges: [], threshold: 0, strength: 0 };
110
- }
111
- return { ...DEFAULT_EDGE_CONFIG, ...input };
112
- }
113
- function isNearEdge(coords, element, config) {
114
- if (config.edges.length === 0) {
115
- return false;
116
- }
117
- const rect = element.getBoundingClientRect();
118
- const { threshold, edges } = config;
119
- return edges.some((edge) => {
120
- if (edge === "left") {
121
- return coords.x - rect.left < threshold;
122
- }
123
- if (edge === "right") {
124
- return rect.right - coords.x < threshold;
125
- }
126
- if (edge === "top") {
127
- return coords.y - rect.top < threshold;
128
- }
129
- if (edge === "bottom") {
130
- return rect.bottom - coords.y < threshold;
131
- }
132
- return false;
133
- });
134
- }
135
- function calculateEdgeDeduction(coords, element, config, depth) {
136
- if (!element || config.edges.length === 0) {
137
- return 0;
138
- }
139
- if (isNearEdge(coords, element, config)) {
140
- return config.strength * depth;
141
- }
142
- return 0;
143
- }
144
-
145
- // src/helpers/scoring.ts
146
- var BASE_SCORE = 1e3;
147
- function calculateScore(context, rules, edgeConfig, coords) {
148
- let score = BASE_SCORE;
149
- let excluded = false;
150
- rules.every((rule) => {
151
- const deduction = rule.evaluate(context);
152
- score -= deduction;
153
- if (score <= 0) {
154
- excluded = true;
155
- return false;
156
- }
157
- return true;
158
- });
159
- if (excluded) {
160
- return -1;
161
- }
162
- const dom = context.view.nodeDOM(context.pos);
163
- score -= calculateEdgeDeduction(coords, dom, edgeConfig, context.depth);
164
- if (score <= 0) {
165
- return -1;
166
- }
167
- return score;
168
- }
169
-
170
- // src/helpers/findBestDragTarget.ts
171
- function hasAncestorOfType($pos, depth, allowedTypes) {
172
- const ancestorDepths = Array.from({ length: depth }, (_, i) => depth - 1 - i);
173
- return ancestorDepths.some((d) => allowedTypes.includes($pos.node(d).type.name));
174
- }
175
- function findBestDragTarget(view, coords, options) {
176
- if (!Number.isFinite(coords.x) || !Number.isFinite(coords.y)) {
177
- return null;
178
- }
179
- const posInfo = view.posAtCoords({ left: coords.x, top: coords.y });
180
- if (!posInfo) {
181
- return null;
182
- }
183
- const { doc } = view.state;
184
- const $pos = doc.resolve(posInfo.pos);
185
- const rules = [];
186
- if (options.defaultRules) {
187
- rules.push(...defaultRules);
188
- }
189
- rules.push(...options.rules);
190
- const depthLevels = Array.from({ length: $pos.depth }, (_, i) => $pos.depth - i);
191
- const candidates = depthLevels.map((depth) => {
192
- const node = $pos.node(depth);
193
- const nodePos = $pos.before(depth);
194
- if (options.allowedContainers && depth > 0) {
195
- const inAllowedContainer = hasAncestorOfType($pos, depth, options.allowedContainers);
196
- if (!inAllowedContainer) {
197
- return null;
198
- }
199
- }
200
- const parent = depth > 0 ? $pos.node(depth - 1) : null;
201
- const index = depth > 0 ? $pos.index(depth - 1) : 0;
202
- const siblingCount = parent ? parent.childCount : 1;
203
- const context = {
204
- node,
205
- pos: nodePos,
206
- depth,
207
- parent,
208
- index,
209
- isFirst: index === 0,
210
- isLast: index === siblingCount - 1,
211
- $pos,
212
- view
213
- };
214
- const score = calculateScore(context, rules, options.edgeDetection, coords);
215
- if (score < 0) {
216
- return null;
217
- }
218
- const dom = view.nodeDOM(nodePos);
219
- return { node, pos: nodePos, depth, score, dom };
220
- }).filter((candidate) => candidate !== null);
221
- const nodeAfter = $pos.nodeAfter;
222
- if (nodeAfter && nodeAfter.isAtom && !nodeAfter.isInline) {
223
- const nodePos = posInfo.pos;
224
- const depth = $pos.depth + 1;
225
- const parent = $pos.parent;
226
- const index = $pos.index();
227
- const siblingCount = parent.childCount;
228
- let inAllowedContainer = true;
229
- if (options.allowedContainers) {
230
- inAllowedContainer = hasAncestorOfType($pos, depth, options.allowedContainers);
231
- }
232
- if (inAllowedContainer) {
233
- const context = {
234
- node: nodeAfter,
235
- pos: nodePos,
236
- depth,
237
- parent,
238
- index,
239
- isFirst: index === 0,
240
- isLast: index === siblingCount - 1,
241
- $pos,
242
- view
243
- };
244
- const score = calculateScore(context, rules, options.edgeDetection, coords);
245
- if (score >= 0) {
246
- const dom = view.nodeDOM(nodePos);
247
- if (dom) {
248
- candidates.push({ node: nodeAfter, pos: nodePos, depth, score, dom });
249
- }
250
- }
251
- }
252
- }
253
- if (candidates.length === 0) {
254
- return null;
255
- }
256
- candidates.sort((a, b) => {
257
- if (b.score !== a.score) {
258
- return b.score - a.score;
259
- }
260
- return b.depth - a.depth;
261
- });
262
- const winner = candidates[0];
263
- if (!winner.dom) {
264
- return null;
265
- }
266
- return {
267
- node: winner.node,
268
- pos: winner.pos,
269
- dom: winner.dom
270
- };
271
- }
272
-
273
- // src/helpers/findNextElementFromCursor.ts
274
- function findClosestTopLevelBlock(element, view) {
275
- let current = element;
276
- while ((current == null ? void 0 : current.parentElement) && current.parentElement !== view.dom) {
277
- current = current.parentElement;
278
- }
279
- return (current == null ? void 0 : current.parentElement) === view.dom ? current : void 0;
280
- }
281
- function isValidRect(rect) {
282
- return Number.isFinite(rect.top) && Number.isFinite(rect.bottom) && Number.isFinite(rect.left) && Number.isFinite(rect.right) && rect.width > 0 && rect.height > 0;
283
- }
284
- function clampToContent(view, x, y, inset = 5) {
285
- if (!Number.isFinite(x) || !Number.isFinite(y)) {
286
- return null;
287
- }
288
- const container = view.dom;
289
- const firstBlock = container.firstElementChild;
290
- const lastBlock = container.lastElementChild;
291
- if (!firstBlock || !lastBlock) {
292
- return null;
293
- }
294
- const topRect = firstBlock.getBoundingClientRect();
295
- const botRect = lastBlock.getBoundingClientRect();
296
- if (!isValidRect(topRect) || !isValidRect(botRect)) {
297
- return null;
298
- }
299
- const clampedY = Math.min(Math.max(topRect.top + inset, y), botRect.bottom - inset);
300
- const epsilon = 0.5;
301
- const sameLeft = Math.abs(topRect.left - botRect.left) < epsilon;
302
- const sameRight = Math.abs(topRect.right - botRect.right) < epsilon;
303
- let rowRect = topRect;
304
- if (sameLeft && sameRight) {
305
- rowRect = topRect;
306
- } else {
307
- }
308
- const clampedX = Math.min(Math.max(rowRect.left + inset, x), rowRect.right - inset);
309
- if (!Number.isFinite(clampedX) || !Number.isFinite(clampedY)) {
310
- return null;
311
- }
312
- return { x: clampedX, y: clampedY };
313
- }
314
- var findElementNextToCoords = (options) => {
315
- const { x, y, editor, nestedOptions } = options;
316
- const { view, state } = editor;
317
- const clamped = clampToContent(view, x, y, 5);
318
- if (!clamped) {
319
- return { resultElement: null, resultNode: null, pos: null };
320
- }
321
- const { x: clampedX, y: clampedY } = clamped;
322
- if (nestedOptions == null ? void 0 : nestedOptions.enabled) {
323
- const target = findBestDragTarget(view, { x: clampedX, y: clampedY }, nestedOptions);
324
- if (!target) {
325
- return { resultElement: null, resultNode: null, pos: null };
326
- }
327
- return {
328
- resultElement: target.dom,
329
- resultNode: target.node,
330
- pos: target.pos
331
- };
332
- }
333
- const elements = view.root.elementsFromPoint(clampedX, clampedY);
334
- let block;
335
- Array.prototype.some.call(elements, (el) => {
336
- if (!view.dom.contains(el)) {
337
- return false;
338
- }
339
- const candidate = findClosestTopLevelBlock(el, view);
340
- if (candidate) {
341
- block = candidate;
342
- return true;
343
- }
344
- return false;
345
- });
346
- if (!block) {
347
- return { resultElement: null, resultNode: null, pos: null };
348
- }
349
- let pos;
350
- try {
351
- pos = view.posAtDOM(block, 0);
352
- } catch {
353
- return { resultElement: null, resultNode: null, pos: null };
354
- }
355
- const node = state.doc.nodeAt(pos);
356
- if (!node) {
357
- const resolvedPos = state.doc.resolve(pos);
358
- const parent = resolvedPos.parent;
359
- return {
360
- resultElement: block,
361
- resultNode: parent,
362
- pos: resolvedPos.start()
363
- };
364
- }
365
- return {
366
- resultElement: block,
367
- resultNode: node,
368
- pos
369
- };
370
- };
371
-
372
- // src/helpers/removeNode.ts
373
- function removeNode(node) {
374
- var _a;
375
- (_a = node.parentNode) == null ? void 0 : _a.removeChild(node);
376
- }
377
-
378
- // src/helpers/dragHandler.ts
379
- function getDragHandleRanges(event, editor, nestedOptions, dragContext) {
380
- const { doc } = editor.view.state;
381
- if ((nestedOptions == null ? void 0 : nestedOptions.enabled) && (dragContext == null ? void 0 : dragContext.node) && dragContext.pos >= 0) {
382
- const nodeStart = dragContext.pos;
383
- const nodeEnd = dragContext.pos + dragContext.node.nodeSize;
384
- return [
385
- {
386
- $from: doc.resolve(nodeStart),
387
- $to: doc.resolve(nodeEnd)
388
- }
389
- ];
390
- }
391
- const result = findElementNextToCoords({
392
- editor,
393
- x: event.clientX,
394
- y: event.clientY,
395
- direction: "right",
396
- nestedOptions
397
- });
398
- if (!result.resultNode || result.pos === null) {
399
- return [];
400
- }
401
- const offset = result.resultNode.isText || result.resultNode.isAtom ? 0 : -1;
402
- const $from = doc.resolve(result.pos);
403
- const $to = doc.resolve(result.pos + result.resultNode.nodeSize + offset);
404
- return getSelectionRanges($from, $to, 0);
405
- }
406
- function dragHandler(event, editor, nestedOptions, dragContext) {
407
- const { view } = editor;
408
- if (!event.dataTransfer) {
409
- return;
410
- }
411
- const { empty, $from, $to } = view.state.selection;
412
- const dragHandleRanges = getDragHandleRanges(event, editor, nestedOptions, dragContext);
413
- const selectionRanges = getSelectionRanges($from, $to, 0);
414
- const isDragHandleWithinSelection = selectionRanges.some((range) => {
415
- return dragHandleRanges.find((dragHandleRange) => {
416
- return dragHandleRange.$from === range.$from && dragHandleRange.$to === range.$to;
417
- });
418
- });
419
- const ranges = empty || !isDragHandleWithinSelection ? dragHandleRanges : selectionRanges;
420
- if (!ranges.length) {
421
- return;
422
- }
423
- const { tr } = view.state;
424
- const wrapper = document.createElement("div");
425
- const from = ranges[0].$from.pos;
426
- const to = ranges[ranges.length - 1].$to.pos;
427
- const isNestedDrag = (nestedOptions == null ? void 0 : nestedOptions.enabled) && (dragContext == null ? void 0 : dragContext.node);
428
- let slice;
429
- let selection;
430
- if (isNestedDrag) {
431
- slice = view.state.doc.slice(from, to);
432
- selection = NodeSelection.create(view.state.doc, from);
433
- } else {
434
- selection = NodeRangeSelection.create(view.state.doc, from, to);
435
- slice = selection.content();
436
- }
437
- ranges.forEach((range) => {
438
- const element = view.nodeDOM(range.$from.pos);
439
- const clonedElement = cloneElement(element);
440
- wrapper.append(clonedElement);
441
- });
442
- wrapper.style.position = "absolute";
443
- wrapper.style.top = "-10000px";
444
- document.body.append(wrapper);
445
- event.dataTransfer.clearData();
446
- event.dataTransfer.setDragImage(wrapper, 0, 0);
447
- const nodeSelection = selection instanceof NodeSelection ? selection : void 0;
448
- view.dragging = { slice, move: true, node: nodeSelection };
449
- tr.setSelection(selection);
450
- view.dispatch(tr);
451
- document.addEventListener("drop", () => removeNode(wrapper), { once: true });
452
- }
453
-
454
- // src/helpers/getOuterNode.ts
455
- var getOuterNodePos = (doc, pos) => {
456
- const resolvedPos = doc.resolve(pos);
457
- const { depth } = resolvedPos;
458
- if (depth === 0) {
459
- return pos;
460
- }
461
- const a = resolvedPos.pos - resolvedPos.parentOffset;
462
- return a - 1;
463
- };
464
- var getOuterNode = (doc, pos) => {
465
- const node = doc.nodeAt(pos);
466
- const resolvedPos = doc.resolve(pos);
467
- let { depth } = resolvedPos;
468
- let parent = node;
469
- while (depth > 0) {
470
- const currentNode = resolvedPos.node(depth);
471
- depth -= 1;
472
- if (depth === 0) {
473
- parent = currentNode;
474
- }
475
- }
476
- return parent;
477
- };
478
-
479
- // src/drag-handle-plugin.ts
480
- var getRelativePos = (state, absolutePos) => {
481
- const ystate = ySyncPluginKey.getState(state);
482
- if (!ystate) {
483
- return null;
484
- }
485
- return absolutePositionToRelativePosition(absolutePos, ystate.type, ystate.binding.mapping);
486
- };
487
- var getAbsolutePos = (state, relativePos) => {
488
- const ystate = ySyncPluginKey.getState(state);
489
- if (!ystate) {
490
- return -1;
491
- }
492
- return relativePositionToAbsolutePosition(ystate.doc, ystate.type, relativePos, ystate.binding.mapping) || 0;
493
- };
494
- var getOuterDomNode = (view, domNode) => {
495
- let tmpDomNode = domNode;
496
- while (tmpDomNode == null ? void 0 : tmpDomNode.parentNode) {
497
- if (tmpDomNode.parentNode === view.dom) {
498
- break;
499
- }
500
- tmpDomNode = tmpDomNode.parentNode;
501
- }
502
- return tmpDomNode;
503
- };
504
- var dragHandlePluginDefaultKey = new PluginKey("dragHandle");
505
- var DragHandlePlugin = ({
506
- pluginKey = dragHandlePluginDefaultKey,
507
- element,
508
- editor,
509
- computePositionConfig,
510
- getReferencedVirtualElement,
511
- onNodeChange,
512
- onElementDragStart,
513
- onElementDragEnd,
514
- nestedOptions
515
- }) => {
516
- const wrapper = document.createElement("div");
517
- let locked = false;
518
- let currentNode = null;
519
- let currentNodePos = -1;
520
- let currentNodeRelPos;
521
- let rafId = null;
522
- let pendingMouseCoords = null;
523
- function hideHandle() {
524
- if (!element) {
525
- return;
526
- }
527
- element.style.visibility = "hidden";
528
- element.style.pointerEvents = "none";
529
- }
530
- function showHandle() {
531
- if (!element) {
532
- return;
533
- }
534
- if (!editor.isEditable) {
535
- hideHandle();
536
- return;
537
- }
538
- element.style.visibility = "";
539
- element.style.pointerEvents = "auto";
540
- }
541
- function repositionDragHandle(dom) {
542
- const virtualElement = (getReferencedVirtualElement == null ? void 0 : getReferencedVirtualElement()) || {
543
- getBoundingClientRect: () => dom.getBoundingClientRect()
544
- };
545
- computePosition(virtualElement, element, computePositionConfig).then((val) => {
546
- Object.assign(element.style, {
547
- position: val.strategy,
548
- left: `${val.x}px`,
549
- top: `${val.y}px`
550
- });
551
- });
552
- }
553
- function onDragStart(e) {
554
- onElementDragStart == null ? void 0 : onElementDragStart(e);
555
- dragHandler(e, editor, nestedOptions, { node: currentNode, pos: currentNodePos });
556
- if (element) {
557
- element.dataset.dragging = "true";
558
- }
559
- setTimeout(() => {
560
- if (element) {
561
- element.style.pointerEvents = "none";
562
- }
563
- }, 0);
564
- }
565
- function onDragEnd(e) {
566
- onElementDragEnd == null ? void 0 : onElementDragEnd(e);
567
- hideHandle();
568
- if (element) {
569
- element.style.pointerEvents = "auto";
570
- element.dataset.dragging = "false";
571
- }
572
- }
573
- function onDrop() {
574
- if (isFirefox()) {
575
- const editorElement = editor.view.dom;
576
- requestAnimationFrame(() => {
577
- if (editorElement.isContentEditable) {
578
- editorElement.contentEditable = "false";
579
- editorElement.contentEditable = "true";
580
- }
581
- });
582
- }
583
- }
584
- wrapper.appendChild(element);
585
- return {
586
- unbind() {
587
- element.removeEventListener("dragstart", onDragStart);
588
- element.removeEventListener("dragend", onDragEnd);
589
- document.removeEventListener("drop", onDrop);
590
- if (rafId) {
591
- cancelAnimationFrame(rafId);
592
- rafId = null;
593
- pendingMouseCoords = null;
594
- }
595
- },
596
- plugin: new Plugin({
597
- key: typeof pluginKey === "string" ? new PluginKey(pluginKey) : pluginKey,
598
- state: {
599
- init() {
600
- return { locked: false };
601
- },
602
- apply(tr, value, _oldState, state) {
603
- const isLocked = tr.getMeta("lockDragHandle");
604
- const hideDragHandle = tr.getMeta("hideDragHandle");
605
- if (isLocked !== void 0) {
606
- locked = isLocked;
607
- }
608
- if (hideDragHandle) {
609
- hideHandle();
610
- locked = false;
611
- currentNode = null;
612
- currentNodePos = -1;
613
- onNodeChange == null ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
614
- return value;
615
- }
616
- if (tr.docChanged && currentNodePos !== -1 && element) {
617
- if (isChangeOrigin(tr)) {
618
- const newPos = getAbsolutePos(state, currentNodeRelPos);
619
- if (newPos !== currentNodePos) {
620
- currentNodePos = newPos;
621
- }
622
- } else {
623
- const newPos = tr.mapping.map(currentNodePos);
624
- if (newPos !== currentNodePos) {
625
- currentNodePos = newPos;
626
- currentNodeRelPos = getRelativePos(state, currentNodePos);
627
- }
628
- }
629
- }
630
- return value;
631
- }
632
- },
633
- view: (view) => {
634
- var _a;
635
- element.draggable = true;
636
- element.style.pointerEvents = "auto";
637
- element.dataset.dragging = "false";
638
- (_a = editor.view.dom.parentElement) == null ? void 0 : _a.appendChild(wrapper);
639
- wrapper.style.pointerEvents = "none";
640
- wrapper.style.position = "absolute";
641
- wrapper.style.top = "0";
642
- wrapper.style.left = "0";
643
- element.addEventListener("dragstart", onDragStart);
644
- element.addEventListener("dragend", onDragEnd);
645
- document.addEventListener("drop", onDrop);
646
- return {
647
- update(_, oldState) {
648
- if (!element) {
649
- return;
650
- }
651
- if (!editor.isEditable) {
652
- hideHandle();
653
- return;
654
- }
655
- if (locked) {
656
- element.draggable = false;
657
- } else {
658
- element.draggable = true;
659
- }
660
- if (view.state.doc.eq(oldState.doc) || currentNodePos === -1) {
661
- return;
662
- }
663
- let domNode = view.nodeDOM(currentNodePos);
664
- domNode = getOuterDomNode(view, domNode);
665
- if (domNode === view.dom) {
666
- return;
667
- }
668
- if ((domNode == null ? void 0 : domNode.nodeType) !== 1) {
669
- return;
670
- }
671
- const domNodePos = view.posAtDOM(domNode, 0);
672
- const outerNode = getOuterNode(editor.state.doc, domNodePos);
673
- const outerNodePos = getOuterNodePos(editor.state.doc, domNodePos);
674
- currentNode = outerNode;
675
- currentNodePos = outerNodePos;
676
- currentNodeRelPos = getRelativePos(view.state, currentNodePos);
677
- onNodeChange == null ? void 0 : onNodeChange({ editor, node: currentNode, pos: currentNodePos });
678
- repositionDragHandle(domNode);
679
- },
680
- // TODO: Kills even on hot reload
681
- destroy() {
682
- element.removeEventListener("dragstart", onDragStart);
683
- element.removeEventListener("dragend", onDragEnd);
684
- document.removeEventListener("drop", onDrop);
685
- if (rafId) {
686
- cancelAnimationFrame(rafId);
687
- rafId = null;
688
- pendingMouseCoords = null;
689
- }
690
- if (element) {
691
- removeNode(wrapper);
692
- }
693
- }
694
- };
695
- },
696
- props: {
697
- handleDOMEvents: {
698
- keydown(view) {
699
- if (!element || locked) {
700
- return false;
701
- }
702
- if (view.hasFocus()) {
703
- hideHandle();
704
- currentNode = null;
705
- currentNodePos = -1;
706
- onNodeChange == null ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
707
- return false;
708
- }
709
- return false;
710
- },
711
- mouseleave(_view, e) {
712
- if (locked) {
713
- return false;
714
- }
715
- if (e.target && !wrapper.contains(e.relatedTarget)) {
716
- hideHandle();
717
- currentNode = null;
718
- currentNodePos = -1;
719
- onNodeChange == null ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
720
- }
721
- return false;
722
- },
723
- mousemove(view, e) {
724
- if (!element || locked) {
725
- return false;
726
- }
727
- pendingMouseCoords = { x: e.clientX, y: e.clientY };
728
- if (rafId) {
729
- return false;
730
- }
731
- rafId = requestAnimationFrame(() => {
732
- rafId = null;
733
- if (!pendingMouseCoords) {
734
- return;
735
- }
736
- const { x, y } = pendingMouseCoords;
737
- pendingMouseCoords = null;
738
- const nodeData = findElementNextToCoords({
739
- x,
740
- y,
741
- direction: "right",
742
- editor,
743
- nestedOptions
744
- });
745
- if (!nodeData.resultElement) {
746
- return;
747
- }
748
- let domNode = nodeData.resultElement;
749
- let targetNode = nodeData.resultNode;
750
- let targetPos = nodeData.pos;
751
- if (!(nestedOptions == null ? void 0 : nestedOptions.enabled)) {
752
- domNode = getOuterDomNode(view, domNode);
753
- if (domNode === view.dom) {
754
- return;
755
- }
756
- if ((domNode == null ? void 0 : domNode.nodeType) !== 1) {
757
- return;
758
- }
759
- const domNodePos = view.posAtDOM(domNode, 0);
760
- targetNode = getOuterNode(editor.state.doc, domNodePos);
761
- targetPos = getOuterNodePos(editor.state.doc, domNodePos);
762
- }
763
- if (targetNode !== currentNode) {
764
- currentNode = targetNode;
765
- currentNodePos = targetPos != null ? targetPos : -1;
766
- currentNodeRelPos = getRelativePos(view.state, currentNodePos);
767
- onNodeChange == null ? void 0 : onNodeChange({ editor, node: currentNode, pos: currentNodePos });
768
- repositionDragHandle(domNode);
769
- showHandle();
770
- }
771
- });
772
- return false;
773
- }
774
- }
775
- }
776
- })
777
- };
778
- };
779
-
780
- // src/helpers/normalizeOptions.ts
781
- function normalizeNestedOptions(input) {
782
- var _a, _b;
783
- if (input === false || input === void 0) {
784
- return {
785
- enabled: false,
786
- rules: [],
787
- defaultRules: true,
788
- allowedContainers: void 0,
789
- edgeDetection: normalizeEdgeDetection("none")
790
- };
791
- }
792
- if (input === true) {
793
- return {
794
- enabled: true,
795
- rules: [],
796
- defaultRules: true,
797
- allowedContainers: void 0,
798
- edgeDetection: normalizeEdgeDetection("left")
799
- };
800
- }
801
- return {
802
- enabled: true,
803
- rules: (_a = input.rules) != null ? _a : [],
804
- defaultRules: (_b = input.defaultRules) != null ? _b : true,
805
- allowedContainers: input.allowedContainers,
806
- edgeDetection: normalizeEdgeDetection(input.edgeDetection)
807
- };
808
- }
809
-
810
- // src/drag-handle.ts
811
- var defaultComputePositionConfig = {
812
- placement: "left-start",
813
- strategy: "absolute"
814
- };
815
- var DragHandle = Extension.create({
816
- name: "dragHandle",
817
- addOptions() {
818
- return {
819
- render() {
820
- const element = document.createElement("div");
821
- element.classList.add("drag-handle");
822
- return element;
823
- },
824
- computePositionConfig: {},
825
- locked: false,
826
- onNodeChange: () => {
827
- return null;
828
- },
829
- onElementDragStart: void 0,
830
- onElementDragEnd: void 0,
831
- nested: false
832
- };
833
- },
834
- addCommands() {
835
- return {
836
- lockDragHandle: () => ({ editor }) => {
837
- this.options.locked = true;
838
- return editor.commands.setMeta("lockDragHandle", this.options.locked);
839
- },
840
- unlockDragHandle: () => ({ editor }) => {
841
- this.options.locked = false;
842
- return editor.commands.setMeta("lockDragHandle", this.options.locked);
843
- },
844
- toggleDragHandle: () => ({ editor }) => {
845
- this.options.locked = !this.options.locked;
846
- return editor.commands.setMeta("lockDragHandle", this.options.locked);
847
- }
848
- };
849
- },
850
- addProseMirrorPlugins() {
851
- const element = this.options.render();
852
- const nestedOptions = normalizeNestedOptions(this.options.nested);
853
- return [
854
- DragHandlePlugin({
855
- computePositionConfig: { ...defaultComputePositionConfig, ...this.options.computePositionConfig },
856
- getReferencedVirtualElement: this.options.getReferencedVirtualElement,
857
- element,
858
- editor: this.editor,
859
- onNodeChange: this.options.onNodeChange,
860
- onElementDragStart: this.options.onElementDragStart,
861
- onElementDragEnd: this.options.onElementDragEnd,
862
- nestedOptions
863
- }).plugin
864
- ];
865
- }
866
- });
867
-
868
- // src/index.ts
869
- var index_default = DragHandle;
870
- export {
871
- DragHandle,
872
- DragHandlePlugin,
873
- index_default as default,
874
- defaultComputePositionConfig,
875
- defaultRules,
876
- dragHandlePluginDefaultKey,
877
- normalizeNestedOptions
878
- };
879
- //# sourceMappingURL=index.js.map