@prosekit/web 0.5.11 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,4 +8,14 @@ function getStateWithDefaults(state, props) {
8
8
  }
9
9
 
10
10
  //#endregion
11
- export { getStateWithDefaults };
11
+ //#region src/utils/get-safe-editor-view.ts
12
+ /**
13
+ * @internal
14
+ */
15
+ function getSafeEditorView(editor) {
16
+ if (!editor || !editor.mounted) return;
17
+ return editor.view;
18
+ }
19
+
20
+ //#endregion
21
+ export { getSafeEditorView, getStateWithDefaults };
@@ -1,4 +1,4 @@
1
- import { getStateWithDefaults } from "./get-default-state-CIEy7xrl.js";
1
+ import { getSafeEditorView, getStateWithDefaults } from "./get-safe-editor-view-CqJWgxo1.js";
2
2
  import { useEditorExtension } from "./use-editor-extension-Cc7ZG7uj.js";
3
3
  import { createComputed, createContext, createSignal, defineCustomElement, registerCustomElement, useAnimationFrame, useAttribute, useEffect, useEventListener } from "@aria-ui/core";
4
4
  import { listboxProps, useListbox, useListboxEmpty, useListboxItem } from "@aria-ui/listbox/elements";
@@ -227,7 +227,8 @@ function useAutocompleteExtension(host, editor, regex, reference, query, onDismi
227
227
  }
228
228
  function createAutocompleteRule(editor, regex, reference, query, onDismiss, onSubmit) {
229
229
  const handleEnter = (options) => {
230
- const span = editor.view.dom.querySelector(".prosemirror-prediction-match");
230
+ const view = getSafeEditorView(editor);
231
+ const span = view?.dom.querySelector(".prosemirror-prediction-match");
231
232
  if (span) reference.set(span);
232
233
  query.set(defaultQueryBuilder(options.match));
233
234
  onDismiss.set(options.ignoreMatch);
@@ -1,6 +1,7 @@
1
- import { BaseElementConstructor, ConnectableElement, EventDeclarations, PropDeclarations, SignalState } from "@aria-ui/core";
1
+ import { BaseElementConstructor, ConnectableElement, EventDeclarations, PropDeclarations, SetupOptions, SignalState } from "@aria-ui/core";
2
2
  import { Editor } from "@prosekit/core";
3
- import { OverlayPositionerProps } from "@aria-ui/overlay/elements";
3
+ import { OverlayPositionerEvents, OverlayPositionerProps } from "@aria-ui/overlay/elements";
4
+ import { ProseMirrorNode } from "@prosekit/pm/model";
4
5
  import { Placement } from "@floating-ui/dom";
5
6
 
6
7
  //#region src/components/block-handle/block-handle-add/types.d.ts
@@ -90,8 +91,15 @@ interface BlockHandlePopoverProps extends Omit<OverlayPositionerProps, "placemen
90
91
  }
91
92
  /** @internal */
92
93
  declare const blockHandlePopoverProps: PropDeclarations<BlockHandlePopoverProps>;
93
- /** @internal */
94
- interface BlockHandlePopoverEvents {}
94
+ interface BlockHandlePopoverEvents extends OverlayPositionerEvents {
95
+ /**
96
+ * Fired when the hovered block changes.
97
+ */
98
+ stateChange: CustomEvent<{
99
+ node: ProseMirrorNode;
100
+ pos: number;
101
+ } | null>;
102
+ }
95
103
  /** @internal */
96
104
  declare const blockHandlePopoverEvents: EventDeclarations<BlockHandlePopoverEvents>;
97
105
  //#endregion
@@ -104,9 +112,8 @@ declare class BlockHandlePopoverElement extends BlockHandlePopoverElementBase {}
104
112
  * @internal
105
113
  */
106
114
  declare function useBlockHandlePopover(host: ConnectableElement, {
107
- state
108
- }: {
109
- state: SignalState<BlockHandlePopoverProps>;
110
- }): void;
115
+ state,
116
+ emit
117
+ }: SetupOptions<BlockHandlePopoverProps, BlockHandlePopoverEvents>): void;
111
118
  //#endregion
112
119
  export { BlockHandleAddElement, BlockHandleAddEvents, BlockHandleAddProps, BlockHandleDraggableElement, BlockHandleDraggableEvents, BlockHandleDraggableProps, BlockHandlePopoverElement, BlockHandlePopoverEvents, BlockHandlePopoverProps, blockHandleAddEvents, blockHandleAddProps, blockHandleDraggableEvents, blockHandleDraggableProps, blockHandlePopoverEvents, blockHandlePopoverProps, useBlockHandleAdd, useBlockHandleDraggable, useBlockHandlePopover };
@@ -1,7 +1,7 @@
1
1
  import { useEditorExtension } from "./use-editor-extension-Cc7ZG7uj.js";
2
2
  import { createContext, createSignal, defineCustomElement, registerCustomElement, useAttribute, useEffect, useEventListener } from "@aria-ui/core";
3
3
  import { defineDOMEventHandler, insertDefaultBlock, union } from "@prosekit/core";
4
- import { overlayPositionerProps, useOverlayPositionerState } from "@aria-ui/overlay/elements";
4
+ import { overlayPositionerEvents, overlayPositionerProps, useOverlayPositionerState } from "@aria-ui/overlay/elements";
5
5
  import { usePresence } from "@aria-ui/presence";
6
6
  import { isElement, isHTMLElement, isTextNode } from "@ocavue/utils";
7
7
  import { Fragment, Slice } from "@prosekit/pm/model";
