@prosekit/web 0.5.6 → 0.5.8
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 +135 -20
- package/dist/prosekit-web-autocomplete.js +240 -349
- package/dist/prosekit-web-block-handle.d.ts +88 -15
- package/dist/prosekit-web-block-handle.js +422 -392
- 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 +34 -15
- package/dist/prosekit-web-popover.js +31 -70
- package/dist/prosekit-web-resizable.d.ts +52 -10
- package/dist/prosekit-web-resizable.js +210 -238
- package/dist/prosekit-web-table-handle.d.ts +165 -35
- package/dist/prosekit-web-table-handle.js +364 -491
- package/dist/prosekit-web-tooltip.d.ts +34 -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 -22
- package/dist/_tsup-dts-rollup.d.ts +0 -1100
- package/dist/chunk-WTW6FOH3.js +0 -13
- package/dist/chunk-ZGQ225UP.js +0 -17
|
@@ -1,451 +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
|
-
|
|
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
|
+
});
|
|
109
177
|
}
|
|
110
178
|
function useDataDraggingAttribute(host) {
|
|
111
|
-
|
|
112
|
-
|
|
179
|
+
const dragging = useDragging(host);
|
|
180
|
+
useAttribute(host, "data-dragging", () => dragging.get() ? "" : void 0);
|
|
113
181
|
}
|
|
114
182
|
function useDragging(host) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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;
|
|
123
191
|
}
|
|
124
192
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
// src/components/block-handle/block-handle-draggable/element.gen.ts
|
|
132
|
-
var BlockHandleDraggableElement = class extends defineCustomElement2({
|
|
133
|
-
props: blockHandleDraggableProps,
|
|
134
|
-
events: blockHandleDraggableEvents,
|
|
135
|
-
setup: useBlockHandleDraggable
|
|
136
|
-
}) {
|
|
137
|
-
};
|
|
138
|
-
registerCustomElement2("prosekit-block-handle-draggable", BlockHandleDraggableElement);
|
|
139
|
-
|
|
140
|
-
// src/components/block-handle/block-handle-popover/element.gen.ts
|
|
141
|
-
import { defineCustomElement as defineCustomElement3, registerCustomElement as registerCustomElement3 } from "@aria-ui/core";
|
|
142
|
-
|
|
143
|
-
// src/components/block-handle/block-handle-popover/setup.ts
|
|
144
|
-
import {
|
|
145
|
-
createSignal as createSignal2,
|
|
146
|
-
useAttribute as useAttribute2,
|
|
147
|
-
useEffect as useEffect2
|
|
148
|
-
} from "@aria-ui/core";
|
|
149
|
-
import { useOverlayPositionerState } from "@aria-ui/overlay/elements";
|
|
150
|
-
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 = {};
|
|
151
199
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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);
|
|
157
209
|
|
|
158
|
-
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/utils/get-client-rect.ts
|
|
212
|
+
/**
|
|
213
|
+
* Similar to `element.getBoundingClientRect`, but handles `display: contents` elements.
|
|
214
|
+
*/
|
|
159
215
|
function getClientRect(element) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
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;
|
|
180
232
|
}
|
|
181
233
|
|
|
182
|
-
|
|
234
|
+
//#endregion
|
|
235
|
+
//#region src/utils/throttle.ts
|
|
236
|
+
/**
|
|
237
|
+
* @internal
|
|
238
|
+
*/
|
|
183
239
|
function throttle(callback, wait) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
+
};
|
|
192
248
|
}
|
|
193
249
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
var ELEMENT_NODE = 1;
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/components/block-handle/block-handle-popover/pointer-move.ts
|
|
197
252
|
function defineElementHoverHandler(handler) {
|
|
198
|
-
|
|
199
|
-
|
|
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
|
-
function getElementAtPos(view, pos) {
|
|
236
|
-
const node = view.nodeDOM(pos);
|
|
237
|
-
if (node && node.nodeType === ELEMENT_NODE) {
|
|
238
|
-
return node;
|
|
239
|
-
}
|
|
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)));
|
|
240
288
|
}
|
|
241
289
|
function findBlockByCoordinate(view, x, y) {
|
|
242
|
-
|
|
243
|
-
|
|
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
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
parent = children[lo];
|
|
282
|
-
pos = positions[lo];
|
|
283
|
-
}
|
|
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
|
+
}
|
|
284
327
|
}
|
|
285
328
|
function getNodeRect(node) {
|
|
286
|
-
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
const element = node;
|
|
290
|
-
if (!element.isConnected) {
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
return getClientRect(element);
|
|
329
|
+
if (node && isElement(node) && node.isConnected) return getClientRect(node);
|
|
294
330
|
}
|
|
295
331
|
function isWithinRect(rect, x, y) {
|
|
296
|
-
|
|
332
|
+
return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
|
|
297
333
|
}
|
|
298
334
|
function findFirstLineRect(outer, inner) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
return findFirstLineRectInNode(outer);
|
|
317
|
-
} else if (inner) {
|
|
318
|
-
return findFirstLineRectInNode(inner);
|
|
319
|
-
}
|
|
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);
|
|
320
352
|
}
|
|
321
353
|
function findOuterRect(node) {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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
|
+
};
|
|
333
367
|
}
|
|
334
368
|
function findFirstLineRectInNode(node) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
return findFirstLineRectInTextNode(node);
|
|
338
|
-
case ELEMENT_NODE:
|
|
339
|
-
return findFirstLineRectInElement(node);
|
|
340
|
-
}
|
|
369
|
+
if (isElement(node)) return findFirstLineRectInElement(node);
|
|
370
|
+
else if (isTextNode(node)) return findFirstLineRectInTextNode(node);
|
|
341
371
|
}
|
|
342
372
|
function findFirstLineRectInTextNode(node) {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const rects = range.getClientRects();
|
|
351
|
-
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];
|
|
352
380
|
}
|
|
353
381
|
function findFirstLineRectInElement(element) {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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
|
+
};
|
|
369
400
|
}
|
|
370
401
|
function fulfillRect({ top, right, bottom, left }) {
|
|
371
|
-
|
|
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
|
+
};
|
|
372
412
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
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
|
|
382
422
|
});
|
|
383
423
|
|
|
384
|
-
|
|
424
|
+
//#endregion
|
|
425
|
+
//#region src/components/block-handle/block-handle-popover/setup.ts
|
|
385
426
|
function useBlockHandlePopover(host, { state }) {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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);
|
|
401
442
|
}
|
|
402
443
|
function useHoverExtension(host, editor, handler) {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
});
|
|
411
|
-
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);
|
|
412
451
|
}
|
|
413
452
|
function isHoverStateEqual(a, b) {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
453
|
+
if (!a && !b) return true;
|
|
454
|
+
if (!a || !b) return false;
|
|
455
|
+
return a.pos === b.pos && a.node.eq(b.node);
|
|
417
456
|
}
|
|
418
457
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
// Enabling `hoist` will cause the block handle to have a small delay when
|
|
428
|
-
// scrolling the page.
|
|
429
|
-
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 }
|
|
430
466
|
};
|
|
431
|
-
|
|
467
|
+
/** @internal */
|
|
468
|
+
const blockHandlePopoverEvents = {};
|
|
432
469
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
};
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
blockHandleAddEvents,
|
|
446
|
-
blockHandleAddProps,
|
|
447
|
-
blockHandleDraggableEvents,
|
|
448
|
-
blockHandleDraggableProps,
|
|
449
|
-
blockHandlePopoverEvents,
|
|
450
|
-
blockHandlePopoverProps
|
|
451
|
-
};
|
|
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 };
|