@slash-editor/core 0.0.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.
- package/dist/index.d.mts +1191 -0
- package/dist/index.mjs +2514 -0
- package/package.json +40 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,1191 @@
|
|
|
1
|
+
import { Editor, Extension, Extensions, Mark, Node, Range } from "@tiptap/core";
|
|
2
|
+
import { Node as Node$1, NodeType } from "@tiptap/pm/model";
|
|
3
|
+
import { EditorState, PluginKey } from "@tiptap/pm/state";
|
|
4
|
+
import { SuggestionProps } from "@tiptap/suggestion";
|
|
5
|
+
import { TableKit, TableKitOptions } from "@tiptap/extension-table";
|
|
6
|
+
import { Doc } from "yjs";
|
|
7
|
+
//#region src/slash-items.d.ts
|
|
8
|
+
interface SlashContext {
|
|
9
|
+
editor: Editor;
|
|
10
|
+
/** Document range covering the trigger character and the typed query. */
|
|
11
|
+
range: Range;
|
|
12
|
+
}
|
|
13
|
+
interface SlashItem {
|
|
14
|
+
/** Stable identity used for keyboard selection and analytics. */
|
|
15
|
+
id: string;
|
|
16
|
+
title: string;
|
|
17
|
+
/** Section the item is listed under. */
|
|
18
|
+
group: string;
|
|
19
|
+
/** One-line hint rendered next to the title. */
|
|
20
|
+
description?: string;
|
|
21
|
+
/** Alternative names matched with the same weight as the title. */
|
|
22
|
+
aliases?: string[];
|
|
23
|
+
/** Lower-weight search terms that are never displayed. */
|
|
24
|
+
keywords?: string[];
|
|
25
|
+
/** Icon key resolved by the UI layer; the core ships no components. */
|
|
26
|
+
icon?: string;
|
|
27
|
+
/** Hides the item when the current editor cannot run it. */
|
|
28
|
+
when?: (editor: Editor) => boolean;
|
|
29
|
+
run: (context: SlashContext) => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Ranks items against a slash query. Ties keep declaration order, so the item
|
|
33
|
+
* list doubles as the default ordering of the menu.
|
|
34
|
+
*/
|
|
35
|
+
declare function filterSlashItems(items: SlashItem[], query: string, editor?: Editor): SlashItem[];
|
|
36
|
+
declare const defaultSlashItems: SlashItem[];
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/ai-block.d.ts
|
|
39
|
+
/** Lifecycle of a transient `aiBlock` node. */
|
|
40
|
+
type AiActionStatus = "streaming" | "done" | "error";
|
|
41
|
+
interface StreamContext {
|
|
42
|
+
/** Aborted when the request is superseded by a retry or the block is discarded. */
|
|
43
|
+
signal: AbortSignal;
|
|
44
|
+
}
|
|
45
|
+
interface AiRequest {
|
|
46
|
+
/** Slash action id that triggered this request, e.g. `"continue-writing"`. */
|
|
47
|
+
action: string;
|
|
48
|
+
/** Instruction sent to the model. */
|
|
49
|
+
prompt: string;
|
|
50
|
+
/** Plain-text context the instruction operates on. */
|
|
51
|
+
context: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Bring-your-own AI backend. `stream` yields incremental text chunks — core
|
|
55
|
+
* has no opinion on the wire format (SSE, `fetch` streaming, WebSocket),
|
|
56
|
+
* only on the async-iterable contract, so a real deployment can proxy any
|
|
57
|
+
* provider behind one endpoint and the demo can swap in a mock for tests.
|
|
58
|
+
*/
|
|
59
|
+
interface StreamAdapter {
|
|
60
|
+
stream(request: AiRequest, context: StreamContext): AsyncIterable<string>;
|
|
61
|
+
}
|
|
62
|
+
interface PendingEntry$1 {
|
|
63
|
+
request: AiRequest;
|
|
64
|
+
adapter: StreamAdapter;
|
|
65
|
+
controller: AbortController;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Per-node registry of in-flight/completed AI requests, keyed by the node's
|
|
69
|
+
* `id`. Unlike `PendingUploadRegistry`, entries are kept on success too —
|
|
70
|
+
* "try again" always needs the last request/adapter to replay — and are
|
|
71
|
+
* only dropped (aborting anything still in flight) when the block is
|
|
72
|
+
* discarded or its streamed text is accepted into the document.
|
|
73
|
+
*/
|
|
74
|
+
declare class PendingAiRegistry {
|
|
75
|
+
private readonly pending;
|
|
76
|
+
set(id: string, entry: PendingEntry$1): void;
|
|
77
|
+
get(id: string): PendingEntry$1 | undefined;
|
|
78
|
+
delete(id: string): void;
|
|
79
|
+
}
|
|
80
|
+
interface RunAiActionOptions {
|
|
81
|
+
action: string;
|
|
82
|
+
prompt: string;
|
|
83
|
+
context: string;
|
|
84
|
+
adapter: StreamAdapter;
|
|
85
|
+
}
|
|
86
|
+
declare module "@tiptap/core" {
|
|
87
|
+
interface Commands<ReturnType> {
|
|
88
|
+
aiBlock: {
|
|
89
|
+
/** Inserts a transient AI block and starts streaming through `adapter`. */
|
|
90
|
+
runAiAction: (options: RunAiActionOptions) => ReturnType;
|
|
91
|
+
/** Re-runs the last request for the node with this id, from scratch. */
|
|
92
|
+
retryAiAction: (id: string) => ReturnType;
|
|
93
|
+
/** Replaces the transient node with real paragraph(s) built from its streamed text. */
|
|
94
|
+
acceptAiAction: (id: string) => ReturnType;
|
|
95
|
+
/** Removes the transient node without applying anything. */
|
|
96
|
+
discardAiAction: (id: string) => ReturnType;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
interface AiBlockOptions {
|
|
101
|
+
HTMLAttributes: Record<string, unknown>;
|
|
102
|
+
}
|
|
103
|
+
interface AiBlockStorage {
|
|
104
|
+
pending: PendingAiRegistry;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* A transient block that streams an AI response into the document: never
|
|
108
|
+
* meant to be the doc's final shape, only a staging area. `status`/`text`/
|
|
109
|
+
* `error` live in node attrs (part of the doc) so streaming re-renders
|
|
110
|
+
* through the normal transaction pipeline, the same reasoning `Image`
|
|
111
|
+
* documents for upload progress — until the user accepts (replaced by real
|
|
112
|
+
* paragraphs) or discards (removed) it.
|
|
113
|
+
*/
|
|
114
|
+
declare const AiBlock: Node<AiBlockOptions, AiBlockStorage>;
|
|
115
|
+
/** Configures the AI block node. */
|
|
116
|
+
declare function aiBlock(options?: Partial<AiBlockOptions>): Node<AiBlockOptions, AiBlockStorage>;
|
|
117
|
+
interface AiSlashAction {
|
|
118
|
+
id: string;
|
|
119
|
+
title: string;
|
|
120
|
+
description?: string;
|
|
121
|
+
icon?: string;
|
|
122
|
+
/** Instruction sent to the model. */
|
|
123
|
+
prompt: string;
|
|
124
|
+
}
|
|
125
|
+
declare const defaultAiSlashActions: AiSlashAction[];
|
|
126
|
+
interface AiKitOptions {
|
|
127
|
+
adapter: StreamAdapter;
|
|
128
|
+
/** @default defaultAiSlashActions */
|
|
129
|
+
actions: AiSlashAction[];
|
|
130
|
+
/** Opts out of registering the built-in `aiBlock` node — for a host supplying its own via `extend`. @default true */
|
|
131
|
+
node: boolean;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Builds slash items for each configured action, bound to `options.adapter`.
|
|
135
|
+
* Every action operates on the document text up to the slash trigger — a
|
|
136
|
+
* slash command never carries a real user text selection the way a bubble
|
|
137
|
+
* toolbar action does, so there is nothing else to extract context from.
|
|
138
|
+
*/
|
|
139
|
+
declare function createAiSlashItems(options: Pick<AiKitOptions, "adapter" | "actions">): SlashItem[];
|
|
140
|
+
//#endregion
|
|
141
|
+
//#region src/block-drag.d.ts
|
|
142
|
+
type DropMode = "before" | "after" | "inside";
|
|
143
|
+
/** A drag unit's geometry at the moment it was measured. No DOM access, so this is what keeps `resolveDropTarget` pure. */
|
|
144
|
+
interface BlockRect {
|
|
145
|
+
pos: number;
|
|
146
|
+
size: number;
|
|
147
|
+
type: string;
|
|
148
|
+
left: number;
|
|
149
|
+
right: number;
|
|
150
|
+
top: number;
|
|
151
|
+
bottom: number;
|
|
152
|
+
/** Immediate container's type — `"doc"` for a top-level block, the list's type for a list item. */
|
|
153
|
+
parentType: string;
|
|
154
|
+
/**
|
|
155
|
+
* Bounds of the nearest ancestor-or-self that is itself a direct doc
|
|
156
|
+
* child — this block for a top-level block, the enclosing list for a
|
|
157
|
+
* list item. The escape hatch when `source` can't sit beside `closest`.
|
|
158
|
+
*/
|
|
159
|
+
containerPos: number;
|
|
160
|
+
containerSize: number;
|
|
161
|
+
}
|
|
162
|
+
interface DropTarget {
|
|
163
|
+
/** Document position to insert at, already in the pre-move coordinate space. */
|
|
164
|
+
pos: number;
|
|
165
|
+
mode: DropMode;
|
|
166
|
+
/** The block the decision was made against, so a caller can draw an indicator without another DOM lookup. */
|
|
167
|
+
rect: BlockRect;
|
|
168
|
+
}
|
|
169
|
+
interface ResolveDropTargetOptions {
|
|
170
|
+
/** Rightward pointer travel, in px, from the source's left edge that turns a drop into a nest. */
|
|
171
|
+
indentThreshold: number;
|
|
172
|
+
/** Whether `target` can legally contain `source` as a child, per the live schema. */
|
|
173
|
+
canNest: (source: BlockRect, target: BlockRect) => boolean;
|
|
174
|
+
/** Whether `source` can legally sit next to `target` — i.e. `target`'s own container accepts `source`. */
|
|
175
|
+
canPlaceBeside: (source: BlockRect, target: BlockRect) => boolean;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Pure geometry: given the current block rects, the pointer position, and
|
|
179
|
+
* the block being dragged, decides where it would land. No DOM or schema
|
|
180
|
+
* access beyond the injected `canNest` predicate, so the gesture rules are
|
|
181
|
+
* testable without a browser.
|
|
182
|
+
*/
|
|
183
|
+
declare function resolveDropTarget(blocks: readonly BlockRect[], point: {
|
|
184
|
+
x: number;
|
|
185
|
+
y: number;
|
|
186
|
+
}, source: BlockRect, options: ResolveDropTargetOptions): DropTarget | null;
|
|
187
|
+
/** Whether `source` can be inserted as one more child at the end of `target`'s existing content. */
|
|
188
|
+
declare function canAppendChild(target: Node$1, source: NodeType): boolean;
|
|
189
|
+
interface BlockTarget {
|
|
190
|
+
pos: number;
|
|
191
|
+
size: number;
|
|
192
|
+
type: string;
|
|
193
|
+
id: string | null;
|
|
194
|
+
/** Live rect lookup; re-evaluated on every read so scroll/resize never leaves it stale. */
|
|
195
|
+
getClientRect: () => DOMRect | null;
|
|
196
|
+
}
|
|
197
|
+
interface BlockDragState {
|
|
198
|
+
hovered: BlockTarget | null;
|
|
199
|
+
dragging: BlockTarget | null;
|
|
200
|
+
drop: (DropTarget & {
|
|
201
|
+
getClientRect: () => DOMRect | null;
|
|
202
|
+
}) | null;
|
|
203
|
+
}
|
|
204
|
+
interface BlockDragStorage {
|
|
205
|
+
state: BlockDragState;
|
|
206
|
+
/** @internal Subscribers notified after every state change. */
|
|
207
|
+
listeners: Set<() => void>;
|
|
208
|
+
/** @internal Set once in `onCreate`; lets `setDragging` nudge a decoration recompute. */
|
|
209
|
+
editor: Editor | null;
|
|
210
|
+
/** Subscribes to drag state changes. Returns an unsubscribe function. */
|
|
211
|
+
subscribe(this: BlockDragStorage, listener: () => void): () => void;
|
|
212
|
+
setHovered(this: BlockDragStorage, target: BlockTarget | null): void;
|
|
213
|
+
setDragging(this: BlockDragStorage, target: BlockTarget | null): void;
|
|
214
|
+
setDrop(this: BlockDragStorage, drop: BlockDragState["drop"]): void;
|
|
215
|
+
}
|
|
216
|
+
declare module "@tiptap/core" {
|
|
217
|
+
interface Storage {
|
|
218
|
+
blockDrag: BlockDragStorage;
|
|
219
|
+
}
|
|
220
|
+
interface Commands<ReturnType> {
|
|
221
|
+
blockDrag: {
|
|
222
|
+
/** Moves the node at `from`/`size` to `to`, as one undo step. */
|
|
223
|
+
moveBlock: (options: {
|
|
224
|
+
from: number;
|
|
225
|
+
size: number;
|
|
226
|
+
to: number;
|
|
227
|
+
}) => ReturnType;
|
|
228
|
+
/** Swaps the block under the selection with its previous sibling. */
|
|
229
|
+
moveBlockUp: () => ReturnType;
|
|
230
|
+
/** Swaps the block under the selection with its next sibling. */
|
|
231
|
+
moveBlockDown: () => ReturnType;
|
|
232
|
+
/** Inserts a copy of the node at `pos`/`size` right after it. */
|
|
233
|
+
duplicateBlock: (options: {
|
|
234
|
+
pos: number;
|
|
235
|
+
size: number;
|
|
236
|
+
}) => ReturnType;
|
|
237
|
+
/** Deletes the node at `pos`/`size`. */
|
|
238
|
+
deleteBlock: (options: {
|
|
239
|
+
pos: number;
|
|
240
|
+
size: number;
|
|
241
|
+
}) => ReturnType;
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
declare const blockDragPluginKey: PluginKey<null>;
|
|
246
|
+
interface BlockDragOptions {
|
|
247
|
+
/**
|
|
248
|
+
* Pixels to the left of the content box that still resolve to a block,
|
|
249
|
+
* so hovering the gutter (which is rendered outside the editor DOM)
|
|
250
|
+
* highlights the row underneath it.
|
|
251
|
+
*
|
|
252
|
+
* @default 48
|
|
253
|
+
*/
|
|
254
|
+
gutterWidth: number;
|
|
255
|
+
/**
|
|
256
|
+
* Pixels of rightward pointer travel that turns a drop into a nest.
|
|
257
|
+
*
|
|
258
|
+
* @default 32
|
|
259
|
+
*/
|
|
260
|
+
indentThreshold: number;
|
|
261
|
+
/**
|
|
262
|
+
* Pixels from the nearest scrollable ancestor's edge that scrolls it
|
|
263
|
+
* during a drag.
|
|
264
|
+
*
|
|
265
|
+
* @default 48
|
|
266
|
+
*/
|
|
267
|
+
autoScrollMargin: number;
|
|
268
|
+
onError?: (error: unknown, context: {
|
|
269
|
+
editor: Editor;
|
|
270
|
+
}) => void;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Hover targeting, pointer-driven reordering, and list nesting for the
|
|
274
|
+
* block gutter. Geometry is pointer-driven (not HTML5 DnD) so the drop
|
|
275
|
+
* indicator and the nest gesture stay fully in our control; the gutter
|
|
276
|
+
* itself is rendered by the registry layer, anchored to `state.hovered`.
|
|
277
|
+
*/
|
|
278
|
+
declare const BlockDrag: Extension<BlockDragOptions, BlockDragStorage>;
|
|
279
|
+
/** Configures the block drag extension. */
|
|
280
|
+
declare function blockDrag(options?: Partial<BlockDragOptions>): Extension<BlockDragOptions, BlockDragStorage>;
|
|
281
|
+
//#endregion
|
|
282
|
+
//#region src/block-id.d.ts
|
|
283
|
+
interface BlockIdOptions {
|
|
284
|
+
/**
|
|
285
|
+
* Node type names that receive an id, or `"auto"` to derive them from
|
|
286
|
+
* every registered extension whose resolved `group` or `content`
|
|
287
|
+
* expression contains `block`. Mirrors how `getSchemaByResolvedExtensions`
|
|
288
|
+
* resolves those fields, so function-valued extensions resolve the same
|
|
289
|
+
* way here as they do in the schema.
|
|
290
|
+
*
|
|
291
|
+
* @default "auto"
|
|
292
|
+
*/
|
|
293
|
+
types: string[] | "auto";
|
|
294
|
+
/** Node type names excluded from an `"auto"` derivation. */
|
|
295
|
+
exclude: string[];
|
|
296
|
+
}
|
|
297
|
+
declare const blockIdPluginKey: PluginKey<null>;
|
|
298
|
+
/**
|
|
299
|
+
* Transactions carrying this meta flag are skipped by the assignment pass.
|
|
300
|
+
* A future collaboration provider sets it on transactions that apply a
|
|
301
|
+
* remote change, keeping ids deterministic across peers.
|
|
302
|
+
*/
|
|
303
|
+
declare const BLOCK_ID_REMOTE_META = "blockId:remote";
|
|
304
|
+
/**
|
|
305
|
+
* Injects a stable `attrs.id` into every block-capable node and renders it
|
|
306
|
+
* as `data-block-id`, alongside a constant `data-block-type` per node type
|
|
307
|
+
* for the styling seam. Ids are assigned on insert/parse only, never
|
|
308
|
+
* regenerated on attribute update or remote change — the invariant the
|
|
309
|
+
* eventual Yjs identity (M4) depends on.
|
|
310
|
+
*/
|
|
311
|
+
declare const BlockId: Extension<BlockIdOptions, any>;
|
|
312
|
+
/** Configures the block id extension. */
|
|
313
|
+
declare function blockId(options?: Partial<BlockIdOptions>): Extension<BlockIdOptions, any>;
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region src/bubble-toolbar.d.ts
|
|
316
|
+
interface BubbleToolbarItem {
|
|
317
|
+
/** Stable identity for React keys. */
|
|
318
|
+
id: string;
|
|
319
|
+
label: string;
|
|
320
|
+
/** Icon key resolved by the UI layer; the core ships no components. */
|
|
321
|
+
icon?: string;
|
|
322
|
+
/** Whether the button should render pressed for the current selection. */
|
|
323
|
+
isActive: (editor: Editor) => boolean;
|
|
324
|
+
run: (editor: Editor) => void;
|
|
325
|
+
/** Hides the item when the current editor cannot run it. */
|
|
326
|
+
when?: (editor: Editor) => boolean;
|
|
327
|
+
}
|
|
328
|
+
interface BubbleToolbarState {
|
|
329
|
+
open: boolean;
|
|
330
|
+
/** Items visible for the current editor; already filtered by `when`. */
|
|
331
|
+
items: BubbleToolbarItem[];
|
|
332
|
+
/** Selection rectangle the toolbar anchors to; `null` while closed. */
|
|
333
|
+
getClientRect: (() => DOMRect | null) | null;
|
|
334
|
+
}
|
|
335
|
+
interface BubbleToolbarStorage {
|
|
336
|
+
state: BubbleToolbarState;
|
|
337
|
+
/** @internal Subscribers notified after every state change. */
|
|
338
|
+
listeners: Set<() => void>;
|
|
339
|
+
/** Subscribes to toolbar state changes. Returns an unsubscribe function. */
|
|
340
|
+
subscribe(this: BubbleToolbarStorage, listener: () => void): () => void;
|
|
341
|
+
/** @internal Replaces state and notifies subscribers, skipping no-op closed transitions. */
|
|
342
|
+
setState(this: BubbleToolbarStorage, next: BubbleToolbarState): void;
|
|
343
|
+
}
|
|
344
|
+
interface BubbleToolbarOptions {
|
|
345
|
+
items: BubbleToolbarItem[] | ((editor: Editor) => BubbleToolbarItem[]);
|
|
346
|
+
}
|
|
347
|
+
declare module "@tiptap/core" {
|
|
348
|
+
interface Storage {
|
|
349
|
+
bubbleToolbar: BubbleToolbarStorage;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Ranks are irrelevant here (there's no query to match against); this just
|
|
354
|
+
* hides items the current schema or selection context can't run.
|
|
355
|
+
*/
|
|
356
|
+
declare function filterBubbleToolbarItems(items: BubbleToolbarItem[], editor: Editor): BubbleToolbarItem[];
|
|
357
|
+
declare const defaultBubbleToolbarItems: BubbleToolbarItem[];
|
|
358
|
+
/**
|
|
359
|
+
* Selection-anchored inline formatting toolbar. Unlike the slash menu, there
|
|
360
|
+
* is no query to rank: core only decides *whether* the toolbar is visible
|
|
361
|
+
* and *which* items apply, and the React layer renders it fully controlled
|
|
362
|
+
* (`item.isActive`/`item.run` are called straight from the demo on click).
|
|
363
|
+
*/
|
|
364
|
+
declare const BubbleToolbar: Extension<BubbleToolbarOptions, BubbleToolbarStorage>;
|
|
365
|
+
/** Configures the bubble toolbar extension. */
|
|
366
|
+
declare function bubbleToolbar(options?: Partial<BubbleToolbarOptions>): Extension<BubbleToolbarOptions, BubbleToolbarStorage>;
|
|
367
|
+
//#endregion
|
|
368
|
+
//#region src/collaboration.d.ts
|
|
369
|
+
/** Local user attributes broadcast to every connected peer's awareness state. */
|
|
370
|
+
interface CollaborationUser {
|
|
371
|
+
name: string;
|
|
372
|
+
/** Hex color (`#RRGGBB`); an invalid value renders as `transparent`. */
|
|
373
|
+
color: string;
|
|
374
|
+
[key: string]: unknown;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* The awareness surface `collaboration()` needs from a network provider.
|
|
378
|
+
* `HocuspocusProvider`, `y-websocket`'s `WebsocketProvider`, and `y-webrtc`'s
|
|
379
|
+
* `WebrtcProvider` all satisfy this shape without a direct dependency on any
|
|
380
|
+
* one of them — the host picks the transport, core only touches awareness.
|
|
381
|
+
*/
|
|
382
|
+
interface CollaborationProvider {
|
|
383
|
+
awareness: {
|
|
384
|
+
setLocalStateField(field: string, value: unknown): void;
|
|
385
|
+
getStates(): Map<number, Record<string, unknown>>;
|
|
386
|
+
on(event: "update" | "change", listener: () => void): void;
|
|
387
|
+
off(event: "update" | "change", listener: () => void): void;
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
interface CollaborationOptions {
|
|
391
|
+
/** Shared Yjs document. The host owns its lifecycle: creation, persistence, provider wiring. */
|
|
392
|
+
document: Doc;
|
|
393
|
+
/**
|
|
394
|
+
* Name of the Yjs XML fragment within `document` this editor instance
|
|
395
|
+
* syncs. Change it to sync more than one editor off the same document.
|
|
396
|
+
*
|
|
397
|
+
* @default "content"
|
|
398
|
+
*/
|
|
399
|
+
field?: string;
|
|
400
|
+
/**
|
|
401
|
+
* Network/awareness provider. Enables presence carets via
|
|
402
|
+
* `CollaborationCaret`; omit to sync the document with no presence UI
|
|
403
|
+
* (e.g. an offline-first `IndexeddbPersistence`-only setup).
|
|
404
|
+
*/
|
|
405
|
+
provider?: CollaborationProvider;
|
|
406
|
+
/**
|
|
407
|
+
* Local user's presence attributes. Only meaningful with `provider` set.
|
|
408
|
+
*
|
|
409
|
+
* @default { name: "Anonymous", color: "#94A3B8" }
|
|
410
|
+
*/
|
|
411
|
+
user?: CollaborationUser;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Wires a shared Yjs document into the editor via Tiptap's official
|
|
415
|
+
* `Collaboration`/`CollaborationCaret` extensions (themselves a thin layer
|
|
416
|
+
* over `y-prosemirror`). `BlockId`'s remote-skip check already recognizes
|
|
417
|
+
* the `"y-sync$"` transaction meta these extensions set, so ids stay
|
|
418
|
+
* deterministic across peers with no further wiring.
|
|
419
|
+
*
|
|
420
|
+
* Callers must disable local undo/redo (`createBlockKit`'s `history:
|
|
421
|
+
* false`): Yjs owns the undo stack once a document is shared, and running
|
|
422
|
+
* both corrupts it.
|
|
423
|
+
*/
|
|
424
|
+
declare function collaboration(options: CollaborationOptions): Extensions;
|
|
425
|
+
//#endregion
|
|
426
|
+
//#region src/columns.d.ts
|
|
427
|
+
interface ColumnsOptions {
|
|
428
|
+
HTMLAttributes: Record<string, unknown>;
|
|
429
|
+
}
|
|
430
|
+
interface ColumnOptions {
|
|
431
|
+
HTMLAttributes: Record<string, unknown>;
|
|
432
|
+
}
|
|
433
|
+
declare module "@tiptap/core" {
|
|
434
|
+
interface Commands<ReturnType> {
|
|
435
|
+
columns: {
|
|
436
|
+
/** Inserts a `columns` container with `count` empty columns, clamped to 2–6. */
|
|
437
|
+
setColumns: (count?: number) => ReturnType;
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* A single column inside `Columns`. Not a `block`-group node itself — it
|
|
443
|
+
* only exists as `columns`'s child — but its `block+` content still picks
|
|
444
|
+
* up a `BlockId` (auto mode matches on `content`, not just `group`), giving
|
|
445
|
+
* every nesting depth stable identity for comment anchoring (M4).
|
|
446
|
+
*/
|
|
447
|
+
declare const Column: Node<ColumnOptions, any>;
|
|
448
|
+
/**
|
|
449
|
+
* Side-by-side layout container: the first M2 nesting surface beyond
|
|
450
|
+
* lists. `content: "column{2,}"` bakes the two-column floor into the
|
|
451
|
+
* schema itself, so there is no separate "remove last column" guard to
|
|
452
|
+
* maintain — deleting a column below the minimum is simply not a legal
|
|
453
|
+
* document.
|
|
454
|
+
*/
|
|
455
|
+
declare const Columns: Node<ColumnsOptions, any>;
|
|
456
|
+
/** Configures the columns container node. */
|
|
457
|
+
declare function columns(options?: Partial<ColumnsOptions>): Node<ColumnsOptions, any>;
|
|
458
|
+
/** Configures the column node. */
|
|
459
|
+
declare function column(options?: Partial<ColumnOptions>): Node<ColumnOptions, any>;
|
|
460
|
+
//#endregion
|
|
461
|
+
//#region src/comment.d.ts
|
|
462
|
+
/** A single reply in a comment thread. */
|
|
463
|
+
interface CommentMessage {
|
|
464
|
+
id: string;
|
|
465
|
+
author: string;
|
|
466
|
+
body: string;
|
|
467
|
+
createdAt: number;
|
|
468
|
+
}
|
|
469
|
+
/** A comment thread as the host's store persists it. Bodies never enter the document. */
|
|
470
|
+
interface CommentThread {
|
|
471
|
+
id: string;
|
|
472
|
+
status: "open" | "resolved";
|
|
473
|
+
messages: CommentMessage[];
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Bring-your-own comment backend. Core anchors comments in the document
|
|
477
|
+
* (the `comment` mark carries only a `threadId`); thread bodies, authors,
|
|
478
|
+
* and resolution state live entirely outside the document in a host-owned
|
|
479
|
+
* store, the same way `UploadAdapter`/`StreamAdapter` keep binary/model
|
|
480
|
+
* work out of doc attrs. Deleting the anchored text drops the mark but
|
|
481
|
+
* never the thread — an orphaned thread is a store-side concern, not a
|
|
482
|
+
* document one.
|
|
483
|
+
*/
|
|
484
|
+
interface CommentThreadStore {
|
|
485
|
+
createThread(input: {
|
|
486
|
+
body: string;
|
|
487
|
+
}): CommentThread | Promise<CommentThread>;
|
|
488
|
+
addMessage(threadId: string, input: {
|
|
489
|
+
body: string;
|
|
490
|
+
}): CommentThread | Promise<CommentThread>;
|
|
491
|
+
resolveThread(threadId: string): void | Promise<void>;
|
|
492
|
+
reopenThread(threadId: string): void | Promise<void>;
|
|
493
|
+
getThread(threadId: string): CommentThread | undefined | Promise<CommentThread | undefined>;
|
|
494
|
+
listThreads(): CommentThread[] | Promise<CommentThread[]>;
|
|
495
|
+
}
|
|
496
|
+
interface CommentOptions {
|
|
497
|
+
HTMLAttributes: Record<string, unknown>;
|
|
498
|
+
}
|
|
499
|
+
interface CommentState {
|
|
500
|
+
/** Distinct thread ids anchored under the current selection, in mark order. */
|
|
501
|
+
activeThreadIds: string[];
|
|
502
|
+
}
|
|
503
|
+
interface CommentStorage {
|
|
504
|
+
state: CommentState;
|
|
505
|
+
/** @internal Subscribers notified after every state change. */
|
|
506
|
+
listeners: Set<() => void>;
|
|
507
|
+
/** Subscribes to selection-driven comment state. Returns an unsubscribe function. */
|
|
508
|
+
subscribe(this: CommentStorage, listener: () => void): () => void;
|
|
509
|
+
/** @internal Replaces state and notifies subscribers, skipping no-op empty transitions. */
|
|
510
|
+
setState(this: CommentStorage, next: CommentState): void;
|
|
511
|
+
}
|
|
512
|
+
declare module "@tiptap/core" {
|
|
513
|
+
interface Commands<ReturnType> {
|
|
514
|
+
comment: {
|
|
515
|
+
/** Anchors `threadId` over the current selection. */
|
|
516
|
+
setComment: (threadId: string) => ReturnType;
|
|
517
|
+
/** Removes only `threadId`'s anchors from the current selection. */
|
|
518
|
+
unsetComment: (threadId: string) => ReturnType;
|
|
519
|
+
/** Anchors `threadId` if absent from the selection, removes it if present. */
|
|
520
|
+
toggleComment: (threadId: string) => ReturnType;
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
interface Storage {
|
|
524
|
+
comment: CommentStorage;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Distinct `threadId`s anchored under `state`'s selection: every mark
|
|
529
|
+
* instance touching a non-empty range, or the marks that would apply to
|
|
530
|
+
* text typed at a collapsed cursor. Pure and DOM-free so it is testable
|
|
531
|
+
* against a bare `EditorState`.
|
|
532
|
+
*/
|
|
533
|
+
declare function activeThreadIds(state: EditorState): string[];
|
|
534
|
+
/**
|
|
535
|
+
* Comment anchors are a mark, not a node: `threadId` is the only attribute,
|
|
536
|
+
* so multiple distinct threads can anchor overlapping ranges (`excludes:
|
|
537
|
+
* ""` opts out of ProseMirror's default same-type exclusion). Thread
|
|
538
|
+
* bodies, authors, and resolved state never live here — see
|
|
539
|
+
* `CommentThreadStore`.
|
|
540
|
+
*/
|
|
541
|
+
declare const Comment: Mark<CommentOptions, CommentStorage>;
|
|
542
|
+
/** Configures the comment mark. */
|
|
543
|
+
declare function comment(options?: Partial<CommentOptions>): Mark<CommentOptions, CommentStorage>;
|
|
544
|
+
//#endregion
|
|
545
|
+
//#region src/embed.d.ts
|
|
546
|
+
interface EmbedOptions {
|
|
547
|
+
HTMLAttributes: Record<string, unknown>;
|
|
548
|
+
}
|
|
549
|
+
type EmbedMode = "bookmark" | "iframe";
|
|
550
|
+
interface SetEmbedOptions {
|
|
551
|
+
/** Omit to insert an empty placeholder a `NodeView` can fill in later. */
|
|
552
|
+
url?: string;
|
|
553
|
+
/** @default "bookmark" */
|
|
554
|
+
mode?: EmbedMode;
|
|
555
|
+
title?: string;
|
|
556
|
+
description?: string;
|
|
557
|
+
thumbnail?: string;
|
|
558
|
+
}
|
|
559
|
+
declare module "@tiptap/core" {
|
|
560
|
+
interface Commands<ReturnType> {
|
|
561
|
+
embed: {
|
|
562
|
+
/** Inserts a bookmark or iframe embed node. */
|
|
563
|
+
setEmbed: (options?: SetEmbedOptions) => ReturnType;
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* A block-level external embed: a bookmark link card or a sandboxed
|
|
569
|
+
* iframe, chosen by `mode`. No upload adapter — the URL (and, for
|
|
570
|
+
* bookmarks, the optional title/description/thumbnail metadata) is set
|
|
571
|
+
* directly, either at insert time or later by a `NodeView` reading a
|
|
572
|
+
* pasted link.
|
|
573
|
+
*/
|
|
574
|
+
declare const Embed: Node<EmbedOptions, any>;
|
|
575
|
+
/** Configures the embed node. */
|
|
576
|
+
declare function embed(options?: Partial<EmbedOptions>): Node<EmbedOptions, any>;
|
|
577
|
+
//#endregion
|
|
578
|
+
//#region src/upload.d.ts
|
|
579
|
+
/** Lifecycle of a media node backed by an {@link UploadAdapter}. */
|
|
580
|
+
type UploadStatus = "uploading" | "ready" | "error";
|
|
581
|
+
interface UploadContext {
|
|
582
|
+
/** Aborted when the node carrying this upload is deleted before it settles. */
|
|
583
|
+
signal: AbortSignal;
|
|
584
|
+
}
|
|
585
|
+
interface UploadResult {
|
|
586
|
+
url: string;
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Bring-your-own upload backend. Nodes never talk to a network directly —
|
|
590
|
+
* every image/file/video command takes an adapter instance explicitly, so
|
|
591
|
+
* core stays backend-agnostic and the demo can swap in a mock for tests.
|
|
592
|
+
*/
|
|
593
|
+
interface UploadAdapter<TResult extends UploadResult = UploadResult> {
|
|
594
|
+
upload(file: File, context: UploadContext): Promise<TResult>;
|
|
595
|
+
}
|
|
596
|
+
interface BlockLocation {
|
|
597
|
+
pos: number;
|
|
598
|
+
node: Node$1;
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* Finds a node by its `BlockId`-assigned `id` attribute. Pure: takes a doc,
|
|
602
|
+
* not an editor, so it is testable without a live view.
|
|
603
|
+
*/
|
|
604
|
+
declare function findNodeById(doc: Node$1, id: string): BlockLocation | null;
|
|
605
|
+
interface PendingEntry {
|
|
606
|
+
file: File;
|
|
607
|
+
adapter: UploadAdapter;
|
|
608
|
+
controller: AbortController;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Per-node-type registry of in-flight/failed uploads, keyed by the node's
|
|
612
|
+
* `id`. Retrying re-sends the same `File` without asking the user to pick it
|
|
613
|
+
* again; entries are dropped on success, kept on failure and on abort.
|
|
614
|
+
*
|
|
615
|
+
* Files are never stored in node attrs: attrs must stay JSON-serializable
|
|
616
|
+
* for Yjs (M4), so the pending `File` lives here instead.
|
|
617
|
+
*/
|
|
618
|
+
declare class PendingUploadRegistry {
|
|
619
|
+
private readonly pending;
|
|
620
|
+
set(id: string, entry: PendingEntry): void;
|
|
621
|
+
get(id: string): PendingEntry | undefined;
|
|
622
|
+
delete(id: string): void;
|
|
623
|
+
}
|
|
624
|
+
interface RunUploadOptions<TResult extends UploadResult> {
|
|
625
|
+
editor: Editor;
|
|
626
|
+
typeName: string;
|
|
627
|
+
id: string;
|
|
628
|
+
file: File;
|
|
629
|
+
adapter: UploadAdapter<TResult>;
|
|
630
|
+
pending: PendingUploadRegistry;
|
|
631
|
+
/** Maps a successful result onto the node-specific attrs to persist (e.g. `{ src: result.url }`). */
|
|
632
|
+
toAttrs: (result: TResult) => Record<string, unknown>;
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Starts (or restarts) an upload for a node already present in the
|
|
636
|
+
* document. Resolves by locating the node through `id` — not a captured
|
|
637
|
+
* position — since the doc may change while the network request is in
|
|
638
|
+
* flight. Completion never creates a separate undo step.
|
|
639
|
+
*/
|
|
640
|
+
declare function runUpload<TResult extends UploadResult>(options: RunUploadOptions<TResult>): void;
|
|
641
|
+
interface RetryUploadOptions<TResult extends UploadResult> {
|
|
642
|
+
editor: Editor;
|
|
643
|
+
typeName: string;
|
|
644
|
+
id: string;
|
|
645
|
+
pending: PendingUploadRegistry;
|
|
646
|
+
toAttrs: (result: TResult) => Record<string, unknown>;
|
|
647
|
+
/**
|
|
648
|
+
* Starts from this file/adapter instead of the last one recorded in
|
|
649
|
+
* `pending` — the same machinery also covers "attach a file to an empty
|
|
650
|
+
* placeholder node" (nothing has been attempted yet, so there is no
|
|
651
|
+
* pending entry to fall back on).
|
|
652
|
+
*/
|
|
653
|
+
override?: {
|
|
654
|
+
file: File;
|
|
655
|
+
adapter: UploadAdapter<TResult>;
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* (Re)starts an upload for a node already in the document: from the last
|
|
660
|
+
* `File` passed to `runUpload` for this id, or from `override` when the
|
|
661
|
+
* node has never had an upload attempt (e.g. a placeholder that just had a
|
|
662
|
+
* file attached). Returns `false` — a no-op — when neither is available.
|
|
663
|
+
*/
|
|
664
|
+
declare function retryUpload<TResult extends UploadResult>(options: RetryUploadOptions<TResult>): boolean;
|
|
665
|
+
//#endregion
|
|
666
|
+
//#region src/file.d.ts
|
|
667
|
+
interface FileOptions {
|
|
668
|
+
HTMLAttributes: Record<string, unknown>;
|
|
669
|
+
}
|
|
670
|
+
interface FileStorage {
|
|
671
|
+
pending: PendingUploadRegistry;
|
|
672
|
+
}
|
|
673
|
+
/** Inserted with a picked file: uploads through `adapter`; name/size/mime read from the `File` immediately. */
|
|
674
|
+
interface SetFileFromFile {
|
|
675
|
+
file: File$1;
|
|
676
|
+
adapter: UploadAdapter;
|
|
677
|
+
}
|
|
678
|
+
/** Inserted directly from a known URL. */
|
|
679
|
+
interface SetFileFromSrc {
|
|
680
|
+
src: string;
|
|
681
|
+
name?: string;
|
|
682
|
+
size?: number | null;
|
|
683
|
+
mime?: string | null;
|
|
684
|
+
}
|
|
685
|
+
type SetFileOptions = SetFileFromFile | SetFileFromSrc;
|
|
686
|
+
declare module "@tiptap/core" {
|
|
687
|
+
interface Commands<ReturnType> {
|
|
688
|
+
file: {
|
|
689
|
+
/** Inserts a file node. Omit the options to insert an empty placeholder. */
|
|
690
|
+
setFile: (options?: SetFileOptions) => ReturnType;
|
|
691
|
+
/**
|
|
692
|
+
* Re-sends the last `File` for the node with this id, or `override`
|
|
693
|
+
* to attach a file to a node that has never had an upload attempt
|
|
694
|
+
* (e.g. an empty placeholder).
|
|
695
|
+
*/
|
|
696
|
+
retryFile: (id: string, override?: {
|
|
697
|
+
file: File$1;
|
|
698
|
+
adapter: UploadAdapter;
|
|
699
|
+
}) => ReturnType;
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* A block-level generic-file attachment. Same upload/retry shape as
|
|
705
|
+
* `Image`: `status`/`error` live in doc attrs, the picked `File` lives in
|
|
706
|
+
* `storage.pending` keyed by `id`. See `image.ts` for the full rationale.
|
|
707
|
+
*/
|
|
708
|
+
declare const File$1: Node<FileOptions, FileStorage>;
|
|
709
|
+
/** Configures the file node. */
|
|
710
|
+
declare function file(options?: Partial<FileOptions>): Node<FileOptions, FileStorage>;
|
|
711
|
+
//#endregion
|
|
712
|
+
//#region src/image.d.ts
|
|
713
|
+
interface ImageOptions {
|
|
714
|
+
HTMLAttributes: Record<string, unknown>;
|
|
715
|
+
}
|
|
716
|
+
interface ImageStorage {
|
|
717
|
+
pending: PendingUploadRegistry;
|
|
718
|
+
}
|
|
719
|
+
/** Inserted with a picked file: uploads through `adapter`, no `src` until it resolves. */
|
|
720
|
+
interface SetImageFromFile {
|
|
721
|
+
file: File;
|
|
722
|
+
adapter: UploadAdapter;
|
|
723
|
+
alt?: string;
|
|
724
|
+
}
|
|
725
|
+
/** Inserted directly from a known URL: skips the upload adapter entirely. */
|
|
726
|
+
interface SetImageFromSrc {
|
|
727
|
+
src: string;
|
|
728
|
+
alt?: string;
|
|
729
|
+
width?: number | null;
|
|
730
|
+
}
|
|
731
|
+
type SetImageOptions = SetImageFromFile | SetImageFromSrc;
|
|
732
|
+
declare module "@tiptap/core" {
|
|
733
|
+
interface Commands<ReturnType> {
|
|
734
|
+
image: {
|
|
735
|
+
/** Inserts an image node. Omit the options to insert an empty placeholder. */
|
|
736
|
+
setImage: (options?: SetImageOptions) => ReturnType;
|
|
737
|
+
/**
|
|
738
|
+
* Re-sends the last `File` for the node with this id, or `override`
|
|
739
|
+
* to attach a file to a node that has never had an upload attempt
|
|
740
|
+
* (e.g. an empty placeholder).
|
|
741
|
+
*/
|
|
742
|
+
retryImage: (id: string, override?: {
|
|
743
|
+
file: File;
|
|
744
|
+
adapter: UploadAdapter;
|
|
745
|
+
}) => ReturnType;
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* A block-level image, optionally backed by an in-flight `UploadAdapter`
|
|
751
|
+
* upload. `status`/`error` live in node attrs (part of the doc) so a
|
|
752
|
+
* completed or failed upload re-renders through the normal transaction
|
|
753
|
+
* pipeline — no separate subscribe/storage channel like the slash menu or
|
|
754
|
+
* bubble toolbar, which track ephemeral UI state instead of document state.
|
|
755
|
+
*
|
|
756
|
+
* The picked `File` itself never touches attrs (not JSON-serializable, not
|
|
757
|
+
* Yjs-safe); it lives in `storage.pending`, keyed by the node's `BlockId`,
|
|
758
|
+
* so `retryImage` can resend it without the user picking again.
|
|
759
|
+
*/
|
|
760
|
+
declare const Image: Node<ImageOptions, ImageStorage>;
|
|
761
|
+
/** Configures the image node. */
|
|
762
|
+
declare function image(options?: Partial<ImageOptions>): Node<ImageOptions, ImageStorage>;
|
|
763
|
+
//#endregion
|
|
764
|
+
//#region src/link-editor.d.ts
|
|
765
|
+
interface LinkEditorState {
|
|
766
|
+
open: boolean;
|
|
767
|
+
/** Draft href shown in the popover input. */
|
|
768
|
+
href: string;
|
|
769
|
+
/** `true` when editing a link already on the selection; `false` when drafting one over new text. */
|
|
770
|
+
editing: boolean;
|
|
771
|
+
/** Selection rectangle the popover anchors to; `null` while closed. */
|
|
772
|
+
getClientRect: (() => DOMRect | null) | null;
|
|
773
|
+
}
|
|
774
|
+
interface LinkEditorStorage {
|
|
775
|
+
state: LinkEditorState;
|
|
776
|
+
/** @internal Subscribers notified after every state change. */
|
|
777
|
+
listeners: Set<() => void>;
|
|
778
|
+
/** Subscribes to popover state changes. Returns an unsubscribe function. */
|
|
779
|
+
subscribe(this: LinkEditorStorage, listener: () => void): () => void;
|
|
780
|
+
/** @internal Replaces state and notifies subscribers, skipping no-op closed transitions. */
|
|
781
|
+
setState(this: LinkEditorStorage, next: LinkEditorState): void;
|
|
782
|
+
}
|
|
783
|
+
interface LinkEditorOptions {
|
|
784
|
+
/** Opens automatically when the selection lands inside an existing link. @default true */
|
|
785
|
+
autoOpenOnLinkActive: boolean;
|
|
786
|
+
}
|
|
787
|
+
declare module "@tiptap/core" {
|
|
788
|
+
interface Storage {
|
|
789
|
+
linkEditor: LinkEditorStorage;
|
|
790
|
+
}
|
|
791
|
+
interface Commands<ReturnType> {
|
|
792
|
+
linkEditor: {
|
|
793
|
+
/** Opens the popover: prefilled with the active link's href, or empty over a fresh text selection. */
|
|
794
|
+
openLinkEditor: () => ReturnType;
|
|
795
|
+
/** Updates the draft href. Local UI state only — it never touches the document. */
|
|
796
|
+
setLinkEditorHref: (href: string) => ReturnType;
|
|
797
|
+
/** Closes without applying, refocusing the document. */
|
|
798
|
+
closeLinkEditor: () => ReturnType;
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
/** Whether a link can be created (non-empty text selection) or edited (cursor inside one) right now. */
|
|
803
|
+
declare function canOpenLinkEditor(editor: Editor): boolean;
|
|
804
|
+
/**
|
|
805
|
+
* Selection-anchored link editing popover. Two entry points feed the same
|
|
806
|
+
* state: a bubble-toolbar "Link" button calls `openLinkEditor` over a fresh
|
|
807
|
+
* text selection (`editing: false`), and this extension auto-opens itself
|
|
808
|
+
* (`editing: true`) whenever the cursor lands inside an existing link — a
|
|
809
|
+
* case a plain "selection is non-empty" check (à la `BubbleToolbar`) can't
|
|
810
|
+
* catch, since placing a cursor inside a link selects no text.
|
|
811
|
+
*
|
|
812
|
+
* Applying or removing the link itself is not a custom command here: once
|
|
813
|
+
* open, a UI layer calls the `link` mark's own `setLink`/`unsetLink` (from
|
|
814
|
+
* `@tiptap/extension-link`) directly, the same way `BubbleToolbarItem.run`
|
|
815
|
+
* calls `toggleBold` directly — this extension only owns popover
|
|
816
|
+
* visibility and the draft href.
|
|
817
|
+
*
|
|
818
|
+
* The popover is never closed by `onTransaction`/`onBlur` alone once open:
|
|
819
|
+
* its own input needs real DOM focus to type a URL, and a blur there must
|
|
820
|
+
* not read as "dismiss". Only an explicit command (`closeLinkEditor`, or a
|
|
821
|
+
* document selection change while `editing`) closes it.
|
|
822
|
+
*/
|
|
823
|
+
declare const LinkEditor: Extension<LinkEditorOptions, LinkEditorStorage>;
|
|
824
|
+
/** Configures the link editor extension. */
|
|
825
|
+
declare function linkEditor(options?: Partial<LinkEditorOptions>): Extension<LinkEditorOptions, LinkEditorStorage>;
|
|
826
|
+
//#endregion
|
|
827
|
+
//#region src/mention.d.ts
|
|
828
|
+
interface MentionItem {
|
|
829
|
+
/** Stable identity of the mentioned entity (user id, page id, …). */
|
|
830
|
+
id: string;
|
|
831
|
+
/** Rendered label, e.g. a display name. */
|
|
832
|
+
label: string;
|
|
833
|
+
/** One-line hint rendered next to the label (e.g. an email or handle). */
|
|
834
|
+
description?: string;
|
|
835
|
+
/** Icon key resolved by the UI layer; the core ships no components. */
|
|
836
|
+
icon?: string;
|
|
837
|
+
}
|
|
838
|
+
interface MentionState {
|
|
839
|
+
open: boolean;
|
|
840
|
+
/** Text typed after the trigger character. */
|
|
841
|
+
query: string;
|
|
842
|
+
/** Items returned by the provider for the current query. */
|
|
843
|
+
items: MentionItem[];
|
|
844
|
+
/** Index of the keyboard-highlighted item; `-1` when there are no items. */
|
|
845
|
+
activeIndex: number;
|
|
846
|
+
/** `true` while the provider's promise for the current query is in flight. */
|
|
847
|
+
loading: boolean;
|
|
848
|
+
/** Caret rectangle the menu anchors to; `null` while closed. */
|
|
849
|
+
getClientRect: (() => DOMRect | null) | null;
|
|
850
|
+
}
|
|
851
|
+
interface MentionStorage {
|
|
852
|
+
state: MentionState;
|
|
853
|
+
/** @internal Subscribers notified after every state change. */
|
|
854
|
+
listeners: Set<() => void>;
|
|
855
|
+
/** @internal Live suggestion handle; `null` while the menu is closed. */
|
|
856
|
+
active: SuggestionProps<MentionItem, MentionItem> | null;
|
|
857
|
+
/** Subscribes to menu state changes. Returns an unsubscribe function. */
|
|
858
|
+
subscribe(this: MentionStorage, listener: () => void): () => void;
|
|
859
|
+
/** Moves the keyboard highlight; the index wraps around the item list. */
|
|
860
|
+
setActiveIndex(this: MentionStorage, index: number): void;
|
|
861
|
+
/** Runs an item, defaulting to the highlighted one. */
|
|
862
|
+
select(this: MentionStorage, index?: number): void;
|
|
863
|
+
/** Closes the menu and leaves the typed text in the document. */
|
|
864
|
+
close(this: MentionStorage): void;
|
|
865
|
+
/** @internal Called by the suggestion plugin on start/update/exit. */
|
|
866
|
+
setActive(this: MentionStorage, props: SuggestionProps<MentionItem, MentionItem> | null): void;
|
|
867
|
+
}
|
|
868
|
+
interface MentionOptions {
|
|
869
|
+
/** Trigger character. @default "@" */
|
|
870
|
+
char: string;
|
|
871
|
+
/**
|
|
872
|
+
* Async provider, called for every query with the current query text and
|
|
873
|
+
* an `AbortSignal` for the in-flight request. `@tiptap/suggestion` aborts
|
|
874
|
+
* a call itself as soon as a newer keystroke supersedes it.
|
|
875
|
+
*/
|
|
876
|
+
items: (query: string, context: {
|
|
877
|
+
editor: Editor;
|
|
878
|
+
signal: AbortSignal;
|
|
879
|
+
}) => MentionItem[] | Promise<MentionItem[]>;
|
|
880
|
+
/** Debounce, in ms, before `items` runs after the user stops typing. @default 150 */
|
|
881
|
+
debounce: number;
|
|
882
|
+
/** Minimum query length before `items` runs. @default 0 */
|
|
883
|
+
minQueryLength: number;
|
|
884
|
+
HTMLAttributes: Record<string, unknown>;
|
|
885
|
+
/**
|
|
886
|
+
* Called when `items` rejects. The menu shows an empty result set either
|
|
887
|
+
* way, so a mention query never gets stuck loading forever.
|
|
888
|
+
*/
|
|
889
|
+
onError?: (error: unknown, context: {
|
|
890
|
+
editor: Editor;
|
|
891
|
+
}) => void;
|
|
892
|
+
}
|
|
893
|
+
declare module "@tiptap/core" {
|
|
894
|
+
interface Storage {
|
|
895
|
+
mention: MentionStorage;
|
|
896
|
+
}
|
|
897
|
+
interface Commands<ReturnType> {
|
|
898
|
+
mention: {
|
|
899
|
+
/** Inserts a mention node for `item` at the current selection. */
|
|
900
|
+
insertMention: (item: MentionItem) => ReturnType;
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
declare const mentionPluginKey: PluginKey<any>;
|
|
905
|
+
/**
|
|
906
|
+
* `@`-mention node backed by an async, bring-your-own provider. Mirrors
|
|
907
|
+
* `SlashCommand`'s architecture (a `Suggestion` plugin, per-editor storage
|
|
908
|
+
* with a `subscribe`/state-machine shape) with one addition: `items` may
|
|
909
|
+
* return a `Promise`, so `state.loading` reflects an in-flight request the
|
|
910
|
+
* slash menu never has to model.
|
|
911
|
+
*/
|
|
912
|
+
declare const Mention: Node<MentionOptions, MentionStorage>;
|
|
913
|
+
/** Configures the mention node. `items` is required — there is no default provider. */
|
|
914
|
+
declare function mention(options: Partial<MentionOptions> & Pick<MentionOptions, "items">): Node<MentionOptions, MentionStorage>;
|
|
915
|
+
//#endregion
|
|
916
|
+
//#region src/slash-command.d.ts
|
|
917
|
+
interface SlashMenuState {
|
|
918
|
+
open: boolean;
|
|
919
|
+
/** Text typed after the trigger character. */
|
|
920
|
+
query: string;
|
|
921
|
+
/** Ranked items for the current query. */
|
|
922
|
+
items: SlashItem[];
|
|
923
|
+
/** Index of the keyboard-highlighted item; `-1` when there are no items. */
|
|
924
|
+
activeIndex: number;
|
|
925
|
+
/** Caret rectangle the menu anchors to; `null` while closed. */
|
|
926
|
+
getClientRect: (() => DOMRect | null) | null;
|
|
927
|
+
}
|
|
928
|
+
interface SlashCommandStorage {
|
|
929
|
+
state: SlashMenuState;
|
|
930
|
+
/** @internal Subscribers notified after every state change. */
|
|
931
|
+
listeners: Set<() => void>;
|
|
932
|
+
/** @internal Live suggestion handle; `null` while the menu is closed. */
|
|
933
|
+
active: SuggestionProps<SlashItem, SlashItem> | null;
|
|
934
|
+
/** Subscribes to menu state changes. Returns an unsubscribe function. */
|
|
935
|
+
subscribe(this: SlashCommandStorage, listener: () => void): () => void;
|
|
936
|
+
/** Moves the keyboard highlight; the index wraps around the item list. */
|
|
937
|
+
setActiveIndex(this: SlashCommandStorage, index: number): void;
|
|
938
|
+
/** Runs an item, defaulting to the highlighted one. */
|
|
939
|
+
select(this: SlashCommandStorage, index?: number): void;
|
|
940
|
+
/** Closes the menu and leaves the typed text in the document. */
|
|
941
|
+
close(this: SlashCommandStorage): void;
|
|
942
|
+
/** @internal Called by the suggestion plugin on start/update/exit. */
|
|
943
|
+
setActive(this: SlashCommandStorage, props: SuggestionProps<SlashItem, SlashItem> | null): void;
|
|
944
|
+
}
|
|
945
|
+
interface SlashCommandOptions {
|
|
946
|
+
/** Trigger character. */
|
|
947
|
+
char: string;
|
|
948
|
+
/** Item registry, or a resolver called with the live editor. */
|
|
949
|
+
items: SlashItem[] | ((editor: Editor) => SlashItem[]);
|
|
950
|
+
/**
|
|
951
|
+
* Called when an item's `run` throws. The failing transaction is never
|
|
952
|
+
* applied, so the document keeps the state it had before the item ran.
|
|
953
|
+
*/
|
|
954
|
+
onError?: (error: unknown, context: {
|
|
955
|
+
item: SlashItem;
|
|
956
|
+
editor: Editor;
|
|
957
|
+
}) => void;
|
|
958
|
+
}
|
|
959
|
+
declare module "@tiptap/core" {
|
|
960
|
+
interface Storage {
|
|
961
|
+
slashCommand: SlashCommandStorage;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
declare const slashCommandPluginKey: PluginKey<any>;
|
|
965
|
+
declare const SlashCommand: Extension<SlashCommandOptions, SlashCommandStorage>;
|
|
966
|
+
/** Configures the slash menu extension. */
|
|
967
|
+
declare function slashCommand(options?: Partial<SlashCommandOptions>): Extension<SlashCommandOptions, SlashCommandStorage>;
|
|
968
|
+
//#endregion
|
|
969
|
+
//#region src/table.d.ts
|
|
970
|
+
/**
|
|
971
|
+
* Configures Tiptap's table kit (table/tableRow/tableHeader/tableCell) with
|
|
972
|
+
* resizable columns on by default — the one behavior worth diverging from
|
|
973
|
+
* upstream's default, since a fixed-width table is the common Notion-parity
|
|
974
|
+
* expectation. `insertTable`/`addColumnBefore`/`deleteRow`/… ship from the
|
|
975
|
+
* upstream extension; slash-editor adds no table-specific commands.
|
|
976
|
+
*/
|
|
977
|
+
declare function table(options?: Partial<TableKitOptions>): import("@tiptap/core").Extension<TableKitOptions, any>;
|
|
978
|
+
//#endregion
|
|
979
|
+
//#region src/video.d.ts
|
|
980
|
+
interface VideoOptions {
|
|
981
|
+
HTMLAttributes: Record<string, unknown>;
|
|
982
|
+
}
|
|
983
|
+
interface VideoStorage {
|
|
984
|
+
pending: PendingUploadRegistry;
|
|
985
|
+
}
|
|
986
|
+
/** Inserted with a picked file: uploads through `adapter`, no `src` until it resolves. */
|
|
987
|
+
interface SetVideoFromFile {
|
|
988
|
+
file: File;
|
|
989
|
+
adapter: UploadAdapter;
|
|
990
|
+
poster?: string;
|
|
991
|
+
}
|
|
992
|
+
/** Inserted directly from a known URL. */
|
|
993
|
+
interface SetVideoFromSrc {
|
|
994
|
+
src: string;
|
|
995
|
+
poster?: string;
|
|
996
|
+
}
|
|
997
|
+
type SetVideoOptions = SetVideoFromFile | SetVideoFromSrc;
|
|
998
|
+
declare module "@tiptap/core" {
|
|
999
|
+
interface Commands<ReturnType> {
|
|
1000
|
+
video: {
|
|
1001
|
+
/** Inserts a video node. Omit the options to insert an empty placeholder. */
|
|
1002
|
+
setVideo: (options?: SetVideoOptions) => ReturnType;
|
|
1003
|
+
/**
|
|
1004
|
+
* Re-sends the last `File` for the node with this id, or `override`
|
|
1005
|
+
* to attach a file to a node that has never had an upload attempt
|
|
1006
|
+
* (e.g. an empty placeholder).
|
|
1007
|
+
*/
|
|
1008
|
+
retryVideo: (id: string, override?: {
|
|
1009
|
+
file: File;
|
|
1010
|
+
adapter: UploadAdapter;
|
|
1011
|
+
}) => ReturnType;
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
/**
|
|
1016
|
+
* A block-level video, same upload/retry shape as `Image`: `status`/`error`
|
|
1017
|
+
* live in doc attrs, the picked `File` lives in `storage.pending` keyed by
|
|
1018
|
+
* `id`. See `image.ts` for the full rationale.
|
|
1019
|
+
*/
|
|
1020
|
+
declare const Video: Node<VideoOptions, VideoStorage>;
|
|
1021
|
+
/** Configures the video node. */
|
|
1022
|
+
declare function video(options?: Partial<VideoOptions>): Node<VideoOptions, VideoStorage>;
|
|
1023
|
+
//#endregion
|
|
1024
|
+
//#region src/block-kit.d.ts
|
|
1025
|
+
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
1026
|
+
interface BlockKitOptions {
|
|
1027
|
+
/**
|
|
1028
|
+
* Heading levels offered by the editor.
|
|
1029
|
+
*
|
|
1030
|
+
* @default [1, 2, 3]
|
|
1031
|
+
*/
|
|
1032
|
+
headingLevels?: HeadingLevel[];
|
|
1033
|
+
/**
|
|
1034
|
+
* Local undo/redo history.
|
|
1035
|
+
*
|
|
1036
|
+
* Set to `false` when a collaboration provider owns history: Yjs ships its
|
|
1037
|
+
* own undo manager and running both corrupts the undo stack.
|
|
1038
|
+
*
|
|
1039
|
+
* @default true
|
|
1040
|
+
*/
|
|
1041
|
+
history?: boolean;
|
|
1042
|
+
/**
|
|
1043
|
+
* Slash menu configuration, or `false` to leave the trigger character inert.
|
|
1044
|
+
*
|
|
1045
|
+
* @default { char: "/", items: defaultSlashItems }
|
|
1046
|
+
*/
|
|
1047
|
+
slash?: Partial<SlashCommandOptions> | false;
|
|
1048
|
+
/**
|
|
1049
|
+
* Stable per-block id configuration, or `false` to opt out. Drag
|
|
1050
|
+
* targeting and the future comment/collaboration surfaces depend on it.
|
|
1051
|
+
*
|
|
1052
|
+
* @default { types: "auto" }
|
|
1053
|
+
*/
|
|
1054
|
+
blockId?: Partial<BlockIdOptions> | false;
|
|
1055
|
+
/**
|
|
1056
|
+
* Block gutter drag handle: reorder and list nesting. Requires
|
|
1057
|
+
* `blockId`, since drag targets are addressed by id.
|
|
1058
|
+
*
|
|
1059
|
+
* @default {}
|
|
1060
|
+
*/
|
|
1061
|
+
drag?: Partial<BlockDragOptions> | false;
|
|
1062
|
+
/**
|
|
1063
|
+
* Selection-anchored inline formatting toolbar, or `false` to opt out.
|
|
1064
|
+
*
|
|
1065
|
+
* @default { items: defaultBubbleToolbarItems }
|
|
1066
|
+
*/
|
|
1067
|
+
bubbleToolbar?: Partial<BubbleToolbarOptions> | false;
|
|
1068
|
+
/**
|
|
1069
|
+
* Extensions appended after the baseline set. Later extensions win on
|
|
1070
|
+
* conflicting keymaps, so this is the seam for overriding defaults.
|
|
1071
|
+
*/
|
|
1072
|
+
extend?: Extensions;
|
|
1073
|
+
/**
|
|
1074
|
+
* Image node configuration, or `false` to opt out and supply a
|
|
1075
|
+
* `NodeView`-augmented variant via `extend` instead (see `Image`,
|
|
1076
|
+
* exported for `.extend()`).
|
|
1077
|
+
*
|
|
1078
|
+
* @default {}
|
|
1079
|
+
*/
|
|
1080
|
+
image?: Partial<ImageOptions> | false;
|
|
1081
|
+
/**
|
|
1082
|
+
* File attachment node configuration, or `false` to opt out.
|
|
1083
|
+
*
|
|
1084
|
+
* @default {}
|
|
1085
|
+
*/
|
|
1086
|
+
file?: Partial<FileOptions> | false;
|
|
1087
|
+
/**
|
|
1088
|
+
* Video node configuration, or `false` to opt out.
|
|
1089
|
+
*
|
|
1090
|
+
* @default {}
|
|
1091
|
+
*/
|
|
1092
|
+
video?: Partial<VideoOptions> | false;
|
|
1093
|
+
/**
|
|
1094
|
+
* Bookmark/iframe embed node configuration, or `false` to opt out.
|
|
1095
|
+
*
|
|
1096
|
+
* @default {}
|
|
1097
|
+
*/
|
|
1098
|
+
embed?: Partial<EmbedOptions> | false;
|
|
1099
|
+
/**
|
|
1100
|
+
* Table kit configuration (resizable columns on by default), or `false`
|
|
1101
|
+
* to opt out.
|
|
1102
|
+
*
|
|
1103
|
+
* @default { table: { resizable: true } }
|
|
1104
|
+
*/
|
|
1105
|
+
table?: Partial<TableKitOptions> | false;
|
|
1106
|
+
/**
|
|
1107
|
+
* Columns container configuration, or `false` to opt out.
|
|
1108
|
+
*
|
|
1109
|
+
* @default {}
|
|
1110
|
+
*/
|
|
1111
|
+
columns?: Partial<ColumnsOptions> | false;
|
|
1112
|
+
/**
|
|
1113
|
+
* Selection-anchored link editing popover, or `false` to opt out.
|
|
1114
|
+
* Requires the `link` mark, configured on by `createBlockKit` with
|
|
1115
|
+
* `openOnClick: false, enableClickSelection: true` so clicking a link
|
|
1116
|
+
* while editing selects it instead of navigating away.
|
|
1117
|
+
*
|
|
1118
|
+
* @default {}
|
|
1119
|
+
*/
|
|
1120
|
+
linkEditor?: Partial<LinkEditorOptions> | false;
|
|
1121
|
+
/**
|
|
1122
|
+
* `@`-mention node with an async, bring-your-own provider. Omit to leave
|
|
1123
|
+
* the trigger character inert — there is no default provider to fall
|
|
1124
|
+
* back to, unlike the always-on `slash` menu.
|
|
1125
|
+
*/
|
|
1126
|
+
mention?: (Partial<MentionOptions> & Pick<MentionOptions, "items">) | false;
|
|
1127
|
+
/**
|
|
1128
|
+
* AI slash actions (`Continue writing`, `Summarize`, …) streamed through
|
|
1129
|
+
* a bring-your-own `StreamAdapter`. Omit to leave those slash items out —
|
|
1130
|
+
* there is no default adapter to fall back to.
|
|
1131
|
+
*/
|
|
1132
|
+
ai?: (Partial<AiKitOptions> & Pick<AiKitOptions, "adapter">) | false;
|
|
1133
|
+
/**
|
|
1134
|
+
* Shared Yjs document, network provider, and presence config. No
|
|
1135
|
+
* default — omit to run local-only. Forces `history: false` (Yjs owns
|
|
1136
|
+
* the undo stack once a document is shared) regardless of the `history`
|
|
1137
|
+
* option.
|
|
1138
|
+
*/
|
|
1139
|
+
collaboration?: CollaborationOptions | false;
|
|
1140
|
+
/**
|
|
1141
|
+
* Comment mark (`threadId` anchor) plus the selection-driven active-thread
|
|
1142
|
+
* state a UI reads to open a thread panel. Thread bodies live in a
|
|
1143
|
+
* host-provided `CommentThreadStore`, never in the document.
|
|
1144
|
+
*
|
|
1145
|
+
* @default {}
|
|
1146
|
+
*/
|
|
1147
|
+
comment?: Partial<CommentOptions> | false;
|
|
1148
|
+
}
|
|
1149
|
+
/**
|
|
1150
|
+
* The baseline block schema: document, text, paragraph, headings, lists,
|
|
1151
|
+
* task lists, blockquote, callout, toggle (details), code block, horizontal
|
|
1152
|
+
* rule, hard break, and the inline marks.
|
|
1153
|
+
*
|
|
1154
|
+
* Emits no class names. UI layers style content through element selectors and
|
|
1155
|
+
* the `data-*` attributes rendered by slash-editor nodes.
|
|
1156
|
+
*/
|
|
1157
|
+
declare function createBlockKit(options?: BlockKitOptions): Extensions;
|
|
1158
|
+
//#endregion
|
|
1159
|
+
//#region src/callout.d.ts
|
|
1160
|
+
interface CalloutOptions {
|
|
1161
|
+
/**
|
|
1162
|
+
* Emoji shown when a callout is created and no icon attribute is parsed
|
|
1163
|
+
* from HTML.
|
|
1164
|
+
*
|
|
1165
|
+
* @default "💡"
|
|
1166
|
+
*/
|
|
1167
|
+
defaultIcon: string;
|
|
1168
|
+
HTMLAttributes: Record<string, unknown>;
|
|
1169
|
+
}
|
|
1170
|
+
declare module "@tiptap/core" {
|
|
1171
|
+
interface Commands<ReturnType> {
|
|
1172
|
+
callout: {
|
|
1173
|
+
/** Wraps the current block range in a callout. */
|
|
1174
|
+
setCallout: () => ReturnType;
|
|
1175
|
+
/** Wraps in a callout, or lifts out of one if already inside. */
|
|
1176
|
+
toggleCallout: () => ReturnType;
|
|
1177
|
+
/** Lifts the current block out of its enclosing callout. */
|
|
1178
|
+
unsetCallout: () => ReturnType;
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* A highlighted aside with a leading emoji, wrapping arbitrary block content
|
|
1184
|
+
* (`content: block+`) rather than a flat textblock. Nesting follows the
|
|
1185
|
+
* container-node approach used across M1: no universal block wrapper.
|
|
1186
|
+
*/
|
|
1187
|
+
declare const Callout: Node<CalloutOptions, any>;
|
|
1188
|
+
/** Configures the callout node. */
|
|
1189
|
+
declare function callout(options?: Partial<CalloutOptions>): Node<CalloutOptions, any>;
|
|
1190
|
+
//#endregion
|
|
1191
|
+
export { type AiActionStatus, AiBlock, type AiBlockOptions, type AiBlockStorage, type AiKitOptions, type AiRequest, type AiSlashAction, BLOCK_ID_REMOTE_META, BlockDrag, type BlockDragOptions, type BlockDragState, type BlockDragStorage, BlockId, type BlockIdOptions, type BlockKitOptions, type BlockLocation, type BlockRect, type BlockTarget, BubbleToolbar, type BubbleToolbarItem, type BubbleToolbarOptions, type BubbleToolbarState, type BubbleToolbarStorage, Callout, type CalloutOptions, type CollaborationOptions, type CollaborationProvider, type CollaborationUser, Column, type ColumnOptions, Columns, type ColumnsOptions, Comment, type CommentMessage, type CommentOptions, type CommentState, type CommentStorage, type CommentThread, type CommentThreadStore, type DropMode, type DropTarget, Embed, type EmbedMode, type EmbedOptions, File$1 as File, type FileOptions, type FileStorage, type HeadingLevel, Image, type ImageOptions, type ImageStorage, LinkEditor, type LinkEditorOptions, type LinkEditorState, type LinkEditorStorage, Mention, type MentionItem, type MentionOptions, type MentionState, type MentionStorage, PendingAiRegistry, PendingUploadRegistry, type RetryUploadOptions, type RunAiActionOptions, type RunUploadOptions, type SetEmbedOptions, type SetFileFromFile, type SetFileFromSrc, type SetFileOptions, type SetImageFromFile, type SetImageFromSrc, type SetImageOptions, type SetVideoFromFile, type SetVideoFromSrc, type SetVideoOptions, SlashCommand, type SlashCommandOptions, type SlashCommandStorage, type SlashContext, type SlashItem, type SlashMenuState, type StreamAdapter, type StreamContext, TableKit, type TableKitOptions, type UploadAdapter, type UploadContext, type UploadResult, type UploadStatus, Video, type VideoOptions, type VideoStorage, activeThreadIds, aiBlock, blockDrag, blockDragPluginKey, blockId, blockIdPluginKey, bubbleToolbar, callout, canAppendChild, canOpenLinkEditor, collaboration, column, columns, comment, createAiSlashItems, createBlockKit, defaultAiSlashActions, defaultBubbleToolbarItems, defaultSlashItems, embed, file, filterBubbleToolbarItems, filterSlashItems, findNodeById, image, linkEditor, mention, mentionPluginKey, resolveDropTarget, retryUpload, runUpload, slashCommand, slashCommandPluginKey, table, video };
|