@@ -432,7 +432,7 @@ const fallbackRect = Object.freeze({
432
432
  /**
433
433
  * @internal
434
434
  */
435
- function useBlockHandlePopover(host, { state }) {
435
+ function useBlockHandlePopover(host, { state, emit }) {
436
436
  const { editor,...overlayState } = state;
437
437
  const reference = createSignal(null);
438
438
  useOverlayPositionerState(host, overlayState, { reference });
@@ -445,6 +445,11 @@ function useBlockHandlePopover(host, { state }) {
445
445
  useHoverExtension(host, editor, (referenceValue, hoverState) => {
446
446
  reference.set(referenceValue);
447
447
  context.set(hoverState);
448
+ const stateChangeDetails = hoverState ? {
449
+ node: hoverState.node,
450
+ pos: hoverState.pos
451
+ } : null;
452
+ emit("stateChange", stateChangeDetails);
448
453
  });
449
454
  useAttribute(host, "data-state", () => open.get() ? "open" : "closed");
450
455
  usePresence(host, open);
@@ -474,7 +479,10 @@ const blockHandlePopoverProps = {
474
479
  hoist: { default: false }
475
480
  };
476
481
  /** @internal */
477
- const blockHandlePopoverEvents = {};
482
+ const blockHandlePopoverEvents = {
483
+ ...overlayPositionerEvents,
484
+ stateChange: {}
485
+ };
478
486
 
479
487
  //#endregion
480
488
  //#region src/components/block-handle/block-handle-popover/element.gen.ts
@@ -2,9 +2,9 @@ import { BaseElementConstructor, ConnectableElement, EventDeclarations, PropDecl
2
2
  import { Editor } from "@prosekit/core";
3
3
  import { OverlayPositionerEvents, OverlayPositionerProps } from "@aria-ui/overlay";
4
4
  import { MenuContentEvents, MenuContentProps } from "@aria-ui/menu/elements";
5
- import { defineTableCommands } from "@prosekit/extensions/table";
6
- import { MenuItemEvents, MenuItemProps } from "@aria-ui/menu";
5
+ import { TableCommandsExtension, defineTableCommands } from "@prosekit/extensions/table";
7
6
  import { Placement } from "@floating-ui/dom";
7
+ import { MenuItemEvents, MenuItemProps } from "@aria-ui/menu";
8
8
 
9
9
  //#region src/components/table-handle/table-handle-column-root/types.d.ts
10
10
  interface TableHandleColumnRootProps extends Omit<OverlayPositionerProps, "placement"> {
@@ -44,9 +44,9 @@ declare function useTableHandleColumnRoot(host: ConnectableElement, {
44
44
  }): void;
45
45
  //#endregion
46
46
  //#region src/components/table-handle/table-handle-column-trigger/types.d.ts
47
- type TableCommandsExtension$1 = ReturnType<typeof defineTableCommands>;
47
+ type TableCommandsExtension$2 = ReturnType<typeof defineTableCommands>;
48
48
  interface TableHandleColumnTriggerProps {
49
- editor: Editor<TableCommandsExtension$1> | null;
49
+ editor: Editor<TableCommandsExtension$2> | null;
50
50
  }
51
51
  /** @internal */
52
52
  declare const tableHandleColumnTriggerProps: PropDeclarations<TableHandleColumnTriggerProps>;
@@ -65,8 +65,50 @@ declare class TableHandleColumnTriggerElement extends TableHandleColumnTriggerEl
65
65
  */
66
66
  declare function useTableHandleColumnTrigger(host: ConnectableElement, {
67
67
  state
68
+ }: SetupOptions<TableHandleColumnTriggerProps, TableHandleColumnTriggerEvents>): void;
69
+ //#endregion
70
+ //#region src/components/table-handle/table-handle-drag-preview/types.d.ts
71
+ interface TableHandleDragPreviewProps {
72
+ editor: Editor | null;
73
+ }
74
+ declare const tableHandleDragPreviewProps: PropDeclarations<TableHandleDragPreviewProps>;
75
+ interface TableHandleDragPreviewEvents {}
76
+ declare const tableHandleDragPreviewEvents: EventDeclarations<TableHandleDragPreviewEvents>;
77
+ //#endregion
78
+ //#region src/components/table-handle/table-handle-drag-preview/element.gen.d.ts
79
+ declare const TableHandleDragPreviewElementBase: BaseElementConstructor<TableHandleDragPreviewProps>;
80
+ declare class TableHandleDragPreviewElement extends TableHandleDragPreviewElementBase {}
81
+ //#endregion
82
+ //#region src/components/table-handle/table-handle-drag-preview/setup.d.ts
83
+ /**
84
+ * @internal
85
+ */
86
+ declare function useTableHandleDragPreview(host: ConnectableElement, {
87
+ state
68
88
  }: {
69
- state: SignalState<TableHandleColumnTriggerProps>;
89
+ state: SignalState<TableHandleDragPreviewProps>;
90
+ }): void;
91
+ //#endregion
92
+ //#region src/components/table-handle/table-handle-drop-indicator/types.d.ts
93
+ interface TableHandleDropIndicatorProps {
94
+ editor: Editor<TableCommandsExtension> | null;
95
+ }
96
+ declare const tableHandleDropIndicatorProps: PropDeclarations<TableHandleDropIndicatorProps>;
97
+ interface TableHandleDropIndicatorEvents {}
98
+ declare const tableHandleDropIndicatorEvents: EventDeclarations<TableHandleDropIndicatorEvents>;
99
+ //#endregion
100
+ //#region src/components/table-handle/table-handle-drop-indicator/element.gen.d.ts
101
+ declare const TableHandleDropIndicatorElementBase: BaseElementConstructor<TableHandleDropIndicatorProps>;
102
+ declare class TableHandleDropIndicatorElement extends TableHandleDropIndicatorElementBase {}
103
+ //#endregion
104
+ //#region src/components/table-handle/table-handle-drop-indicator/setup.d.ts
105
+ /**
106
+ * @internal
107
+ */
108
+ declare function useTableHandleDropIndicator(host: ConnectableElement, {
109
+ state
110
+ }: {
111
+ state: SignalState<TableHandleDropIndicatorProps>;
70
112
  }): void;
71
113
  //#endregion
72
114
  //#region src/components/table-handle/table-handle-popover-content/types.d.ts
@@ -188,9 +230,9 @@ declare function useTableHandleRowRoot(host: ConnectableElement, {
188
230
  }: SetupOptions<TableHandleRowRootProps, TableHandleRowRootEvents>): void;
189
231
  //#endregion
190
232
  //#region src/components/table-handle/table-handle-row-trigger/types.d.ts
191
- type TableCommandsExtension = ReturnType<typeof defineTableCommands>;
233
+ type TableCommandsExtension$1 = ReturnType<typeof defineTableCommands>;
192
234
  interface TableHandleRowTriggerProps {
193
- editor: Editor<TableCommandsExtension> | null;
235
+ editor: Editor<TableCommandsExtension$1> | null;
194
236
  }
195
237
  /** @internal */
196
238
  declare const tableHandleRowTriggerProps: PropDeclarations<TableHandleRowTriggerProps>;
@@ -212,4 +254,4 @@ declare function useTableHandleRowTrigger(host: ConnectableElement, {
212
254
  state
213
255
  }: SetupOptions<TableHandleRowTriggerProps, TableHandleRowTriggerEvents>): void;
214
256
  //#endregion
215
- export { TableHandleColumnRootElement, TableHandleColumnRootEvents, TableHandleColumnRootProps, TableHandleColumnTriggerElement, TableHandleColumnTriggerEvents, TableHandleColumnTriggerProps, TableHandlePopoverContentElement, TableHandlePopoverContentEvents, TableHandlePopoverContentProps, TableHandlePopoverItemElement, TableHandlePopoverItemEvents, TableHandlePopoverItemProps, TableHandleRootElement, TableHandleRootEvents, TableHandleRootProps, TableHandleRowRootElement, TableHandleRowRootEvents, TableHandleRowRootProps, TableHandleRowTriggerElement, TableHandleRowTriggerEvents, TableHandleRowTriggerProps, tableHandleColumnRootEvents, tableHandleColumnRootProps, tableHandleColumnTriggerEvents, tableHandleColumnTriggerProps, tableHandlePopoverContentEvents, tableHandlePopoverContentProps, tableHandlePopoverItemEvents, tableHandlePopoverItemProps, tableHandleRootEvents, tableHandleRootProps, tableHandleRowRootEvents, tableHandleRowRootProps, tableHandleRowTriggerEvents, tableHandleRowTriggerProps, useTableHandleColumnRoot, useTableHandleColumnTrigger, useTableHandlePopoverContent, useTableHandlePopoverItem, useTableHandleRoot, useTableHandleRowRoot, useTableHandleRowTrigger };
257
+ export { TableHandleColumnRootElement, TableHandleColumnRootEvents, TableHandleColumnRootProps, TableHandleColumnTriggerElement, TableHandleColumnTriggerEvents, TableHandleColumnTriggerProps, TableHandleDragPreviewElement, TableHandleDragPreviewEvents, TableHandleDragPreviewProps, TableHandleDropIndicatorElement, TableHandleDropIndicatorEvents, TableHandleDropIndicatorProps, TableHandlePopoverContentElement, TableHandlePopoverContentEvents, TableHandlePopoverContentProps, TableHandlePopoverItemElement, TableHandlePopoverItemEvents, TableHandlePopoverItemProps, TableHandleRootElement, TableHandleRootEvents, TableHandleRootProps, TableHandleRowRootElement, TableHandleRowRootEvents, TableHandleRowRootProps, TableHandleRowTriggerElement, TableHandleRowTriggerEvents, TableHandleRowTriggerProps, tableHandleColumnRootEvents, tableHandleColumnRootProps, tableHandleColumnTriggerEvents, tableHandleColumnTriggerProps, tableHandleDragPreviewEvents, tableHandleDragPreviewProps, tableHandleDropIndicatorEvents, tableHandleDropIndicatorProps, tableHandlePopoverContentEvents, tableHandlePopoverContentProps, tableHandlePopoverItemEvents, tableHandlePopoverItemProps, tableHandleRootEvents, tableHandleRootProps, tableHandleRowRootEvents, tableHandleRowRootProps, tableHandleRowTriggerEvents, tableHandleRowTriggerProps, useTableHandleColumnRoot, useTableHandleColumnTrigger, useTableHandleDragPreview, useTableHandleDropIndicator, useTableHandlePopoverContent, useTableHandlePopoverItem, useTableHandleRoot, useTableHandleRowRoot, useTableHandleRowTrigger };
@@ -1,12 +1,14 @@
1
- import { getStateWithDefaults } from "./get-default-state-CIEy7xrl.js";
1
+ import { getSafeEditorView, getStateWithDefaults } from "./get-safe-editor-view-CqJWgxo1.js";
2
2
  import { useEditorExtension } from "./use-editor-extension-Cc7ZG7uj.js";
3
3
  import { createComputed, createContext, createSignal, defineCustomElement, defineEmit, registerCustomElement, useAttribute, useEffect, useEventListener } from "@aria-ui/core";
4
4
  import { defineDOMEventHandler, union } from "@prosekit/core";
5
5
  import { useOverlayPositionerState } from "@aria-ui/overlay/elements";
6
6
  import { usePresence } from "@aria-ui/presence";
7
+ import { isHTMLElement } from "@ocavue/utils";
7
8
  import { overlayPositionerEvents as overlayPositionerEvents$1, overlayPositionerProps as overlayPositionerProps$1 } from "@aria-ui/overlay";
8
9
  import { menuContentEvents, menuContentProps, menuRootEvents, menuRootProps, useMenuContent, useMenuItem, useMenuRoot, useMenuTrigger } from "@aria-ui/menu/elements";
9
- import { selectTableColumn, selectTableRow } from "@prosekit/extensions/table";
10
+ import { moveTableColumn, moveTableRow, selectTableColumn, selectTableRow } from "@prosekit/extensions/table";
11
+ import { computePosition, offset } from "@floating-ui/dom";
10
12
  import { menuItemEvents, menuItemProps } from "@aria-ui/menu";
11
13
  import { TableMap, cellAround } from "prosemirror-tables";
12
14
 
@@ -15,6 +17,23 @@ import { TableMap, cellAround } from "prosemirror-tables";
15
17
  * @internal
16
18
  */
17
19
  const tableHandleRootContext = createContext("prosekit-table-handle-root-context", null);
20
+ /**
21
+ * @internal
22
+ */
23
+ const defaultTableHandleDndContext = {
24
+ dragging: false,
25
+ direction: "row",
26
+ draggingIndex: -1,
27
+ droppingIndex: -1,
28
+ x: -1,
29
+ y: -1,
30
+ startX: -1,
31
+ startY: -1
32
+ };
33
+ /**
34
+ * @internal
35
+ */
36
+ const tableHandleDndContext = createContext("prosekit-table-handle-dnd-context", defaultTableHandleDndContext);
18
37
 
19
38
  //#endregion
20
39
  //#region src/components/table-handle/table-handle-column-root/setup.ts
@@ -29,7 +48,7 @@ function useTableHandleColumnRoot(host, { state }) {
29
48
  });
30
49
  const referenceCell = createComputed(() => {
31
50
  const pos = colFirstCellPos.get();
32
- const view = editor.get()?.view;
51
+ const view = getSafeEditorView(editor.get());
33
52
  if (!pos || !view) return null;
34
53
  return view.nodeDOM(pos);
35
54
  });
@@ -70,6 +89,31 @@ const TableHandleColumnRootElementBase = defineCustomElement({
70
89
  var TableHandleColumnRootElement = class extends TableHandleColumnRootElementBase {};
71
90
  registerCustomElement("prosekit-table-handle-column-root", TableHandleColumnRootElement);
72
91
 
92
+ //#endregion
93
+ //#region src/components/table-handle/hooks/use-empty-image.ts
94
+ /**
95
+ * Returns a function that returns a 1x1 transparent image. This is used to
96
+ * prevent the browser from showing the default drag image. An earth icon in
97
+ * chrome is used as the default drag image. This image must be loaded before
98
+ * the dragStart event triggers.
99
+ *
100
+ * See https://stackoverflow.com/a/40923520
101
+ *
102
+ * @internal
103
+ */
104
+ function useEmptyImage(host) {
105
+ let image;
106
+ useEffect(host, () => {
107
+ image = new Image(1, 1);
108
+ image.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
109
+ return () => {
110
+ image?.remove();
111
+ image = void 0;
112
+ };
113
+ });
114
+ return () => image;
115
+ }
116
+
73
117
  //#endregion
74
118
  //#region src/components/table-handle/table-handle-column-trigger/setup.ts
75
119
  /**
@@ -78,12 +122,58 @@ registerCustomElement("prosekit-table-handle-column-root", TableHandleColumnRoot
78
122
  function useTableHandleColumnTrigger(host, { state }) {
79
123
  useMenuTrigger(host);
80
124
  const context = tableHandleRootContext.consume(host);
125
+ const dndContext = tableHandleDndContext.consume(host);
81
126
  useEventListener(host, "pointerdown", () => {
82
127
  const editor = state.editor.peek();
83
128
  const cellPos = context.peek()?.cellPos;
84
129
  if (!editor || !cellPos) return;
85
130
  editor.exec(selectTableColumn({ head: cellPos }));
86
131
  });
132
+ useEffect(host, () => {
133
+ host.draggable = true;
134
+ });
135
+ const getEmptyImage = useEmptyImage(host);
136
+ useEventListener(host, "dragstart", (event) => {
137
+ const dataTransfer = event.dataTransfer;
138
+ if (dataTransfer) {
139
+ dataTransfer.effectAllowed = "move";
140
+ const emptyImage = getEmptyImage();
141
+ if (emptyImage) dataTransfer.setDragImage(emptyImage, 0, 0);
142
+ }
143
+ const prev = dndContext.peek();
144
+ const index = context.peek()?.colIndex ?? -1;
145
+ if (index < 0) {
146
+ console.warn("[prosekit] Invalid column index for drag operation:", index);
147
+ event.preventDefault();
148
+ return;
149
+ }
150
+ dndContext.set({
151
+ ...prev,
152
+ direction: "col",
153
+ dragging: true,
154
+ draggingIndex: index,
155
+ startX: event.clientX,
156
+ startY: event.clientY
157
+ });
158
+ });
159
+ useEventListener(host, "drag", (event) => {
160
+ const prev = dndContext.peek();
161
+ if (event.clientX === 0 && event.clientY === 0) return;
162
+ dndContext.set({
163
+ ...prev,
164
+ direction: "col",
165
+ dragging: true,
166
+ x: event.clientX,
167
+ y: event.clientY
168
+ });
169
+ });
170
+ useEventListener(host, "dragend", () => {
171
+ const prev = dndContext.peek();
172
+ dndContext.set({
173
+ ...prev,
174
+ dragging: false
175
+ });
176
+ });
87
177
  }
88
178
 
89
179
  //#endregion
@@ -103,6 +193,384 @@ const TableHandleColumnTriggerElementBase = defineCustomElement({
103
193
  var TableHandleColumnTriggerElement = class extends TableHandleColumnTriggerElementBase {};
104
194
  registerCustomElement("prosekit-table-handle-column-trigger", TableHandleColumnTriggerElement);
105
195
 
196
+ //#endregion
197
+ //#region src/components/table-handle/dnd.ts
198
+ function useInitDndPosition(host, editor, onInit) {
199
+ const dndContext = tableHandleDndContext.consume(host);
200
+ const rootContext = tableHandleRootContext.consume(host);
201
+ const draggingSignal = createComputed(() => {
202
+ const context = dndContext.get();
203
+ return context.dragging;
204
+ });
205
+ const directionSignal = createComputed(() => {
206
+ const context = dndContext.get();
207
+ return context.direction;
208
+ });
209
+ const draggingIndexSignal = createComputed(() => {
210
+ const context = dndContext.get();
211
+ return context.draggingIndex;
212
+ });
213
+ useEffect(host, () => {
214
+ const view = getSafeEditorView(editor.get());
215
+ if (!view) return;
216
+ const dragging = draggingSignal.get();
217
+ const direction = directionSignal.get();
218
+ host.dataset.direction = direction;
219
+ host.dataset.dragging = dragging.toString();
220
+ const draggingIndex = draggingIndexSignal.get();
221
+ const relatedDOMs = getDndRelatedDOMs(view, rootContext.peek()?.cellPos, draggingIndex, direction);
222
+ if (!relatedDOMs) return;
223
+ const { table, cell } = relatedDOMs;
224
+ onInit({
225
+ host,
226
+ direction,
227
+ dragging,
228
+ draggingIndex,
229
+ table,
230
+ cell
231
+ });
232
+ if (!dragging) return;
233
+ let cancelled = false;
234
+ computePosition(cell, host, {
235
+ placement: direction === "row" ? "right" : "bottom",
236
+ middleware: [offset(({ rects }) => {
237
+ if (direction === "col") return -rects.reference.height;
238
+ return -rects.reference.width;
239
+ })]
240
+ }).then(({ x, y }) => {
241
+ if (cancelled) return;
242
+ Object.assign(host.style, {
243
+ left: `${x}px`,
244
+ top: `${y}px`
245
+ });
246
+ });
247
+ return () => {
248
+ cancelled = true;
249
+ };
250
+ });
251
+ }
252
+ function getTableDOMByPos(view, pos) {
253
+ const dom = view.domAtPos(pos).node;
254
+ if (!dom) return;
255
+ const element = isHTMLElement(dom) ? dom : dom.parentElement;
256
+ const table = element?.closest("table");
257
+ return table ?? void 0;
258
+ }
259
+ function getTargetFirstCellDOM(table, index, direction) {
260
+ if (direction === "row") {
261
+ const row = table.querySelectorAll("tr")[index];
262
+ const cell = row?.querySelector("td");
263
+ return cell ?? void 0;
264
+ } else {
265
+ const row = table.querySelector("tr");
266
+ const cell = row?.querySelectorAll("td")[index];
267
+ return cell ?? void 0;
268
+ }
269
+ }
270
+ function getDndRelatedDOMs(view, cellPos, draggingIndex, direction) {
271
+ if (cellPos == null) return;
272
+ const table = getTableDOMByPos(view, cellPos);
273
+ if (!table) return;
274
+ const cell = getTargetFirstCellDOM(table, draggingIndex, direction);
275
+ if (!cell) return;
276
+ return {
277
+ table,
278
+ cell
279
+ };
280
+ }
281
+
282
+ //#endregion
283
+ //#region src/components/table-handle/table-handle-drag-preview/render-preview.ts
284
+ function clearPreviewDOM(previewRoot) {
285
+ while (previewRoot.firstChild) previewRoot.removeChild(previewRoot.firstChild);
286
+ }
287
+ function createPreviewDOM(table, previewRoot, index, direction) {
288
+ clearPreviewDOM(previewRoot);
289
+ const previewTable = document.createElement("table");
290
+ const previewTableBody = document.createElement("tbody");
291
+ previewTable.appendChild(previewTableBody);
292
+ previewRoot.appendChild(previewTable);
293
+ const rows = table.querySelectorAll("tr");
294
+ if (direction === "row") {
295
+ const row = rows[index];
296
+ const rowDOM = row.cloneNode(true);
297
+ previewTableBody.appendChild(rowDOM);
298
+ } else rows.forEach((row) => {
299
+ const rowDOM = row.cloneNode(false);
300
+ const cells = row.querySelectorAll("td");
301
+ if (cells[index]) {
302
+ const cellDOM = cells[index].cloneNode(true);
303
+ rowDOM.appendChild(cellDOM);
304
+ previewTableBody.appendChild(rowDOM);
305
+ }
306
+ });
307
+ }
308
+
309
+ //#endregion
310
+ //#region src/components/table-handle/table-handle-drag-preview/updater.ts
311
+ function useUpdatePreviewPosition(host, editor) {
312
+ const dndContext = tableHandleDndContext.consume(host);
313
+ const rootContext = tableHandleRootContext.consume(host);
314
+ const draggingSignal = createComputed(() => {
315
+ const context = dndContext.get();
316
+ return context.dragging;
317
+ });
318
+ const clientXSignal = createComputed(() => {
319
+ const context = dndContext.get();
320
+ return context.x;
321
+ });
322
+ const clientYSignal = createComputed(() => {
323
+ const context = dndContext.get();
324
+ return context.y;
325
+ });
326
+ useEffect(host, () => {
327
+ const view = getSafeEditorView(editor.get());
328
+ if (!view) return;
329
+ if (!draggingSignal.get()) return;
330
+ const { draggingIndex, direction } = dndContext.peek();
331
+ const x = clientXSignal.get();
332
+ const y = clientYSignal.get();
333
+ const relatedDOMs = getDndRelatedDOMs(view, rootContext.peek()?.cellPos, draggingIndex, direction);
334
+ if (!relatedDOMs) return;
335
+ const { cell } = relatedDOMs;
336
+ let cancelled = false;
337
+ computePosition(getVirtualElement(cell, x, y), host, { placement: direction === "row" ? "right" : "bottom" }).then(({ x: x$1, y: y$1 }) => {
338
+ if (cancelled) return;
339
+ if (direction === "row") {
340
+ Object.assign(host.style, { top: `${y$1}px` });
341
+ return;
342
+ }
343
+ if (direction === "col") {
344
+ Object.assign(host.style, { left: `${x$1}px` });
345
+ return;
346
+ }
347
+ });
348
+ return () => {
349
+ cancelled = true;
350
+ };
351
+ });
352
+ }
353
+ function getVirtualElement(cell, x, y) {
354
+ return {
355
+ contextElement: cell,
356
+ getBoundingClientRect: () => {
357
+ const rect = cell.getBoundingClientRect();
358
+ return {
359
+ width: rect.width,
360
+ height: rect.height,
361
+ right: x + rect.width / 2,
362
+ bottom: y + rect.height / 2,
363
+ top: y - rect.height / 2,
364
+ left: x - rect.width / 2,
365
+ x: x - rect.width / 2,
366
+ y: y - rect.height / 2
367
+ };
368
+ }
369
+ };
370
+ }
371
+
372
+ //#endregion
373
+ //#region src/components/table-handle/table-handle-drag-preview/setup.ts
374
+ /**
375
+ * @internal
376
+ */
377
+ function useTableHandleDragPreview(host, { state }) {
378
+ const { editor } = state;
379
+ useEffect(host, () => {
380
+ host.classList.add("ProseMirror");
381
+ Object.assign(host.style, {
382
+ position: "absolute",
383
+ pointerEvents: "none"
384
+ });
385
+ });
386
+ useInitDndPosition(host, editor, onInitPreviewPosition);
387
+ useUpdatePreviewPosition(host, editor);
388
+ }
389
+ function onInitPreviewPosition({ host, direction, dragging, table, cell, draggingIndex }) {
390
+ Object.assign(host.style, { display: dragging ? "block" : "none" });
391
+ if (!dragging) {
392
+ clearPreviewDOM(host);
393
+ return;
394
+ }
395
+ createPreviewDOM(table, host, draggingIndex, direction);
396
+ const tableRect = table.getBoundingClientRect();
397
+ const cellRect = cell.getBoundingClientRect();
398
+ if (direction === "col") Object.assign(host.style, {
399
+ width: `${cellRect.width}px`,
400
+ height: `${tableRect.height}px`
401
+ });
402
+ if (direction === "row") Object.assign(host.style, {
403
+ width: `${tableRect.width}px`,
404
+ height: `${cellRect.height}px`
405
+ });
406
+ }
407
+
408
+ //#endregion
409
+ //#region src/components/table-handle/table-handle-drag-preview/types.ts
410
+ const tableHandleDragPreviewProps = { editor: { default: null } };
411
+ const tableHandleDragPreviewEvents = {};
412
+
413
+ //#endregion
414
+ //#region src/components/table-handle/table-handle-drag-preview/element.gen.ts
415
+ const TableHandleDragPreviewElementBase = defineCustomElement({
416
+ props: tableHandleDragPreviewProps,
417
+ events: tableHandleDragPreviewEvents,
418
+ setup: useTableHandleDragPreview
419
+ });
420
+ var TableHandleDragPreviewElement = class extends TableHandleDragPreviewElementBase {};
421
+ registerCustomElement("prosekit-table-handle-drag-preview", TableHandleDragPreviewElement);
422
+
423
+ //#endregion
424
+ //#region src/components/table-handle/table-handle-drop-indicator/calc-drag-over.ts
425
+ function findDragOverElement(elements, pointer, axis) {
426
+ const startProp = axis === "x" ? "left" : "top";
427
+ const endProp = axis === "x" ? "right" : "bottom";
428
+ const lastIndex = elements.length - 1;
429
+ const index = elements.findIndex((el, index$1) => {
430
+ const rect = el.getBoundingClientRect();
431
+ const boundaryStart = rect[startProp];
432
+ const boundaryEnd = rect[endProp];
433
+ if (boundaryStart <= pointer && pointer <= boundaryEnd) return true;
434
+ if (index$1 === lastIndex && pointer > boundaryEnd) return true;
435
+ if (index$1 === 0 && pointer < boundaryStart) return true;
436
+ return false;
437
+ });
438
+ return index >= 0 ? [elements[index], index] : void 0;
439
+ }
440
+ function getDragOverColumn(table, pointerX) {
441
+ const firstRow = table.querySelector("tr");
442
+ if (!firstRow) return;
443
+ const cells = Array.from(firstRow.children);
444
+ return findDragOverElement(cells, pointerX, "x");
445
+ }
446
+ function getDragOverRow(table, pointerY) {
447
+ const rows = Array.from(table.querySelectorAll("tr"));
448
+ return findDragOverElement(rows, pointerY, "y");
449
+ }
450
+
451
+ //#endregion
452
+ //#region src/components/table-handle/table-handle-drop-indicator/updater.ts
453
+ function useUpdateIndicatorPosition(host, editor, handleWidth) {
454
+ const dndContext = tableHandleDndContext.consume(host);
455
+ const rootContext = tableHandleRootContext.consume(host);
456
+ const draggingSignal = createComputed(() => {
457
+ const context = dndContext.get();
458
+ return context.dragging;
459
+ });
460
+ const clientXSignal = createComputed(() => {
461
+ const context = dndContext.get();
462
+ return context.x;
463
+ });
464
+ const clientYSignal = createComputed(() => {
465
+ const context = dndContext.get();
466
+ return context.y;
467
+ });
468
+ const startXSignal = createComputed(() => {
469
+ return dndContext.get().startX;
470
+ });
471
+ const startYSignal = createComputed(() => {
472
+ return dndContext.get().startY;
473
+ });
474
+ useEffect(host, () => {
475
+ const view = getSafeEditorView(editor.get());
476
+ if (!view) return;
477
+ if (!draggingSignal.get()) return;
478
+ const { draggingIndex, direction } = dndContext.peek();
479
+ const x = clientXSignal.get();
480
+ const y = clientYSignal.get();
481
+ const relatedDOMs = getDndRelatedDOMs(view, rootContext.peek()?.cellPos, draggingIndex, direction);
482
+ if (!relatedDOMs) return;
483
+ const { table } = relatedDOMs;
484
+ let cancelled = false;
485
+ let cleanup = () => {
486
+ cancelled = true;
487
+ };
488
+ if (direction === "col") {
489
+ const direction$1 = startXSignal.get() > x ? "left" : "right";
490
+ const dragOverColumn = getDragOverColumn(table, x);
491
+ if (dragOverColumn) {
492
+ const [col, index] = dragOverColumn;
493
+ dndContext.set({
494
+ ...dndContext.peek(),
495
+ droppingIndex: index
496
+ });
497
+ computePosition(col, host, {
498
+ placement: direction$1 === "left" ? "left" : "right",
499
+ middleware: [offset(direction$1 === "left" ? -1 * handleWidth : 0)]
500
+ }).then(({ x: x$1 }) => {
501
+ if (cancelled) return;
502
+ Object.assign(host.style, { left: `${x$1}px` });
503
+ });
504
+ }
505
+ return cleanup;
506
+ }
507
+ if (direction === "row") {
508
+ const direction$1 = startYSignal.get() > y ? "up" : "down";
509
+ const dragOverRow = getDragOverRow(table, y);
510
+ if (dragOverRow) {
511
+ const [row, index] = dragOverRow;
512
+ dndContext.set({
513
+ ...dndContext.peek(),
514
+ droppingIndex: index
515
+ });
516
+ computePosition(row, host, {
517
+ placement: direction$1 === "up" ? "top" : "bottom",
518
+ middleware: [offset(direction$1 === "up" ? -1 * handleWidth : 0)]
519
+ }).then(({ y: y$1 }) => {
520
+ if (cancelled) return;
521
+ Object.assign(host.style, { top: `${y$1}px` });
522
+ });
523
+ }
524
+ return cleanup;
525
+ }
526
+ });
527
+ }
528
+
529
+ //#endregion
530
+ //#region src/components/table-handle/table-handle-drop-indicator/setup.ts
531
+ const HANDLE_WIDTH = 2;
532
+ /**
533
+ * @internal
534
+ */
535
+ function useTableHandleDropIndicator(host, { state }) {
536
+ const { editor } = state;
537
+ useEffect(host, () => {
538
+ Object.assign(host.style, {
539
+ pointerEvents: "none",
540
+ position: "absolute"
541
+ });
542
+ });
543
+ useInitDndPosition(host, editor, onInitIndicatorPosition);
544
+ useUpdateIndicatorPosition(host, editor, HANDLE_WIDTH);
545
+ }
546
+ function onInitIndicatorPosition({ host, direction, dragging, table }) {
547
+ Object.assign(host.style, { display: dragging ? "block" : "none" });
548
+ const tableRect = table.getBoundingClientRect();
549
+ if (direction === "col") Object.assign(host.style, {
550
+ width: `${HANDLE_WIDTH}px`,
551
+ height: `${tableRect.height}px`
552
+ });
553
+ if (direction === "row") Object.assign(host.style, {
554
+ width: `${tableRect.width}px`,
555
+ height: `${HANDLE_WIDTH}px`
556
+ });
557
+ }
558
+
559
+ //#endregion
560
+ //#region src/components/table-handle/table-handle-drop-indicator/types.ts
561
+ const tableHandleDropIndicatorProps = { editor: { default: null } };
562
+ const tableHandleDropIndicatorEvents = {};
563
+
564
+ //#endregion
565
+ //#region src/components/table-handle/table-handle-drop-indicator/element.gen.ts
566
+ const TableHandleDropIndicatorElementBase = defineCustomElement({
567
+ props: tableHandleDropIndicatorProps,
568
+ events: tableHandleDropIndicatorEvents,
569
+ setup: useTableHandleDropIndicator
570
+ });
571
+ var TableHandleDropIndicatorElement = class extends TableHandleDropIndicatorElementBase {};
572
+ registerCustomElement("prosekit-table-handle-drop-indicator", TableHandleDropIndicatorElement);
573
+
106
574
  //#endregion
107
575
  //#region src/components/table-handle/table-handle-popover-content/setup.ts
108
576
  /**
@@ -216,6 +684,54 @@ function useEditorTyping(host, editor) {
216
684
  return typing;
217
685
  }
218
686
 
687
+ //#endregion
688
+ //#region src/components/table-handle/hooks/use-drop.ts
689
+ function useDrop(host, editor, dndContext) {
690
+ const dragging = createComputed(() => dndContext.get().dragging);
691
+ useEffect(host, () => {
692
+ if (!dragging.get()) return;
693
+ const view = getSafeEditorView(editor.peek());
694
+ if (!view || !view.editable) return;
695
+ const ownerDocument = view.dom?.ownerDocument;
696
+ if (!ownerDocument) return;
697
+ const handleDrop = () => {
698
+ const editorValue = editor.peek();
699
+ if (!editorValue) return;
700
+ const { droppingIndex, draggingIndex, direction } = dndContext.peek();
701
+ if (draggingIndex < 0 || droppingIndex < 0) {
702
+ console.warn("[prosekit] Invalid drag indices:", {
703
+ draggingIndex,
704
+ droppingIndex
705
+ });
706
+ return;
707
+ }
708
+ if (direction === "row") {
709
+ editorValue.exec(moveTableRow({
710
+ from: draggingIndex,
711
+ to: droppingIndex
712
+ }));
713
+ return;
714
+ }
715
+ if (direction === "col") {
716
+ editorValue.exec(moveTableColumn({
717
+ from: draggingIndex,
718
+ to: droppingIndex
719
+ }));
720
+ return;
721
+ }
722
+ };
723
+ const handleDragOver = (event) => {
724
+ event.preventDefault();
725
+ };
726
+ ownerDocument.addEventListener("dragover", handleDragOver);
727
+ ownerDocument.addEventListener("drop", handleDrop);
728
+ return () => {
729
+ ownerDocument.removeEventListener("dragover", handleDragOver);
730
+ ownerDocument.removeEventListener("drop", handleDrop);
731
+ };
732
+ });
733
+ }
734
+
219
735
  //#endregion
220
736
  //#region src/components/table-handle/utils.ts
221
737
  function isHoveringCellInfoEqual(a, b) {
@@ -273,6 +789,7 @@ function getCellIndex(map, rowIndex, colIndex) {
273
789
  function useTableHandleRoot(host, { state }) {
274
790
  const { editor } = state;
275
791
  const context = createSignal(null);
792
+ const dndContext = createSignal(defaultTableHandleDndContext);
276
793
  const hoveringCell = useHoveringCell(host, editor);
277
794
  const typing = useEditorTyping(host, editor);
278
795
  const isInTable = createComputed(() => !!hoveringCell.get());
@@ -284,6 +801,8 @@ function useTableHandleRoot(host, { state }) {
284
801
  context.set(typingValue || selectingValue ? null : hoveringCellValue);
285
802
  });
286
803
  tableHandleRootContext.provide(host, context);
804
+ tableHandleDndContext.provide(host, dndContext);
805
+ useDrop(host, editor, dndContext);
287
806
  }
288
807
  function useHoveringCell(host, editor) {
289
808
  const hoveringCell = createSignal(null);
@@ -308,7 +827,8 @@ function useSelecting(host, editor, isInTable) {
308
827
  const selecting = createSignal(false);
309
828
  useEffect(host, () => {
310
829
  if (!isInTable.get()) return;
311
- const root = editor.peek()?.view.root;
830
+ const view = getSafeEditorView(editor.peek());
831
+ const root = view?.root;
312
832
  if (!root) return;
313
833
  const pointerDownHandler = (event) => {
314
834
  const target = event.target;
@@ -358,7 +878,7 @@ function useTableHandleRowRoot(host, { state }) {
358
878
  });
359
879
  const referenceCell = createComputed(() => {
360
880
  const pos = rowFirstCellPos.get();
361
- const view = editor.get()?.view;
881
+ const view = getSafeEditorView(editor.get());
362
882
  if (!pos || !view) return null;
363
883
  return view.nodeDOM(pos);
364
884
  });
@@ -407,12 +927,58 @@ registerCustomElement("prosekit-table-handle-row-root", TableHandleRowRootElemen
407
927
  function useTableHandleRowTrigger(host, { state }) {
408
928
  useMenuTrigger(host);
409
929
  const context = tableHandleRootContext.consume(host);
930
+ const dndContext = tableHandleDndContext.consume(host);
410
931
  useEventListener(host, "pointerdown", () => {
411
932
  const editor = state.editor.peek();
412
933
  const cellPos = context.peek()?.cellPos;
413
934
  if (!editor || !cellPos) return;
414
935
  editor.exec(selectTableRow({ head: cellPos }));
415
936
  });
937
+ useEffect(host, () => {
938
+ host.draggable = true;
939
+ });
940
+ const getEmptyImage = useEmptyImage(host);
941
+ useEventListener(host, "dragstart", (event) => {
942
+ const dataTransfer = event.dataTransfer;
943
+ if (dataTransfer) {
944
+ dataTransfer.effectAllowed = "move";
945
+ const emptyImage = getEmptyImage();
946
+ if (emptyImage) dataTransfer.setDragImage(emptyImage, 0, 0);
947
+ }
948
+ const prev = dndContext.peek();
949
+ const index = context.peek()?.rowIndex ?? -1;
950
+ if (index < 0) {
951
+ console.warn("[prosekit] Invalid row index for drag operation:", index);
952
+ event.preventDefault();
953
+ return;
954
+ }
955
+ dndContext.set({
956
+ ...prev,
957
+ direction: "row",
958
+ dragging: true,
959
+ draggingIndex: index,
960
+ startX: event.clientX,
961
+ startY: event.clientY
962
+ });
963
+ });
964
+ useEventListener(host, "drag", (event) => {
965
+ const prev = dndContext.peek();
966
+ if (event.clientX === 0 && event.clientY === 0) return;
967
+ dndContext.set({
968
+ ...prev,
969
+ direction: "row",
970
+ dragging: true,
971
+ x: event.clientX,
972
+ y: event.clientY
973
+ });
974
+ });
975
+ useEventListener(host, "dragend", () => {
976
+ const prev = dndContext.peek();
977
+ dndContext.set({
978
+ ...prev,
979
+ dragging: false
980
+ });
981
+ });
416
982
  }
417
983
 
418
984
  //#endregion
@@ -433,4 +999,4 @@ var TableHandleRowTriggerElement = class extends TableHandleRowTriggerElementBas
433
999
  registerCustomElement("prosekit-table-handle-row-trigger", TableHandleRowTriggerElement);
434
1000
 
435
1001
  //#endregion
436
- export { TableHandleColumnRootElement, TableHandleColumnTriggerElement, TableHandlePopoverContentElement, TableHandlePopoverItemElement, TableHandleRootElement, TableHandleRowRootElement, TableHandleRowTriggerElement, tableHandleColumnRootEvents, tableHandleColumnRootProps, tableHandleColumnTriggerEvents, tableHandleColumnTriggerProps, tableHandlePopoverContentEvents, tableHandlePopoverContentProps, tableHandlePopoverItemEvents, tableHandlePopoverItemProps, tableHandleRootEvents, tableHandleRootProps, tableHandleRowRootEvents, tableHandleRowRootProps, tableHandleRowTriggerEvents, tableHandleRowTriggerProps, useTableHandleColumnRoot, useTableHandleColumnTrigger, useTableHandlePopoverContent, useTableHandlePopoverItem, useTableHandleRoot, useTableHandleRowRoot, useTableHandleRowTrigger };
1002
+ export { TableHandleColumnRootElement, TableHandleColumnTriggerElement, TableHandleDragPreviewElement, TableHandleDropIndicatorElement, TableHandlePopoverContentElement, TableHandlePopoverItemElement, TableHandleRootElement, TableHandleRowRootElement, TableHandleRowTriggerElement, tableHandleColumnRootEvents, tableHandleColumnRootProps, tableHandleColumnTriggerEvents, tableHandleColumnTriggerProps, tableHandleDragPreviewEvents, tableHandleDragPreviewProps, tableHandleDropIndicatorEvents, tableHandleDropIndicatorProps, tableHandlePopoverContentEvents, tableHandlePopoverContentProps, tableHandlePopoverItemEvents, tableHandlePopoverItemProps, tableHandleRootEvents, tableHandleRootProps, tableHandleRowRootEvents, tableHandleRowRootProps, tableHandleRowTriggerEvents, tableHandleRowTriggerProps, useTableHandleColumnRoot, useTableHandleColumnTrigger, useTableHandleDragPreview, useTableHandleDropIndicator, useTableHandlePopoverContent, useTableHandlePopoverItem, useTableHandleRoot, useTableHandleRowRoot, useTableHandleRowTrigger };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@prosekit/web",
3
3
  "type": "module",
4
- "version": "0.5.11",
4
+ "version": "0.6.0",
5
5
  "private": false,
6
6
  "description": "A collection of web components for ProseKit",
7
7
  "author": {
@@ -66,24 +66,24 @@
66
66
  "@aria-ui/collection": "^0.0.5",
67
67
  "@aria-ui/core": "^0.0.21",
68
68
  "@aria-ui/listbox": "^0.0.24",
69
- "@aria-ui/menu": "^0.0.19",
69
+ "@aria-ui/menu": "^0.0.20",
70
70
  "@aria-ui/overlay": "^0.0.24",
71
71
  "@aria-ui/popover": "^0.0.27",
72
72
  "@aria-ui/presence": "^0.0.19",
73
73
  "@aria-ui/tooltip": "^0.0.29",
74
- "@floating-ui/dom": "^1.7.1",
74
+ "@floating-ui/dom": "^1.7.2",
75
75
  "@ocavue/utils": "^0.5.0",
76
76
  "prosemirror-tables": "^1.7.1",
77
+ "@prosekit/extensions": "^0.10.0",
77
78
  "@prosekit/pm": "^0.1.11",
78
- "@prosekit/core": "^0.8.2",
79
- "@prosekit/extensions": "^0.9.3"
79
+ "@prosekit/core": "^0.8.3"
80
80
  },
81
81
  "devDependencies": {
82
- "tsdown": "^0.12.7",
82
+ "tsdown": "^0.12.9",
83
83
  "typescript": "~5.8.3",
84
- "vitest": "^3.2.3",
85
- "@prosekit/config-tsdown": "0.0.0",
86
- "@prosekit/config-vitest": "0.0.0"
84
+ "vitest": "^3.2.4",
85
+ "@prosekit/config-vitest": "0.0.0",
86
+ "@prosekit/config-tsdown": "0.0.0"
87
87
  },
88
88
  "publishConfig": {
89
89
  "dev": {}