@blockslides/extension-drag-handle 0.1.0

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/LICENSE.md ADDED
@@ -0,0 +1,36 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 BlockSlides
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---
24
+
25
+ ## Acknowledgments
26
+
27
+ This project includes code and patterns adapted from [Tiptap](https://tiptap.dev),
28
+ an open-source headless editor framework for web artisans.
29
+
30
+ **Tiptap License:**
31
+
32
+ - Copyright (c) 2025, Tiptap GmbH
33
+ - Licensed under MIT License
34
+ - Original source: https://github.com/ueberdosis/tiptap
35
+
36
+ See `_tiptap/LICENSE.md` for the full Tiptap license.
package/dist/index.cjs ADDED
@@ -0,0 +1,572 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ DragHandle: () => DragHandle,
24
+ DragHandlePlugin: () => DragHandlePlugin,
25
+ default: () => index_default,
26
+ defaultComputePositionConfig: () => defaultComputePositionConfig,
27
+ dragHandlePluginDefaultKey: () => dragHandlePluginDefaultKey
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+
31
+ // src/drag-handle.ts
32
+ var import_core = require("@blockslides/core");
33
+
34
+ // src/drag-handle-plugin.ts
35
+ var import_dom = require("@floating-ui/dom");
36
+ var import_state = require("@blockslides/pm/state");
37
+
38
+ // src/helpers/dragHandler.ts
39
+ var import_extension_node_range = require("@blockslides/extension-node-range");
40
+
41
+ // src/helpers/cloneElement.ts
42
+ function getCSSText(element) {
43
+ let value = "";
44
+ const style = getComputedStyle(element);
45
+ for (let i = 0; i < style.length; i += 1) {
46
+ value += `${style[i]}:${style.getPropertyValue(style[i])};`;
47
+ }
48
+ return value;
49
+ }
50
+ function cloneElement(node) {
51
+ const clonedNode = node.cloneNode(true);
52
+ const sourceElements = [node, ...Array.from(node.getElementsByTagName("*"))];
53
+ const targetElements = [clonedNode, ...Array.from(clonedNode.getElementsByTagName("*"))];
54
+ sourceElements.forEach((sourceElement, index) => {
55
+ targetElements[index].style.cssText = getCSSText(sourceElement);
56
+ });
57
+ return clonedNode;
58
+ }
59
+
60
+ // src/helpers/findNextElementFromCursor.ts
61
+ function findClosestTopLevelBlock(element, view) {
62
+ let current = element;
63
+ while ((current == null ? void 0 : current.parentElement) && current.parentElement !== view.dom) {
64
+ current = current.parentElement;
65
+ }
66
+ return (current == null ? void 0 : current.parentElement) === view.dom ? current : void 0;
67
+ }
68
+ function clampToContent(view, x, y, inset = 5) {
69
+ const container = view.dom;
70
+ const firstBlock = container.firstElementChild;
71
+ const lastBlock = container.lastElementChild;
72
+ if (!firstBlock || !lastBlock) {
73
+ return { x, y };
74
+ }
75
+ const topRect = firstBlock.getBoundingClientRect();
76
+ const botRect = lastBlock.getBoundingClientRect();
77
+ const clampedY = Math.min(Math.max(topRect.top + inset, y), botRect.bottom - inset);
78
+ const epsilon = 0.5;
79
+ const sameLeft = Math.abs(topRect.left - botRect.left) < epsilon;
80
+ const sameRight = Math.abs(topRect.right - botRect.right) < epsilon;
81
+ let rowRect = topRect;
82
+ if (sameLeft && sameRight) {
83
+ rowRect = topRect;
84
+ } else {
85
+ }
86
+ const clampedX = Math.min(Math.max(rowRect.left + inset, x), rowRect.right - inset);
87
+ return { x: clampedX, y: clampedY };
88
+ }
89
+ var findElementNextToCoords = (options) => {
90
+ const { x, y, editor } = options;
91
+ const { view, state } = editor;
92
+ const { x: clampedX, y: clampedY } = clampToContent(view, x, y, 5);
93
+ const elements = view.root.elementsFromPoint(clampedX, clampedY);
94
+ let block;
95
+ Array.prototype.some.call(elements, (el) => {
96
+ if (!view.dom.contains(el)) {
97
+ return false;
98
+ }
99
+ const candidate = findClosestTopLevelBlock(el, view);
100
+ if (candidate) {
101
+ block = candidate;
102
+ return true;
103
+ }
104
+ return false;
105
+ });
106
+ if (!block) {
107
+ return { resultElement: null, resultNode: null, pos: null };
108
+ }
109
+ let pos;
110
+ try {
111
+ pos = view.posAtDOM(block, 0);
112
+ } catch {
113
+ return { resultElement: null, resultNode: null, pos: null };
114
+ }
115
+ const node = state.doc.nodeAt(pos);
116
+ if (!node) {
117
+ const resolvedPos = state.doc.resolve(pos);
118
+ const parent = resolvedPos.parent;
119
+ return {
120
+ resultElement: block,
121
+ resultNode: parent,
122
+ pos: resolvedPos.start()
123
+ };
124
+ }
125
+ return {
126
+ resultElement: block,
127
+ resultNode: node,
128
+ pos
129
+ };
130
+ };
131
+
132
+ // src/helpers/getComputedStyle.ts
133
+ function getComputedStyle2(node, property) {
134
+ const style = window.getComputedStyle(node);
135
+ return style[property];
136
+ }
137
+
138
+ // src/helpers/minMax.ts
139
+ function minMax(value = 0, min = 0, max = 0) {
140
+ return Math.min(Math.max(value, min), max);
141
+ }
142
+
143
+ // src/helpers/getInnerCoords.ts
144
+ function getInnerCoords(view, x, y) {
145
+ const paddingLeft = parseInt(getComputedStyle2(view.dom, "paddingLeft"), 10);
146
+ const paddingRight = parseInt(getComputedStyle2(view.dom, "paddingRight"), 10);
147
+ const borderLeft = parseInt(getComputedStyle2(view.dom, "borderLeftWidth"), 10);
148
+ const borderRight = parseInt(getComputedStyle2(view.dom, "borderLeftWidth"), 10);
149
+ const bounds = view.dom.getBoundingClientRect();
150
+ const coords = {
151
+ left: minMax(x, bounds.left + paddingLeft + borderLeft, bounds.right - paddingRight - borderRight),
152
+ top: y
153
+ };
154
+ return coords;
155
+ }
156
+
157
+ // src/helpers/removeNode.ts
158
+ function removeNode(node) {
159
+ var _a;
160
+ (_a = node.parentNode) == null ? void 0 : _a.removeChild(node);
161
+ }
162
+
163
+ // src/helpers/dragHandler.ts
164
+ function getDragHandleRanges(event, editor) {
165
+ const { doc } = editor.view.state;
166
+ const result = findElementNextToCoords({
167
+ editor,
168
+ x: event.clientX,
169
+ y: event.clientY,
170
+ direction: "right"
171
+ });
172
+ if (!result.resultNode || result.pos === null) {
173
+ return [];
174
+ }
175
+ const x = event.clientX;
176
+ const coords = getInnerCoords(editor.view, x, event.clientY);
177
+ const posAtCoords = editor.view.posAtCoords(coords);
178
+ if (!posAtCoords) {
179
+ return [];
180
+ }
181
+ const { pos } = posAtCoords;
182
+ const nodeAt = doc.resolve(pos).parent;
183
+ if (!nodeAt) {
184
+ return [];
185
+ }
186
+ const $from = doc.resolve(result.pos);
187
+ const $to = doc.resolve(result.pos + 1);
188
+ return (0, import_extension_node_range.getSelectionRanges)($from, $to, 0);
189
+ }
190
+ function dragHandler(event, editor) {
191
+ const { view } = editor;
192
+ if (!event.dataTransfer) {
193
+ return;
194
+ }
195
+ const { empty, $from, $to } = view.state.selection;
196
+ const dragHandleRanges = getDragHandleRanges(event, editor);
197
+ const selectionRanges = (0, import_extension_node_range.getSelectionRanges)($from, $to, 0);
198
+ const isDragHandleWithinSelection = selectionRanges.some((range) => {
199
+ return dragHandleRanges.find((dragHandleRange) => {
200
+ return dragHandleRange.$from === range.$from && dragHandleRange.$to === range.$to;
201
+ });
202
+ });
203
+ const ranges = empty || !isDragHandleWithinSelection ? dragHandleRanges : selectionRanges;
204
+ if (!ranges.length) {
205
+ return;
206
+ }
207
+ const { tr } = view.state;
208
+ const wrapper = document.createElement("div");
209
+ const from = ranges[0].$from.pos;
210
+ const to = ranges[ranges.length - 1].$to.pos;
211
+ const selection = import_extension_node_range.NodeRangeSelection.create(view.state.doc, from, to);
212
+ const slice = selection.content();
213
+ ranges.forEach((range) => {
214
+ const element = view.nodeDOM(range.$from.pos);
215
+ const clonedElement = cloneElement(element);
216
+ wrapper.append(clonedElement);
217
+ });
218
+ wrapper.style.position = "absolute";
219
+ wrapper.style.top = "-10000px";
220
+ document.body.append(wrapper);
221
+ event.dataTransfer.clearData();
222
+ event.dataTransfer.setDragImage(wrapper, 0, 0);
223
+ view.dragging = { slice, move: true };
224
+ tr.setSelection(selection);
225
+ view.dispatch(tr);
226
+ document.addEventListener("drop", () => removeNode(wrapper), { once: true });
227
+ }
228
+
229
+ // src/helpers/getOuterNode.ts
230
+ var getOuterNodePos = (doc, pos) => {
231
+ const resolvedPos = doc.resolve(pos);
232
+ const { depth } = resolvedPos;
233
+ if (depth === 0) {
234
+ return pos;
235
+ }
236
+ const a = resolvedPos.pos - resolvedPos.parentOffset;
237
+ return a - 1;
238
+ };
239
+ var getOuterNode = (doc, pos) => {
240
+ const node = doc.nodeAt(pos);
241
+ const resolvedPos = doc.resolve(pos);
242
+ let { depth } = resolvedPos;
243
+ let parent = node;
244
+ while (depth > 0) {
245
+ const currentNode = resolvedPos.node(depth);
246
+ depth -= 1;
247
+ if (depth === 0) {
248
+ parent = currentNode;
249
+ }
250
+ }
251
+ return parent;
252
+ };
253
+
254
+ // src/drag-handle-plugin.ts
255
+ var getOuterDomNode = (view, domNode) => {
256
+ let tmpDomNode = domNode;
257
+ while (tmpDomNode == null ? void 0 : tmpDomNode.parentNode) {
258
+ if (tmpDomNode.parentNode === view.dom) {
259
+ break;
260
+ }
261
+ tmpDomNode = tmpDomNode.parentNode;
262
+ }
263
+ return tmpDomNode;
264
+ };
265
+ var dragHandlePluginDefaultKey = new import_state.PluginKey("dragHandle");
266
+ var DragHandlePlugin = ({
267
+ pluginKey = dragHandlePluginDefaultKey,
268
+ element,
269
+ editor,
270
+ computePositionConfig,
271
+ getReferencedVirtualElement,
272
+ onNodeChange,
273
+ onElementDragStart,
274
+ onElementDragEnd
275
+ }) => {
276
+ const wrapper = document.createElement("div");
277
+ let locked = false;
278
+ let currentNode = null;
279
+ let currentNodePos = -1;
280
+ let rafId = null;
281
+ let pendingMouseCoords = null;
282
+ function hideHandle() {
283
+ if (!element) {
284
+ return;
285
+ }
286
+ element.style.visibility = "hidden";
287
+ element.style.pointerEvents = "none";
288
+ }
289
+ function showHandle() {
290
+ if (!element) {
291
+ return;
292
+ }
293
+ if (!editor.isEditable) {
294
+ hideHandle();
295
+ return;
296
+ }
297
+ element.style.visibility = "";
298
+ element.style.pointerEvents = "auto";
299
+ }
300
+ function repositionDragHandle(dom) {
301
+ const virtualElement = (getReferencedVirtualElement == null ? void 0 : getReferencedVirtualElement()) || {
302
+ getBoundingClientRect: () => dom.getBoundingClientRect()
303
+ };
304
+ (0, import_dom.computePosition)(virtualElement, element, computePositionConfig).then((val) => {
305
+ Object.assign(element.style, {
306
+ position: val.strategy,
307
+ left: `${val.x}px`,
308
+ top: `${val.y}px`
309
+ });
310
+ });
311
+ }
312
+ function onDragStart(e) {
313
+ onElementDragStart == null ? void 0 : onElementDragStart(e);
314
+ dragHandler(e, editor);
315
+ if (element) {
316
+ element.dataset.dragging = "true";
317
+ }
318
+ setTimeout(() => {
319
+ if (element) {
320
+ element.style.pointerEvents = "none";
321
+ }
322
+ }, 0);
323
+ }
324
+ function onDragEnd(e) {
325
+ onElementDragEnd == null ? void 0 : onElementDragEnd(e);
326
+ hideHandle();
327
+ if (element) {
328
+ element.style.pointerEvents = "auto";
329
+ element.dataset.dragging = "false";
330
+ }
331
+ }
332
+ element.addEventListener("dragstart", onDragStart);
333
+ element.addEventListener("dragend", onDragEnd);
334
+ wrapper.appendChild(element);
335
+ return {
336
+ unbind() {
337
+ element.removeEventListener("dragstart", onDragStart);
338
+ element.removeEventListener("dragend", onDragEnd);
339
+ if (rafId) {
340
+ cancelAnimationFrame(rafId);
341
+ rafId = null;
342
+ pendingMouseCoords = null;
343
+ }
344
+ },
345
+ plugin: new import_state.Plugin({
346
+ key: typeof pluginKey === "string" ? new import_state.PluginKey(pluginKey) : pluginKey,
347
+ state: {
348
+ init() {
349
+ return { locked: false };
350
+ },
351
+ apply(tr, value, _oldState, state) {
352
+ const isLocked = tr.getMeta("lockDragHandle");
353
+ const hideDragHandle = tr.getMeta("hideDragHandle");
354
+ if (isLocked !== void 0) {
355
+ locked = isLocked;
356
+ }
357
+ if (hideDragHandle) {
358
+ hideHandle();
359
+ locked = false;
360
+ currentNode = null;
361
+ currentNodePos = -1;
362
+ onNodeChange == null ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
363
+ return value;
364
+ }
365
+ if (tr.docChanged && currentNodePos !== -1 && element) {
366
+ const newPos = tr.mapping.map(currentNodePos);
367
+ if (newPos !== currentNodePos) {
368
+ currentNodePos = newPos;
369
+ }
370
+ }
371
+ return value;
372
+ }
373
+ },
374
+ view: (view) => {
375
+ var _a;
376
+ element.draggable = true;
377
+ element.style.pointerEvents = "auto";
378
+ element.dataset.dragging = "false";
379
+ (_a = editor.view.dom.parentElement) == null ? void 0 : _a.appendChild(wrapper);
380
+ wrapper.style.pointerEvents = "none";
381
+ wrapper.style.position = "absolute";
382
+ wrapper.style.top = "0";
383
+ wrapper.style.left = "0";
384
+ return {
385
+ update(_, oldState) {
386
+ if (!element) {
387
+ return;
388
+ }
389
+ if (!editor.isEditable) {
390
+ hideHandle();
391
+ return;
392
+ }
393
+ if (locked) {
394
+ element.draggable = false;
395
+ } else {
396
+ element.draggable = true;
397
+ }
398
+ if (view.state.doc.eq(oldState.doc) || currentNodePos === -1) {
399
+ return;
400
+ }
401
+ let domNode = view.nodeDOM(currentNodePos);
402
+ domNode = getOuterDomNode(view, domNode);
403
+ if (domNode === view.dom) {
404
+ return;
405
+ }
406
+ if ((domNode == null ? void 0 : domNode.nodeType) !== 1) {
407
+ return;
408
+ }
409
+ const domNodePos = view.posAtDOM(domNode, 0);
410
+ const outerNode = getOuterNode(editor.state.doc, domNodePos);
411
+ const outerNodePos = getOuterNodePos(editor.state.doc, domNodePos);
412
+ currentNode = outerNode;
413
+ currentNodePos = outerNodePos;
414
+ onNodeChange == null ? void 0 : onNodeChange({ editor, node: currentNode, pos: currentNodePos });
415
+ repositionDragHandle(domNode);
416
+ },
417
+ // TODO: Kills even on hot reload
418
+ destroy() {
419
+ if (rafId) {
420
+ cancelAnimationFrame(rafId);
421
+ rafId = null;
422
+ pendingMouseCoords = null;
423
+ }
424
+ if (element) {
425
+ removeNode(wrapper);
426
+ }
427
+ }
428
+ };
429
+ },
430
+ props: {
431
+ handleDOMEvents: {
432
+ keydown(view) {
433
+ if (!element || locked) {
434
+ return false;
435
+ }
436
+ if (view.hasFocus()) {
437
+ hideHandle();
438
+ currentNode = null;
439
+ currentNodePos = -1;
440
+ onNodeChange == null ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
441
+ return false;
442
+ }
443
+ return false;
444
+ },
445
+ mouseleave(_view, e) {
446
+ if (locked) {
447
+ return false;
448
+ }
449
+ if (e.target && !wrapper.contains(e.relatedTarget)) {
450
+ hideHandle();
451
+ currentNode = null;
452
+ currentNodePos = -1;
453
+ onNodeChange == null ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
454
+ }
455
+ return false;
456
+ },
457
+ mousemove(view, e) {
458
+ if (!element || locked) {
459
+ return false;
460
+ }
461
+ pendingMouseCoords = { x: e.clientX, y: e.clientY };
462
+ if (rafId) {
463
+ return false;
464
+ }
465
+ rafId = requestAnimationFrame(() => {
466
+ rafId = null;
467
+ if (!pendingMouseCoords) {
468
+ return;
469
+ }
470
+ const { x, y } = pendingMouseCoords;
471
+ pendingMouseCoords = null;
472
+ const nodeData = findElementNextToCoords({
473
+ x,
474
+ y,
475
+ direction: "right",
476
+ editor
477
+ });
478
+ if (!nodeData.resultElement) {
479
+ return;
480
+ }
481
+ let domNode = nodeData.resultElement;
482
+ domNode = getOuterDomNode(view, domNode);
483
+ if (domNode === view.dom) {
484
+ return;
485
+ }
486
+ if ((domNode == null ? void 0 : domNode.nodeType) !== 1) {
487
+ return;
488
+ }
489
+ const domNodePos = view.posAtDOM(domNode, 0);
490
+ const outerNode = getOuterNode(editor.state.doc, domNodePos);
491
+ if (outerNode !== currentNode) {
492
+ const outerNodePos = getOuterNodePos(editor.state.doc, domNodePos);
493
+ currentNode = outerNode;
494
+ currentNodePos = outerNodePos;
495
+ onNodeChange == null ? void 0 : onNodeChange({ editor, node: currentNode, pos: currentNodePos });
496
+ repositionDragHandle(domNode);
497
+ showHandle();
498
+ }
499
+ });
500
+ return false;
501
+ }
502
+ }
503
+ }
504
+ })
505
+ };
506
+ };
507
+
508
+ // src/drag-handle.ts
509
+ var defaultComputePositionConfig = {
510
+ placement: "left-start",
511
+ strategy: "absolute"
512
+ };
513
+ var DragHandle = import_core.Extension.create({
514
+ name: "dragHandle",
515
+ addOptions() {
516
+ return {
517
+ render() {
518
+ const element = document.createElement("div");
519
+ element.classList.add("drag-handle");
520
+ return element;
521
+ },
522
+ computePositionConfig: {},
523
+ locked: false,
524
+ onNodeChange: () => {
525
+ return null;
526
+ },
527
+ onElementDragStart: void 0,
528
+ onElementDragEnd: void 0
529
+ };
530
+ },
531
+ addCommands() {
532
+ return {
533
+ lockDragHandle: () => ({ editor }) => {
534
+ this.options.locked = true;
535
+ return editor.commands.setMeta("lockDragHandle", this.options.locked);
536
+ },
537
+ unlockDragHandle: () => ({ editor }) => {
538
+ this.options.locked = false;
539
+ return editor.commands.setMeta("lockDragHandle", this.options.locked);
540
+ },
541
+ toggleDragHandle: () => ({ editor }) => {
542
+ this.options.locked = !this.options.locked;
543
+ return editor.commands.setMeta("lockDragHandle", this.options.locked);
544
+ }
545
+ };
546
+ },
547
+ addProseMirrorPlugins() {
548
+ const element = this.options.render();
549
+ return [
550
+ DragHandlePlugin({
551
+ computePositionConfig: { ...defaultComputePositionConfig, ...this.options.computePositionConfig },
552
+ getReferencedVirtualElement: this.options.getReferencedVirtualElement,
553
+ element,
554
+ editor: this.editor,
555
+ onNodeChange: this.options.onNodeChange,
556
+ onElementDragStart: this.options.onElementDragStart,
557
+ onElementDragEnd: this.options.onElementDragEnd
558
+ }).plugin
559
+ ];
560
+ }
561
+ });
562
+
563
+ // src/index.ts
564
+ var index_default = DragHandle;
565
+ // Annotate the CommonJS export names for ESM import in node:
566
+ 0 && (module.exports = {
567
+ DragHandle,
568
+ DragHandlePlugin,
569
+ defaultComputePositionConfig,
570
+ dragHandlePluginDefaultKey
571
+ });
572
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/drag-handle.ts","../src/drag-handle-plugin.ts","../src/helpers/dragHandler.ts","../src/helpers/cloneElement.ts","../src/helpers/findNextElementFromCursor.ts","../src/helpers/getComputedStyle.ts","../src/helpers/minMax.ts","../src/helpers/getInnerCoords.ts","../src/helpers/removeNode.ts","../src/helpers/getOuterNode.ts"],"sourcesContent":["import { DragHandle } from './drag-handle.js'\n\nexport * from './drag-handle.js'\nexport * from './drag-handle-plugin.js'\n\nexport default DragHandle\n","import type { ComputePositionConfig, VirtualElement } from '@floating-ui/dom'\nimport type { Editor } from '@blockslides/core'\nimport type { Node } from '@blockslides/pm/model'\nimport { Extension } from '@blockslides/core'\n\nimport { DragHandlePlugin } from './drag-handle-plugin.js'\n\nexport const defaultComputePositionConfig: ComputePositionConfig = {\n placement: 'left-start',\n strategy: 'absolute',\n}\n\nexport interface DragHandleOptions {\n /**\n * Renders an element that is positioned with the floating-ui/dom package\n */\n render(): HTMLElement\n /**\n * Configuration for position computation of the drag handle\n * using the floating-ui/dom package\n */\n computePositionConfig?: ComputePositionConfig\n /**\n * A function that returns the virtual element for the drag handle.\n * This is useful when the menu needs to be positioned relative to a specific DOM element.\n */\n getReferencedVirtualElement?: () => VirtualElement | null\n /**\n * Locks the draghandle in place and visibility\n */\n locked?: boolean\n /**\n * Returns a node or null when a node is hovered over\n */\n onNodeChange?: (options: { node: Node | null; editor: Editor }) => void\n /**\n * The callback function that will be called when drag start.\n */\n onElementDragStart?: (e: DragEvent) => void\n /**\n * The callback function that will be called when drag end.\n */\n onElementDragEnd?: (e: DragEvent) => void\n}\n\ndeclare module '@blockslides/core' {\n interface Commands<ReturnType> {\n dragHandle: {\n /**\n * Locks the draghandle in place and visibility\n */\n lockDragHandle: () => ReturnType\n /**\n * Unlocks the draghandle\n */\n unlockDragHandle: () => ReturnType\n /**\n * Toggle draghandle lock state\n */\n toggleDragHandle: () => ReturnType\n }\n }\n}\n\nexport const DragHandle = Extension.create<DragHandleOptions>({\n name: 'dragHandle',\n\n addOptions() {\n return {\n render() {\n const element = document.createElement('div')\n\n element.classList.add('drag-handle')\n\n return element\n },\n computePositionConfig: {},\n locked: false,\n onNodeChange: () => {\n return null\n },\n onElementDragStart: undefined,\n onElementDragEnd: undefined,\n }\n },\n\n addCommands() {\n return {\n lockDragHandle:\n () =>\n ({ editor }) => {\n this.options.locked = true\n return editor.commands.setMeta('lockDragHandle', this.options.locked)\n },\n unlockDragHandle:\n () =>\n ({ editor }) => {\n this.options.locked = false\n return editor.commands.setMeta('lockDragHandle', this.options.locked)\n },\n toggleDragHandle:\n () =>\n ({ editor }) => {\n this.options.locked = !this.options.locked\n return editor.commands.setMeta('lockDragHandle', this.options.locked)\n },\n }\n },\n\n addProseMirrorPlugins() {\n const element = this.options.render()\n\n return [\n DragHandlePlugin({\n computePositionConfig: { ...defaultComputePositionConfig, ...this.options.computePositionConfig },\n getReferencedVirtualElement: this.options.getReferencedVirtualElement,\n element,\n editor: this.editor,\n onNodeChange: this.options.onNodeChange,\n onElementDragStart: this.options.onElementDragStart,\n onElementDragEnd: this.options.onElementDragEnd,\n }).plugin,\n ]\n },\n})\n","import { type ComputePositionConfig, type VirtualElement, computePosition } from '@floating-ui/dom'\nimport type { Editor } from '@blockslides/core'\nimport type { Node } from '@blockslides/pm/model'\nimport { type EditorState, type Transaction, Plugin, PluginKey } from '@blockslides/pm/state'\nimport type { EditorView } from '@blockslides/pm/view'\n\nimport { dragHandler } from './helpers/dragHandler.js'\nimport { findElementNextToCoords } from './helpers/findNextElementFromCursor.js'\nimport { getOuterNode, getOuterNodePos } from './helpers/getOuterNode.js'\nimport { removeNode } from './helpers/removeNode.js'\n\ntype PluginState = {\n locked: boolean\n}\n\nconst getOuterDomNode = (view: EditorView, domNode: HTMLElement) => {\n let tmpDomNode = domNode\n\n // Traverse to top level node.\n while (tmpDomNode?.parentNode) {\n if (tmpDomNode.parentNode === view.dom) {\n break\n }\n\n tmpDomNode = tmpDomNode.parentNode as HTMLElement\n }\n\n return tmpDomNode\n}\n\nexport interface DragHandlePluginProps {\n pluginKey?: PluginKey | string\n editor: Editor\n element: HTMLElement\n onNodeChange?: (data: { editor: Editor; node: Node | null; pos: number }) => void\n onElementDragStart?: (e: DragEvent) => void\n onElementDragEnd?: (e: DragEvent) => void\n computePositionConfig?: ComputePositionConfig\n getReferencedVirtualElement?: () => VirtualElement | null\n}\n\nexport const dragHandlePluginDefaultKey = new PluginKey('dragHandle')\n\nexport const DragHandlePlugin = ({\n pluginKey = dragHandlePluginDefaultKey,\n element,\n editor,\n computePositionConfig,\n getReferencedVirtualElement,\n onNodeChange,\n onElementDragStart,\n onElementDragEnd,\n}: DragHandlePluginProps) => {\n const wrapper = document.createElement('div')\n let locked = false\n let currentNode: Node | null = null\n let currentNodePos = -1\n let rafId: number | null = null\n let pendingMouseCoords: { x: number; y: number } | null = null\n\n function hideHandle() {\n if (!element) {\n return\n }\n\n element.style.visibility = 'hidden'\n element.style.pointerEvents = 'none'\n }\n\n function showHandle() {\n if (!element) {\n return\n }\n\n if (!editor.isEditable) {\n hideHandle()\n return\n }\n\n element.style.visibility = ''\n element.style.pointerEvents = 'auto'\n }\n\n function repositionDragHandle(dom: Element) {\n const virtualElement = getReferencedVirtualElement?.() || {\n getBoundingClientRect: () => dom.getBoundingClientRect(),\n }\n\n computePosition(virtualElement, element, computePositionConfig).then(val => {\n Object.assign(element.style, {\n position: val.strategy,\n left: `${val.x}px`,\n top: `${val.y}px`,\n })\n })\n }\n\n function onDragStart(e: DragEvent) {\n onElementDragStart?.(e)\n // Push this to the end of the event cue\n // Fixes bug where incorrect drag pos is returned if drag handle has position: absolute\n // @ts-ignore\n dragHandler(e, editor)\n\n if (element) {\n element.dataset.dragging = 'true'\n }\n\n setTimeout(() => {\n if (element) {\n element.style.pointerEvents = 'none'\n }\n }, 0)\n }\n\n function onDragEnd(e: DragEvent) {\n onElementDragEnd?.(e)\n hideHandle()\n if (element) {\n element.style.pointerEvents = 'auto'\n element.dataset.dragging = 'false'\n }\n }\n\n element.addEventListener('dragstart', onDragStart)\n element.addEventListener('dragend', onDragEnd)\n\n wrapper.appendChild(element)\n\n return {\n unbind() {\n element.removeEventListener('dragstart', onDragStart)\n element.removeEventListener('dragend', onDragEnd)\n if (rafId) {\n cancelAnimationFrame(rafId)\n rafId = null\n pendingMouseCoords = null\n }\n },\n plugin: new Plugin({\n key: typeof pluginKey === 'string' ? new PluginKey(pluginKey) : pluginKey,\n\n state: {\n init() {\n return { locked: false }\n },\n apply(tr: Transaction, value: PluginState, _oldState: EditorState, state: EditorState) {\n const isLocked = tr.getMeta('lockDragHandle')\n const hideDragHandle = tr.getMeta('hideDragHandle')\n\n if (isLocked !== undefined) {\n locked = isLocked\n }\n\n if (hideDragHandle) {\n hideHandle()\n\n locked = false\n currentNode = null\n currentNodePos = -1\n\n onNodeChange?.({ editor, node: null, pos: -1 })\n\n return value\n }\n\n // Something has changed and drag handler is visible…\n if (tr.docChanged && currentNodePos !== -1 && element) {\n const newPos = tr.mapping.map(currentNodePos)\n\n if (newPos !== currentNodePos) {\n currentNodePos = newPos\n // We will get the outer node with data and position in views update method.\n }\n }\n\n return value\n },\n },\n\n view: view => {\n element.draggable = true\n element.style.pointerEvents = 'auto'\n element.dataset.dragging = 'false'\n\n editor.view.dom.parentElement?.appendChild(wrapper)\n\n wrapper.style.pointerEvents = 'none'\n wrapper.style.position = 'absolute'\n wrapper.style.top = '0'\n wrapper.style.left = '0'\n\n return {\n update(_, oldState) {\n if (!element) {\n return\n }\n\n if (!editor.isEditable) {\n hideHandle()\n return\n }\n\n // Prevent element being draggend while being open.\n if (locked) {\n element.draggable = false\n } else {\n element.draggable = true\n }\n\n // Recalculate popup position if doc has changend and drag handler is visible.\n if (view.state.doc.eq(oldState.doc) || currentNodePos === -1) {\n return\n }\n\n // Get domNode from (new) position.\n let domNode = view.nodeDOM(currentNodePos) as HTMLElement\n\n // Since old element could have been wrapped, we need to find\n // the outer node and take its position and node data.\n domNode = getOuterDomNode(view, domNode)\n\n // Skip if domNode is editor dom.\n if (domNode === view.dom) {\n return\n }\n\n // We only want `Element`.\n if (domNode?.nodeType !== 1) {\n return\n }\n\n const domNodePos = view.posAtDOM(domNode, 0)\n const outerNode = getOuterNode(editor.state.doc, domNodePos)\n const outerNodePos = getOuterNodePos(editor.state.doc, domNodePos) // TODO: needed?\n\n currentNode = outerNode\n currentNodePos = outerNodePos\n\n onNodeChange?.({ editor, node: currentNode, pos: currentNodePos })\n\n repositionDragHandle(domNode as Element)\n },\n\n // TODO: Kills even on hot reload\n destroy() {\n if (rafId) {\n cancelAnimationFrame(rafId)\n rafId = null\n pendingMouseCoords = null\n }\n\n if (element) {\n removeNode(wrapper)\n }\n },\n }\n },\n\n props: {\n handleDOMEvents: {\n keydown(view) {\n if (!element || locked) {\n return false\n }\n\n if (view.hasFocus()) {\n hideHandle()\n currentNode = null\n currentNodePos = -1\n onNodeChange?.({ editor, node: null, pos: -1 })\n\n // We want to still continue with other keydown events.\n return false\n }\n\n return false\n },\n mouseleave(_view, e) {\n // Do not hide open popup on mouseleave.\n if (locked) {\n return false\n }\n\n // If e.target is not inside the wrapper, hide.\n if (e.target && !wrapper.contains(e.relatedTarget as HTMLElement)) {\n hideHandle()\n\n currentNode = null\n currentNodePos = -1\n\n onNodeChange?.({ editor, node: null, pos: -1 })\n }\n\n return false\n },\n\n mousemove(view, e) {\n // Do not continue if popup is not initialized or open.\n if (!element || locked) {\n return false\n }\n\n // Store latest mouse coords and schedule a single RAF per frame\n pendingMouseCoords = { x: e.clientX, y: e.clientY }\n\n if (rafId) {\n return false\n }\n\n rafId = requestAnimationFrame(() => {\n rafId = null\n\n if (!pendingMouseCoords) {\n return\n }\n\n const { x, y } = pendingMouseCoords\n pendingMouseCoords = null\n\n const nodeData = findElementNextToCoords({\n x,\n y,\n direction: 'right',\n editor,\n })\n\n // Skip if there is no node next to coords\n if (!nodeData.resultElement) {\n return\n }\n\n let domNode = nodeData.resultElement as HTMLElement\n\n domNode = getOuterDomNode(view, domNode)\n\n // Skip if domNode is editor dom.\n if (domNode === view.dom) {\n return\n }\n\n // We only want `Element`.\n if (domNode?.nodeType !== 1) {\n return\n }\n\n const domNodePos = view.posAtDOM(domNode, 0)\n const outerNode = getOuterNode(editor.state.doc, domNodePos)\n\n if (outerNode !== currentNode) {\n const outerNodePos = getOuterNodePos(editor.state.doc, domNodePos)\n\n currentNode = outerNode\n currentNodePos = outerNodePos\n\n onNodeChange?.({ editor, node: currentNode, pos: currentNodePos })\n\n // Set nodes clientRect.\n repositionDragHandle(domNode as Element)\n\n showHandle()\n }\n })\n\n return false\n },\n },\n },\n }),\n }\n}\n","import type { Editor } from '@blockslides/core'\nimport { getSelectionRanges, NodeRangeSelection } from '@blockslides/extension-node-range'\nimport type { SelectionRange } from '@blockslides/pm/state'\n\nimport { cloneElement } from './cloneElement.js'\nimport { findElementNextToCoords } from './findNextElementFromCursor.js'\nimport { getInnerCoords } from './getInnerCoords.js'\nimport { removeNode } from './removeNode.js'\n\nfunction getDragHandleRanges(event: DragEvent, editor: Editor): SelectionRange[] {\n const { doc } = editor.view.state\n\n const result = findElementNextToCoords({\n editor,\n x: event.clientX,\n y: event.clientY,\n direction: 'right',\n })\n\n if (!result.resultNode || result.pos === null) {\n return []\n }\n\n const x = event.clientX\n\n // @ts-ignore\n const coords = getInnerCoords(editor.view, x, event.clientY)\n const posAtCoords = editor.view.posAtCoords(coords)\n\n if (!posAtCoords) {\n return []\n }\n\n const { pos } = posAtCoords\n const nodeAt = doc.resolve(pos).parent\n\n if (!nodeAt) {\n return []\n }\n\n const $from = doc.resolve(result.pos)\n const $to = doc.resolve(result.pos + 1)\n\n return getSelectionRanges($from, $to, 0)\n}\n\nexport function dragHandler(event: DragEvent, editor: Editor) {\n const { view } = editor\n\n if (!event.dataTransfer) {\n return\n }\n\n const { empty, $from, $to } = view.state.selection\n\n const dragHandleRanges = getDragHandleRanges(event, editor)\n\n const selectionRanges = getSelectionRanges($from, $to, 0)\n const isDragHandleWithinSelection = selectionRanges.some(range => {\n return dragHandleRanges.find(dragHandleRange => {\n return dragHandleRange.$from === range.$from && dragHandleRange.$to === range.$to\n })\n })\n\n const ranges = empty || !isDragHandleWithinSelection ? dragHandleRanges : selectionRanges\n\n if (!ranges.length) {\n return\n }\n\n const { tr } = view.state\n const wrapper = document.createElement('div')\n const from = ranges[0].$from.pos\n const to = ranges[ranges.length - 1].$to.pos\n\n const selection = NodeRangeSelection.create(view.state.doc, from, to)\n const slice = selection.content()\n\n ranges.forEach(range => {\n const element = view.nodeDOM(range.$from.pos) as HTMLElement\n const clonedElement = cloneElement(element)\n\n wrapper.append(clonedElement)\n })\n\n wrapper.style.position = 'absolute'\n wrapper.style.top = '-10000px'\n document.body.append(wrapper)\n\n event.dataTransfer.clearData()\n event.dataTransfer.setDragImage(wrapper, 0, 0)\n\n // tell ProseMirror the dragged content\n view.dragging = { slice, move: true }\n\n tr.setSelection(selection)\n\n view.dispatch(tr)\n\n // clean up\n document.addEventListener('drop', () => removeNode(wrapper), { once: true })\n}\n","function getCSSText(element: Element) {\n let value = ''\n const style = getComputedStyle(element)\n\n for (let i = 0; i < style.length; i += 1) {\n value += `${style[i]}:${style.getPropertyValue(style[i])};`\n }\n\n return value\n}\n\nexport function cloneElement(node: HTMLElement) {\n const clonedNode = node.cloneNode(true) as HTMLElement\n const sourceElements = [node, ...Array.from(node.getElementsByTagName('*'))] as HTMLElement[]\n const targetElements = [clonedNode, ...Array.from(clonedNode.getElementsByTagName('*'))] as HTMLElement[]\n\n sourceElements.forEach((sourceElement, index) => {\n targetElements[index].style.cssText = getCSSText(sourceElement)\n })\n\n return clonedNode\n}\n","import type { Editor } from '@blockslides/core'\nimport type { Node } from '@blockslides/pm/model'\nimport type { EditorView } from '@blockslides/pm/view'\n\nexport type FindElementNextToCoords = {\n x: number\n y: number\n direction?: 'left' | 'right'\n editor: Editor\n}\n\n/**\n * Finds the draggable block element that is a direct child of view.dom\n */\nexport function findClosestTopLevelBlock(element: Element, view: EditorView): HTMLElement | undefined {\n let current: Element | null = element\n\n while (current?.parentElement && current.parentElement !== view.dom) {\n current = current.parentElement\n }\n\n return current?.parentElement === view.dom ? (current as HTMLElement) : undefined\n}\n\n/**\n * Clamps coordinates to content bounds with O(1) layout reads\n */\nfunction clampToContent(view: EditorView, x: number, y: number, inset = 5): { x: number; y: number } {\n const container = view.dom\n const firstBlock = container.firstElementChild\n const lastBlock = container.lastElementChild\n\n if (!firstBlock || !lastBlock) {\n // this condition will never be met, as the first child element will be treated as last child element too\n return { x, y }\n }\n\n // Clamp Y between first and last block\n const topRect = firstBlock.getBoundingClientRect()\n const botRect = lastBlock.getBoundingClientRect()\n const clampedY = Math.min(Math.max(topRect.top + inset, y), botRect.bottom - inset)\n\n const epsilon = 0.5\n const sameLeft = Math.abs(topRect.left - botRect.left) < epsilon\n const sameRight = Math.abs(topRect.right - botRect.right) < epsilon\n\n let rowRect: DOMRect = topRect\n\n if (sameLeft && sameRight) {\n // Most of the time, every block has the same width\n rowRect = topRect\n } else {\n // TODO\n // find the actual block at the clamped Y\n // This case is rare, avoid for now\n }\n\n // Clamp X to the chosen block’s bounds\n const clampedX = Math.min(Math.max(rowRect.left + inset, x), rowRect.right - inset)\n\n return { x: clampedX, y: clampedY }\n}\n\nexport const findElementNextToCoords = (\n options: FindElementNextToCoords,\n): {\n resultElement: HTMLElement | null\n resultNode: Node | null\n pos: number | null\n} => {\n const { x, y, editor } = options\n const { view, state } = editor\n\n const { x: clampedX, y: clampedY } = clampToContent(view, x, y, 5)\n\n const elements = view.root.elementsFromPoint(clampedX, clampedY)\n\n let block: HTMLElement | undefined\n\n Array.prototype.some.call(elements, (el: Element) => {\n if (!view.dom.contains(el)) {\n return false\n }\n const candidate = findClosestTopLevelBlock(el, view)\n if (candidate) {\n block = candidate\n return true\n }\n return false\n })\n\n if (!block) {\n return { resultElement: null, resultNode: null, pos: null }\n }\n\n let pos: number\n try {\n pos = view.posAtDOM(block, 0)\n } catch {\n return { resultElement: null, resultNode: null, pos: null }\n }\n\n const node = state.doc.nodeAt(pos)\n\n if (!node) {\n // This case occurs when an atom node is allowed to contain inline content.\n // We need to resolve the position here to ensure we target the correct parent node.\n const resolvedPos = state.doc.resolve(pos)\n const parent = resolvedPos.parent\n\n return {\n resultElement: block,\n resultNode: parent,\n pos: resolvedPos.start(),\n }\n }\n\n return {\n resultElement: block,\n resultNode: node,\n pos,\n }\n}\n","export function getComputedStyle(node: Element, property: keyof CSSStyleDeclaration): any {\n const style = window.getComputedStyle(node)\n\n return style[property]\n}\n","export function minMax(value = 0, min = 0, max = 0): number {\n return Math.min(Math.max(value, min), max)\n}\n","import type { EditorView } from '@blockslides/pm/view'\n\nimport { getComputedStyle } from './getComputedStyle.js'\nimport { minMax } from './minMax.js'\n\nexport function getInnerCoords(view: EditorView, x: number, y: number): { left: number; top: number } {\n const paddingLeft = parseInt(getComputedStyle(view.dom, 'paddingLeft'), 10)\n const paddingRight = parseInt(getComputedStyle(view.dom, 'paddingRight'), 10)\n const borderLeft = parseInt(getComputedStyle(view.dom, 'borderLeftWidth'), 10)\n const borderRight = parseInt(getComputedStyle(view.dom, 'borderLeftWidth'), 10)\n const bounds = view.dom.getBoundingClientRect()\n const coords = {\n left: minMax(x, bounds.left + paddingLeft + borderLeft, bounds.right - paddingRight - borderRight),\n top: y,\n }\n\n return coords\n}\n","export function removeNode(node: HTMLElement) {\n node.parentNode?.removeChild(node)\n}\n","import type { Node } from '@blockslides/pm/model'\n\nexport const getOuterNodePos = (doc: Node, pos: number): number => {\n const resolvedPos = doc.resolve(pos)\n const { depth } = resolvedPos\n\n if (depth === 0) {\n return pos\n }\n\n const a = resolvedPos.pos - resolvedPos.parentOffset\n\n return a - 1\n}\n\nexport const getOuterNode = (doc: Node, pos: number): Node | null => {\n const node = doc.nodeAt(pos)\n const resolvedPos = doc.resolve(pos)\n\n let { depth } = resolvedPos\n let parent = node\n\n while (depth > 0) {\n const currentNode = resolvedPos.node(depth)\n\n depth -= 1\n\n if (depth === 0) {\n parent = currentNode\n }\n }\n\n return parent\n}\n"],"mappings":"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","names":["getComputedStyle","getComputedStyle"]}