@blocknote/core 0.47.1 → 0.47.2
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/BlockNoteExtension-BWw0r8Gy.cjs.map +1 -1
- package/dist/BlockNoteExtension-C2X7LW-V.js.map +1 -1
- package/dist/{BlockNoteSchema-CwhtPpVC.cjs → BlockNoteSchema-CCs_V3lo.cjs} +2 -2
- package/dist/{BlockNoteSchema-CwhtPpVC.cjs.map → BlockNoteSchema-CCs_V3lo.cjs.map} +1 -1
- package/dist/{BlockNoteSchema-dmbNkHA-.js → BlockNoteSchema-ooiKsd5B.js} +2 -2
- package/dist/{BlockNoteSchema-dmbNkHA-.js.map → BlockNoteSchema-ooiKsd5B.js.map} +1 -1
- package/dist/{TrailingNode-F9hX_UlQ.js → TrailingNode-GzE59m_7.js} +585 -415
- package/dist/TrailingNode-GzE59m_7.js.map +1 -0
- package/dist/TrailingNode-n0WdMPUl.cjs +2 -0
- package/dist/TrailingNode-n0WdMPUl.cjs.map +1 -0
- package/dist/blocknote.cjs +4 -4
- package/dist/blocknote.cjs.map +1 -1
- package/dist/blocknote.js +76 -40
- package/dist/blocknote.js.map +1 -1
- package/dist/blocks.cjs +1 -1
- package/dist/blocks.js +2 -2
- package/dist/comments.cjs.map +1 -1
- package/dist/comments.js.map +1 -1
- package/dist/defaultBlocks-Dg9kQWXm.cjs +6 -0
- package/dist/defaultBlocks-Dg9kQWXm.cjs.map +1 -0
- package/dist/{defaultBlocks-Caw1U1oV.js → defaultBlocks-ZzGbYgQn.js} +611 -530
- package/dist/defaultBlocks-ZzGbYgQn.js.map +1 -0
- package/dist/extensions.cjs +1 -1
- package/dist/extensions.cjs.map +1 -1
- package/dist/extensions.js +33 -54
- package/dist/extensions.js.map +1 -1
- package/dist/locales.cjs +1 -1
- package/dist/locales.cjs.map +1 -1
- package/dist/locales.js +25 -24
- package/dist/locales.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +1 -10
- package/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.ts +4 -1
- package/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +7 -1
- package/src/blocks/Heading/block.ts +48 -1
- package/src/blocks/ListItem/ToggleListItem/block.ts +51 -1
- package/src/blocks/Paragraph/block.ts +1 -1
- package/src/blocks/getDetailsContent.ts +77 -0
- package/src/comments/threadstore/TipTapThreadStore.ts +5 -5
- package/src/comments/threadstore/tiptap/types.ts +131 -0
- package/src/editor/Block.css +6 -0
- package/src/editor/BlockNoteEditor.ts +9 -14
- package/src/editor/managers/ExtensionManager/symbol.ts +0 -1
- package/src/editor/managers/SelectionManager.ts +3 -1
- package/src/extensions/DropCursor/DropCursor.ts +262 -25
- package/src/extensions/DropCursor/utils.ts +195 -0
- package/src/extensions/tiptap-extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +15 -10
- package/src/i18n/locales/fa.ts +4 -21
- package/src/i18n/locales/index.ts +1 -1
- package/src/i18n/locales/ru.ts +1 -1
- package/src/i18n/locales/uz.ts +22 -4
- package/src/index.ts +1 -0
- package/src/schema/blocks/createSpec.ts +33 -45
- package/src/schema/blocks/types.ts +101 -1
- package/types/src/blocks/getDetailsContent.d.ts +19 -0
- package/types/src/comments/threadstore/TipTapThreadStore.d.ts +1 -1
- package/types/src/comments/threadstore/tiptap/types.d.ts +73 -0
- package/types/src/editor/BlockNoteEditor.d.ts +6 -9
- package/types/src/extensions/DropCursor/DropCursor.d.ts +42 -5
- package/types/src/extensions/DropCursor/utils.d.ts +48 -0
- package/types/src/index.d.ts +1 -0
- package/types/src/schema/blocks/createSpec.d.ts +3 -3
- package/types/src/schema/blocks/types.d.ts +31 -1
- package/dist/TrailingNode-DHOdUVUO.cjs +0 -2
- package/dist/TrailingNode-DHOdUVUO.cjs.map +0 -1
- package/dist/TrailingNode-F9hX_UlQ.js.map +0 -1
- package/dist/defaultBlocks-CSB5GiAu.cjs +0 -6
- package/dist/defaultBlocks-CSB5GiAu.cjs.map +0 -1
- package/dist/defaultBlocks-Caw1U1oV.js.map +0 -1
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
getSchema,
|
|
6
6
|
Editor as TiptapEditor,
|
|
7
7
|
} from "@tiptap/core";
|
|
8
|
-
import { type Command, type
|
|
8
|
+
import { type Command, type Transaction } from "@tiptap/pm/state";
|
|
9
9
|
import { Node, Schema } from "prosemirror-model";
|
|
10
10
|
import type { BlocksChanged } from "../api/getBlocksChangedByTransaction.js";
|
|
11
11
|
import { blockToNode } from "../api/nodeConversions/blockToNode.js";
|
|
@@ -18,7 +18,10 @@ import {
|
|
|
18
18
|
PartialBlock,
|
|
19
19
|
} from "../blocks/index.js";
|
|
20
20
|
import type { CollaborationOptions } from "../extensions/Collaboration/Collaboration.js";
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
BlockChangeExtension,
|
|
23
|
+
DropCursorOptions,
|
|
24
|
+
} from "../extensions/index.js";
|
|
22
25
|
import { UniqueID } from "../extensions/tiptap-extensions/UniqueID/UniqueID.js";
|
|
23
26
|
import type { Dictionary } from "../i18n/dictionary.js";
|
|
24
27
|
import { en } from "../i18n/locales/index.js";
|
|
@@ -118,19 +121,11 @@ export interface BlockNoteEditorOptions<
|
|
|
118
121
|
domAttributes?: Partial<BlockNoteDOMAttributes>;
|
|
119
122
|
|
|
120
123
|
/**
|
|
121
|
-
*
|
|
122
|
-
*
|
|
124
|
+
* Options for configuring the drop cursor behavior when dragging and dropping blocks.
|
|
125
|
+
* Allows customization of cursor appearance and drop position computation through hooks.
|
|
126
|
+
* @remarks `DropCursorOptions`
|
|
123
127
|
*/
|
|
124
|
-
dropCursor?:
|
|
125
|
-
editor: BlockNoteEditor<
|
|
126
|
-
NoInfer<BSchema>,
|
|
127
|
-
NoInfer<ISchema>,
|
|
128
|
-
NoInfer<SSchema>
|
|
129
|
-
>;
|
|
130
|
-
color?: string | false;
|
|
131
|
-
width?: number;
|
|
132
|
-
class?: string;
|
|
133
|
-
}) => Plugin;
|
|
128
|
+
dropCursor?: DropCursorOptions;
|
|
134
129
|
|
|
135
130
|
/**
|
|
136
131
|
* The content that should be in the editor when it's created, represented as an array of {@link PartialBlock} objects.
|
|
@@ -48,7 +48,9 @@ export class SelectionManager<
|
|
|
48
48
|
* only the part of the block that is included in the selection.
|
|
49
49
|
*/
|
|
50
50
|
public getSelectionCutBlocks(expandToWords = false) {
|
|
51
|
-
return this.editor.transact((tr) =>
|
|
51
|
+
return this.editor.transact((tr) =>
|
|
52
|
+
getSelectionCutBlocks(tr, expandToWords),
|
|
53
|
+
);
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
/**
|
|
@@ -1,26 +1,263 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { dropPoint } from "prosemirror-transform";
|
|
2
|
+
import type { EditorView } from "prosemirror-view";
|
|
2
3
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
4
|
+
applyOrientationClasses,
|
|
5
|
+
getBlockDropRect,
|
|
6
|
+
getInlineDropRect,
|
|
7
|
+
getParentOffsets,
|
|
8
|
+
hasExclusionClassname,
|
|
9
|
+
type DropCursorPosition,
|
|
10
|
+
} from "./utils.js";
|
|
11
|
+
import type { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
|
|
12
|
+
import { createExtension } from "../../editor/BlockNoteExtension.js";
|
|
13
|
+
|
|
14
|
+
export const DRAG_EXCLUSION_CLASSNAME = "bn-drag-exclude";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Context passed to the computeDropPosition hook.
|
|
18
|
+
*/
|
|
19
|
+
export interface ComputeDropPositionContext {
|
|
20
|
+
editor: BlockNoteEditor<any, any, any>;
|
|
21
|
+
event: DragEvent;
|
|
22
|
+
view: EditorView;
|
|
23
|
+
defaultPosition: DropCursorPosition | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Hooks for customizing drop cursor behavior.
|
|
28
|
+
*/
|
|
29
|
+
export interface DropCursorHooks {
|
|
30
|
+
/**
|
|
31
|
+
* Compute cursor position and orientation.
|
|
32
|
+
* Return null to prevent dropping (no cursor shown).
|
|
33
|
+
*/
|
|
34
|
+
computeDropPosition?: (
|
|
35
|
+
context: ComputeDropPositionContext,
|
|
36
|
+
) => DropCursorPosition | null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Options for the DropCursor extension.
|
|
41
|
+
*/
|
|
42
|
+
export interface DropCursorOptions {
|
|
43
|
+
width?: number; // Cursor width in pixels (default: 5)
|
|
44
|
+
color?: string | false; // Cursor color (default: "#ddeeff")
|
|
45
|
+
exclude?: string; // CSS class for exclusion (default: "bn-drag-exclude")
|
|
46
|
+
hooks?: DropCursorHooks; // Optional behavior hooks
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Drop cursor visualization based on prosemirror-dropcursor:
|
|
51
|
+
* https://github.com/ProseMirror/prosemirror-dropcursor/blob/master/src/dropcursor.ts
|
|
52
|
+
*
|
|
53
|
+
* Refactored to use BlockNote extension pattern with mount callback and AbortSignal
|
|
54
|
+
* for lifecycle management instead of ProseMirror PluginView.
|
|
55
|
+
*/
|
|
56
|
+
export const DropCursorExtension = createExtension<
|
|
57
|
+
any,
|
|
58
|
+
{
|
|
59
|
+
dropCursor?: DropCursorOptions;
|
|
60
|
+
}
|
|
61
|
+
>(({ editor, options }) => {
|
|
62
|
+
// State
|
|
63
|
+
let cursorPos: DropCursorPosition | null = null;
|
|
64
|
+
let element: HTMLElement | null = null;
|
|
65
|
+
let timeout = -1;
|
|
66
|
+
let dragSourceElement: Element | null = null;
|
|
67
|
+
|
|
68
|
+
const config = {
|
|
69
|
+
width: options.dropCursor?.width ?? 5,
|
|
70
|
+
color: options.dropCursor?.color ?? "#ddeeff",
|
|
71
|
+
exclude: options.dropCursor?.exclude ?? DRAG_EXCLUSION_CLASSNAME,
|
|
72
|
+
hooks: options.dropCursor?.hooks,
|
|
73
|
+
} as const;
|
|
74
|
+
|
|
75
|
+
// Helper functions
|
|
76
|
+
const setCursor = (pos: DropCursorPosition | null) => {
|
|
77
|
+
if (
|
|
78
|
+
pos?.pos === cursorPos?.pos &&
|
|
79
|
+
pos?.orientation === cursorPos?.orientation
|
|
80
|
+
) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
cursorPos = pos;
|
|
84
|
+
|
|
85
|
+
if (pos == null) {
|
|
86
|
+
if (element && element.parentNode) {
|
|
87
|
+
element.parentNode.removeChild(element);
|
|
88
|
+
}
|
|
89
|
+
element = null;
|
|
90
|
+
} else {
|
|
91
|
+
updateOverlay();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const updateOverlay = () => {
|
|
96
|
+
if (!cursorPos) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const view = editor.prosemirrorView;
|
|
101
|
+
const editorDOM = view.dom;
|
|
102
|
+
const editorRect = editorDOM.getBoundingClientRect();
|
|
103
|
+
const scaleX = editorRect.width / editorDOM.offsetWidth;
|
|
104
|
+
const scaleY = editorRect.height / editorDOM.offsetHeight;
|
|
105
|
+
|
|
106
|
+
const blockRect = getBlockDropRect(
|
|
107
|
+
view,
|
|
108
|
+
cursorPos,
|
|
109
|
+
config.width,
|
|
110
|
+
scaleX,
|
|
111
|
+
scaleY,
|
|
112
|
+
);
|
|
113
|
+
const rect =
|
|
114
|
+
blockRect ?? getInlineDropRect(view, cursorPos, config.width, scaleX);
|
|
115
|
+
|
|
116
|
+
const parent = view.dom.offsetParent as HTMLElement;
|
|
117
|
+
if (!element) {
|
|
118
|
+
element = parent.appendChild(document.createElement("div"));
|
|
119
|
+
element.style.cssText =
|
|
120
|
+
"position: absolute; z-index: 50; pointer-events: none;";
|
|
121
|
+
if (config.color) {
|
|
122
|
+
element.style.backgroundColor = config.color;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
applyOrientationClasses(element, cursorPos.orientation);
|
|
127
|
+
|
|
128
|
+
const { parentLeft, parentTop } = getParentOffsets(parent);
|
|
129
|
+
|
|
130
|
+
element.style.left = (rect.left - parentLeft) / scaleX + "px";
|
|
131
|
+
element.style.top = (rect.top - parentTop) / scaleY + "px";
|
|
132
|
+
element.style.width = (rect.right - rect.left) / scaleX + "px";
|
|
133
|
+
element.style.height = (rect.bottom - rect.top) / scaleY + "px";
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const scheduleRemoval = (ms: number) => {
|
|
137
|
+
clearTimeout(timeout);
|
|
138
|
+
timeout = window.setTimeout(() => setCursor(null), ms);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// Event handlers
|
|
142
|
+
const onDragStart = (event: Event) => {
|
|
143
|
+
const e = event as DragEvent;
|
|
144
|
+
dragSourceElement = e.target instanceof Element ? e.target : null;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const onDragOver = (event: Event) => {
|
|
148
|
+
const e = event as DragEvent;
|
|
149
|
+
|
|
150
|
+
// Check if drag source has exclusion classname
|
|
151
|
+
if (
|
|
152
|
+
dragSourceElement &&
|
|
153
|
+
hasExclusionClassname(dragSourceElement, config.exclude)
|
|
154
|
+
) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Check if drop target has exclusion classname
|
|
159
|
+
if (
|
|
160
|
+
e.target instanceof Element &&
|
|
161
|
+
hasExclusionClassname(e.target, config.exclude)
|
|
162
|
+
) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const view = editor.prosemirrorView;
|
|
167
|
+
if (!view.editable) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const pos = view.posAtCoords({
|
|
172
|
+
left: e.clientX,
|
|
173
|
+
top: e.clientY,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const node = pos && pos.inside >= 0 && view.state.doc.nodeAt(pos.inside);
|
|
177
|
+
const disableDropCursor = node && (node.type.spec as any).disableDropCursor;
|
|
178
|
+
const disabled =
|
|
179
|
+
typeof disableDropCursor === "function"
|
|
180
|
+
? disableDropCursor(view, pos, e)
|
|
181
|
+
: disableDropCursor;
|
|
182
|
+
|
|
183
|
+
if (pos && !disabled) {
|
|
184
|
+
let target = pos.pos;
|
|
185
|
+
if (view.dragging && view.dragging.slice) {
|
|
186
|
+
const point = dropPoint(view.state.doc, target, view.dragging.slice);
|
|
187
|
+
if (point != null) {
|
|
188
|
+
target = point;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Compute default position
|
|
193
|
+
const $pos = view.state.doc.resolve(target);
|
|
194
|
+
const isBlock = !$pos.parent.inlineContent;
|
|
195
|
+
const defaultPosition: DropCursorPosition = {
|
|
196
|
+
pos: target,
|
|
197
|
+
orientation: isBlock ? "block-horizontal" : "inline",
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Allow hook to override position
|
|
201
|
+
let finalPosition = defaultPosition;
|
|
202
|
+
if (config.hooks?.computeDropPosition) {
|
|
203
|
+
const hookResult = config.hooks.computeDropPosition({
|
|
204
|
+
editor,
|
|
205
|
+
event: e,
|
|
206
|
+
view,
|
|
207
|
+
defaultPosition,
|
|
208
|
+
});
|
|
209
|
+
if (hookResult === null) {
|
|
210
|
+
// Hook returned null - don't show cursor
|
|
211
|
+
setCursor(null);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
finalPosition = hookResult;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
setCursor(finalPosition);
|
|
218
|
+
scheduleRemoval(5000);
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const onDragLeave = (event: Event) => {
|
|
223
|
+
const e = event as DragEvent;
|
|
224
|
+
if (
|
|
225
|
+
!(e.relatedTarget instanceof Node) ||
|
|
226
|
+
!editor.prosemirrorView.dom.contains(e.relatedTarget)
|
|
227
|
+
) {
|
|
228
|
+
setCursor(null);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const onDrop = () => {
|
|
233
|
+
scheduleRemoval(20);
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const onDragEnd = () => {
|
|
237
|
+
scheduleRemoval(20);
|
|
238
|
+
dragSourceElement = null;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
key: "dropCursor",
|
|
243
|
+
mount({ signal, dom, root }) {
|
|
244
|
+
// Track drag source at document level
|
|
245
|
+
root.addEventListener("dragstart", onDragStart, {
|
|
246
|
+
capture: true,
|
|
247
|
+
signal,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Handle drag events on the editor
|
|
251
|
+
dom.addEventListener("dragover", onDragOver, { signal });
|
|
252
|
+
dom.addEventListener("dragleave", onDragLeave, { signal });
|
|
253
|
+
dom.addEventListener("drop", onDrop, { signal });
|
|
254
|
+
dom.addEventListener("dragend", onDragEnd, { signal });
|
|
255
|
+
|
|
256
|
+
// Clean up on unmount
|
|
257
|
+
signal.addEventListener("abort", () => {
|
|
258
|
+
clearTimeout(timeout);
|
|
259
|
+
setCursor(null);
|
|
260
|
+
});
|
|
261
|
+
},
|
|
262
|
+
} as const;
|
|
263
|
+
});
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import type { EditorView } from "prosemirror-view";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The orientation of the drop cursor.
|
|
5
|
+
*/
|
|
6
|
+
export type DropCursorOrientation =
|
|
7
|
+
| "inline" // Vertical line within text
|
|
8
|
+
| "block-horizontal" // Horizontal line between blocks
|
|
9
|
+
| "block-vertical-left" // Vertical line on left edge of block
|
|
10
|
+
| "block-vertical-right"; // Vertical line on right edge of block
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The position and orientation of the drop cursor.
|
|
14
|
+
*/
|
|
15
|
+
export type DropCursorPosition = {
|
|
16
|
+
pos: number; // Document position
|
|
17
|
+
orientation: DropCursorOrientation;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Bounding rectangle in viewport coordinates (e.g. from getBoundingClientRect).
|
|
21
|
+
*/
|
|
22
|
+
export type Rect = {
|
|
23
|
+
left: number;
|
|
24
|
+
right: number;
|
|
25
|
+
top: number;
|
|
26
|
+
bottom: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns true if the element or any ancestor has the given CSS class.
|
|
31
|
+
* Used to skip drop cursor for elements marked with the exclusion class (e.g. drag handles).
|
|
32
|
+
*/
|
|
33
|
+
export function hasExclusionClassname(
|
|
34
|
+
element: Element | null,
|
|
35
|
+
exclude: string,
|
|
36
|
+
): boolean {
|
|
37
|
+
if (!element || !exclude) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return !!element.closest(`.${exclude}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Computes the viewport rect for a block-level drop cursor (horizontal line between blocks
|
|
45
|
+
* or vertical line on left/right edge). Returns null for inline positions or when no DOM node exists.
|
|
46
|
+
*/
|
|
47
|
+
export function getBlockDropRect(
|
|
48
|
+
view: EditorView,
|
|
49
|
+
cursorPos: DropCursorPosition,
|
|
50
|
+
width: number,
|
|
51
|
+
scaleX: number,
|
|
52
|
+
scaleY: number,
|
|
53
|
+
): Rect | null {
|
|
54
|
+
const $pos = view.state.doc.resolve(cursorPos.pos);
|
|
55
|
+
const isBlock = !$pos.parent.inlineContent;
|
|
56
|
+
|
|
57
|
+
if (!isBlock || cursorPos.orientation === "inline") {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const before = $pos.nodeBefore;
|
|
62
|
+
|
|
63
|
+
const after = $pos.nodeAfter;
|
|
64
|
+
|
|
65
|
+
if (!before && !after) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const isVertical =
|
|
70
|
+
cursorPos.orientation === "block-vertical-left" ||
|
|
71
|
+
cursorPos.orientation === "block-vertical-right";
|
|
72
|
+
// For vertical cursors, position is at the node position, for horizontal cursors, position is at the node before position
|
|
73
|
+
const nodePos = isVertical
|
|
74
|
+
? cursorPos.pos
|
|
75
|
+
: cursorPos.pos - (before ? before.nodeSize : 0);
|
|
76
|
+
|
|
77
|
+
const node = view.nodeDOM(nodePos) as HTMLElement | null;
|
|
78
|
+
if (!node) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const nodeRect = node.getBoundingClientRect();
|
|
83
|
+
|
|
84
|
+
if (isVertical) {
|
|
85
|
+
const halfWidth = (width / 2) * scaleX;
|
|
86
|
+
const left =
|
|
87
|
+
cursorPos.orientation === "block-vertical-left"
|
|
88
|
+
? nodeRect.left
|
|
89
|
+
: nodeRect.right;
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
left: left - halfWidth,
|
|
93
|
+
right: left + halfWidth,
|
|
94
|
+
top: nodeRect.top,
|
|
95
|
+
bottom: nodeRect.bottom,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let top = before ? nodeRect.bottom : nodeRect.top;
|
|
100
|
+
if (before && after) {
|
|
101
|
+
top =
|
|
102
|
+
(top +
|
|
103
|
+
(view.nodeDOM(cursorPos.pos) as HTMLElement).getBoundingClientRect()
|
|
104
|
+
.top) /
|
|
105
|
+
2;
|
|
106
|
+
}
|
|
107
|
+
const halfHeight = (width / 2) * scaleY;
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
left: nodeRect.left,
|
|
111
|
+
right: nodeRect.right,
|
|
112
|
+
top: top - halfHeight,
|
|
113
|
+
bottom: top + halfHeight,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Computes the viewport rect for an inline drop cursor (vertical line within text).
|
|
119
|
+
*/
|
|
120
|
+
export function getInlineDropRect(
|
|
121
|
+
view: EditorView,
|
|
122
|
+
cursorPos: DropCursorPosition,
|
|
123
|
+
width: number,
|
|
124
|
+
scaleX: number,
|
|
125
|
+
): Rect {
|
|
126
|
+
const coords = view.coordsAtPos(cursorPos.pos);
|
|
127
|
+
const halfWidth = (width / 2) * scaleX;
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
left: coords.left - halfWidth,
|
|
131
|
+
right: coords.left + halfWidth,
|
|
132
|
+
top: coords.top,
|
|
133
|
+
bottom: coords.bottom,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Applies orientation-specific CSS classes to the drop cursor element so it can be
|
|
139
|
+
* styled correctly (e.g. horizontal vs vertical line, inline vs block).
|
|
140
|
+
*/
|
|
141
|
+
export function applyOrientationClasses(
|
|
142
|
+
el: HTMLElement,
|
|
143
|
+
orientation: DropCursorOrientation,
|
|
144
|
+
) {
|
|
145
|
+
el.classList.toggle(
|
|
146
|
+
"prosemirror-dropcursor-inline",
|
|
147
|
+
orientation === "inline",
|
|
148
|
+
);
|
|
149
|
+
el.classList.toggle(
|
|
150
|
+
"prosemirror-dropcursor-block-horizontal",
|
|
151
|
+
orientation === "block-horizontal",
|
|
152
|
+
);
|
|
153
|
+
el.classList.toggle(
|
|
154
|
+
"prosemirror-dropcursor-block-vertical-left",
|
|
155
|
+
orientation === "block-vertical-left",
|
|
156
|
+
);
|
|
157
|
+
el.classList.toggle(
|
|
158
|
+
"prosemirror-dropcursor-block-vertical-right",
|
|
159
|
+
orientation === "block-vertical-right",
|
|
160
|
+
);
|
|
161
|
+
el.classList.toggle(
|
|
162
|
+
"prosemirror-dropcursor-block",
|
|
163
|
+
orientation === "block-horizontal",
|
|
164
|
+
);
|
|
165
|
+
el.classList.toggle(
|
|
166
|
+
"prosemirror-dropcursor-vertical",
|
|
167
|
+
orientation === "block-vertical-left" ||
|
|
168
|
+
orientation === "block-vertical-right",
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Returns the offset of the parent element for converting viewport coordinates to
|
|
174
|
+
* parent-relative coordinates. Handles document.body and static positioning.
|
|
175
|
+
*/
|
|
176
|
+
export function getParentOffsets(parent: HTMLElement | null) {
|
|
177
|
+
if (
|
|
178
|
+
!parent ||
|
|
179
|
+
(parent === document.body && getComputedStyle(parent).position === "static")
|
|
180
|
+
) {
|
|
181
|
+
return {
|
|
182
|
+
parentLeft: -window.pageXOffset,
|
|
183
|
+
parentTop: -window.pageYOffset,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const parentRect = parent.getBoundingClientRect();
|
|
188
|
+
const parentScaleX = parentRect.width / parent.offsetWidth;
|
|
189
|
+
const parentScaleY = parentRect.height / parent.offsetHeight;
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
parentLeft: parentRect.left - parent.scrollLeft * parentScaleX,
|
|
193
|
+
parentTop: parentRect.top - parent.scrollTop * parentScaleY,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
@@ -538,7 +538,7 @@ export const KeyboardShortcutsExtension = Extension.create<{
|
|
|
538
538
|
// Deletes the next block at either the same or lower nesting level, if
|
|
539
539
|
// the selection is empty and at the end of the block. If both the
|
|
540
540
|
// current and next blocks have inline content, the next block's
|
|
541
|
-
// content is appended to the current block's. The next block's own
|
|
541
|
+
// content is appended to the current block's. The next block's own
|
|
542
542
|
// children are unindented before it's deleted.
|
|
543
543
|
() =>
|
|
544
544
|
commands.command(({ state }) => {
|
|
@@ -708,15 +708,20 @@ export const KeyboardShortcutsExtension = Extension.create<{
|
|
|
708
708
|
nextBlockInfo.blockContent.node.childCount === 0);
|
|
709
709
|
|
|
710
710
|
if (nextBlockNotTableAndNoContent) {
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
.
|
|
711
|
+
const childBlocks =
|
|
712
|
+
nextBlockInfo.bnBlock.node.lastChild!.content;
|
|
713
|
+
return chain()
|
|
714
|
+
.deleteRange({
|
|
715
|
+
from: nextBlockInfo.bnBlock.beforePos,
|
|
716
|
+
to: nextBlockInfo.bnBlock.afterPos,
|
|
717
|
+
})
|
|
718
|
+
.insertContentAt(
|
|
719
|
+
blockInfo.bnBlock.afterPos,
|
|
720
|
+
nextBlockInfo.bnBlock.node.childCount === 2
|
|
721
|
+
? childBlocks
|
|
722
|
+
: null,
|
|
723
|
+
)
|
|
724
|
+
.run();
|
|
720
725
|
}
|
|
721
726
|
}
|
|
722
727
|
|
package/src/i18n/locales/fa.ts
CHANGED
|
@@ -81,7 +81,7 @@ export const fa = {
|
|
|
81
81
|
check_list: {
|
|
82
82
|
title: "بازینه",
|
|
83
83
|
subtext: "فهرست با جعبه انتخاب",
|
|
84
|
-
aliases: ["چک لیست", "لیست انجام کار", "لیست تیک دار","بازینه"],
|
|
84
|
+
aliases: ["چک لیست", "لیست انجام کار", "لیست تیک دار", "بازینه"],
|
|
85
85
|
group: "بلوکهای پایه",
|
|
86
86
|
},
|
|
87
87
|
paragraph: {
|
|
@@ -111,36 +111,19 @@ export const fa = {
|
|
|
111
111
|
image: {
|
|
112
112
|
title: "تصویر",
|
|
113
113
|
subtext: "تصویر با قابلیت تغییر اندازه و زیرنویس",
|
|
114
|
-
aliases: [
|
|
115
|
-
"تصویر",
|
|
116
|
-
"عکس",
|
|
117
|
-
"آپلود تصویر",
|
|
118
|
-
"مدیا",
|
|
119
|
-
"لینک عکس",
|
|
120
|
-
],
|
|
114
|
+
aliases: ["تصویر", "عکس", "آپلود تصویر", "مدیا", "لینک عکس"],
|
|
121
115
|
group: "رسانه",
|
|
122
116
|
},
|
|
123
117
|
video: {
|
|
124
118
|
title: "ویدیو",
|
|
125
119
|
subtext: "ویدیو با قابلیت تغییر اندازه و زیرنویس",
|
|
126
|
-
aliases: [
|
|
127
|
-
"ویدیو",
|
|
128
|
-
"فیلم",
|
|
129
|
-
"آپلود ویدیو",
|
|
130
|
-
"مدیا",
|
|
131
|
-
],
|
|
120
|
+
aliases: ["ویدیو", "فیلم", "آپلود ویدیو", "مدیا"],
|
|
132
121
|
group: "رسانه",
|
|
133
122
|
},
|
|
134
123
|
audio: {
|
|
135
124
|
title: "صوتی",
|
|
136
125
|
subtext: "فایل صوتی جاسازی شده با زیرنویس",
|
|
137
|
-
aliases: [
|
|
138
|
-
"صوتی",
|
|
139
|
-
"صدا",
|
|
140
|
-
"آهنگ",
|
|
141
|
-
"موسیقی",
|
|
142
|
-
"آپلود صدا",
|
|
143
|
-
],
|
|
126
|
+
aliases: ["صوتی", "صدا", "آهنگ", "موسیقی", "آپلود صدا"],
|
|
144
127
|
group: "رسانه",
|
|
145
128
|
},
|
|
146
129
|
file: {
|
package/src/i18n/locales/ru.ts
CHANGED