@prosekit/extensions 0.11.5 → 0.11.6
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/drop-indicator-E7nCfdnR.js +58 -0
- package/dist/drop-indicator-E7nCfdnR.js.map +1 -0
- package/dist/file-DVUhe5KJ.js +134 -0
- package/dist/file-DVUhe5KJ.js.map +1 -0
- package/dist/index-DY6lIIYV.d.ts +134 -0
- package/dist/index-DY6lIIYV.d.ts.map +1 -0
- package/dist/{mark-rule-BCqIZMDu.js → mark-rule-CGmswjQ_.js} +1 -1
- package/dist/{mark-rule-BCqIZMDu.js.map → mark-rule-CGmswjQ_.js.map} +1 -1
- package/dist/{paste-rule-DIEJKIje.js → paste-rule-BIztzELg.js} +1 -1
- package/dist/{paste-rule-DIEJKIje.js.map → paste-rule-BIztzELg.js.map} +1 -1
- package/dist/prosekit-extensions-code-block.d.ts +1 -1
- package/dist/prosekit-extensions-drop-indicator.d.ts +3 -106
- package/dist/prosekit-extensions-drop-indicator.d.ts.map +1 -1
- package/dist/prosekit-extensions-drop-indicator.js +1 -1
- package/dist/prosekit-extensions-file.d.ts +2 -126
- package/dist/prosekit-extensions-file.js +2 -128
- package/dist/prosekit-extensions-hard-break.d.ts +0 -4
- package/dist/prosekit-extensions-hard-break.d.ts.map +1 -1
- package/dist/prosekit-extensions-image.d.ts +79 -3
- package/dist/prosekit-extensions-image.d.ts.map +1 -1
- package/dist/prosekit-extensions-image.js +88 -8
- package/dist/prosekit-extensions-image.js.map +1 -1
- package/dist/prosekit-extensions-link.js +2 -2
- package/dist/prosekit-extensions-list.js +2 -2
- package/dist/prosekit-extensions-mark-rule.js +1 -1
- package/dist/prosekit-extensions-paragraph.d.ts +0 -4
- package/dist/prosekit-extensions-paragraph.d.ts.map +1 -1
- package/dist/prosekit-extensions-paste-rule.js +1 -1
- package/dist/prosekit-extensions-placeholder.js +2 -2
- package/dist/prosekit-extensions-table.js +2 -2
- package/dist/prosekit-extensions.d.ts +1 -1
- package/dist/{shiki-highlighter-chunk-DSPM0T27.d.ts → shiki-highlighter-chunk-Cwu1Jr9o.d.ts} +1 -1
- package/dist/{shiki-highlighter-chunk-DSPM0T27.d.ts.map → shiki-highlighter-chunk-Cwu1Jr9o.d.ts.map} +1 -1
- package/dist/shiki-highlighter-chunk.d.ts +1 -1
- package/dist/{table-Bi7WsMI3.js → table-BNwuK7xg.js} +2 -2
- package/dist/{table-Bi7WsMI3.js.map → table-BNwuK7xg.js.map} +1 -1
- package/package.json +7 -6
- package/src/drop-indicator/drop-indicator-facet.ts +6 -28
- package/src/drop-indicator/drop-indicator.ts +3 -5
- package/src/drop-indicator/index.ts +6 -6
- package/src/file/file-upload.ts +29 -8
- package/src/image/image-commands.ts +12 -3
- package/src/image/image-upload-handler.ts +156 -0
- package/src/image/index.ts +9 -0
- package/dist/drop-indicator-D1eHOhSi.js +0 -267
- package/dist/drop-indicator-D1eHOhSi.js.map +0 -1
- package/dist/prosekit-extensions-file.d.ts.map +0 -1
- package/dist/prosekit-extensions-file.js.map +0 -1
- package/src/drop-indicator/drop-indicator-plugin.ts +0 -147
- package/src/drop-indicator/drop-target.ts +0 -168
- package/src/drop-indicator/types.ts +0 -90
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
import { defineFacet, defineFacetPayload, isNodeSelection, pluginFacet } from "@prosekit/core";
|
|
2
|
-
import { NodeSelection, Plugin, PluginKey, TextSelection } from "@prosekit/pm/state";
|
|
3
|
-
import { isHTMLElement } from "@ocavue/utils";
|
|
4
|
-
|
|
5
|
-
//#region src/drop-indicator/drop-target.ts
|
|
6
|
-
function getTargetsByView(view) {
|
|
7
|
-
let stack = [[-1, view.state.doc]];
|
|
8
|
-
let targets = [];
|
|
9
|
-
while (stack.length > 0) {
|
|
10
|
-
const [pos, node] = stack.pop();
|
|
11
|
-
if (pos >= 0) {
|
|
12
|
-
let dom = view.nodeDOM(pos);
|
|
13
|
-
if (dom && isHTMLElement(dom)) {
|
|
14
|
-
let { top, bottom, left: x1, right: x2 } = dom.getBoundingClientRect();
|
|
15
|
-
targets.push([pos, [
|
|
16
|
-
x1,
|
|
17
|
-
top,
|
|
18
|
-
x2,
|
|
19
|
-
top
|
|
20
|
-
]], [pos + node.nodeSize, [
|
|
21
|
-
x1,
|
|
22
|
-
bottom,
|
|
23
|
-
x2,
|
|
24
|
-
bottom
|
|
25
|
-
]]);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
if (node.isBlock && !node.isTextblock) {
|
|
29
|
-
let childPos = pos + 1;
|
|
30
|
-
for (let child of node.children) {
|
|
31
|
-
stack.push([childPos, child]);
|
|
32
|
-
childPos += child.nodeSize;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return targets;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* @internal
|
|
40
|
-
*/
|
|
41
|
-
function buildGetTarget(view, onDrag) {
|
|
42
|
-
let prevTargets = [];
|
|
43
|
-
let prevDoc;
|
|
44
|
-
let prevRect;
|
|
45
|
-
const getTargets = () => {
|
|
46
|
-
const rect = view.dom.getBoundingClientRect();
|
|
47
|
-
const doc = view.state.doc;
|
|
48
|
-
if (prevTargets && prevDoc && prevRect && rect.width === prevRect.width && rect.height === prevRect.height && rect.x === prevRect.x && rect.y === prevRect.y && prevDoc.eq(doc)) return prevTargets;
|
|
49
|
-
prevRect = rect;
|
|
50
|
-
prevDoc = doc;
|
|
51
|
-
prevTargets = getTargetsByView(view);
|
|
52
|
-
return prevTargets;
|
|
53
|
-
};
|
|
54
|
-
const getTargetImpl = (point, event) => {
|
|
55
|
-
if (!view.editable || view.isDestroyed) return;
|
|
56
|
-
const compare = (p1, p2) => {
|
|
57
|
-
const [pos1, line1] = p1;
|
|
58
|
-
const [pos2, line2] = p2;
|
|
59
|
-
const p1Distance = pointLineDistance(point, line1);
|
|
60
|
-
const p2Distance = pointLineDistance(point, line2);
|
|
61
|
-
return p1Distance - p2Distance || pos1 - pos2;
|
|
62
|
-
};
|
|
63
|
-
let targets = getTargets();
|
|
64
|
-
targets.sort(compare);
|
|
65
|
-
targets = targets.slice(0, 8);
|
|
66
|
-
const target = targets.find((target$1) => onDrag({
|
|
67
|
-
view,
|
|
68
|
-
pos: target$1[0],
|
|
69
|
-
event
|
|
70
|
-
}) !== false);
|
|
71
|
-
if (target && isDraggingToItself(view, target[0])) return;
|
|
72
|
-
return target;
|
|
73
|
-
};
|
|
74
|
-
let prevPoint;
|
|
75
|
-
let prevTarget;
|
|
76
|
-
const getTargetCached = (point, event) => {
|
|
77
|
-
if (prevPoint && pointEqual(prevPoint, point)) return prevTarget;
|
|
78
|
-
prevPoint = point;
|
|
79
|
-
prevTarget = getTargetImpl(point, event);
|
|
80
|
-
return prevTarget;
|
|
81
|
-
};
|
|
82
|
-
return getTargetCached;
|
|
83
|
-
}
|
|
84
|
-
function pointEqual(a, b) {
|
|
85
|
-
return a[0] === b[0] && a[1] === b[1];
|
|
86
|
-
}
|
|
87
|
-
function pointPointDistance(a, b) {
|
|
88
|
-
return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]);
|
|
89
|
-
}
|
|
90
|
-
function pointLineDistance(point, line) {
|
|
91
|
-
return Math.min(pointPointDistance(point, [line[0], line[1]]), pointPointDistance(point, [line[2], line[3]]));
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Whether the dragging node is being dragged to the same position. For example,
|
|
95
|
-
* dragging a list node into a new position that is just below the list node, or
|
|
96
|
-
* dragging a nested quoteblock into itself.
|
|
97
|
-
*/
|
|
98
|
-
function isDraggingToItself(view, pos) {
|
|
99
|
-
const dragging = view.dragging;
|
|
100
|
-
if (!dragging) return;
|
|
101
|
-
const { move } = dragging;
|
|
102
|
-
if (!move) return;
|
|
103
|
-
const selection = view.state.selection;
|
|
104
|
-
if (!isNodeSelection(selection)) return;
|
|
105
|
-
const { from, to } = selection;
|
|
106
|
-
return from <= pos && pos <= to;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
//#endregion
|
|
110
|
-
//#region src/drop-indicator/drop-indicator-plugin.ts
|
|
111
|
-
/**
|
|
112
|
-
* @internal
|
|
113
|
-
*/
|
|
114
|
-
function createDropIndicatorPlugin(options) {
|
|
115
|
-
let getTarget;
|
|
116
|
-
return new Plugin({
|
|
117
|
-
key: new PluginKey("prosekit-drop-indicator"),
|
|
118
|
-
view: (view) => {
|
|
119
|
-
getTarget = buildGetTarget(view, options.onDrag);
|
|
120
|
-
return createDropIndicatorView(view, getTarget, options);
|
|
121
|
-
},
|
|
122
|
-
props: { handleDrop(view, event, slice, move) {
|
|
123
|
-
if (!getTarget) return false;
|
|
124
|
-
const target = getTarget([event.clientX, event.clientY], event);
|
|
125
|
-
if (!target) return false;
|
|
126
|
-
event.preventDefault();
|
|
127
|
-
let insertPos = target[0];
|
|
128
|
-
let tr = view.state.tr;
|
|
129
|
-
if (move) {
|
|
130
|
-
let { node } = view.dragging || {};
|
|
131
|
-
if (node) node.replace(tr);
|
|
132
|
-
else tr.deleteSelection();
|
|
133
|
-
}
|
|
134
|
-
let pos = tr.mapping.map(insertPos);
|
|
135
|
-
let isNode = slice.openStart == 0 && slice.openEnd == 0 && slice.content.childCount == 1;
|
|
136
|
-
let beforeInsert = tr.doc;
|
|
137
|
-
if (isNode) tr.replaceRangeWith(pos, pos, slice.content.firstChild);
|
|
138
|
-
else tr.replaceRange(pos, pos, slice);
|
|
139
|
-
if (tr.doc.eq(beforeInsert)) return true;
|
|
140
|
-
let $pos = tr.doc.resolve(pos);
|
|
141
|
-
if (isNode && NodeSelection.isSelectable(slice.content.firstChild) && $pos.nodeAfter && $pos.nodeAfter.sameMarkup(slice.content.firstChild)) tr.setSelection(new NodeSelection($pos));
|
|
142
|
-
else {
|
|
143
|
-
let end = tr.mapping.map(insertPos);
|
|
144
|
-
tr.mapping.maps[tr.mapping.maps.length - 1].forEach((_from, _to, _newFrom, newTo) => end = newTo);
|
|
145
|
-
tr.setSelection(selectionBetween(view, $pos, tr.doc.resolve(end)));
|
|
146
|
-
}
|
|
147
|
-
view.focus();
|
|
148
|
-
view.dispatch(tr.setMeta("uiEvent", "drop"));
|
|
149
|
-
return true;
|
|
150
|
-
} }
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
function selectionBetween(view, $anchor, $head, bias) {
|
|
154
|
-
return view.someProp("createSelectionBetween", (f) => f(view, $anchor, $head)) || TextSelection.between($anchor, $head, bias);
|
|
155
|
-
}
|
|
156
|
-
function createDropIndicatorView(view, getTarget, options) {
|
|
157
|
-
let dom = view.dom;
|
|
158
|
-
let hideId;
|
|
159
|
-
let prevX;
|
|
160
|
-
let prevY;
|
|
161
|
-
let hasDragOverEvent = false;
|
|
162
|
-
const scheduleHide = () => {
|
|
163
|
-
if (hideId) clearTimeout(hideId);
|
|
164
|
-
hasDragOverEvent = false;
|
|
165
|
-
hideId = setTimeout(() => {
|
|
166
|
-
if (hasDragOverEvent) return;
|
|
167
|
-
options.onHide();
|
|
168
|
-
}, 30);
|
|
169
|
-
};
|
|
170
|
-
const handleDragOver = (event) => {
|
|
171
|
-
hasDragOverEvent = true;
|
|
172
|
-
const { clientX, clientY } = event;
|
|
173
|
-
if (prevX === clientX && prevY === clientY) return;
|
|
174
|
-
prevX = clientX;
|
|
175
|
-
prevY = clientY;
|
|
176
|
-
let target = getTarget([clientX, clientY], event);
|
|
177
|
-
if (!target) {
|
|
178
|
-
scheduleHide();
|
|
179
|
-
return;
|
|
180
|
-
} else {
|
|
181
|
-
const [pos, [x1, y1, x2, y2]] = target;
|
|
182
|
-
const line = {
|
|
183
|
-
p1: {
|
|
184
|
-
x: x1,
|
|
185
|
-
y: y1
|
|
186
|
-
},
|
|
187
|
-
p2: {
|
|
188
|
-
x: x2,
|
|
189
|
-
y: y2
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
options.onShow({
|
|
193
|
-
view,
|
|
194
|
-
pos,
|
|
195
|
-
line
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
dom.addEventListener("dragover", handleDragOver);
|
|
200
|
-
dom.addEventListener("dragend", scheduleHide);
|
|
201
|
-
dom.addEventListener("drop", scheduleHide);
|
|
202
|
-
dom.addEventListener("dragleave", scheduleHide);
|
|
203
|
-
const destroy = () => {
|
|
204
|
-
dom.removeEventListener("dragover", handleDragOver);
|
|
205
|
-
dom.removeEventListener("dragend", scheduleHide);
|
|
206
|
-
dom.removeEventListener("drop", scheduleHide);
|
|
207
|
-
dom.removeEventListener("dragleave", scheduleHide);
|
|
208
|
-
};
|
|
209
|
-
return { destroy };
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
//#endregion
|
|
213
|
-
//#region src/drop-indicator/drop-indicator-facet.ts
|
|
214
|
-
/**
|
|
215
|
-
* @internal
|
|
216
|
-
*/
|
|
217
|
-
function defineDropIndicatorPayload(payload) {
|
|
218
|
-
return defineFacetPayload(dropIndicatorFacet, [payload]);
|
|
219
|
-
}
|
|
220
|
-
const dropIndicatorFacet = defineFacet({
|
|
221
|
-
parent: pluginFacet,
|
|
222
|
-
singleton: true,
|
|
223
|
-
reducer: (payloads) => {
|
|
224
|
-
let showHandlers = payloads.map((p) => p.onShow).filter((x) => !!x);
|
|
225
|
-
let hideHandlers = payloads.map((p) => p.onHide).filter((x) => !!x);
|
|
226
|
-
let dragHandlers = payloads.map((p) => p.onDrag).filter((x) => !!x);
|
|
227
|
-
let showHandler = (options) => {
|
|
228
|
-
for (let fn of showHandlers) fn(options);
|
|
229
|
-
};
|
|
230
|
-
let hideHandler = () => {
|
|
231
|
-
for (let fn of hideHandlers) fn();
|
|
232
|
-
};
|
|
233
|
-
let dragHandler = (options) => {
|
|
234
|
-
for (let fn of dragHandlers) if (fn(options) === false) return false;
|
|
235
|
-
return true;
|
|
236
|
-
};
|
|
237
|
-
if (showHandlers.length === 0) return [];
|
|
238
|
-
return createDropIndicatorPlugin({
|
|
239
|
-
onDrag: dragHandler,
|
|
240
|
-
onShow: showHandler,
|
|
241
|
-
onHide: hideHandler
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
//#endregion
|
|
247
|
-
//#region src/drop-indicator/drop-indicator.ts
|
|
248
|
-
/**
|
|
249
|
-
* Defines an extension that controls the behavior of the drop indicator.
|
|
250
|
-
*
|
|
251
|
-
* This extension itself doesn't draw the drop indicator, but it provides the
|
|
252
|
-
* necessary callbacks to do so. You probably don't want to use this extension
|
|
253
|
-
* directly, but rather use the `<DropIndicator>` component.
|
|
254
|
-
*
|
|
255
|
-
* You can add this extension multiple times. If any extension has `onDrag`
|
|
256
|
-
* callback defined, and it returns `false`, then the drop point will be
|
|
257
|
-
* discarded.
|
|
258
|
-
*
|
|
259
|
-
* @public
|
|
260
|
-
*/
|
|
261
|
-
function defineDropIndicator(options) {
|
|
262
|
-
return defineDropIndicatorPayload(options ?? {});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
//#endregion
|
|
266
|
-
export { defineDropIndicator };
|
|
267
|
-
//# sourceMappingURL=drop-indicator-D1eHOhSi.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"drop-indicator-D1eHOhSi.js","names":["stack: StackItem[]","targets: DropTarget[]","prevTargets: DropTarget[]","prevDoc: ProseMirrorNode | undefined","prevRect: DOMRect | undefined","getTargetImpl: GetTarget","target","prevPoint: Point | undefined","prevTarget: DropTarget | undefined","getTargetCached: GetTarget","getTarget: GetTarget | undefined","hideId: ReturnType<typeof setTimeout> | undefined","prevX: number | undefined","prevY: number | undefined","hasDragOverEvent: boolean","showHandler: ShowHandler","hideHandler: VoidFunction","dragHandler: DragEventHandler"],"sources":["../src/drop-indicator/drop-target.ts","../src/drop-indicator/drop-indicator-plugin.ts","../src/drop-indicator/drop-indicator-facet.ts","../src/drop-indicator/drop-indicator.ts"],"sourcesContent":["import { isHTMLElement } from '@ocavue/utils'\nimport { isNodeSelection } from '@prosekit/core'\nimport type { ProseMirrorNode } from '@prosekit/pm/model'\nimport type { EditorView } from '@prosekit/pm/view'\n\nimport type { DragEventHandler } from './types'\n\ntype Point = readonly [x: number, y: number]\n\ntype Line = readonly [x1: number, y1: number, x2: number, y2: number]\n\n/**\n * @internal\n */\ntype DropTarget = readonly [pos: number, line: Line]\n\nfunction getTargetsByView(view: EditorView): DropTarget[] {\n type StackItem = [pos: number, node: ProseMirrorNode]\n let stack: StackItem[] = [[-1, view.state.doc]]\n let targets: DropTarget[] = []\n\n while (stack.length > 0) {\n const [pos, node] = stack.pop()!\n if (pos >= 0) {\n let dom = view.nodeDOM(pos)\n if (dom && isHTMLElement(dom)) {\n let rect = dom.getBoundingClientRect()\n let { top, bottom, left: x1, right: x2 } = rect\n targets.push(\n [pos, [x1, top, x2, top]],\n [pos + node.nodeSize, [x1, bottom, x2, bottom]],\n )\n }\n }\n if (node.isBlock && !node.isTextblock) {\n let childPos = pos + 1\n for (let child of node.children) {\n stack.push([childPos, child])\n childPos += child.nodeSize\n }\n }\n }\n\n return targets\n}\n\n/**\n * @internal\n */\nexport type GetTarget = (point: Point, event: DragEvent) => DropTarget | undefined\n\n/**\n * @internal\n */\nexport function buildGetTarget(\n view: EditorView,\n onDrag: DragEventHandler,\n): GetTarget {\n let prevTargets: DropTarget[] = []\n let prevDoc: ProseMirrorNode | undefined\n let prevRect: DOMRect | undefined\n\n const getTargets = (): DropTarget[] => {\n const rect = view.dom.getBoundingClientRect()\n const doc = view.state.doc\n\n if (\n prevTargets && prevDoc && prevRect\n && rect.width === prevRect.width\n && rect.height === prevRect.height\n && rect.x === prevRect.x\n && rect.y === prevRect.y\n && prevDoc.eq(doc)\n ) {\n return prevTargets\n }\n\n prevRect = rect\n prevDoc = doc\n prevTargets = getTargetsByView(view)\n return prevTargets\n }\n\n const getTargetImpl: GetTarget = (point, event) => {\n if (!view.editable || view.isDestroyed) {\n return\n }\n\n const compare = (p1: DropTarget, p2: DropTarget): number => {\n const [pos1, line1] = p1\n const [pos2, line2] = p2\n const p1Distance = pointLineDistance(point, line1)\n const p2Distance = pointLineDistance(point, line2)\n\n return (p1Distance - p2Distance) || (pos1 - pos2)\n }\n\n let targets = getTargets()\n targets.sort(compare)\n\n // Only consider the first few targets for performance reasons.\n targets = targets.slice(0, 8)\n\n // Find the closest valid target.\n const target = targets.find(target => onDrag({ view, pos: target[0], event }) !== false)\n\n // If the dragging node is already at the target position, we ignore this\n // target. Notice that we don't pick the second better target here.\n if (target && isDraggingToItself(view, target[0])) {\n return undefined\n }\n\n return target\n }\n\n let prevPoint: Point | undefined\n let prevTarget: DropTarget | undefined\n\n const getTargetCached: GetTarget = (point, event) => {\n if (prevPoint && pointEqual(prevPoint, point)) {\n return prevTarget\n }\n\n prevPoint = point\n prevTarget = getTargetImpl(point, event)\n return prevTarget\n }\n\n return getTargetCached\n}\n\nfunction pointEqual(a: Point, b: Point) {\n return a[0] === b[0] && a[1] === b[1]\n}\n\nfunction pointPointDistance(a: Point, b: Point) {\n // Manhattan distance\n return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1])\n}\n\nfunction pointLineDistance(point: Point, line: Line) {\n // Notice that we are actually not calculating the distance between the point\n // and the line. Instead, we are calculating the distance between the point\n // and the two endpoints of the line.\n return Math.min(\n pointPointDistance(point, [line[0], line[1]]),\n pointPointDistance(point, [line[2], line[3]]),\n )\n}\n\n/**\n * Whether the dragging node is being dragged to the same position. For example,\n * dragging a list node into a new position that is just below the list node, or\n * dragging a nested quoteblock into itself.\n */\nfunction isDraggingToItself(view: EditorView, pos: number) {\n const dragging = view.dragging\n if (!dragging) return\n\n const { move } = dragging\n if (!move) return\n\n const selection = view.state.selection\n if (!isNodeSelection(selection)) return\n\n const { from, to } = selection\n return from <= pos && pos <= to\n}\n","import type { ResolvedPos } from '@prosekit/pm/model'\nimport {\n NodeSelection,\n Plugin,\n PluginKey,\n TextSelection,\n type PluginView,\n} from '@prosekit/pm/state'\nimport type { EditorView } from '@prosekit/pm/view'\n\nimport {\n buildGetTarget,\n type GetTarget,\n} from './drop-target'\nimport type {\n DragEventHandler,\n ShowHandler,\n ViewDragging,\n} from './types'\n\n/**\n * @internal\n */\ninterface DropIndicatorPluginOptions {\n onDrag: DragEventHandler\n onShow: ShowHandler\n onHide: VoidFunction\n}\n\n/**\n * @internal\n */\nexport function createDropIndicatorPlugin(options: DropIndicatorPluginOptions): Plugin {\n let getTarget: GetTarget | undefined\n\n return new Plugin({\n key: new PluginKey('prosekit-drop-indicator'),\n view: (view) => {\n getTarget = buildGetTarget(view, options.onDrag)\n return createDropIndicatorView(view, getTarget, options)\n },\n props: {\n handleDrop(view, event, slice, move): boolean {\n if (!getTarget) return false\n\n const target = getTarget([event.clientX, event.clientY], event)\n\n if (!target) return false\n\n event.preventDefault()\n let insertPos = target[0]\n\n let tr = view.state.tr\n if (move) {\n let { node } = (view.dragging as ViewDragging | null) || {}\n if (node) node.replace(tr)\n else tr.deleteSelection()\n }\n\n let pos = tr.mapping.map(insertPos)\n let isNode = slice.openStart == 0 && slice.openEnd == 0 && slice.content.childCount == 1\n let beforeInsert = tr.doc\n if (isNode) tr.replaceRangeWith(pos, pos, slice.content.firstChild!)\n else tr.replaceRange(pos, pos, slice)\n if (tr.doc.eq(beforeInsert)) {\n return true\n }\n\n let $pos = tr.doc.resolve(pos)\n if (\n isNode && NodeSelection.isSelectable(slice.content.firstChild!)\n && $pos.nodeAfter && $pos.nodeAfter.sameMarkup(slice.content.firstChild!)\n ) {\n tr.setSelection(new NodeSelection($pos))\n } else {\n let end = tr.mapping.map(insertPos)\n tr.mapping.maps[tr.mapping.maps.length - 1].forEach((_from, _to, _newFrom, newTo) => end = newTo)\n tr.setSelection(selectionBetween(view, $pos, tr.doc.resolve(end)))\n }\n view.focus()\n view.dispatch(tr.setMeta('uiEvent', 'drop'))\n return true\n },\n },\n })\n}\n\nfunction selectionBetween(view: EditorView, $anchor: ResolvedPos, $head: ResolvedPos, bias?: number) {\n return view.someProp('createSelectionBetween', f => f(view, $anchor, $head))\n || TextSelection.between($anchor, $head, bias)\n}\n\nfunction createDropIndicatorView(view: EditorView, getTarget: GetTarget, options: DropIndicatorPluginOptions): PluginView {\n let dom = view.dom\n let hideId: ReturnType<typeof setTimeout> | undefined\n let prevX: number | undefined\n let prevY: number | undefined\n let hasDragOverEvent: boolean = false\n\n const scheduleHide = () => {\n if (hideId) {\n clearTimeout(hideId)\n }\n\n hasDragOverEvent = false\n hideId = setTimeout(() => {\n if (hasDragOverEvent) return\n options.onHide()\n }, 30)\n }\n\n const handleDragOver = (event: DragEvent): void => {\n hasDragOverEvent = true\n\n const { clientX, clientY } = event\n if (prevX === clientX && prevY === clientY) {\n return\n }\n prevX = clientX\n prevY = clientY\n\n let target = getTarget([clientX, clientY], event)\n\n if (!target) {\n scheduleHide()\n return\n } else {\n const [pos, [x1, y1, x2, y2]] = target\n const line = { p1: { x: x1, y: y1 }, p2: { x: x2, y: y2 } }\n options.onShow({ view, pos, line })\n }\n }\n\n dom.addEventListener('dragover', handleDragOver)\n dom.addEventListener('dragend', scheduleHide)\n dom.addEventListener('drop', scheduleHide)\n dom.addEventListener('dragleave', scheduleHide)\n\n const destroy = () => {\n dom.removeEventListener('dragover', handleDragOver)\n dom.removeEventListener('dragend', scheduleHide)\n dom.removeEventListener('drop', scheduleHide)\n dom.removeEventListener('dragleave', scheduleHide)\n }\n\n return { destroy }\n}\n","import {\n defineFacet,\n defineFacetPayload,\n pluginFacet,\n type PlainExtension,\n type PluginPayload,\n} from '@prosekit/core'\n\nimport { createDropIndicatorPlugin } from './drop-indicator-plugin'\nimport type {\n DragEventHandler,\n ShowHandler,\n} from './types'\n\n/**\n * @internal\n */\nexport function defineDropIndicatorPayload(\n payload: DropIndicatorPayload,\n): PlainExtension {\n return defineFacetPayload(dropIndicatorFacet, [payload]) as PlainExtension\n}\n\n/**\n * @internal\n */\nexport interface DropIndicatorPayload {\n /**\n * A callback that is called when the drop indicator should be shown.\n */\n onShow?: ShowHandler\n\n /**\n * A callback that is called when the drop indicator should be hidden.\n */\n onHide?: VoidFunction\n\n /**\n * A callback that is called when the `dragover` event is fired. You can\n * return `false` to disable the current drop point and thus hide the drop\n * indicator.\n */\n onDrag?: DragEventHandler\n}\n\nconst dropIndicatorFacet = defineFacet<DropIndicatorPayload, PluginPayload>({\n parent: pluginFacet,\n singleton: true,\n reducer: (payloads: DropIndicatorPayload[]): PluginPayload => {\n let showHandlers = payloads.map(p => p.onShow).filter(x => !!x)\n let hideHandlers = payloads.map(p => p.onHide).filter(x => !!x)\n let dragHandlers = payloads.map(p => p.onDrag).filter(x => !!x)\n\n let showHandler: ShowHandler = (options) => {\n for (let fn of showHandlers) {\n fn(options)\n }\n }\n\n let hideHandler: VoidFunction = () => {\n for (let fn of hideHandlers) {\n fn()\n }\n }\n\n let dragHandler: DragEventHandler = (options): boolean => {\n for (let fn of dragHandlers) {\n if (fn(options) === false) return false\n }\n return true\n }\n\n if (showHandlers.length === 0) {\n // No `onShow` event handler, so we don't need to create a plugin.\n return []\n }\n\n return createDropIndicatorPlugin({\n onDrag: dragHandler,\n onShow: showHandler,\n onHide: hideHandler,\n })\n },\n})\n","import type { PlainExtension } from '@prosekit/core'\n\nimport {\n defineDropIndicatorPayload,\n type DropIndicatorPayload,\n} from './drop-indicator-facet'\n\n/**\n * @internal\n */\nexport type DropIndicatorExtension = PlainExtension\n\n/**\n * Defines an extension that controls the behavior of the drop indicator.\n *\n * This extension itself doesn't draw the drop indicator, but it provides the\n * necessary callbacks to do so. You probably don't want to use this extension\n * directly, but rather use the `<DropIndicator>` component.\n *\n * You can add this extension multiple times. If any extension has `onDrag`\n * callback defined, and it returns `false`, then the drop point will be\n * discarded.\n *\n * @public\n */\nexport function defineDropIndicator(\n options?: DropIndicatorOptions,\n): DropIndicatorExtension {\n return defineDropIndicatorPayload(options ?? {})\n}\n\n/**\n * Options for {@link defineDropIndicator}.\n *\n * @public\n */\nexport interface DropIndicatorOptions extends DropIndicatorPayload {}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prosekit-extensions-file.d.ts","names":[],"sources":["../src/file/file-drop-handler.ts","../src/file/file-paste-handler.ts","../src/file/file-upload.ts"],"sourcesContent":[],"mappings":";;;;UAYiB,sBAAA;;AAAjB;;MAIQ,EAAA,UAAA;;;;EAwBI,KAAA,EAnBH,SAmBG;EAII;;;MAEb,EApBK,IAoBL;EAAc;;;;AClCjB;;;;;;AAuBA;AAIgB,KDCJ,eAAA,GCD0B,CAAA,OAAA,EDE3B,sBCF2B,EAAA,GAAA,OAAA,GAAA,IAAA;AAAA,iBDKtB,qBAAA,CCLsB,OAAA,EDM3B,eCN2B,CAAA,EDOnC,cCPmC;;;UA3BrB,uBAAA;;ADAjB;;MAIQ,ECAA,UDAA;;;;EAwBI,KAAA,ECnBH,cDmBkB;EAIX;;;MAEb,ECpBK,IDoBL;;;;;AClCH;;;AASS,KAcG,gBAAA,GAdH,CAAA,OAAA,EAeE,uBAfF,EAAA,GAAA,OAAA,GAAA,IAAA;AAKD,iBAaQ,sBAAA,CAbR,OAAA,EAcG,gBAdH,CAAA,EAeL,cAfK;;;;;;UCvBS,cAAA;EFSA,MAAA,EAAA,MAAA;EAAsB,KAAA,EAAA,MAAA;;AAS9B,UETQ,eAAA,CFSR;;;AAmBT;EAIgB,IAAA,EE5BR,IF4BQ;EAAqB;;;EAEpB,UAAA,EAAA,CAAA,QAAA,EEzBQ,cFyBR,EAAA,GAAA,IAAA;;;;AClCjB;;AAIQ,KCYI,QDZJ,CAAA,MAAA,CAAA,GAAA,CAAA,OAAA,ECYiC,eDZjC,EAAA,GCYqD,ODZrD,CCY6D,MDZ7D,CAAA;;;;AAmBI,cCFC,UDEe,CAAA,MACjB,CAAA,CAAA;EAGK;;;;;;;;ACpChB;EASiB,UAAA,IAAA,EAAA,OAAe;EAAA;;;EASO,SAAA,QAAA,EA4BlB,OA5BkB,CA4BV,MA5BU,CAAA;EAO3B,QAAA,WAAQ;EAAA;;;;;AAKpB;EAAuB,WAAA,CAAA;IAAA,IAAA;IAAA;GAAA,EAAA;IAgBM,IAAA,EAUa,IAVb;IAAR,QAAA,EAUqC,QAVrC,CAU8C,MAV9C,CAAA;;;;;mBAUqC,CAAA,QAAA,EAAA,CAAA,QAAA,EAgCjC,cAhCiC,EAAA,GAAA,IAAA,CAAA,EAiCrD,YAjCqD;;;;SA+CrD,GAAA,CAAA,SAAA,OAAA,CAAA,CAAA,SAAA,EAAA,MAAA,CAAA,EAAA,UAAA,CAAW,MAAX,CAAA,GAAA,SAAA;EAAU"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prosekit-extensions-file.js","names":["getFiles","facet","getFiles","dropHandler: DropHandler","pasteHandler: PasteHandler"],"sources":["../src/file/helpers.ts","../src/file/file-drop-handler.ts","../src/file/file-paste-handler.ts","../src/file/file-upload.ts"],"sourcesContent":["import type { EditorView } from '@prosekit/pm/view'\n\ntype FileHandler<E extends Event> = (options: {\n view: EditorView\n event: E\n file: File\n}) => boolean | void\n\nfunction handleFile<E extends Event>(\n view: EditorView,\n event: E,\n file: File,\n handlers: FileHandler<E>[],\n) {\n // The last item in `handlers` should has the highest priority.\n for (let i = handlers.length - 1; i >= 0; i--) {\n const handler = handlers[i]\n if (handler({ view, event, file })) {\n return true\n }\n }\n return false\n}\n\nexport function handleEvent<E extends Event>(\n view: EditorView,\n event: E,\n handlers: FileHandler<E>[],\n getFiles: (event: E) => File[],\n): boolean {\n const files = getFiles(event)\n let handled = false\n for (const file of files) {\n if (handleFile(view, event, file, handlers)) {\n handled = true\n }\n }\n return handled\n}\n","import {\n defineFacet,\n defineFacetPayload,\n editorEventFacet,\n type DropHandler,\n type EditorEventPayload,\n type PlainExtension,\n} from '@prosekit/core'\nimport type { EditorView } from '@prosekit/pm/view'\n\nimport { handleEvent } from './helpers'\n\nexport interface FileDropHandlerOptions {\n /**\n * The editor view.\n */\n view: EditorView\n\n /**\n * The event that triggered the drop.\n */\n event: DragEvent\n\n /**\n * The file that was dropped.\n */\n file: File\n\n /**\n * The position of the document where the file was dropped.\n */\n pos: number\n}\n\n/**\n * A function that handles one of the files in a drop event.\n *\n * Returns `true` if the file was handled and thus should not be handled by\n * other handlers.\n */\nexport type FileDropHandler = (\n options: FileDropHandlerOptions,\n) => boolean | void\n\nexport function defineFileDropHandler(\n handler: FileDropHandler,\n): PlainExtension {\n return defineFacetPayload(facet, [handler]) as PlainExtension\n}\n\nfunction getFiles(event: DragEvent) {\n return Array.from(event.dataTransfer?.files ?? [])\n}\n\nconst facet = defineFacet<FileDropHandler, EditorEventPayload>({\n parent: editorEventFacet,\n singleton: true,\n reducer: (handlers: FileDropHandler[]): EditorEventPayload => {\n const dropHandler: DropHandler = (view, event): boolean => {\n const position = view.posAtCoords({ left: event.x, top: event.y })\n if (!position) {\n return false\n }\n const pos = position.inside > 0 ? position.inside : position.pos\n\n return handleEvent<DragEvent>(\n view,\n event,\n handlers.map((handler) => (options) => handler({ ...options, pos })),\n getFiles,\n )\n }\n return ['drop', dropHandler]\n },\n})\n","import {\n defineFacet,\n defineFacetPayload,\n editorEventFacet,\n type EditorEventPayload,\n type PasteHandler,\n type PlainExtension,\n} from '@prosekit/core'\nimport type { EditorView } from '@prosekit/pm/view'\n\nimport { handleEvent } from './helpers'\n\nexport interface FilePasteHandlerOptions {\n /**\n * The editor view.\n */\n view: EditorView\n\n /**\n * The event that triggered the paste.\n */\n event: ClipboardEvent\n\n /**\n * The file that was pasted.\n */\n file: File\n}\n\n/**\n * A function that handles one of the files in a paste event.\n *\n * Returns `true` if the file was handled and thus should not be handled by\n * other handlers.\n */\nexport type FilePasteHandler = (\n options: FilePasteHandlerOptions,\n) => boolean | void\n\nexport function defineFilePasteHandler(\n handler: FilePasteHandler,\n): PlainExtension {\n return defineFacetPayload(facet, [handler]) as PlainExtension\n}\n\nfunction getFiles(event: ClipboardEvent) {\n return Array.from(event.clipboardData?.files ?? [])\n}\n\nconst facet = defineFacet<FilePasteHandler, EditorEventPayload>({\n parent: editorEventFacet,\n singleton: true,\n reducer: (handlers: FilePasteHandler[]): EditorEventPayload => {\n const pasteHandler: PasteHandler = (view, event): boolean => {\n return handleEvent<ClipboardEvent>(view, event, handlers, getFiles)\n }\n return ['paste', pasteHandler]\n },\n})\n","/**\n * An interface representing the upload progress.\n */\nexport interface UploadProgress {\n // A number representing the amount of work already performed by the\n // underlying process.\n loaded: number\n // A number representing the total amount of work that the underlying\n // process is in the progress of performing.\n total: number\n}\n\nexport interface UploaderOptions {\n /**\n * The file to be uploaded.\n */\n file: File\n\n /**\n * A callback function that should be called with the upload progress updates.\n */\n onProgress: (progress: UploadProgress) => void\n}\n\n/**\n * The implementation of the actual upload function. You need to implement this\n * function to upload files to your desired destination.\n */\nexport type Uploader<Result> = (options: UploaderOptions) => Promise<Result>\n\n/**\n * A class that represents a upload task.\n */\nexport class UploadTask<Result> {\n /**\n * An [object URL](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL)\n * representing the file to be uploaded. This URL will be revoked once the\n * upload is complete successfully.\n */\n readonly objectURL: string\n\n /**\n * A boolean indicating whether the upload is complete (either successfully or with an error).\n */\n protected done = false\n\n /**\n * A promise that fulfills once the upload is complete, or rejects if an error occurs.\n */\n readonly finished: Promise<Result>\n\n private subscribers: ((progress: UploadProgress) => void)[] = []\n\n /**\n * Creates a new upload task. You can find the upload task by its object URL\n * later using `UploadTask.get()`.\n *\n * @param options - The options for the upload task.\n */\n constructor({ file, uploader }: { file: File; uploader: Uploader<Result> }) {\n this.objectURL = URL.createObjectURL(file)\n this.finished = new Promise((resolve, reject) => {\n const maybePromise = uploader({\n file,\n onProgress: (progress) => {\n for (const subscriber of this.subscribers) {\n subscriber(progress)\n }\n },\n })\n Promise.resolve(maybePromise).then(\n (result) => {\n this.done = true\n URL.revokeObjectURL(this.objectURL)\n resolve(result)\n },\n (error) => {\n this.done = true\n reject(\n new Error('[prosekit] Failed to upload file', { cause: error }),\n )\n },\n )\n })\n store.set(this.objectURL, this)\n }\n\n /**\n * Subscribes to progress updates. Returns a function to unsubscribe.\n */\n public subscribeProgress(\n callback: (progress: UploadProgress) => void,\n ): VoidFunction {\n this.subscribers.push(callback)\n return () => {\n this.subscribers = this.subscribers.filter(\n (subscriber) => subscriber !== callback,\n )\n }\n }\n\n /**\n * Finds an upload task by its object URL.\n */\n static get<Result = unknown>(\n objectURL: string,\n ): UploadTask<Result> | undefined {\n return store.get(objectURL) as UploadTask<Result> | undefined\n }\n\n /**\n * Deletes an upload task by its object URL.\n */\n static delete(objectURL: string): void {\n store.delete(objectURL)\n }\n}\n\nconst store = new Map<string, UploadTask<unknown>>()\n"],"mappings":";;;AAQA,SAAS,WACP,MACA,OACA,MACA,UACA;AAEA,MAAK,IAAI,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;EAC7C,MAAM,UAAU,SAAS;AACzB,MAAI,QAAQ;GAAE;GAAM;GAAO;GAAM,CAAC,CAChC,QAAO;;AAGX,QAAO;;AAGT,SAAgB,YACd,MACA,OACA,UACA,YACS;CACT,MAAM,QAAQA,WAAS,MAAM;CAC7B,IAAI,UAAU;AACd,MAAK,MAAM,QAAQ,MACjB,KAAI,WAAW,MAAM,OAAO,MAAM,SAAS,CACzC,WAAU;AAGd,QAAO;;;;;ACOT,SAAgB,sBACd,SACgB;AAChB,QAAO,mBAAmBC,SAAO,CAAC,QAAQ,CAAC;;AAG7C,SAASC,WAAS,OAAkB;AAClC,QAAO,MAAM,KAAK,MAAM,cAAc,SAAS,EAAE,CAAC;;AAGpD,MAAMD,UAAQ,YAAiD;CAC7D,QAAQ;CACR,WAAW;CACX,UAAU,aAAoD;EAC5D,MAAME,eAA4B,MAAM,UAAmB;GACzD,MAAM,WAAW,KAAK,YAAY;IAAE,MAAM,MAAM;IAAG,KAAK,MAAM;IAAG,CAAC;AAClE,OAAI,CAAC,SACH,QAAO;GAET,MAAM,MAAM,SAAS,SAAS,IAAI,SAAS,SAAS,SAAS;AAE7D,UAAO,YACL,MACA,OACA,SAAS,KAAK,aAAa,YAAY,QAAQ;IAAE,GAAG;IAAS;IAAK,CAAC,CAAC,EACpED,WACD;;AAEH,SAAO,CAAC,QAAQ,YAAY;;CAE/B,CAAC;;;;ACnCF,SAAgB,uBACd,SACgB;AAChB,QAAO,mBAAmB,OAAO,CAAC,QAAQ,CAAC;;AAG7C,SAAS,SAAS,OAAuB;AACvC,QAAO,MAAM,KAAK,MAAM,eAAe,SAAS,EAAE,CAAC;;AAGrD,MAAM,QAAQ,YAAkD;CAC9D,QAAQ;CACR,WAAW;CACX,UAAU,aAAqD;EAC7D,MAAME,gBAA8B,MAAM,UAAmB;AAC3D,UAAO,YAA4B,MAAM,OAAO,UAAU,SAAS;;AAErE,SAAO,CAAC,SAAS,aAAa;;CAEjC,CAAC;;;;;;;ACzBF,IAAa,aAAb,MAAgC;;;;;;;CA0B9B,YAAY,EAAE,MAAM,YAAwD;cAf3D;qBAO6C,EAAE;AAS9D,OAAK,YAAY,IAAI,gBAAgB,KAAK;AAC1C,OAAK,WAAW,IAAI,SAAS,SAAS,WAAW;GAC/C,MAAM,eAAe,SAAS;IAC5B;IACA,aAAa,aAAa;AACxB,UAAK,MAAM,cAAc,KAAK,YAC5B,YAAW,SAAS;;IAGzB,CAAC;AACF,WAAQ,QAAQ,aAAa,CAAC,MAC3B,WAAW;AACV,SAAK,OAAO;AACZ,QAAI,gBAAgB,KAAK,UAAU;AACnC,YAAQ,OAAO;OAEhB,UAAU;AACT,SAAK,OAAO;AACZ,WACE,IAAI,MAAM,oCAAoC,EAAE,OAAO,OAAO,CAAC,CAChE;KAEJ;IACD;AACF,QAAM,IAAI,KAAK,WAAW,KAAK;;;;;CAMjC,AAAO,kBACL,UACc;AACd,OAAK,YAAY,KAAK,SAAS;AAC/B,eAAa;AACX,QAAK,cAAc,KAAK,YAAY,QACjC,eAAe,eAAe,SAChC;;;;;;CAOL,OAAO,IACL,WACgC;AAChC,SAAO,MAAM,IAAI,UAAU;;;;;CAM7B,OAAO,OAAO,WAAyB;AACrC,QAAM,OAAO,UAAU;;;AAI3B,MAAM,wBAAQ,IAAI,KAAkC"}
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import type { ResolvedPos } from '@prosekit/pm/model'
|
|
2
|
-
import {
|
|
3
|
-
NodeSelection,
|
|
4
|
-
Plugin,
|
|
5
|
-
PluginKey,
|
|
6
|
-
TextSelection,
|
|
7
|
-
type PluginView,
|
|
8
|
-
} from '@prosekit/pm/state'
|
|
9
|
-
import type { EditorView } from '@prosekit/pm/view'
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
buildGetTarget,
|
|
13
|
-
type GetTarget,
|
|
14
|
-
} from './drop-target'
|
|
15
|
-
import type {
|
|
16
|
-
DragEventHandler,
|
|
17
|
-
ShowHandler,
|
|
18
|
-
ViewDragging,
|
|
19
|
-
} from './types'
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @internal
|
|
23
|
-
*/
|
|
24
|
-
interface DropIndicatorPluginOptions {
|
|
25
|
-
onDrag: DragEventHandler
|
|
26
|
-
onShow: ShowHandler
|
|
27
|
-
onHide: VoidFunction
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @internal
|
|
32
|
-
*/
|
|
33
|
-
export function createDropIndicatorPlugin(options: DropIndicatorPluginOptions): Plugin {
|
|
34
|
-
let getTarget: GetTarget | undefined
|
|
35
|
-
|
|
36
|
-
return new Plugin({
|
|
37
|
-
key: new PluginKey('prosekit-drop-indicator'),
|
|
38
|
-
view: (view) => {
|
|
39
|
-
getTarget = buildGetTarget(view, options.onDrag)
|
|
40
|
-
return createDropIndicatorView(view, getTarget, options)
|
|
41
|
-
},
|
|
42
|
-
props: {
|
|
43
|
-
handleDrop(view, event, slice, move): boolean {
|
|
44
|
-
if (!getTarget) return false
|
|
45
|
-
|
|
46
|
-
const target = getTarget([event.clientX, event.clientY], event)
|
|
47
|
-
|
|
48
|
-
if (!target) return false
|
|
49
|
-
|
|
50
|
-
event.preventDefault()
|
|
51
|
-
let insertPos = target[0]
|
|
52
|
-
|
|
53
|
-
let tr = view.state.tr
|
|
54
|
-
if (move) {
|
|
55
|
-
let { node } = (view.dragging as ViewDragging | null) || {}
|
|
56
|
-
if (node) node.replace(tr)
|
|
57
|
-
else tr.deleteSelection()
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let pos = tr.mapping.map(insertPos)
|
|
61
|
-
let isNode = slice.openStart == 0 && slice.openEnd == 0 && slice.content.childCount == 1
|
|
62
|
-
let beforeInsert = tr.doc
|
|
63
|
-
if (isNode) tr.replaceRangeWith(pos, pos, slice.content.firstChild!)
|
|
64
|
-
else tr.replaceRange(pos, pos, slice)
|
|
65
|
-
if (tr.doc.eq(beforeInsert)) {
|
|
66
|
-
return true
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let $pos = tr.doc.resolve(pos)
|
|
70
|
-
if (
|
|
71
|
-
isNode && NodeSelection.isSelectable(slice.content.firstChild!)
|
|
72
|
-
&& $pos.nodeAfter && $pos.nodeAfter.sameMarkup(slice.content.firstChild!)
|
|
73
|
-
) {
|
|
74
|
-
tr.setSelection(new NodeSelection($pos))
|
|
75
|
-
} else {
|
|
76
|
-
let end = tr.mapping.map(insertPos)
|
|
77
|
-
tr.mapping.maps[tr.mapping.maps.length - 1].forEach((_from, _to, _newFrom, newTo) => end = newTo)
|
|
78
|
-
tr.setSelection(selectionBetween(view, $pos, tr.doc.resolve(end)))
|
|
79
|
-
}
|
|
80
|
-
view.focus()
|
|
81
|
-
view.dispatch(tr.setMeta('uiEvent', 'drop'))
|
|
82
|
-
return true
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
})
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function selectionBetween(view: EditorView, $anchor: ResolvedPos, $head: ResolvedPos, bias?: number) {
|
|
89
|
-
return view.someProp('createSelectionBetween', f => f(view, $anchor, $head))
|
|
90
|
-
|| TextSelection.between($anchor, $head, bias)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function createDropIndicatorView(view: EditorView, getTarget: GetTarget, options: DropIndicatorPluginOptions): PluginView {
|
|
94
|
-
let dom = view.dom
|
|
95
|
-
let hideId: ReturnType<typeof setTimeout> | undefined
|
|
96
|
-
let prevX: number | undefined
|
|
97
|
-
let prevY: number | undefined
|
|
98
|
-
let hasDragOverEvent: boolean = false
|
|
99
|
-
|
|
100
|
-
const scheduleHide = () => {
|
|
101
|
-
if (hideId) {
|
|
102
|
-
clearTimeout(hideId)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
hasDragOverEvent = false
|
|
106
|
-
hideId = setTimeout(() => {
|
|
107
|
-
if (hasDragOverEvent) return
|
|
108
|
-
options.onHide()
|
|
109
|
-
}, 30)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const handleDragOver = (event: DragEvent): void => {
|
|
113
|
-
hasDragOverEvent = true
|
|
114
|
-
|
|
115
|
-
const { clientX, clientY } = event
|
|
116
|
-
if (prevX === clientX && prevY === clientY) {
|
|
117
|
-
return
|
|
118
|
-
}
|
|
119
|
-
prevX = clientX
|
|
120
|
-
prevY = clientY
|
|
121
|
-
|
|
122
|
-
let target = getTarget([clientX, clientY], event)
|
|
123
|
-
|
|
124
|
-
if (!target) {
|
|
125
|
-
scheduleHide()
|
|
126
|
-
return
|
|
127
|
-
} else {
|
|
128
|
-
const [pos, [x1, y1, x2, y2]] = target
|
|
129
|
-
const line = { p1: { x: x1, y: y1 }, p2: { x: x2, y: y2 } }
|
|
130
|
-
options.onShow({ view, pos, line })
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
dom.addEventListener('dragover', handleDragOver)
|
|
135
|
-
dom.addEventListener('dragend', scheduleHide)
|
|
136
|
-
dom.addEventListener('drop', scheduleHide)
|
|
137
|
-
dom.addEventListener('dragleave', scheduleHide)
|
|
138
|
-
|
|
139
|
-
const destroy = () => {
|
|
140
|
-
dom.removeEventListener('dragover', handleDragOver)
|
|
141
|
-
dom.removeEventListener('dragend', scheduleHide)
|
|
142
|
-
dom.removeEventListener('drop', scheduleHide)
|
|
143
|
-
dom.removeEventListener('dragleave', scheduleHide)
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return { destroy }
|
|
147
|
-
}
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import { isHTMLElement } from '@ocavue/utils'
|
|
2
|
-
import { isNodeSelection } from '@prosekit/core'
|
|
3
|
-
import type { ProseMirrorNode } from '@prosekit/pm/model'
|
|
4
|
-
import type { EditorView } from '@prosekit/pm/view'
|
|
5
|
-
|
|
6
|
-
import type { DragEventHandler } from './types'
|
|
7
|
-
|
|
8
|
-
type Point = readonly [x: number, y: number]
|
|
9
|
-
|
|
10
|
-
type Line = readonly [x1: number, y1: number, x2: number, y2: number]
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @internal
|
|
14
|
-
*/
|
|
15
|
-
type DropTarget = readonly [pos: number, line: Line]
|
|
16
|
-
|
|
17
|
-
function getTargetsByView(view: EditorView): DropTarget[] {
|
|
18
|
-
type StackItem = [pos: number, node: ProseMirrorNode]
|
|
19
|
-
let stack: StackItem[] = [[-1, view.state.doc]]
|
|
20
|
-
let targets: DropTarget[] = []
|
|
21
|
-
|
|
22
|
-
while (stack.length > 0) {
|
|
23
|
-
const [pos, node] = stack.pop()!
|
|
24
|
-
if (pos >= 0) {
|
|
25
|
-
let dom = view.nodeDOM(pos)
|
|
26
|
-
if (dom && isHTMLElement(dom)) {
|
|
27
|
-
let rect = dom.getBoundingClientRect()
|
|
28
|
-
let { top, bottom, left: x1, right: x2 } = rect
|
|
29
|
-
targets.push(
|
|
30
|
-
[pos, [x1, top, x2, top]],
|
|
31
|
-
[pos + node.nodeSize, [x1, bottom, x2, bottom]],
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
if (node.isBlock && !node.isTextblock) {
|
|
36
|
-
let childPos = pos + 1
|
|
37
|
-
for (let child of node.children) {
|
|
38
|
-
stack.push([childPos, child])
|
|
39
|
-
childPos += child.nodeSize
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return targets
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* @internal
|
|
49
|
-
*/
|
|
50
|
-
export type GetTarget = (point: Point, event: DragEvent) => DropTarget | undefined
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* @internal
|
|
54
|
-
*/
|
|
55
|
-
export function buildGetTarget(
|
|
56
|
-
view: EditorView,
|
|
57
|
-
onDrag: DragEventHandler,
|
|
58
|
-
): GetTarget {
|
|
59
|
-
let prevTargets: DropTarget[] = []
|
|
60
|
-
let prevDoc: ProseMirrorNode | undefined
|
|
61
|
-
let prevRect: DOMRect | undefined
|
|
62
|
-
|
|
63
|
-
const getTargets = (): DropTarget[] => {
|
|
64
|
-
const rect = view.dom.getBoundingClientRect()
|
|
65
|
-
const doc = view.state.doc
|
|
66
|
-
|
|
67
|
-
if (
|
|
68
|
-
prevTargets && prevDoc && prevRect
|
|
69
|
-
&& rect.width === prevRect.width
|
|
70
|
-
&& rect.height === prevRect.height
|
|
71
|
-
&& rect.x === prevRect.x
|
|
72
|
-
&& rect.y === prevRect.y
|
|
73
|
-
&& prevDoc.eq(doc)
|
|
74
|
-
) {
|
|
75
|
-
return prevTargets
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
prevRect = rect
|
|
79
|
-
prevDoc = doc
|
|
80
|
-
prevTargets = getTargetsByView(view)
|
|
81
|
-
return prevTargets
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const getTargetImpl: GetTarget = (point, event) => {
|
|
85
|
-
if (!view.editable || view.isDestroyed) {
|
|
86
|
-
return
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const compare = (p1: DropTarget, p2: DropTarget): number => {
|
|
90
|
-
const [pos1, line1] = p1
|
|
91
|
-
const [pos2, line2] = p2
|
|
92
|
-
const p1Distance = pointLineDistance(point, line1)
|
|
93
|
-
const p2Distance = pointLineDistance(point, line2)
|
|
94
|
-
|
|
95
|
-
return (p1Distance - p2Distance) || (pos1 - pos2)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
let targets = getTargets()
|
|
99
|
-
targets.sort(compare)
|
|
100
|
-
|
|
101
|
-
// Only consider the first few targets for performance reasons.
|
|
102
|
-
targets = targets.slice(0, 8)
|
|
103
|
-
|
|
104
|
-
// Find the closest valid target.
|
|
105
|
-
const target = targets.find(target => onDrag({ view, pos: target[0], event }) !== false)
|
|
106
|
-
|
|
107
|
-
// If the dragging node is already at the target position, we ignore this
|
|
108
|
-
// target. Notice that we don't pick the second better target here.
|
|
109
|
-
if (target && isDraggingToItself(view, target[0])) {
|
|
110
|
-
return undefined
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return target
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
let prevPoint: Point | undefined
|
|
117
|
-
let prevTarget: DropTarget | undefined
|
|
118
|
-
|
|
119
|
-
const getTargetCached: GetTarget = (point, event) => {
|
|
120
|
-
if (prevPoint && pointEqual(prevPoint, point)) {
|
|
121
|
-
return prevTarget
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
prevPoint = point
|
|
125
|
-
prevTarget = getTargetImpl(point, event)
|
|
126
|
-
return prevTarget
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return getTargetCached
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function pointEqual(a: Point, b: Point) {
|
|
133
|
-
return a[0] === b[0] && a[1] === b[1]
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function pointPointDistance(a: Point, b: Point) {
|
|
137
|
-
// Manhattan distance
|
|
138
|
-
return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1])
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function pointLineDistance(point: Point, line: Line) {
|
|
142
|
-
// Notice that we are actually not calculating the distance between the point
|
|
143
|
-
// and the line. Instead, we are calculating the distance between the point
|
|
144
|
-
// and the two endpoints of the line.
|
|
145
|
-
return Math.min(
|
|
146
|
-
pointPointDistance(point, [line[0], line[1]]),
|
|
147
|
-
pointPointDistance(point, [line[2], line[3]]),
|
|
148
|
-
)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Whether the dragging node is being dragged to the same position. For example,
|
|
153
|
-
* dragging a list node into a new position that is just below the list node, or
|
|
154
|
-
* dragging a nested quoteblock into itself.
|
|
155
|
-
*/
|
|
156
|
-
function isDraggingToItself(view: EditorView, pos: number) {
|
|
157
|
-
const dragging = view.dragging
|
|
158
|
-
if (!dragging) return
|
|
159
|
-
|
|
160
|
-
const { move } = dragging
|
|
161
|
-
if (!move) return
|
|
162
|
-
|
|
163
|
-
const selection = view.state.selection
|
|
164
|
-
if (!isNodeSelection(selection)) return
|
|
165
|
-
|
|
166
|
-
const { from, to } = selection
|
|
167
|
-
return from <= pos && pos <= to
|
|
168
|
-
}
|