@prosekit/extensions 0.10.1 → 0.11.1

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.
@@ -0,0 +1,255 @@
1
+ import { defineFacet, defineFacetPayload, isNodeSelection, pluginFacet } from "@prosekit/core";
2
+ import { NodeSelection, Plugin, PluginKey, TextSelection } from "@prosekit/pm/state";
3
+ import { isHTMLElement } from "@ocavue/utils";
4
+
5
+ //#region src/drop-indicator/drop-target.ts
6
+ function getTargetsByView(view) {
7
+ let stack = [[-1, view.state.doc]];
8
+ let targets = [];
9
+ while (stack.length > 0) {
10
+ const [pos, node] = stack.pop();
11
+ if (pos >= 0) {
12
+ let dom = view.nodeDOM(pos);
13
+ if (dom && isHTMLElement(dom)) {
14
+ let rect = dom.getBoundingClientRect();
15
+ let { top, bottom, left: x1, right: x2 } = rect;
16
+ targets.push([pos, [
17
+ x1,
18
+ top,
19
+ x2,
20
+ top
21
+ ]], [pos + node.nodeSize, [
22
+ x1,
23
+ bottom,
24
+ x2,
25
+ bottom
26
+ ]]);
27
+ }
28
+ }
29
+ if (node.isBlock && !node.isTextblock) {
30
+ let childPos = pos + 1;
31
+ for (let child of node.children) {
32
+ stack.push([childPos, child]);
33
+ childPos += child.nodeSize;
34
+ }
35
+ }
36
+ }
37
+ return targets;
38
+ }
39
+ /**
40
+ * @internal
41
+ */
42
+ function buildGetTarget(view, onDrag) {
43
+ let prevTargets = [];
44
+ let prevDoc;
45
+ let prevRect;
46
+ const getTargets = () => {
47
+ const rect = view.dom.getBoundingClientRect();
48
+ const doc = view.state.doc;
49
+ if (prevTargets && prevDoc && prevRect && rect.width === prevRect.width && rect.height === prevRect.height && rect.x === prevRect.x && rect.y === prevRect.y && prevDoc.eq(doc)) return prevTargets;
50
+ prevRect = rect;
51
+ prevDoc = doc;
52
+ prevTargets = getTargetsByView(view);
53
+ return prevTargets;
54
+ };
55
+ const getTarget = (point, event) => {
56
+ if (!view.editable || view.isDestroyed) return;
57
+ const compare = (p1, p2) => {
58
+ const [pos1, line1] = p1;
59
+ const [pos2, line2] = p2;
60
+ const p1Distance = pointLineDistance(point, line1);
61
+ const p2Distance = pointLineDistance(point, line2);
62
+ return p1Distance - p2Distance || pos1 - pos2;
63
+ };
64
+ const targets = getTargets();
65
+ targets.sort(compare);
66
+ const target = targets.find((target$1) => onDrag({
67
+ view,
68
+ pos: target$1[0],
69
+ event
70
+ }) !== false);
71
+ if (target && isDraggingToItself(view, target[0])) return void 0;
72
+ return target;
73
+ };
74
+ return getTarget;
75
+ }
76
+ function pointPointDistance(a, b) {
77
+ return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]);
78
+ }
79
+ function pointLineDistance(point, line) {
80
+ return Math.min(pointPointDistance(point, [line[0], line[1]]), pointPointDistance(point, [line[2], line[3]]));
81
+ }
82
+ /**
83
+ * Whether the dragging node is being dragged to the same position. For example,
84
+ * dragging a list node into a new position that is just below the list node, or
85
+ * dragging a nested quoteblock into itself.
86
+ */
87
+ function isDraggingToItself(view, pos) {
88
+ const dragging = view.dragging;
89
+ if (!dragging) return;
90
+ const { move } = dragging;
91
+ if (!move) return;
92
+ const selection = view.state.selection;
93
+ if (!isNodeSelection(selection)) return;
94
+ const { from, to } = selection;
95
+ return from <= pos && pos <= to;
96
+ }
97
+
98
+ //#endregion
99
+ //#region src/drop-indicator/drop-indicator-plugin.ts
100
+ /**
101
+ * @internal
102
+ */
103
+ function createDropIndicatorPlugin(options) {
104
+ let getTarget;
105
+ return new Plugin({
106
+ key: new PluginKey("prosekit-drop-indicator"),
107
+ view: (view) => {
108
+ getTarget = buildGetTarget(view, options.onDrag);
109
+ return createDropIndicatorView(view, getTarget, options);
110
+ },
111
+ props: { handleDrop(view, event, slice, move) {
112
+ if (!getTarget) return false;
113
+ const target = getTarget([event.clientX, event.clientY], event);
114
+ if (!target) return false;
115
+ event.preventDefault();
116
+ let insertPos = target[0];
117
+ let tr = view.state.tr;
118
+ if (move) {
119
+ let { node } = view.dragging || {};
120
+ if (node) node.replace(tr);
121
+ else tr.deleteSelection();
122
+ }
123
+ let pos = tr.mapping.map(insertPos);
124
+ let isNode = slice.openStart == 0 && slice.openEnd == 0 && slice.content.childCount == 1;
125
+ let beforeInsert = tr.doc;
126
+ if (isNode) tr.replaceRangeWith(pos, pos, slice.content.firstChild);
127
+ else tr.replaceRange(pos, pos, slice);
128
+ if (tr.doc.eq(beforeInsert)) return true;
129
+ let $pos = tr.doc.resolve(pos);
130
+ if (isNode && NodeSelection.isSelectable(slice.content.firstChild) && $pos.nodeAfter && $pos.nodeAfter.sameMarkup(slice.content.firstChild)) tr.setSelection(new NodeSelection($pos));
131
+ else {
132
+ let end = tr.mapping.map(insertPos);
133
+ tr.mapping.maps[tr.mapping.maps.length - 1].forEach((_from, _to, _newFrom, newTo) => end = newTo);
134
+ tr.setSelection(selectionBetween(view, $pos, tr.doc.resolve(end)));
135
+ }
136
+ view.focus();
137
+ view.dispatch(tr.setMeta("uiEvent", "drop"));
138
+ return true;
139
+ } }
140
+ });
141
+ }
142
+ function selectionBetween(view, $anchor, $head, bias) {
143
+ return view.someProp("createSelectionBetween", (f) => f(view, $anchor, $head)) || TextSelection.between($anchor, $head, bias);
144
+ }
145
+ function createDropIndicatorView(view, getTarget, options) {
146
+ let dom = view.dom;
147
+ let hideId;
148
+ let prevX;
149
+ let prevY;
150
+ let hasDragOverEvent = false;
151
+ const scheduleHide = () => {
152
+ if (hideId) clearTimeout(hideId);
153
+ hasDragOverEvent = false;
154
+ hideId = setTimeout(() => {
155
+ if (hasDragOverEvent) return;
156
+ options.onHide();
157
+ }, 30);
158
+ };
159
+ const handleDragOver = (event) => {
160
+ hasDragOverEvent = true;
161
+ const { clientX, clientY } = event;
162
+ if (prevX === clientX && prevY === clientY) return;
163
+ prevX = clientX;
164
+ prevY = clientY;
165
+ let target = getTarget([clientX, clientY], event);
166
+ if (!target) {
167
+ scheduleHide();
168
+ return;
169
+ } else {
170
+ const [pos, [x1, y1, x2, y2]] = target;
171
+ const line = {
172
+ p1: {
173
+ x: x1,
174
+ y: y1
175
+ },
176
+ p2: {
177
+ x: x2,
178
+ y: y2
179
+ }
180
+ };
181
+ options.onShow({
182
+ view,
183
+ pos,
184
+ line
185
+ });
186
+ }
187
+ };
188
+ dom.addEventListener("dragover", handleDragOver);
189
+ dom.addEventListener("dragend", scheduleHide);
190
+ dom.addEventListener("drop", scheduleHide);
191
+ dom.addEventListener("dragleave", scheduleHide);
192
+ const destroy = () => {
193
+ dom.removeEventListener("dragover", handleDragOver);
194
+ dom.removeEventListener("dragend", scheduleHide);
195
+ dom.removeEventListener("drop", scheduleHide);
196
+ dom.removeEventListener("dragleave", scheduleHide);
197
+ };
198
+ return { destroy };
199
+ }
200
+
201
+ //#endregion
202
+ //#region src/drop-indicator/drop-indicator-facet.ts
203
+ /**
204
+ * @internal
205
+ */
206
+ function defineDropIndicatorPayload(payload) {
207
+ return defineFacetPayload(dropIndicatorFacet, [payload]);
208
+ }
209
+ const dropIndicatorFacet = defineFacet({
210
+ parent: pluginFacet,
211
+ singleton: true,
212
+ reducer: (payloads) => {
213
+ let showHandlers = payloads.map((p) => p.onShow).filter((x) => !!x);
214
+ let hideHandlers = payloads.map((p) => p.onHide).filter((x) => !!x);
215
+ let dragHandlers = payloads.map((p) => p.onDrag).filter((x) => !!x);
216
+ let showHandler = (options) => {
217
+ for (let fn of showHandlers) fn(options);
218
+ };
219
+ let hideHandler = () => {
220
+ for (let fn of hideHandlers) fn();
221
+ };
222
+ let dragHandler = (options) => {
223
+ for (let fn of dragHandlers) if (fn(options) === false) return false;
224
+ return true;
225
+ };
226
+ if (showHandlers.length === 0) return [];
227
+ return createDropIndicatorPlugin({
228
+ onDrag: dragHandler,
229
+ onShow: showHandler,
230
+ onHide: hideHandler
231
+ });
232
+ }
233
+ });
234
+
235
+ //#endregion
236
+ //#region src/drop-indicator/drop-indicator.ts
237
+ /**
238
+ * Defines an extension that controls the behavior of the drop indicator.
239
+ *
240
+ * This extension itself doesn't draw the drop indicator, but it provides the
241
+ * necessary callbacks to do so. You probably don't want to use this extension
242
+ * directly, but rather use the `<DropIndicator>` component.
243
+ *
244
+ * You can add this extension multiple times. If any extension has `onDrag`
245
+ * callback defined, and it returns `false`, then the drop point will be
246
+ * discarded.
247
+ *
248
+ * @public
249
+ */
250
+ function defineDropIndicator(options) {
251
+ return defineDropIndicatorPayload(options ?? {});
252
+ }
253
+
254
+ //#endregion
255
+ export { defineDropIndicator };
@@ -1,89 +1,129 @@
1
- /* src/style.css */
2
- .prosemirror-flat-list {
3
- padding: 0;
4
- margin-top: 0;
5
- margin-bottom: 0;
6
- margin-left: 32px;
7
- margin-bottom: 0;
8
- position: relative;
9
- display: list-item;
10
- list-style: none;
11
- }
12
- .prosemirror-flat-list.ProseMirror-selectednode {
13
- outline: none;
14
- }
15
- .prosemirror-flat-list.ProseMirror-selectednode:after {
16
- content: "";
17
- position: absolute;
18
- left: -32px;
19
- right: -2px;
20
- top: -2px;
21
- bottom: -2px;
22
- border: 2px solid #8cf;
23
- pointer-events: none;
24
- }
25
- .prosemirror-flat-list[data-list-kind=bullet] {
26
- list-style: disc;
27
- }
28
- .prosemirror-flat-list[data-list-kind=ordered] > * {
29
- contain: style;
30
- }
31
- .prosemirror-flat-list[data-list-kind=ordered]::before {
32
- position: absolute;
33
- right: 100%;
34
- font-variant-numeric: tabular-nums;
35
- content: counter(prosemirror-flat-list-counter, decimal) ". ";
1
+ :root {
2
+ --prosekit-list-bullet-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='2.5' fill='currentColor'/%3E%3C/svg%3E");
3
+ --prosekit-list-toggle-open-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpolygon points='8,10 12,14 16,10' fill='currentColor'/%3E%3C/svg%3E");
4
+ --prosekit-list-toggle-closed-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpolygon points='10,8 14,12 10,16' fill='currentColor'/%3E%3C/svg%3E");
36
5
  }
37
- .prosemirror-flat-list[data-list-kind=ordered] {
38
- counter-increment: prosemirror-flat-list-counter;
39
- }
40
- .prosemirror-flat-list[data-list-kind=ordered]:first-child,
41
- :not(.prosemirror-flat-list[data-list-kind=ordered]) + .prosemirror-flat-list[data-list-kind=ordered] {
42
- counter-reset: prosemirror-flat-list-counter;
43
- }
44
- @supports (counter-set: prosemirror-flat-list-counter 1) {
45
- [data-list-order]:is(.prosemirror-flat-list[data-list-kind=ordered]:first-child, :not(.prosemirror-flat-list[data-list-kind=ordered]) + .prosemirror-flat-list[data-list-kind=ordered]) {
46
- counter-set: prosemirror-flat-list-counter var(--prosemirror-flat-list-order);
6
+
7
+ .prosemirror-flat-list {
8
+ & {
9
+ position: relative;
10
+ margin: 0;
11
+ padding: 0;
12
+ list-style: none;
47
13
  }
48
- }
49
- @supports not (counter-set: prosemirror-flat-list-counter 1) {
50
- [data-list-order]:is(.prosemirror-flat-list[data-list-kind=ordered]:first-child, :not(.prosemirror-flat-list[data-list-kind=ordered]) + .prosemirror-flat-list[data-list-kind=ordered]) {
51
- counter-increment: prosemirror-flat-list-counter var(--prosemirror-flat-list-order);
14
+
15
+ & > .list-marker {
16
+ position: absolute;
17
+ left: 0;
18
+ width: 1.5em;
19
+ width: 1lh;
20
+ height: 1.5em;
21
+ height: 1lh;
22
+ text-align: center;
52
23
  }
53
- }
54
- .prosemirror-flat-list[data-list-kind=task] > .list-marker {
55
- position: absolute;
56
- right: 100%;
57
- text-align: center;
58
- width: 1.5em;
59
- width: 1lh;
60
- }
61
- :is(.prosemirror-flat-list[data-list-kind=task] > .list-marker),
62
- :is(.prosemirror-flat-list[data-list-kind=task] > .list-marker) * {
63
- cursor: pointer;
64
- }
65
- .prosemirror-flat-list[data-list-kind=toggle] > .list-marker {
66
- position: absolute;
67
- right: 100%;
68
- text-align: center;
69
- width: 1.5em;
70
- width: 1lh;
71
- }
72
- .prosemirror-flat-list[data-list-kind=toggle] > .list-marker::before {
73
- content: "\23f7";
74
- }
75
- .prosemirror-flat-list[data-list-kind=toggle][data-list-collapsable][data-list-collapsed] > .list-marker::before {
76
- content: "\23f5";
77
- }
78
- .prosemirror-flat-list[data-list-kind=toggle][data-list-collapsable] > .list-marker {
79
- cursor: pointer;
80
- }
81
- .prosemirror-flat-list[data-list-kind=toggle]:not([data-list-collapsable]) > .list-marker {
82
- opacity: 40%;
83
- pointer-events: none;
84
- }
85
- .prosemirror-flat-list[data-list-kind=toggle][data-list-collapsable][data-list-collapsed] > .list-content > *:nth-child(n+2) {
86
- display: none;
87
- }
88
24
 
25
+ & > .list-content {
26
+ margin-left: 1.5em;
27
+ margin-left: 1lh;
28
+ }
29
+
30
+ &[data-list-kind="bullet"] > .list-marker,
31
+ &[data-list-kind="toggle"] > .list-marker {
32
+ background-color: currentColor;
33
+ mask-position: center;
34
+ mask-repeat: no-repeat;
35
+ mask-size: contain;
36
+ }
37
+
38
+ &[data-list-kind="bullet"] {
39
+ & > .list-marker {
40
+ mask-image: var(--prosekit-list-bullet-icon);
41
+ }
42
+ }
43
+
44
+ &[data-list-kind="toggle"] {
45
+ & > .list-marker {
46
+ mask-image: var(--prosekit-list-toggle-open-icon);
47
+ }
48
+
49
+ &[data-list-collapsable][data-list-collapsed] > .list-marker {
50
+ mask-image: var(--prosekit-list-toggle-closed-icon);
51
+ }
52
+ }
53
+
54
+ &[data-list-kind="ordered"] {
55
+ /*
56
+ Ensure that the counters in children don't escape, so that the sub lists
57
+ won't affect the counter of the parent list.
58
+
59
+ See also https://github.com/ocavue/prosemirror-flat-list/issues/23
60
+ */
61
+ & > * {
62
+ contain: style;
63
+ }
64
+
65
+ &::before {
66
+ position: absolute;
67
+ right: calc(100% - 1.5em);
68
+ right: calc(100% - 1lh);
69
+ content: counter(prosemirror-flat-list-counter, decimal) ". ";
70
+ font-variant-numeric: tabular-nums;
71
+ }
72
+ counter-increment: prosemirror-flat-list-counter;
73
+
74
+ /*
75
+ Reset the counter for the first list node in the sequence.
76
+ */
77
+ &:first-child,
78
+ :not(&) + & {
79
+ counter-reset: prosemirror-flat-list-counter;
80
+
81
+ /*
82
+ If the first list node has a custom order number, set the counter to that value.
83
+ */
84
+ &[data-list-order] {
85
+ @supports (counter-set: prosemirror-flat-list-counter 1) {
86
+ counter-set: prosemirror-flat-list-counter var(--prosemirror-flat-list-order);
87
+ }
88
+
89
+ /*
90
+ Safari older than version 17.2 doesn't support `counter-set`
91
+ */
92
+ @supports not (counter-set: prosemirror-flat-list-counter 1) {
93
+ counter-increment: prosemirror-flat-list-counter var(--prosemirror-flat-list-order);
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ &[data-list-kind="task"] {
100
+ & > .list-marker {
101
+ &,
102
+ & * {
103
+ /* Make sure that the checkbox is at the center */
104
+ display: flex;
105
+ align-items: center;
106
+ justify-content: center;
107
+ margin: 0;
108
+ padding: 0;
109
+ cursor: pointer;
110
+ }
111
+ }
112
+ }
113
+
114
+ &[data-list-kind="toggle"] {
115
+ &[data-list-collapsable] > .list-marker {
116
+ cursor: pointer;
117
+ }
118
+ &:not([data-list-collapsable]) > .list-marker {
119
+ opacity: 40%;
120
+ pointer-events: none;
121
+ }
122
+
123
+ /* If collapsed, hide the second and futher children */
124
+ &[data-list-collapsable][data-list-collapsed] > .list-content > *:nth-child(n+2) {
125
+ display: none;
126
+ }
127
+ }
128
+ }
89
129
 
@@ -1,4 +1,4 @@
1
- import { ShikiHighlighterOptions } from "./shiki-highlighter-chunk-CZGvZlhf.js";
1
+ import { ShikiHighlighterOptions } from "./shiki-highlighter-chunk-NV2F_Qjl.js";
2
2
  import { Extension, PlainExtension, Union } from "@prosekit/core";
3
3
  import { Parser } from "prosemirror-highlight";
4
4
  import { BundledLanguage as ShikiBundledLanguage, BundledLanguageInfo as ShikiBundledLanguageInfo, BundledTheme as ShikiBundledTheme, BundledThemeInfo as ShikiBundledThemeInfo, SpecialLanguage, bundledLanguagesInfo as shikiBundledLanguagesInfo, bundledThemesInfo as shikiBundledThemesInfo } from "shiki";
@@ -28,6 +28,8 @@ type DropCursorExtension = PlainExtension;
28
28
  *
29
29
  * See [prosemirror-dropcursor](https://github.com/ProseMirror/prosemirror-dropcursor) for more information.
30
30
  *
31
+ * You probably want to use `<DropIndicator />` component instead of this extension.
32
+ *
31
33
  * @public
32
34
  */
33
35
  declare function defineDropCursor(options?: DropCursorOptions): DropCursorExtension;
@@ -7,6 +7,8 @@ import { dropCursor } from "prosemirror-dropcursor";
7
7
  *
8
8
  * See [prosemirror-dropcursor](https://github.com/ProseMirror/prosemirror-dropcursor) for more information.
9
9
  *
10
+ * You probably want to use `<DropIndicator />` component instead of this extension.
11
+ *
10
12
  * @public
11
13
  */
12
14
  function defineDropCursor(options) {
@@ -0,0 +1,134 @@
1
+ import { PlainExtension } from "@prosekit/core";
2
+ import { NodeSelection } from "@prosekit/pm/state";
3
+ import { EditorView } from "@prosekit/pm/view";
4
+ import { Slice } from "@prosekit/pm/model";
5
+
6
+ //#region src/drop-indicator/types.d.ts
7
+
8
+ /**
9
+ * A function that will be called when the `dragover` event is fired. You can
10
+ * return `false` to disable the current drop point and thus hide the drop
11
+ * indicator.
12
+ *
13
+ * @public
14
+ */
15
+ type DragEventHandler = (options: DragEventHandlerOptions) => boolean;
16
+ /**
17
+ * Options for {@link DragEventHandler}.
18
+ *
19
+ * @public
20
+ */
21
+ interface DragEventHandlerOptions {
22
+ /**
23
+ * The editor's view.
24
+ */
25
+ view: EditorView;
26
+ /**
27
+ * The drop position in current document.
28
+ */
29
+ pos: number;
30
+ /**
31
+ * The `dragover` event.
32
+ */
33
+ event: DragEvent;
34
+ }
35
+ /**
36
+ * A function that will be called when the drop indicator should be shown.
37
+ *
38
+ * @public
39
+ */
40
+ type ShowHandler = (options: ShowHandlerOptions) => void;
41
+ /**
42
+ * Options for {@link ShowHandler}.
43
+ *
44
+ * @public
45
+ */
46
+ interface ShowHandlerOptions {
47
+ /**
48
+ * The editor's view.
49
+ */
50
+ view: EditorView;
51
+ /**
52
+ * The ProseMirror position that the drop indicator should be shown at.
53
+ */
54
+ pos: number;
55
+ /**
56
+ * The line that the drop indicator should be shown at.
57
+ */
58
+ line: Line;
59
+ }
60
+ /**
61
+ * @internal
62
+ */
63
+ interface Point {
64
+ readonly x: number;
65
+ readonly y: number;
66
+ }
67
+ /**
68
+ * @internal
69
+ */
70
+ interface Line {
71
+ readonly p1: Point;
72
+ readonly p2: Point;
73
+ }
74
+ /**
75
+ * An interface matching the internal ProseMirror implementation.
76
+ *
77
+ * See https://github.com/ProseMirror/prosemirror-view/blob/1.38.1/src/input.ts#L657
78
+ *
79
+ * @internal
80
+ */
81
+ interface ViewDragging {
82
+ readonly slice: Slice;
83
+ readonly move: boolean;
84
+ readonly node?: NodeSelection;
85
+ }
86
+ //#endregion
87
+ //#region src/drop-indicator/drop-indicator-facet.d.ts
88
+ /**
89
+ * @internal
90
+ */
91
+ interface DropIndicatorPayload {
92
+ /**
93
+ * A callback that is called when the drop indicator should be shown.
94
+ */
95
+ onShow?: ShowHandler;
96
+ /**
97
+ * A callback that is called when the drop indicator should be hidden.
98
+ */
99
+ onHide?: VoidFunction;
100
+ /**
101
+ * A callback that is called when the `dragover` event is fired. You can
102
+ * return `false` to disable the current drop point and thus hide the drop
103
+ * indicator.
104
+ */
105
+ onDrag?: DragEventHandler;
106
+ }
107
+ //#endregion
108
+ //#region src/drop-indicator/drop-indicator.d.ts
109
+ /**
110
+ * @internal
111
+ */
112
+ type DropIndicatorExtension = PlainExtension;
113
+ /**
114
+ * Defines an extension that controls the behavior of the drop indicator.
115
+ *
116
+ * This extension itself doesn't draw the drop indicator, but it provides the
117
+ * necessary callbacks to do so. You probably don't want to use this extension
118
+ * directly, but rather use the `<DropIndicator>` component.
119
+ *
120
+ * You can add this extension multiple times. If any extension has `onDrag`
121
+ * callback defined, and it returns `false`, then the drop point will be
122
+ * discarded.
123
+ *
124
+ * @public
125
+ */
126
+ declare function defineDropIndicator(options?: DropIndicatorOptions): DropIndicatorExtension;
127
+ /**
128
+ * Options for {@link defineDropIndicator}.
129
+ *
130
+ * @public
131
+ */
132
+ interface DropIndicatorOptions extends DropIndicatorPayload {}
133
+ //#endregion
134
+ export { type DragEventHandler, type DragEventHandlerOptions, type DropIndicatorExtension, type DropIndicatorOptions, type Line, type Point, type ShowHandler, type ShowHandlerOptions, type ViewDragging, defineDropIndicator };
@@ -0,0 +1,3 @@
1
+ import { defineDropIndicator } from "./drop-indicator-QKkPzJIx.js";
2
+
3
+ export { defineDropIndicator };
@@ -1,6 +1,6 @@
1
1
  import { defineInputRule } from "./input-rule-Gji4N7Oe.js";
2
2
  import { defineEnterRule } from "./enter-rule-RdhEA900.js";
3
- import { defineMarkRule } from "./mark-rule-wEOcDt6i.js";
3
+ import { defineMarkRule } from "./mark-rule-D7zaa32n.js";
4
4
  import { addMark, defineCommands, defineMarkSpec, expandMark, removeMark, toggleMark, union } from "@prosekit/core";
5
5
  import { InputRule } from "@prosekit/pm/inputrules";
6
6
 
@@ -1,9 +1,10 @@
1
1
  import { defineInputRule } from "./input-rule-Gji4N7Oe.js";
2
+ import { defineDropIndicator } from "./drop-indicator-QKkPzJIx.js";
2
3
  import { defineClipboardSerializer, defineCommands, defineKeymap, defineNodeSpec, definePlugin, insertNode, union } from "@prosekit/core";
3
4
  import { Plugin } from "@prosekit/pm/state";
4
5
  import { chainCommands, deleteSelection } from "@prosekit/pm/commands";
5
- import { ListDOMSerializer, createDedentListCommand, createIndentListCommand, createListEventPlugin, createListRenderingPlugin, createListSpec, createMoveListCommand, createSafariInputMethodWorkaroundPlugin, createSplitListCommand, createToggleCollapsedCommand, createToggleListCommand, createUnwrapListCommand, createWrapInListCommand, deleteCommand, enterCommand, joinCollapsedListBackward, joinListElements, joinListUp, listInputRules, listToDOM, protectCollapsed, unwrapListSlice } from "prosemirror-flat-list";
6
6
  import { isElementLike } from "@ocavue/utils";
7
+ import { ListDOMSerializer, createDedentListCommand, createIndentListCommand, createListEventPlugin, createListRenderingPlugin, createListSpec, createMoveListCommand, createSafariInputMethodWorkaroundPlugin, createSplitListCommand, createToggleCollapsedCommand, createToggleListCommand, createUnwrapListCommand, createWrapInListCommand, deleteCommand, enterCommand, joinCollapsedListBackward, joinListElements, joinListUp, listInputRules, listToDOM, protectCollapsed, unwrapListSlice } from "prosemirror-flat-list";
7
8
 
8
9
  //#region src/list/list-commands.ts
9
10
  function insertList(attrs) {
@@ -31,6 +32,31 @@ function defineListCommands() {
31
32
  });
32
33
  }
33
34
 
35
+ //#endregion
36
+ //#region src/list/list-drop-indicator.ts
37
+ /**
38
+ * Configures drop indicator to avoid unexpected drop point.
39
+ *
40
+ * We don't want to drag a list node and drop it as the first
41
+ * child of another list node.
42
+ *
43
+ * @internal
44
+ */
45
+ function defineListDropIndicator() {
46
+ return defineDropIndicator({ onDrag });
47
+ }
48
+ const onDrag = ({ view, pos }) => {
49
+ const slice = view.dragging?.slice;
50
+ if (slice && slice.openStart === 0 && slice.openEnd === 0 && slice.content.childCount === 1) {
51
+ const node = slice.content.child(0);
52
+ if (node.type.name === "list") {
53
+ const $pos = view.state.doc.resolve(pos);
54
+ if ($pos.parent.type.name === "list" && $pos.index() === 0) return false;
55
+ }
56
+ }
57
+ return true;
58
+ };
59
+
34
60
  //#endregion
35
61
  //#region src/list/list-input-rules.ts
36
62
  /**
@@ -120,12 +146,29 @@ function defineListSerializer() {
120
146
 
121
147
  //#endregion
122
148
  //#region src/list/list-spec.ts
149
+ function getMarkers(node) {
150
+ const attrs = node.attrs;
151
+ switch (attrs.kind) {
152
+ case "task": return [["label", ["input", {
153
+ type: "checkbox",
154
+ checked: attrs.checked ? "" : void 0
155
+ }]]];
156
+ default: return [];
157
+ }
158
+ }
123
159
  /**
124
160
  * @internal
125
161
  */
126
162
  function defineListSpec() {
163
+ const spec = createListSpec();
127
164
  return defineNodeSpec({
128
- ...createListSpec(),
165
+ ...spec,
166
+ toDOM: (node) => {
167
+ return listToDOM({
168
+ node,
169
+ getMarkers
170
+ });
171
+ },
129
172
  name: "list"
130
173
  });
131
174
  }
@@ -136,7 +179,7 @@ function defineListSpec() {
136
179
  * @public
137
180
  */
138
181
  function defineList() {
139
- return union(defineListSpec(), defineListPlugins(), defineListKeymap(), defineListInputRules(), defineListCommands(), defineListSerializer());
182
+ return union(defineListSpec(), defineListPlugins(), defineListKeymap(), defineListInputRules(), defineListCommands(), defineListSerializer(), defineListDropIndicator());
140
183
  }
141
184
 
142
185
  //#endregion
@@ -1,3 +1,3 @@
1
- import { defineMarkRule } from "./mark-rule-wEOcDt6i.js";
1
+ import { defineMarkRule } from "./mark-rule-D7zaa32n.js";
2
2
 
3
3
  export { defineMarkRule };
@@ -1,4 +1,4 @@
1
- import { findTable } from "./table-dVQqzLlz.js";
1
+ import { findTable } from "./table-3rDWFyBH.js";
2
2
  import { definePlugin, isInCodeBlock, maybeRun } from "@prosekit/core";
3
3
  import { Plugin, PluginKey } from "@prosekit/pm/state";
4
4
  import { Decoration, DecorationSet } from "@prosekit/pm/view";
@@ -1,3 +1,3 @@
1
- import { defineTable, defineTableCellSpec, defineTableCommands, defineTableHeaderCellSpec, defineTablePlugins, defineTableRowSpec, defineTableSpec, exitTable, findTable, insertTable, isCellSelection, moveTableColumn, moveTableRow, selectTable, selectTableCell, selectTableColumn, selectTableRow } from "./table-dVQqzLlz.js";
1
+ import { defineTable, defineTableCellSpec, defineTableCommands, defineTableHeaderCellSpec, defineTablePlugins, defineTableRowSpec, defineTableSpec, exitTable, findTable, insertTable, isCellSelection, moveTableColumn, moveTableRow, selectTable, selectTableCell, selectTableColumn, selectTableRow } from "./table-3rDWFyBH.js";
2
2
 
3
3
  export { defineTable, defineTableCellSpec, defineTableCommands, defineTableHeaderCellSpec, defineTablePlugins, defineTableRowSpec, defineTableSpec, exitTable, findTable, insertTable, isCellSelection, moveTableColumn, moveTableRow, selectTable, selectTableCell, selectTableColumn, selectTableRow };
@@ -48,7 +48,7 @@ const virtualSelectionPlugin = new ProseMirrorPlugin({
48
48
  },
49
49
  decorations: (state) => {
50
50
  const { selection, doc } = state;
51
- if (selection.empty || !getFocusState(state)) return null;
51
+ if (selection.empty || !getFocusState(state) || !selection.visible) return null;
52
52
  return DecorationSet.create(doc, [Decoration.inline(selection.from, selection.to, { class: "prosekit-virtual-selection" })]);
53
53
  }
54
54
  }
@@ -1,2 +1,2 @@
1
- import { HighlighterOptions, HighlighterResult, ShikiHighlighterOptions, createOrGetHighlighter } from "./shiki-highlighter-chunk-CZGvZlhf.js";
1
+ import { HighlighterOptions, HighlighterResult, ShikiHighlighterOptions, createOrGetHighlighter } from "./shiki-highlighter-chunk-NV2F_Qjl.js";
2
2
  export { HighlighterOptions, HighlighterResult, ShikiHighlighterOptions, createOrGetHighlighter };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@prosekit/extensions",
3
3
  "type": "module",
4
- "version": "0.10.1",
4
+ "version": "0.11.1",
5
5
  "private": false,
6
6
  "description": "A collection of common extensions for ProseKit",
7
7
  "author": {
@@ -10,14 +10,14 @@
10
10
  },
11
11
  "license": "MIT",
12
12
  "funding": "https://github.com/sponsors/ocavue",
13
- "homepage": "https://github.com/ocavue/prosekit#readme",
13
+ "homepage": "https://github.com/prosekit/prosekit#readme",
14
14
  "repository": {
15
15
  "type": "git",
16
- "url": "git+https://github.com/ocavue/prosekit.git",
16
+ "url": "git+https://github.com/prosekit/prosekit.git",
17
17
  "directory": "packages/extensions"
18
18
  },
19
19
  "bugs": {
20
- "url": "https://github.com/ocavue/prosekit/issues"
20
+ "url": "https://github.com/prosekit/prosekit/issues"
21
21
  },
22
22
  "keywords": [
23
23
  "ProseMirror"
@@ -65,6 +65,10 @@
65
65
  "types": "./dist/prosekit-extensions-drop-cursor.d.ts",
66
66
  "default": "./dist/prosekit-extensions-drop-cursor.js"
67
67
  },
68
+ "./drop-indicator": {
69
+ "types": "./dist/prosekit-extensions-drop-indicator.d.ts",
70
+ "default": "./dist/prosekit-extensions-drop-indicator.js"
71
+ },
68
72
  "./enter-rule": {
69
73
  "types": "./dist/prosekit-extensions-enter-rule.d.ts",
70
74
  "default": "./dist/prosekit-extensions-enter-rule.js"
@@ -198,7 +202,7 @@
198
202
  "dist"
199
203
  ],
200
204
  "dependencies": {
201
- "@ocavue/utils": "^0.5.0",
205
+ "@ocavue/utils": "^0.6.0",
202
206
  "prosemirror-changeset": "^2.3.1",
203
207
  "prosemirror-dropcursor": "^1.8.2",
204
208
  "prosemirror-flat-list": "^0.5.5",
@@ -206,9 +210,9 @@
206
210
  "prosemirror-highlight": "^0.13.0",
207
211
  "prosemirror-search": "^1.1.0",
208
212
  "prosemirror-tables": "^1.7.1",
209
- "shiki": "^3.8.1",
210
- "@prosekit/core": "^0.8.3",
211
- "@prosekit/pm": "^0.1.11"
213
+ "shiki": "^3.9.1",
214
+ "@prosekit/pm": "^0.1.11",
215
+ "@prosekit/core": "^0.8.3"
212
216
  },
213
217
  "peerDependencies": {
214
218
  "loro-crdt": ">= 0.16.7",
@@ -242,7 +246,7 @@
242
246
  "remark-html": "^16.0.1",
243
247
  "remark-parse": "^11.0.0",
244
248
  "remark-stringify": "^11.0.0",
245
- "tsdown": "^0.13.0",
249
+ "tsdown": "^0.13.1",
246
250
  "type-fest": "^4.41.0",
247
251
  "typescript": "~5.8.3",
248
252
  "unified": "^11.0.5",
@@ -268,6 +272,7 @@
268
272
  "commit/style": "./src/commit/style.css",
269
273
  "prosekit-extensions-doc": "./src/doc/index.ts",
270
274
  "prosekit-extensions-drop-cursor": "./src/drop-cursor/index.ts",
275
+ "prosekit-extensions-drop-indicator": "./src/drop-indicator/index.ts",
271
276
  "prosekit-extensions-enter-rule": "./src/enter-rule/index.ts",
272
277
  "prosekit-extensions-file": "./src/file/index.ts",
273
278
  "prosekit-extensions-gap-cursor": "./src/gap-cursor/index.ts",
@@ -338,6 +343,9 @@
338
343
  "drop-cursor": [
339
344
  "./dist/prosekit-extensions-drop-cursor.d.ts"
340
345
  ],
346
+ "drop-indicator": [
347
+ "./dist/prosekit-extensions-drop-indicator.d.ts"
348
+ ],
341
349
  "enter-rule": [
342
350
  "./dist/prosekit-extensions-enter-rule.d.ts"
343
351
  ],
File without changes