@tiptap/extensions 3.23.5 → 3.24.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.
- package/dist/index.cjs +285 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -7
- package/dist/index.d.ts +24 -7
- package/dist/index.js +268 -47
- package/dist/index.js.map +1 -1
- package/dist/placeholder/index.cjs +265 -45
- package/dist/placeholder/index.cjs.map +1 -1
- package/dist/placeholder/index.d.cts +25 -8
- package/dist/placeholder/index.d.ts +25 -8
- package/dist/placeholder/index.js +264 -46
- package/dist/placeholder/index.js.map +1 -1
- package/dist/trailing-node/index.cjs +4 -1
- package/dist/trailing-node/index.cjs.map +1 -1
- package/dist/trailing-node/index.js +4 -1
- package/dist/trailing-node/index.js.map +1 -1
- package/package.json +19 -20
- package/src/placeholder/constants.ts +17 -0
- package/src/placeholder/index.ts +3 -0
- package/src/placeholder/placeholder.ts +5 -147
- package/src/placeholder/plugins/PlaceholderPlugin.ts +35 -0
- package/src/placeholder/types.ts +75 -0
- package/src/placeholder/utils/buildPlaceholderDecorations.ts +111 -0
- package/src/placeholder/utils/createPlaceholderDecoration.ts +61 -0
- package/src/placeholder/utils/findScrollParent.ts +38 -0
- package/src/placeholder/utils/getViewportBoundaryPositions.ts +49 -0
- package/src/placeholder/utils/index.ts +6 -0
- package/src/placeholder/utils/preparePlaceholderAttribute.ts +21 -0
- package/src/placeholder/utils/throttle.ts +28 -0
- package/src/placeholder/utils/viewportTracking.ts +118 -0
- package/src/trailing-node/trailing-node.ts +10 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Extension, ParentConfig, Editor } from '@tiptap/core';
|
|
2
2
|
import { Node } from '@tiptap/pm/model';
|
|
3
|
+
import { PluginKey } from '@tiptap/pm/state';
|
|
3
4
|
|
|
4
5
|
interface CharacterCountOptions {
|
|
5
6
|
/**
|
|
@@ -142,11 +143,14 @@ declare module '@tiptap/core' {
|
|
|
142
143
|
declare const Gapcursor: Extension<any, any>;
|
|
143
144
|
|
|
144
145
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
146
|
+
* The viewport positions tracked by the placeholder plugin.
|
|
147
|
+
* `null` means "no viewport info yet" — the decoration callback falls back to
|
|
148
|
+
* a full document scan until the scroll handler fires.
|
|
148
149
|
*/
|
|
149
|
-
|
|
150
|
+
interface ViewportState {
|
|
151
|
+
topPos: number | null;
|
|
152
|
+
bottomPos: number | null;
|
|
153
|
+
}
|
|
150
154
|
interface PlaceholderOptions {
|
|
151
155
|
/**
|
|
152
156
|
* **The class name for the empty editor**
|
|
@@ -193,14 +197,20 @@ interface PlaceholderOptions {
|
|
|
193
197
|
*/
|
|
194
198
|
showOnlyCurrent: boolean;
|
|
195
199
|
/**
|
|
196
|
-
* **Controls if the placeholder should be shown for all
|
|
200
|
+
* **Controls if the placeholder should be shown for all descendants.**
|
|
197
201
|
*
|
|
198
|
-
* If true, the placeholder will be shown for all
|
|
202
|
+
* If true, the placeholder will be shown for all descendants.
|
|
199
203
|
* If false, the placeholder will only be shown for the current node.
|
|
200
204
|
* @default false
|
|
201
205
|
*/
|
|
202
206
|
includeChildren: boolean;
|
|
203
207
|
}
|
|
208
|
+
|
|
209
|
+
/** The default data attribute label */
|
|
210
|
+
declare const DEFAULT_DATA_ATTRIBUTE = "placeholder";
|
|
211
|
+
/** The plugin key used to store and read the placeholder viewport state */
|
|
212
|
+
declare const PLUGIN_KEY: PluginKey<ViewportState>;
|
|
213
|
+
|
|
204
214
|
/**
|
|
205
215
|
* This extension allows you to add a placeholder to your editor.
|
|
206
216
|
* A placeholder is a text that appears when the editor or a node is empty.
|
|
@@ -208,6 +218,13 @@ interface PlaceholderOptions {
|
|
|
208
218
|
*/
|
|
209
219
|
declare const Placeholder: Extension<PlaceholderOptions, any>;
|
|
210
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Prepares the placeholder attribute by ensuring it is properly formatted.
|
|
223
|
+
* @param attr - The placeholder attribute string.
|
|
224
|
+
* @returns The prepared placeholder attribute string.
|
|
225
|
+
*/
|
|
226
|
+
declare function preparePlaceholderAttribute(attr: string): string;
|
|
227
|
+
|
|
211
228
|
type SelectionOptions = {
|
|
212
229
|
/**
|
|
213
230
|
* The class name that should be added to the selected text.
|
|
@@ -289,4 +306,4 @@ declare module '@tiptap/core' {
|
|
|
289
306
|
*/
|
|
290
307
|
declare const UndoRedo: Extension<UndoRedoOptions, any>;
|
|
291
308
|
|
|
292
|
-
export { CharacterCount, type CharacterCountOptions, type CharacterCountStorage, Dropcursor, type DropcursorOptions, Focus, type FocusOptions, Gapcursor, Placeholder, type PlaceholderOptions, Selection, type SelectionOptions, TrailingNode, type TrailingNodeOptions, UndoRedo, type UndoRedoOptions, preparePlaceholderAttribute, skipTrailingNodeMeta };
|
|
309
|
+
export { CharacterCount, type CharacterCountOptions, type CharacterCountStorage, DEFAULT_DATA_ATTRIBUTE, Dropcursor, type DropcursorOptions, Focus, type FocusOptions, Gapcursor, PLUGIN_KEY, Placeholder, type PlaceholderOptions, Selection, type SelectionOptions, TrailingNode, type TrailingNodeOptions, UndoRedo, type UndoRedoOptions, type ViewportState, preparePlaceholderAttribute, skipTrailingNodeMeta };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Extension, ParentConfig, Editor } from '@tiptap/core';
|
|
2
2
|
import { Node } from '@tiptap/pm/model';
|
|
3
|
+
import { PluginKey } from '@tiptap/pm/state';
|
|
3
4
|
|
|
4
5
|
interface CharacterCountOptions {
|
|
5
6
|
/**
|
|
@@ -142,11 +143,14 @@ declare module '@tiptap/core' {
|
|
|
142
143
|
declare const Gapcursor: Extension<any, any>;
|
|
143
144
|
|
|
144
145
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
146
|
+
* The viewport positions tracked by the placeholder plugin.
|
|
147
|
+
* `null` means "no viewport info yet" — the decoration callback falls back to
|
|
148
|
+
* a full document scan until the scroll handler fires.
|
|
148
149
|
*/
|
|
149
|
-
|
|
150
|
+
interface ViewportState {
|
|
151
|
+
topPos: number | null;
|
|
152
|
+
bottomPos: number | null;
|
|
153
|
+
}
|
|
150
154
|
interface PlaceholderOptions {
|
|
151
155
|
/**
|
|
152
156
|
* **The class name for the empty editor**
|
|
@@ -193,14 +197,20 @@ interface PlaceholderOptions {
|
|
|
193
197
|
*/
|
|
194
198
|
showOnlyCurrent: boolean;
|
|
195
199
|
/**
|
|
196
|
-
* **Controls if the placeholder should be shown for all
|
|
200
|
+
* **Controls if the placeholder should be shown for all descendants.**
|
|
197
201
|
*
|
|
198
|
-
* If true, the placeholder will be shown for all
|
|
202
|
+
* If true, the placeholder will be shown for all descendants.
|
|
199
203
|
* If false, the placeholder will only be shown for the current node.
|
|
200
204
|
* @default false
|
|
201
205
|
*/
|
|
202
206
|
includeChildren: boolean;
|
|
203
207
|
}
|
|
208
|
+
|
|
209
|
+
/** The default data attribute label */
|
|
210
|
+
declare const DEFAULT_DATA_ATTRIBUTE = "placeholder";
|
|
211
|
+
/** The plugin key used to store and read the placeholder viewport state */
|
|
212
|
+
declare const PLUGIN_KEY: PluginKey<ViewportState>;
|
|
213
|
+
|
|
204
214
|
/**
|
|
205
215
|
* This extension allows you to add a placeholder to your editor.
|
|
206
216
|
* A placeholder is a text that appears when the editor or a node is empty.
|
|
@@ -208,6 +218,13 @@ interface PlaceholderOptions {
|
|
|
208
218
|
*/
|
|
209
219
|
declare const Placeholder: Extension<PlaceholderOptions, any>;
|
|
210
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Prepares the placeholder attribute by ensuring it is properly formatted.
|
|
223
|
+
* @param attr - The placeholder attribute string.
|
|
224
|
+
* @returns The prepared placeholder attribute string.
|
|
225
|
+
*/
|
|
226
|
+
declare function preparePlaceholderAttribute(attr: string): string;
|
|
227
|
+
|
|
211
228
|
type SelectionOptions = {
|
|
212
229
|
/**
|
|
213
230
|
* The class name that should be added to the selected text.
|
|
@@ -289,4 +306,4 @@ declare module '@tiptap/core' {
|
|
|
289
306
|
*/
|
|
290
307
|
declare const UndoRedo: Extension<UndoRedoOptions, any>;
|
|
291
308
|
|
|
292
|
-
export { CharacterCount, type CharacterCountOptions, type CharacterCountStorage, Dropcursor, type DropcursorOptions, Focus, type FocusOptions, Gapcursor, Placeholder, type PlaceholderOptions, Selection, type SelectionOptions, TrailingNode, type TrailingNodeOptions, UndoRedo, type UndoRedoOptions, preparePlaceholderAttribute, skipTrailingNodeMeta };
|
|
309
|
+
export { CharacterCount, type CharacterCountOptions, type CharacterCountStorage, DEFAULT_DATA_ATTRIBUTE, Dropcursor, type DropcursorOptions, Focus, type FocusOptions, Gapcursor, PLUGIN_KEY, Placeholder, type PlaceholderOptions, Selection, type SelectionOptions, TrailingNode, type TrailingNodeOptions, UndoRedo, type UndoRedoOptions, type ViewportState, preparePlaceholderAttribute, skipTrailingNodeMeta };
|
package/dist/index.js
CHANGED
|
@@ -202,14 +202,271 @@ var Gapcursor = Extension4.create({
|
|
|
202
202
|
}
|
|
203
203
|
});
|
|
204
204
|
|
|
205
|
-
// src/placeholder/
|
|
206
|
-
import {
|
|
207
|
-
import { Plugin as Plugin3, PluginKey as PluginKey3 } from "@tiptap/pm/state";
|
|
208
|
-
import { Decoration as Decoration2, DecorationSet as DecorationSet2 } from "@tiptap/pm/view";
|
|
205
|
+
// src/placeholder/constants.ts
|
|
206
|
+
import { PluginKey as PluginKey3 } from "@tiptap/pm/state";
|
|
209
207
|
var DEFAULT_DATA_ATTRIBUTE = "placeholder";
|
|
208
|
+
var PLUGIN_KEY = new PluginKey3("tiptap__placeholder");
|
|
209
|
+
var VIEWPORT_OVERSCAN_PX = 200;
|
|
210
|
+
|
|
211
|
+
// src/placeholder/placeholder.ts
|
|
212
|
+
import { Extension as Extension5 } from "@tiptap/core";
|
|
213
|
+
|
|
214
|
+
// src/placeholder/plugins/PlaceholderPlugin.ts
|
|
215
|
+
import { Plugin as Plugin3 } from "@tiptap/pm/state";
|
|
216
|
+
|
|
217
|
+
// src/placeholder/utils/buildPlaceholderDecorations.ts
|
|
218
|
+
import { isNodeEmpty } from "@tiptap/core";
|
|
219
|
+
import { DecorationSet as DecorationSet2 } from "@tiptap/pm/view";
|
|
220
|
+
|
|
221
|
+
// src/placeholder/utils/createPlaceholderDecoration.ts
|
|
222
|
+
import { Decoration as Decoration2 } from "@tiptap/pm/view";
|
|
223
|
+
function createPlaceholderDecoration(options) {
|
|
224
|
+
const {
|
|
225
|
+
editor,
|
|
226
|
+
placeholder,
|
|
227
|
+
dataAttribute,
|
|
228
|
+
pos,
|
|
229
|
+
node,
|
|
230
|
+
isEmptyDoc,
|
|
231
|
+
hasAnchor,
|
|
232
|
+
classes: { emptyNode, emptyEditor }
|
|
233
|
+
} = options;
|
|
234
|
+
const classes = [emptyNode];
|
|
235
|
+
if (isEmptyDoc) {
|
|
236
|
+
classes.push(emptyEditor);
|
|
237
|
+
}
|
|
238
|
+
return Decoration2.node(pos, pos + node.nodeSize, {
|
|
239
|
+
class: classes.join(" "),
|
|
240
|
+
[dataAttribute]: typeof placeholder === "function" ? placeholder({
|
|
241
|
+
editor,
|
|
242
|
+
node,
|
|
243
|
+
pos,
|
|
244
|
+
hasAnchor
|
|
245
|
+
}) : placeholder
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// src/placeholder/utils/buildPlaceholderDecorations.ts
|
|
250
|
+
function buildPlaceholderDecorations({
|
|
251
|
+
editor,
|
|
252
|
+
options,
|
|
253
|
+
dataAttribute,
|
|
254
|
+
doc,
|
|
255
|
+
selection
|
|
256
|
+
}) {
|
|
257
|
+
var _a, _b;
|
|
258
|
+
const active = editor.isEditable || !options.showOnlyWhenEditable;
|
|
259
|
+
if (!active) {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
const { anchor } = selection;
|
|
263
|
+
const decorations = [];
|
|
264
|
+
const isEmptyDoc = editor.isEmpty;
|
|
265
|
+
const classes = {
|
|
266
|
+
emptyEditor: options.emptyEditorClass,
|
|
267
|
+
emptyNode: options.emptyNodeClass
|
|
268
|
+
};
|
|
269
|
+
const useResolvedPath = options.showOnlyCurrent && !options.includeChildren;
|
|
270
|
+
if (useResolvedPath) {
|
|
271
|
+
const resolved = doc.resolve(anchor);
|
|
272
|
+
const node = resolved.depth > 0 ? resolved.node(1) : resolved.nodeAfter;
|
|
273
|
+
const nodeStart = resolved.depth > 0 ? resolved.before(1) : anchor;
|
|
274
|
+
if (node && node.type.isTextblock && isNodeEmpty(node)) {
|
|
275
|
+
const hasAnchor = anchor >= nodeStart && anchor <= nodeStart + node.nodeSize;
|
|
276
|
+
decorations.push(
|
|
277
|
+
createPlaceholderDecoration({
|
|
278
|
+
editor,
|
|
279
|
+
isEmptyDoc,
|
|
280
|
+
dataAttribute,
|
|
281
|
+
hasAnchor,
|
|
282
|
+
placeholder: options.placeholder,
|
|
283
|
+
classes,
|
|
284
|
+
node,
|
|
285
|
+
pos: nodeStart
|
|
286
|
+
})
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
} else {
|
|
290
|
+
const pluginState = PLUGIN_KEY.getState(editor.state);
|
|
291
|
+
const from = (_a = pluginState == null ? void 0 : pluginState.topPos) != null ? _a : 0;
|
|
292
|
+
const to = (_b = pluginState == null ? void 0 : pluginState.bottomPos) != null ? _b : doc.content.size;
|
|
293
|
+
doc.nodesBetween(from, to, (node, pos) => {
|
|
294
|
+
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
|
|
295
|
+
const isEmpty = !node.isLeaf && isNodeEmpty(node);
|
|
296
|
+
if (!node.type.isTextblock) {
|
|
297
|
+
return options.includeChildren;
|
|
298
|
+
}
|
|
299
|
+
if ((hasAnchor || !options.showOnlyCurrent) && isEmpty) {
|
|
300
|
+
decorations.push(
|
|
301
|
+
createPlaceholderDecoration({
|
|
302
|
+
editor,
|
|
303
|
+
isEmptyDoc,
|
|
304
|
+
dataAttribute,
|
|
305
|
+
hasAnchor,
|
|
306
|
+
placeholder: options.placeholder,
|
|
307
|
+
classes,
|
|
308
|
+
node,
|
|
309
|
+
pos
|
|
310
|
+
})
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
return options.includeChildren;
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
return DecorationSet2.create(doc, decorations);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// src/placeholder/utils/preparePlaceholderAttribute.ts
|
|
210
320
|
function preparePlaceholderAttribute(attr) {
|
|
211
321
|
return attr.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9-]/g, "").replace(/^[0-9-]+/, "").replace(/^-+/, "").toLowerCase();
|
|
212
322
|
}
|
|
323
|
+
|
|
324
|
+
// src/placeholder/utils/findScrollParent.ts
|
|
325
|
+
function isScrollable(el) {
|
|
326
|
+
const style = getComputedStyle(el);
|
|
327
|
+
const overflow = `${style.overflow} ${style.overflowY} ${style.overflowX}`;
|
|
328
|
+
return /auto|scroll|overlay/.test(overflow);
|
|
329
|
+
}
|
|
330
|
+
function findScrollParent(element) {
|
|
331
|
+
let el = element;
|
|
332
|
+
while (el) {
|
|
333
|
+
if (isScrollable(el)) {
|
|
334
|
+
return el;
|
|
335
|
+
}
|
|
336
|
+
const parent = el.parentElement;
|
|
337
|
+
if (!parent) {
|
|
338
|
+
const root = el.getRootNode();
|
|
339
|
+
if (root instanceof ShadowRoot) {
|
|
340
|
+
el = root.host;
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
return window;
|
|
344
|
+
}
|
|
345
|
+
el = parent;
|
|
346
|
+
}
|
|
347
|
+
return window;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// src/placeholder/utils/getViewportBoundaryPositions.ts
|
|
351
|
+
function getContainerRect(container) {
|
|
352
|
+
if (container === window) {
|
|
353
|
+
return { top: 0, bottom: window.innerHeight };
|
|
354
|
+
}
|
|
355
|
+
return container.getBoundingClientRect();
|
|
356
|
+
}
|
|
357
|
+
function getViewportBoundaryPositions({
|
|
358
|
+
doc,
|
|
359
|
+
view,
|
|
360
|
+
scrollContainer
|
|
361
|
+
}) {
|
|
362
|
+
const editorRect = view.dom.getBoundingClientRect();
|
|
363
|
+
const containerRect = scrollContainer ? getContainerRect(scrollContainer) : { top: 0, bottom: window.innerHeight };
|
|
364
|
+
const visibleTop = Math.max(editorRect.top, containerRect.top) - VIEWPORT_OVERSCAN_PX;
|
|
365
|
+
const visibleBottom = Math.min(editorRect.bottom, containerRect.bottom) + VIEWPORT_OVERSCAN_PX;
|
|
366
|
+
if (visibleTop >= visibleBottom) {
|
|
367
|
+
return { top: 0, bottom: doc.content.size };
|
|
368
|
+
}
|
|
369
|
+
const isRTL = getComputedStyle(view.dom).direction === "rtl";
|
|
370
|
+
const x = isRTL ? Math.max(editorRect.right - 2, editorRect.left + 2) : editorRect.left + 2;
|
|
371
|
+
const topPos = view.posAtCoords({ left: x, top: visibleTop + 2 });
|
|
372
|
+
const bottomPos = view.posAtCoords({ left: x, top: visibleBottom - 2 });
|
|
373
|
+
return {
|
|
374
|
+
top: topPos ? topPos.pos : 0,
|
|
375
|
+
bottom: bottomPos ? bottomPos.pos : doc.content.size
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// src/placeholder/utils/viewportTracking.ts
|
|
380
|
+
var viewportPluginState = {
|
|
381
|
+
/**
|
|
382
|
+
* Initialises the viewport state with no known positions.
|
|
383
|
+
* @returns The initial viewport state.
|
|
384
|
+
*/
|
|
385
|
+
init() {
|
|
386
|
+
return { topPos: null, bottomPos: null };
|
|
387
|
+
},
|
|
388
|
+
/**
|
|
389
|
+
* Updates the viewport state from incoming transactions.
|
|
390
|
+
* @param tr - The transaction being applied.
|
|
391
|
+
* @param prev - The previous viewport state.
|
|
392
|
+
* @returns The next viewport state.
|
|
393
|
+
*/
|
|
394
|
+
apply(tr, prev) {
|
|
395
|
+
const meta = tr.getMeta(PLUGIN_KEY);
|
|
396
|
+
if (meta == null ? void 0 : meta.positions) {
|
|
397
|
+
return { topPos: meta.positions.top, bottomPos: meta.positions.bottom };
|
|
398
|
+
}
|
|
399
|
+
if (!tr.docChanged) {
|
|
400
|
+
return prev;
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
topPos: prev.topPos !== null ? tr.mapping.map(prev.topPos) : null,
|
|
404
|
+
bottomPos: prev.bottomPos !== null ? tr.mapping.map(prev.bottomPos) : null
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
function createViewportPluginView(view) {
|
|
409
|
+
const scrollContainer = findScrollParent(view.dom);
|
|
410
|
+
const computeAndDispatch = () => {
|
|
411
|
+
const positions = getViewportBoundaryPositions({
|
|
412
|
+
view,
|
|
413
|
+
doc: view.state.doc,
|
|
414
|
+
scrollContainer
|
|
415
|
+
});
|
|
416
|
+
const prev = PLUGIN_KEY.getState(view.state);
|
|
417
|
+
if ((prev == null ? void 0 : prev.topPos) === positions.top && (prev == null ? void 0 : prev.bottomPos) === positions.bottom) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
const tr = view.state.tr.setMeta(PLUGIN_KEY, { positions });
|
|
421
|
+
view.dispatch(tr);
|
|
422
|
+
};
|
|
423
|
+
let frame = null;
|
|
424
|
+
let lastCompute = 0;
|
|
425
|
+
const MIN_SCROLL_INTERVAL = 150;
|
|
426
|
+
const scheduleFrame = () => {
|
|
427
|
+
if (frame !== null) return;
|
|
428
|
+
frame = requestAnimationFrame(() => {
|
|
429
|
+
frame = null;
|
|
430
|
+
const now = performance.now();
|
|
431
|
+
if (now - lastCompute >= MIN_SCROLL_INTERVAL) {
|
|
432
|
+
lastCompute = now;
|
|
433
|
+
computeAndDispatch();
|
|
434
|
+
} else {
|
|
435
|
+
scheduleFrame();
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
};
|
|
439
|
+
scrollContainer.addEventListener("scroll", scheduleFrame, { passive: true });
|
|
440
|
+
computeAndDispatch();
|
|
441
|
+
return {
|
|
442
|
+
update(_view, prevState) {
|
|
443
|
+
if (view.state.doc.content.size !== prevState.doc.content.size) {
|
|
444
|
+
scheduleFrame();
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
destroy: () => {
|
|
448
|
+
if (frame !== null) {
|
|
449
|
+
cancelAnimationFrame(frame);
|
|
450
|
+
}
|
|
451
|
+
scrollContainer.removeEventListener("scroll", scheduleFrame);
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// src/placeholder/plugins/PlaceholderPlugin.ts
|
|
457
|
+
function createPlaceholderPlugin({ editor, options }) {
|
|
458
|
+
const dataAttribute = options.dataAttribute ? `data-${preparePlaceholderAttribute(options.dataAttribute)}` : `data-${DEFAULT_DATA_ATTRIBUTE}`;
|
|
459
|
+
return new Plugin3({
|
|
460
|
+
key: PLUGIN_KEY,
|
|
461
|
+
state: viewportPluginState,
|
|
462
|
+
view: createViewportPluginView,
|
|
463
|
+
props: {
|
|
464
|
+
decorations: ({ doc, selection }) => buildPlaceholderDecorations({ editor, options, dataAttribute, doc, selection })
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// src/placeholder/placeholder.ts
|
|
213
470
|
var Placeholder = Extension5.create({
|
|
214
471
|
name: "placeholder",
|
|
215
472
|
addOptions() {
|
|
@@ -224,48 +481,7 @@ var Placeholder = Extension5.create({
|
|
|
224
481
|
};
|
|
225
482
|
},
|
|
226
483
|
addProseMirrorPlugins() {
|
|
227
|
-
|
|
228
|
-
return [
|
|
229
|
-
new Plugin3({
|
|
230
|
-
key: new PluginKey3("placeholder"),
|
|
231
|
-
props: {
|
|
232
|
-
decorations: ({ doc, selection }) => {
|
|
233
|
-
const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
|
|
234
|
-
const { anchor } = selection;
|
|
235
|
-
const decorations = [];
|
|
236
|
-
if (!active) {
|
|
237
|
-
return null;
|
|
238
|
-
}
|
|
239
|
-
const isEmptyDoc = this.editor.isEmpty;
|
|
240
|
-
doc.descendants((node, pos) => {
|
|
241
|
-
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
|
|
242
|
-
const isEmpty = !node.isLeaf && isNodeEmpty(node);
|
|
243
|
-
if (!node.type.isTextblock) {
|
|
244
|
-
return this.options.includeChildren;
|
|
245
|
-
}
|
|
246
|
-
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
|
|
247
|
-
const classes = [this.options.emptyNodeClass];
|
|
248
|
-
if (isEmptyDoc) {
|
|
249
|
-
classes.push(this.options.emptyEditorClass);
|
|
250
|
-
}
|
|
251
|
-
const decoration = Decoration2.node(pos, pos + node.nodeSize, {
|
|
252
|
-
class: classes.join(" "),
|
|
253
|
-
[dataAttribute]: typeof this.options.placeholder === "function" ? this.options.placeholder({
|
|
254
|
-
editor: this.editor,
|
|
255
|
-
node,
|
|
256
|
-
pos,
|
|
257
|
-
hasAnchor
|
|
258
|
-
}) : this.options.placeholder
|
|
259
|
-
});
|
|
260
|
-
decorations.push(decoration);
|
|
261
|
-
}
|
|
262
|
-
return this.options.includeChildren;
|
|
263
|
-
});
|
|
264
|
-
return DecorationSet2.create(doc, decorations);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
})
|
|
268
|
-
];
|
|
484
|
+
return [createPlaceholderPlugin({ editor: this.editor, options: this.options })];
|
|
269
485
|
}
|
|
270
486
|
});
|
|
271
487
|
|
|
@@ -306,7 +522,10 @@ var Selection = Extension6.create({
|
|
|
306
522
|
import { Extension as Extension7 } from "@tiptap/core";
|
|
307
523
|
import { Plugin as Plugin5, PluginKey as PluginKey5 } from "@tiptap/pm/state";
|
|
308
524
|
var skipTrailingNodeMeta = "skipTrailingNode";
|
|
309
|
-
function nodeEqualsType({
|
|
525
|
+
function nodeEqualsType({
|
|
526
|
+
types,
|
|
527
|
+
node
|
|
528
|
+
}) {
|
|
310
529
|
return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
|
|
311
530
|
}
|
|
312
531
|
var TrailingNode = Extension7.create({
|
|
@@ -396,9 +615,11 @@ var UndoRedo = Extension8.create({
|
|
|
396
615
|
});
|
|
397
616
|
export {
|
|
398
617
|
CharacterCount,
|
|
618
|
+
DEFAULT_DATA_ATTRIBUTE,
|
|
399
619
|
Dropcursor,
|
|
400
620
|
Focus,
|
|
401
621
|
Gapcursor,
|
|
622
|
+
PLUGIN_KEY,
|
|
402
623
|
Placeholder,
|
|
403
624
|
Selection,
|
|
404
625
|
TrailingNode,
|