@prosekit/web 0.5.7 → 0.5.9
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/get-default-state-CIEy7xrl.js +11 -0
- package/dist/prosekit-web-autocomplete.d.ts +126 -20
- package/dist/prosekit-web-autocomplete.js +243 -349
- package/dist/prosekit-web-block-handle.d.ts +82 -15
- package/dist/prosekit-web-block-handle.js +422 -394
- package/dist/prosekit-web-inline-popover.d.ts +81 -5
- package/dist/prosekit-web-inline-popover.js +114 -155
- package/dist/prosekit-web-popover.d.ts +28 -15
- package/dist/prosekit-web-popover.js +31 -70
- package/dist/prosekit-web-resizable.d.ts +48 -10
- package/dist/prosekit-web-resizable.js +210 -238
- package/dist/prosekit-web-table-handle.d.ts +151 -35
- package/dist/prosekit-web-table-handle.js +364 -491
- package/dist/prosekit-web-tooltip.d.ts +28 -15
- package/dist/prosekit-web-tooltip.js +31 -70
- package/dist/prosekit-web.d.ts +1 -1
- package/dist/use-editor-extension-Cc7ZG7uj.js +11 -0
- package/package.json +29 -14
- package/dist/_tsup-dts-rollup.d.ts +0 -1100
- package/dist/chunk-WTW6FOH3.js +0 -13
- package/dist/chunk-ZGQ225UP.js +0 -17
|
@@ -1,453 +1,481 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
} from "
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
useEventListener
|
|
11
|
-
} from "@aria-ui/core";
|
|
12
|
-
import { insertDefaultBlock } from "@prosekit/core";
|
|
1
|
+
import { useEditorExtension } from "./use-editor-extension-Cc7ZG7uj.js";
|
|
2
|
+
import { createContext, createSignal, defineCustomElement, registerCustomElement, useAttribute, useEffect, useEventListener } from "@aria-ui/core";
|
|
3
|
+
import { defineDOMEventHandler, insertDefaultBlock, union } from "@prosekit/core";
|
|
4
|
+
import { overlayPositionerProps, useOverlayPositionerState } from "@aria-ui/overlay/elements";
|
|
5
|
+
import { usePresence } from "@aria-ui/presence";
|
|
6
|
+
import { isElement, isHTMLElement, isTextNode } from "@ocavue/utils";
|
|
7
|
+
import { Fragment, Slice } from "@prosekit/pm/model";
|
|
8
|
+
import { NodeSelection } from "@prosekit/pm/state";
|
|
13
9
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
);
|
|
10
|
+
//#region src/components/block-handle/context.ts
|
|
11
|
+
/**
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
const blockPopoverContext = createContext("prosekit-block-popover-context", null);
|
|
20
15
|
|
|
21
|
-
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/components/block-handle/block-handle-add/setup.ts
|
|
22
18
|
function useBlockHandleAdd(host, { state }) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
context.set(null);
|
|
35
|
-
});
|
|
19
|
+
const context = blockPopoverContext.consume(host);
|
|
20
|
+
useEventListener(host, "pointerdown", (event) => {
|
|
21
|
+
event.preventDefault();
|
|
22
|
+
const editor = state.editor.get();
|
|
23
|
+
const hoverState = context.get();
|
|
24
|
+
if (!editor || !hoverState) return;
|
|
25
|
+
const { node, pos } = hoverState;
|
|
26
|
+
editor.exec(insertDefaultBlock({ pos: pos + node.nodeSize }));
|
|
27
|
+
editor.focus();
|
|
28
|
+
context.set(null);
|
|
29
|
+
});
|
|
36
30
|
}
|
|
37
31
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
};
|
|
42
|
-
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/components/block-handle/block-handle-add/types.ts
|
|
34
|
+
/** @internal */
|
|
35
|
+
const blockHandleAddProps = { editor: { default: null } };
|
|
36
|
+
/** @internal */
|
|
37
|
+
const blockHandleAddEvents = {};
|
|
43
38
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
};
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/components/block-handle/block-handle-add/element.gen.ts
|
|
41
|
+
const BlockHandleAddElementBase = defineCustomElement({
|
|
42
|
+
props: blockHandleAddProps,
|
|
43
|
+
events: blockHandleAddEvents,
|
|
44
|
+
setup: useBlockHandleAdd
|
|
45
|
+
});
|
|
46
|
+
var BlockHandleAddElement = class extends BlockHandleAddElementBase {};
|
|
51
47
|
registerCustomElement("prosekit-block-handle-add", BlockHandleAddElement);
|
|
52
48
|
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/utils/asset-styles.ts
|
|
51
|
+
function assignStyles(element, styles) {
|
|
52
|
+
Object.assign(element.style, styles);
|
|
53
|
+
}
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/utils/max-z-index.ts
|
|
57
|
+
const maxZIndex = "2147483647";
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/components/block-handle/block-handle-draggable/deep-clone-element.ts
|
|
61
|
+
/**
|
|
62
|
+
* Creates a deep clone of an Element, including all computed styles so that
|
|
63
|
+
* it looks the same as the original element.
|
|
64
|
+
*/
|
|
65
|
+
function deepCloneElement(element) {
|
|
66
|
+
const clonedElement = element.cloneNode(true);
|
|
67
|
+
deepCopyStyles(element, clonedElement);
|
|
68
|
+
return clonedElement;
|
|
69
|
+
}
|
|
70
|
+
function deepCopyStyles(source, target) {
|
|
71
|
+
const sources = [source];
|
|
72
|
+
const targets = [target];
|
|
73
|
+
while (sources.length > 0 && sources.length === targets.length) {
|
|
74
|
+
const source$1 = sources.pop();
|
|
75
|
+
const target$1 = targets.pop();
|
|
76
|
+
if (!source$1 || !target$1) return;
|
|
77
|
+
copyStyles(source$1, target$1);
|
|
78
|
+
sources.push(...source$1.children);
|
|
79
|
+
targets.push(...target$1.children);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function copyStyles(source, target) {
|
|
83
|
+
const sourceStyle = source.ownerDocument?.defaultView?.getComputedStyle(source);
|
|
84
|
+
const targetStyle = target.style;
|
|
85
|
+
if (!sourceStyle || !targetStyle) return;
|
|
86
|
+
for (const key of sourceStyle) targetStyle.setProperty(key, sourceStyle.getPropertyValue(key), sourceStyle.getPropertyPriority(key));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/components/block-handle/block-handle-draggable/set-drag-preview.ts
|
|
91
|
+
/**
|
|
92
|
+
* Sets a drag preview image for the given element and ensures the preview position
|
|
93
|
+
* relative to the pointer is correct.
|
|
94
|
+
*
|
|
95
|
+
* This function does the following:
|
|
96
|
+
*
|
|
97
|
+
* - Creates a temporary container element.
|
|
98
|
+
* - Puts the container at the end of the document body.
|
|
99
|
+
* - Sets event's drag image.
|
|
100
|
+
* - Removes the container from the document body after the next frame.
|
|
101
|
+
*/
|
|
102
|
+
function setDragPreview(event, element) {
|
|
103
|
+
const rect = element.getBoundingClientRect();
|
|
104
|
+
const { width, height, x: elementX, y: elementY } = rect;
|
|
105
|
+
const { clientX, clientY } = event;
|
|
106
|
+
const document = element.ownerDocument;
|
|
107
|
+
const container = document.createElement("div");
|
|
108
|
+
const outsideX = Math.round(elementX - clientX);
|
|
109
|
+
const outsideY = Math.round(elementY - clientY);
|
|
110
|
+
const borderX = Math.max(outsideX, 0);
|
|
111
|
+
const borderY = Math.max(outsideY, 0);
|
|
112
|
+
assignStyles(container, {
|
|
113
|
+
position: "fixed",
|
|
114
|
+
top: "0",
|
|
115
|
+
left: "0",
|
|
116
|
+
zIndex: maxZIndex,
|
|
117
|
+
borderLeft: `${borderX}px solid transparent`,
|
|
118
|
+
borderTop: `${borderY}px solid transparent`,
|
|
119
|
+
boxSizing: "border-box",
|
|
120
|
+
width: `${width + borderX}px`,
|
|
121
|
+
height: `${height + borderY}px`
|
|
122
|
+
});
|
|
123
|
+
const clonedElement = deepCloneElement(element);
|
|
124
|
+
assignStyles(clonedElement, {
|
|
125
|
+
outline: "none",
|
|
126
|
+
opacity: "0.5"
|
|
127
|
+
});
|
|
128
|
+
document.body.appendChild(container);
|
|
129
|
+
container.appendChild(clonedElement);
|
|
130
|
+
event.dataTransfer?.setDragImage(container, Math.max(-outsideX, 0), Math.max(-outsideY, 0));
|
|
131
|
+
requestAnimationFrame(() => {
|
|
132
|
+
container.remove();
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region src/components/block-handle/block-handle-draggable/setup.ts
|
|
68
138
|
function useBlockHandleDraggable(host, { state }) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
139
|
+
const context = blockPopoverContext.consume(host);
|
|
140
|
+
useEffect(host, () => {
|
|
141
|
+
host.draggable = true;
|
|
142
|
+
});
|
|
143
|
+
usePointerDownHandler(host, context, state.editor);
|
|
144
|
+
useDraggingPreview(host, context, state.editor);
|
|
145
|
+
useDataDraggingAttribute(host);
|
|
76
146
|
}
|
|
77
147
|
function usePointerDownHandler(host, context, editor) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
requestAnimationFrame(() => {
|
|
88
|
-
view.focus();
|
|
89
|
-
});
|
|
90
|
-
});
|
|
148
|
+
useEventListener(host, "pointerdown", () => {
|
|
149
|
+
const { pos } = context.get() ?? {};
|
|
150
|
+
const { view } = editor.get() ?? {};
|
|
151
|
+
if (pos == null || view == null) return;
|
|
152
|
+
view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, pos)));
|
|
153
|
+
requestAnimationFrame(() => {
|
|
154
|
+
view.focus();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
91
157
|
}
|
|
92
158
|
function useDraggingPreview(host, context, editor) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
159
|
+
useEventListener(host, "dragstart", (event) => {
|
|
160
|
+
const hoverState = context.get();
|
|
161
|
+
const { view } = editor.get() ?? {};
|
|
162
|
+
if (!hoverState || !view || !event.dataTransfer) return;
|
|
163
|
+
const { node, pos } = hoverState;
|
|
164
|
+
const element = view.nodeDOM(pos);
|
|
165
|
+
if (!element || !isHTMLElement(element)) return;
|
|
166
|
+
event.dataTransfer.clearData();
|
|
167
|
+
event.dataTransfer.setData("text/html", element.outerHTML);
|
|
168
|
+
event.dataTransfer.effectAllowed = "copyMove";
|
|
169
|
+
setDragPreview(event, element);
|
|
170
|
+
const dragging = {
|
|
171
|
+
slice: new Slice(Fragment.from(node), 0, 0),
|
|
172
|
+
move: true,
|
|
173
|
+
node: NodeSelection.create(view.state.doc, pos)
|
|
174
|
+
};
|
|
175
|
+
view.dragging = dragging;
|
|
176
|
+
});
|
|
111
177
|
}
|
|
112
178
|
function useDataDraggingAttribute(host) {
|
|
113
|
-
|
|
114
|
-
|
|
179
|
+
const dragging = useDragging(host);
|
|
180
|
+
useAttribute(host, "data-dragging", () => dragging.get() ? "" : void 0);
|
|
115
181
|
}
|
|
116
182
|
function useDragging(host) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
183
|
+
const dragging = createSignal(false);
|
|
184
|
+
useEventListener(host, "dragstart", () => {
|
|
185
|
+
dragging.set(true);
|
|
186
|
+
});
|
|
187
|
+
useEventListener(host, "dragend", () => {
|
|
188
|
+
dragging.set(false);
|
|
189
|
+
});
|
|
190
|
+
return dragging;
|
|
125
191
|
}
|
|
126
192
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
// src/components/block-handle/block-handle-draggable/element.gen.ts
|
|
134
|
-
var BlockHandleDraggableElement = class extends defineCustomElement2({
|
|
135
|
-
props: blockHandleDraggableProps,
|
|
136
|
-
events: blockHandleDraggableEvents,
|
|
137
|
-
setup: useBlockHandleDraggable
|
|
138
|
-
}) {
|
|
139
|
-
};
|
|
140
|
-
registerCustomElement2("prosekit-block-handle-draggable", BlockHandleDraggableElement);
|
|
141
|
-
|
|
142
|
-
// src/components/block-handle/block-handle-popover/element.gen.ts
|
|
143
|
-
import { defineCustomElement as defineCustomElement3, registerCustomElement as registerCustomElement3 } from "@aria-ui/core";
|
|
144
|
-
|
|
145
|
-
// src/components/block-handle/block-handle-popover/setup.ts
|
|
146
|
-
import {
|
|
147
|
-
createSignal as createSignal2,
|
|
148
|
-
useAttribute as useAttribute2,
|
|
149
|
-
useEffect as useEffect2
|
|
150
|
-
} from "@aria-ui/core";
|
|
151
|
-
import { useOverlayPositionerState } from "@aria-ui/overlay/elements";
|
|
152
|
-
import { usePresence } from "@aria-ui/presence";
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region src/components/block-handle/block-handle-draggable/types.ts
|
|
195
|
+
/** @internal */
|
|
196
|
+
const blockHandleDraggableProps = { editor: { default: null } };
|
|
197
|
+
/** @internal */
|
|
198
|
+
const blockHandleDraggableEvents = {};
|
|
153
199
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
200
|
+
//#endregion
|
|
201
|
+
//#region src/components/block-handle/block-handle-draggable/element.gen.ts
|
|
202
|
+
const BlockHandleDraggableElementBase = defineCustomElement({
|
|
203
|
+
props: blockHandleDraggableProps,
|
|
204
|
+
events: blockHandleDraggableEvents,
|
|
205
|
+
setup: useBlockHandleDraggable
|
|
206
|
+
});
|
|
207
|
+
var BlockHandleDraggableElement = class extends BlockHandleDraggableElementBase {};
|
|
208
|
+
registerCustomElement("prosekit-block-handle-draggable", BlockHandleDraggableElement);
|
|
159
209
|
|
|
160
|
-
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/utils/get-client-rect.ts
|
|
212
|
+
/**
|
|
213
|
+
* Similar to `element.getBoundingClientRect`, but handles `display: contents` elements.
|
|
214
|
+
*/
|
|
161
215
|
function getClientRect(element) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return rect;
|
|
216
|
+
const rect = element.getBoundingClientRect();
|
|
217
|
+
if (rect.width === 0 && rect.height === 0 && rect.x === 0 && rect.y === 0) {
|
|
218
|
+
if (element.getClientRects().length === 0) {
|
|
219
|
+
const children = Array.from(element.children);
|
|
220
|
+
const rects = children.map((child) => getClientRect(child)).filter((x) => !!x);
|
|
221
|
+
if (rects.length === 0) return rect;
|
|
222
|
+
if (rects.length === 1) return rects[0];
|
|
223
|
+
return {
|
|
224
|
+
top: Math.min(...rects.map((rect$1) => rect$1.top)),
|
|
225
|
+
right: Math.max(...rects.map((rect$1) => rect$1.right)),
|
|
226
|
+
bottom: Math.max(...rects.map((rect$1) => rect$1.bottom)),
|
|
227
|
+
left: Math.min(...rects.map((rect$1) => rect$1.left))
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return rect;
|
|
182
232
|
}
|
|
183
233
|
|
|
184
|
-
|
|
234
|
+
//#endregion
|
|
235
|
+
//#region src/utils/throttle.ts
|
|
236
|
+
/**
|
|
237
|
+
* @internal
|
|
238
|
+
*/
|
|
185
239
|
function throttle(callback, wait) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
240
|
+
let lastTime = 0;
|
|
241
|
+
return (...args) => {
|
|
242
|
+
const now = Date.now();
|
|
243
|
+
if (now - lastTime >= wait) {
|
|
244
|
+
callback(...args);
|
|
245
|
+
lastTime = now;
|
|
246
|
+
}
|
|
247
|
+
};
|
|
194
248
|
}
|
|
195
249
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
var ELEMENT_NODE = 1;
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/components/block-handle/block-handle-popover/pointer-move.ts
|
|
199
252
|
function defineElementHoverHandler(handler) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
function getElementAtPos(view, pos) {
|
|
238
|
-
const node = view.nodeDOM(pos);
|
|
239
|
-
if (node && node.nodeType === ELEMENT_NODE) {
|
|
240
|
-
return node;
|
|
241
|
-
}
|
|
253
|
+
const handleElement = (node, pos, element, parentElement) => {
|
|
254
|
+
const reference = {
|
|
255
|
+
contextElement: element,
|
|
256
|
+
getBoundingClientRect: () => {
|
|
257
|
+
const rect = findFirstLineRect(parentElement, element);
|
|
258
|
+
return rect ? fulfillRect(rect) : fallbackRect;
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
handler(reference, {
|
|
262
|
+
node,
|
|
263
|
+
pos
|
|
264
|
+
});
|
|
265
|
+
};
|
|
266
|
+
const handlePointerEvent = (view, event) => {
|
|
267
|
+
const { x, y } = event;
|
|
268
|
+
const block = findBlockByCoordinate(view, x, y);
|
|
269
|
+
if (!block) {
|
|
270
|
+
handler(null, null);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const { node, pos } = block;
|
|
274
|
+
const element = view.nodeDOM(pos);
|
|
275
|
+
if (!element || !isHTMLElement(element)) {
|
|
276
|
+
handler(null, null);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const $pos = view.state.doc.resolve(pos);
|
|
280
|
+
if ($pos.depth > 0 && $pos.index($pos.depth) === 0) {
|
|
281
|
+
const parentPos = $pos.before($pos.depth);
|
|
282
|
+
const parentNode = $pos.parent;
|
|
283
|
+
const parentElement = view.nodeDOM(parentPos);
|
|
284
|
+
handleElement(parentNode, parentPos, element, parentElement);
|
|
285
|
+
} else handleElement(node, pos, element);
|
|
286
|
+
};
|
|
287
|
+
return union(defineDOMEventHandler("pointermove", throttle(handlePointerEvent, 200)), defineDOMEventHandler("pointerout", handlePointerEvent), defineDOMEventHandler("keypress", () => handler(null, null)));
|
|
242
288
|
}
|
|
243
289
|
function findBlockByCoordinate(view, x, y) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
parent = children[lo];
|
|
284
|
-
pos = positions[lo];
|
|
285
|
-
}
|
|
290
|
+
const dom = view.dom;
|
|
291
|
+
const rect = getClientRect(dom);
|
|
292
|
+
if (!isWithinRect(rect, x, y)) return;
|
|
293
|
+
let parent = view.state.doc;
|
|
294
|
+
let pos = -1;
|
|
295
|
+
while (parent) {
|
|
296
|
+
if (parent.isBlock && (parent.isTextblock || parent.isAtom || parent.type.spec.isolating)) return {
|
|
297
|
+
node: parent,
|
|
298
|
+
pos
|
|
299
|
+
};
|
|
300
|
+
const children = [];
|
|
301
|
+
const positions = [];
|
|
302
|
+
parent.forEach((child, offset) => {
|
|
303
|
+
children.push(child);
|
|
304
|
+
positions.push(offset + pos + 1);
|
|
305
|
+
});
|
|
306
|
+
let lo = 0;
|
|
307
|
+
let hi = children.length - 1;
|
|
308
|
+
while (lo <= hi) {
|
|
309
|
+
const i = hi - (hi - lo >> 1);
|
|
310
|
+
const childDOM = view.nodeDOM(positions[i]);
|
|
311
|
+
const childRect = getNodeRect(childDOM);
|
|
312
|
+
if (!childRect) {
|
|
313
|
+
console.warn("[prosekit] Unable to get rect at position", positions[i]);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
if (childRect.top > y) hi = i - 1;
|
|
317
|
+
else if (childRect.bottom < y) lo = i + 1;
|
|
318
|
+
else {
|
|
319
|
+
lo = i;
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (lo > hi) return;
|
|
324
|
+
parent = children[lo];
|
|
325
|
+
pos = positions[lo];
|
|
326
|
+
}
|
|
286
327
|
}
|
|
287
328
|
function getNodeRect(node) {
|
|
288
|
-
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
const element = node;
|
|
292
|
-
if (!element.isConnected) {
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
return getClientRect(element);
|
|
329
|
+
if (node && isElement(node) && node.isConnected) return getClientRect(node);
|
|
296
330
|
}
|
|
297
331
|
function isWithinRect(rect, x, y) {
|
|
298
|
-
|
|
332
|
+
return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
|
|
299
333
|
}
|
|
300
334
|
function findFirstLineRect(outer, inner) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
return findFirstLineRectInNode(outer);
|
|
319
|
-
} else if (inner) {
|
|
320
|
-
return findFirstLineRectInNode(inner);
|
|
321
|
-
}
|
|
335
|
+
if (outer && !outer.isConnected) return;
|
|
336
|
+
if (inner && !inner.isConnected) return;
|
|
337
|
+
if (outer && inner) {
|
|
338
|
+
const outerRect = findOuterRect(outer);
|
|
339
|
+
const innerRect = findFirstLineRectInNode(inner);
|
|
340
|
+
if (outerRect && innerRect) {
|
|
341
|
+
const { top, bottom } = innerRect;
|
|
342
|
+
const { left, right } = outerRect;
|
|
343
|
+
return {
|
|
344
|
+
top,
|
|
345
|
+
bottom,
|
|
346
|
+
left,
|
|
347
|
+
right
|
|
348
|
+
};
|
|
349
|
+
} else return outerRect || innerRect;
|
|
350
|
+
} else if (outer) return findFirstLineRectInNode(outer);
|
|
351
|
+
else if (inner) return findFirstLineRectInNode(inner);
|
|
322
352
|
}
|
|
323
353
|
function findOuterRect(node) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
354
|
+
if (!isElement(node)) return;
|
|
355
|
+
const rect = getClientRect(node);
|
|
356
|
+
const style = node.ownerDocument.defaultView?.getComputedStyle(node);
|
|
357
|
+
const marginLeft = style && Number.parseInt(style.marginLeft, 10) || 0;
|
|
358
|
+
const marginRight = style && Number.parseInt(style.marginRight, 10) || 0;
|
|
359
|
+
const left = rect.left - marginLeft;
|
|
360
|
+
const right = rect.right + marginRight;
|
|
361
|
+
return {
|
|
362
|
+
top: rect.top,
|
|
363
|
+
bottom: rect.bottom,
|
|
364
|
+
left,
|
|
365
|
+
right
|
|
366
|
+
};
|
|
335
367
|
}
|
|
336
368
|
function findFirstLineRectInNode(node) {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
return findFirstLineRectInTextNode(node);
|
|
340
|
-
case ELEMENT_NODE:
|
|
341
|
-
return findFirstLineRectInElement(node);
|
|
342
|
-
}
|
|
369
|
+
if (isElement(node)) return findFirstLineRectInElement(node);
|
|
370
|
+
else if (isTextNode(node)) return findFirstLineRectInTextNode(node);
|
|
343
371
|
}
|
|
344
372
|
function findFirstLineRectInTextNode(node) {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const rects = range.getClientRects();
|
|
353
|
-
return rects[0];
|
|
373
|
+
const ownerDocument = node.ownerDocument;
|
|
374
|
+
if (!ownerDocument) return;
|
|
375
|
+
const range = ownerDocument.createRange();
|
|
376
|
+
range.setStart(node, 0);
|
|
377
|
+
range.setEnd(node, 0);
|
|
378
|
+
const rects = range.getClientRects();
|
|
379
|
+
return rects[0];
|
|
354
380
|
}
|
|
355
381
|
function findFirstLineRectInElement(element) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
382
|
+
if (element.nodeName === "BR") return element.getBoundingClientRect();
|
|
383
|
+
const rect = getClientRect(element);
|
|
384
|
+
const style = element.ownerDocument.defaultView?.getComputedStyle(element);
|
|
385
|
+
const marginLeft = style && Number.parseInt(style.marginLeft, 10) || 0;
|
|
386
|
+
const marginRight = style && Number.parseInt(style.marginRight, 10) || 0;
|
|
387
|
+
const left = rect.left - marginLeft;
|
|
388
|
+
const right = rect.right + marginRight;
|
|
389
|
+
const lineHeight = style && Number.parseInt(style.lineHeight, 10) || 24;
|
|
390
|
+
const paddingTop = style && Number.parseInt(style.paddingTop, 10) || 0;
|
|
391
|
+
const borderTop = style && Number.parseInt(style.borderTopWidth, 10) || 0;
|
|
392
|
+
const top = rect.top + paddingTop + borderTop;
|
|
393
|
+
const bottom = top + lineHeight;
|
|
394
|
+
return {
|
|
395
|
+
top,
|
|
396
|
+
bottom,
|
|
397
|
+
left,
|
|
398
|
+
right
|
|
399
|
+
};
|
|
371
400
|
}
|
|
372
401
|
function fulfillRect({ top, right, bottom, left }) {
|
|
373
|
-
|
|
402
|
+
return {
|
|
403
|
+
top,
|
|
404
|
+
right,
|
|
405
|
+
bottom,
|
|
406
|
+
left,
|
|
407
|
+
width: right - left,
|
|
408
|
+
height: bottom - top,
|
|
409
|
+
x: left,
|
|
410
|
+
y: top
|
|
411
|
+
};
|
|
374
412
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
413
|
+
const fallbackRect = Object.freeze({
|
|
414
|
+
top: -9999,
|
|
415
|
+
right: -9999,
|
|
416
|
+
bottom: -9999,
|
|
417
|
+
left: -9999,
|
|
418
|
+
width: 0,
|
|
419
|
+
height: 0,
|
|
420
|
+
x: -9999,
|
|
421
|
+
y: -9999
|
|
384
422
|
});
|
|
385
423
|
|
|
386
|
-
|
|
424
|
+
//#endregion
|
|
425
|
+
//#region src/components/block-handle/block-handle-popover/setup.ts
|
|
387
426
|
function useBlockHandlePopover(host, { state }) {
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
427
|
+
const { editor,...overlayState } = state;
|
|
428
|
+
const reference = createSignal(null);
|
|
429
|
+
useOverlayPositionerState(host, overlayState, { reference });
|
|
430
|
+
const context = createSignal(null);
|
|
431
|
+
blockPopoverContext.provide(host, context);
|
|
432
|
+
const open = createSignal(false);
|
|
433
|
+
useEffect(host, () => {
|
|
434
|
+
open.set(!!context.get());
|
|
435
|
+
});
|
|
436
|
+
useHoverExtension(host, editor, (referenceValue, hoverState) => {
|
|
437
|
+
reference.set(referenceValue);
|
|
438
|
+
context.set(hoverState);
|
|
439
|
+
});
|
|
440
|
+
useAttribute(host, "data-state", () => open.get() ? "open" : "closed");
|
|
441
|
+
usePresence(host, open);
|
|
403
442
|
}
|
|
404
443
|
function useHoverExtension(host, editor, handler) {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
});
|
|
413
|
-
useEditorExtension(host, editor, extension);
|
|
444
|
+
let prevHoverState = null;
|
|
445
|
+
const extension = defineElementHoverHandler((reference, hoverState) => {
|
|
446
|
+
if (isHoverStateEqual(prevHoverState, hoverState)) return;
|
|
447
|
+
prevHoverState = hoverState;
|
|
448
|
+
handler(reference, hoverState);
|
|
449
|
+
});
|
|
450
|
+
useEditorExtension(host, editor, extension);
|
|
414
451
|
}
|
|
415
452
|
function isHoverStateEqual(a, b) {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
453
|
+
if (!a && !b) return true;
|
|
454
|
+
if (!a || !b) return false;
|
|
455
|
+
return a.pos === b.pos && a.node.eq(b.node);
|
|
419
456
|
}
|
|
420
457
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
// Enabling `hoist` will cause the block handle to have a small delay when
|
|
430
|
-
// scrolling the page.
|
|
431
|
-
hoist: { default: false }
|
|
458
|
+
//#endregion
|
|
459
|
+
//#region src/components/block-handle/block-handle-popover/types.ts
|
|
460
|
+
/** @internal */
|
|
461
|
+
const blockHandlePopoverProps = {
|
|
462
|
+
...overlayPositionerProps,
|
|
463
|
+
editor: { default: null },
|
|
464
|
+
placement: { default: "left" },
|
|
465
|
+
hoist: { default: false }
|
|
432
466
|
};
|
|
433
|
-
|
|
467
|
+
/** @internal */
|
|
468
|
+
const blockHandlePopoverEvents = {};
|
|
434
469
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
};
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
blockHandleAddEvents,
|
|
448
|
-
blockHandleAddProps,
|
|
449
|
-
blockHandleDraggableEvents,
|
|
450
|
-
blockHandleDraggableProps,
|
|
451
|
-
blockHandlePopoverEvents,
|
|
452
|
-
blockHandlePopoverProps
|
|
453
|
-
};
|
|
470
|
+
//#endregion
|
|
471
|
+
//#region src/components/block-handle/block-handle-popover/element.gen.ts
|
|
472
|
+
const BlockHandlePopoverElementBase = defineCustomElement({
|
|
473
|
+
props: blockHandlePopoverProps,
|
|
474
|
+
events: blockHandlePopoverEvents,
|
|
475
|
+
setup: useBlockHandlePopover
|
|
476
|
+
});
|
|
477
|
+
var BlockHandlePopoverElement = class extends BlockHandlePopoverElementBase {};
|
|
478
|
+
registerCustomElement("prosekit-block-handle-popover", BlockHandlePopoverElement);
|
|
479
|
+
|
|
480
|
+
//#endregion
|
|
481
|
+
export { BlockHandleAddElement, BlockHandleDraggableElement, BlockHandlePopoverElement, blockHandleAddEvents, blockHandleAddProps, blockHandleDraggableEvents, blockHandleDraggableProps, blockHandlePopoverEvents, blockHandlePopoverProps };
|