@slash-editor/core 0.0.6 → 0.0.8
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 +128 -1
- package/dist/index.mjs +363 -11
- package/package.json +2 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Editor, Extension, Extensions, Mark, Node, Range } from "@tiptap/core";
|
|
2
2
|
import { Node as Node$1, NodeType } from "@tiptap/pm/model";
|
|
3
3
|
import { EditorState, PluginKey } from "@tiptap/pm/state";
|
|
4
|
+
import { DetailsOptions } from "@tiptap/extension-details";
|
|
4
5
|
import { SuggestionProps } from "@tiptap/suggestion";
|
|
6
|
+
import { BlockquoteOptions } from "@tiptap/extension-blockquote";
|
|
5
7
|
import { TableKit, TableKitOptions } from "@tiptap/extension-table";
|
|
6
8
|
import { Doc } from "yjs";
|
|
7
9
|
//#region src/slash-items.d.ts
|
|
@@ -22,6 +24,12 @@ interface SlashItem {
|
|
|
22
24
|
aliases?: string[];
|
|
23
25
|
/** Lower-weight search terms that are never displayed. */
|
|
24
26
|
keywords?: string[];
|
|
27
|
+
/**
|
|
28
|
+
* Markdown input-rule shorthand shown as a hint in the menu (`#`, `---`).
|
|
29
|
+
* Display only — ranking never reads it, and it must mirror a rule the
|
|
30
|
+
* editor actually registers.
|
|
31
|
+
*/
|
|
32
|
+
shortcut?: string;
|
|
25
33
|
/** Icon key resolved by the UI layer; the core ships no components. */
|
|
26
34
|
icon?: string;
|
|
27
35
|
/** Hides the item when the current editor cannot run it. */
|
|
@@ -913,6 +921,54 @@ declare const Mention: Node<MentionOptions, MentionStorage>;
|
|
|
913
921
|
/** Configures the mention node. `items` is required — there is no default provider. */
|
|
914
922
|
declare function mention(options: Partial<MentionOptions> & Pick<MentionOptions, "items">): Node<MentionOptions, MentionStorage>;
|
|
915
923
|
//#endregion
|
|
924
|
+
//#region src/placeholder.d.ts
|
|
925
|
+
/**
|
|
926
|
+
* Slot a placeholder string is looked up under. Slots are resolved from the
|
|
927
|
+
* empty node *and its parent*: the empty node inside a list item, a task item,
|
|
928
|
+
* a quote or a callout is a plain `paragraph`, so node type alone cannot tell
|
|
929
|
+
* those cases apart.
|
|
930
|
+
*/
|
|
931
|
+
type PlaceholderKey = "paragraph" | "heading1" | "heading2" | "heading3" | "listItem" | "taskItem" | "blockquote" | "callout" | "details" | "toggleHeading1" | "toggleHeading2" | "toggleHeading3";
|
|
932
|
+
interface PlaceholderContext {
|
|
933
|
+
editor: Editor;
|
|
934
|
+
/** The empty block holding the caret. */
|
|
935
|
+
node: Node$1;
|
|
936
|
+
/** Its parent, which distinguishes a bare paragraph from a list/quote child. */
|
|
937
|
+
parent: Node$1 | null;
|
|
938
|
+
/** Position directly before `node`. */
|
|
939
|
+
pos: number;
|
|
940
|
+
}
|
|
941
|
+
interface PlaceholderOptions {
|
|
942
|
+
/** Per-slot overrides; unset slots keep the default string. */
|
|
943
|
+
text?: Partial<Record<PlaceholderKey, string>>;
|
|
944
|
+
/**
|
|
945
|
+
* Full override. Wins over `text`; returning `null` suppresses the
|
|
946
|
+
* placeholder for that block.
|
|
947
|
+
*/
|
|
948
|
+
resolve?: (context: PlaceholderContext) => string | null;
|
|
949
|
+
}
|
|
950
|
+
declare const defaultPlaceholderText: Record<PlaceholderKey, string>;
|
|
951
|
+
/**
|
|
952
|
+
* Maps an empty block to its placeholder slot, or `null` when it should stay
|
|
953
|
+
* blank. Code blocks are excluded: their content is literal, and a hint would
|
|
954
|
+
* read as source.
|
|
955
|
+
*/
|
|
956
|
+
declare function placeholderKeyFor(node: Node$1, parent: Node$1 | null): PlaceholderKey | null;
|
|
957
|
+
declare const placeholderPluginKey: PluginKey<any>;
|
|
958
|
+
/**
|
|
959
|
+
* Empty-block hints, Notion style: only the block holding the caret shows one.
|
|
960
|
+
*
|
|
961
|
+
* Renders `data-placeholder` and no class names — the UI layer styles
|
|
962
|
+
* `[data-placeholder]::before`, matching how every other core node is styled.
|
|
963
|
+
*
|
|
964
|
+
* The decoration is derived from the state it is drawn against rather than
|
|
965
|
+
* from `editor.state`: during a transaction those are different documents, and
|
|
966
|
+
* resolving a parent in the stale one mislabels every nested block.
|
|
967
|
+
*/
|
|
968
|
+
declare const Placeholder: Extension<PlaceholderOptions, any>;
|
|
969
|
+
/** Configures empty-block placeholders. */
|
|
970
|
+
declare function placeholder(options?: PlaceholderOptions): Extension<PlaceholderOptions, any>;
|
|
971
|
+
//#endregion
|
|
916
972
|
//#region src/slash-command.d.ts
|
|
917
973
|
interface SlashMenuState {
|
|
918
974
|
open: boolean;
|
|
@@ -947,6 +1003,12 @@ interface SlashCommandOptions {
|
|
|
947
1003
|
char: string;
|
|
948
1004
|
/** Item registry, or a resolver called with the live editor. */
|
|
949
1005
|
items: SlashItem[] | ((editor: Editor) => SlashItem[]);
|
|
1006
|
+
/**
|
|
1007
|
+
* Inline hint rendered next to the trigger character while the query is
|
|
1008
|
+
* still empty, the way Notion prompts after `/`. Set to `""` to drop it.
|
|
1009
|
+
* The UI layer renders it from `data-decoration-content`.
|
|
1010
|
+
*/
|
|
1011
|
+
hint: string;
|
|
950
1012
|
/**
|
|
951
1013
|
* Called when an item's `run` throws. The failing transaction is never
|
|
952
1014
|
* applied, so the document keeps the state it had before the item ran.
|
|
@@ -976,6 +1038,40 @@ declare function slashCommand(options?: Partial<SlashCommandOptions>): Extension
|
|
|
976
1038
|
*/
|
|
977
1039
|
declare function table(options?: Partial<TableKitOptions>): import("@tiptap/core").Extension<TableKitOptions, any>;
|
|
978
1040
|
//#endregion
|
|
1041
|
+
//#region src/toggle.d.ts
|
|
1042
|
+
type ToggleOptions = DetailsOptions;
|
|
1043
|
+
/** Heading level a toggle renders its title at; `0` is a plain toggle list. */
|
|
1044
|
+
type ToggleLevel = 0 | 1 | 2 | 3;
|
|
1045
|
+
declare module "@tiptap/core" {
|
|
1046
|
+
interface Commands<ReturnType> {
|
|
1047
|
+
toggle: {
|
|
1048
|
+
/**
|
|
1049
|
+
* Turns the current block into a toggle whose title is that block's
|
|
1050
|
+
* text, or re-levels the toggle already holding the selection.
|
|
1051
|
+
*/
|
|
1052
|
+
setToggle: (level?: ToggleLevel) => ReturnType;
|
|
1053
|
+
/** Sets the heading level of the toggle holding the selection. */
|
|
1054
|
+
setToggleLevel: (level: ToggleLevel) => ReturnType;
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
/** `>` + space: the toggle shorthand. */
|
|
1059
|
+
declare const toggleInputRegex: RegExp;
|
|
1060
|
+
/** `#`…`###` + space inside a toggle title: the toggle-heading shorthand. */
|
|
1061
|
+
declare const toggleHeadingInputRegex: RegExp;
|
|
1062
|
+
/**
|
|
1063
|
+
* Tiptap's `Details` with a `level` attribute, the `>` shorthand, and the
|
|
1064
|
+
* toggle-heading shorthands.
|
|
1065
|
+
*
|
|
1066
|
+
* `level` lives on the container rather than the title because the node view
|
|
1067
|
+
* renders the disclosure button as a *sibling* of the summary: with
|
|
1068
|
+
* `data-level` on the wrapper, one selector sizes both, and the marker stays
|
|
1069
|
+
* centred on a title of any size.
|
|
1070
|
+
*/
|
|
1071
|
+
declare const Toggle: import("@tiptap/core").Node<DetailsOptions, any>;
|
|
1072
|
+
/** Configures the toggle (details) node. */
|
|
1073
|
+
declare function toggle(options?: Partial<ToggleOptions>): import("@tiptap/core").Node<DetailsOptions, any>;
|
|
1074
|
+
//#endregion
|
|
979
1075
|
//#region src/video.d.ts
|
|
980
1076
|
interface VideoOptions {
|
|
981
1077
|
HTMLAttributes: Record<string, unknown>;
|
|
@@ -1045,6 +1141,13 @@ interface BlockKitOptions {
|
|
|
1045
1141
|
* @default { char: "/", items: defaultSlashItems }
|
|
1046
1142
|
*/
|
|
1047
1143
|
slash?: Partial<SlashCommandOptions> | false;
|
|
1144
|
+
/**
|
|
1145
|
+
* Empty-block placeholder hints, or `false` to render none. Only the block
|
|
1146
|
+
* holding the caret shows one.
|
|
1147
|
+
*
|
|
1148
|
+
* @default {}
|
|
1149
|
+
*/
|
|
1150
|
+
placeholder?: PlaceholderOptions | false;
|
|
1048
1151
|
/**
|
|
1049
1152
|
* Stable per-block id configuration, or `false` to opt out. Drag
|
|
1050
1153
|
* targeting and the future comment/collaboration surfaces depend on it.
|
|
@@ -1145,6 +1248,14 @@ interface BlockKitOptions {
|
|
|
1145
1248
|
* @default {}
|
|
1146
1249
|
*/
|
|
1147
1250
|
comment?: Partial<CommentOptions> | false;
|
|
1251
|
+
/**
|
|
1252
|
+
* Toggle (details) node configuration. Options only — the node itself is
|
|
1253
|
+
* unconditional, like blockquote. This is the seam a UI layer uses to
|
|
1254
|
+
* render its own disclosure marker via `renderToggleButton`.
|
|
1255
|
+
*
|
|
1256
|
+
* @default { persist: true }
|
|
1257
|
+
*/
|
|
1258
|
+
toggle?: Partial<ToggleOptions>;
|
|
1148
1259
|
}
|
|
1149
1260
|
/**
|
|
1150
1261
|
* The baseline block schema: document, text, paragraph, headings, lists,
|
|
@@ -1188,4 +1299,20 @@ declare const Callout: Node<CalloutOptions, any>;
|
|
|
1188
1299
|
/** Configures the callout node. */
|
|
1189
1300
|
declare function callout(options?: Partial<CalloutOptions>): Node<CalloutOptions, any>;
|
|
1190
1301
|
//#endregion
|
|
1191
|
-
|
|
1302
|
+
//#region src/quote.d.ts
|
|
1303
|
+
type QuoteOptions = BlockquoteOptions;
|
|
1304
|
+
/** `"` + space at the start of a block, Notion style. */
|
|
1305
|
+
declare const quoteInputRegex: RegExp;
|
|
1306
|
+
/**
|
|
1307
|
+
* Blockquote with its markdown shorthand moved from `>` to `"`. The node name
|
|
1308
|
+
* stays `blockquote`: only the input rule changes, so stored documents,
|
|
1309
|
+
* clipboard HTML, and `Mod+Shift+B` are untouched.
|
|
1310
|
+
*
|
|
1311
|
+
* `>` belongs to the toggle (see `toggle.ts`), which is what Notion users
|
|
1312
|
+
* reach for it expecting.
|
|
1313
|
+
*/
|
|
1314
|
+
declare const Quote: import("@tiptap/core").Node<BlockquoteOptions, any>;
|
|
1315
|
+
/** Configures the quote (blockquote) node. */
|
|
1316
|
+
declare function quote(options?: Partial<QuoteOptions>): import("@tiptap/core").Node<BlockquoteOptions, any>;
|
|
1317
|
+
//#endregion
|
|
1318
|
+
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, Placeholder, type PlaceholderContext, type PlaceholderKey, type PlaceholderOptions, Quote, type QuoteOptions, 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, Toggle, type ToggleLevel, type ToggleOptions, 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, defaultPlaceholderText, defaultSlashItems, embed, file, filterBubbleToolbarItems, filterSlashItems, findNodeById, image, linkEditor, mention, mentionPluginKey, placeholder, placeholderKeyFor, placeholderPluginKey, quote, quoteInputRegex, resolveDropTarget, retryUpload, runUpload, slashCommand, slashCommandPluginKey, table, toggle, toggleHeadingInputRegex, toggleInputRegex, video };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Extension, Mark, Node, callOrReturn, combineTransactionSteps, findChildrenInRange, getChangedRanges, getExtensionField, isTextSelection, mergeAttributes, posToDOMRect } from "@tiptap/core";
|
|
1
|
+
import { Extension, InputRule, Mark, Node, callOrReturn, combineTransactionSteps, findChildrenInRange, findParentNode, getChangedRanges, getExtensionField, isTextSelection, mergeAttributes, posToDOMRect, wrappingInputRule } from "@tiptap/core";
|
|
2
2
|
import { Fragment } from "@tiptap/pm/model";
|
|
3
|
-
import { Plugin, PluginKey } from "@tiptap/pm/state";
|
|
3
|
+
import { Plugin, PluginKey, TextSelection } from "@tiptap/pm/state";
|
|
4
4
|
import { Decoration, DecorationSet } from "@tiptap/pm/view";
|
|
5
5
|
import { StarterKit } from "@tiptap/starter-kit";
|
|
6
6
|
import { Details, DetailsContent, DetailsSummary } from "@tiptap/extension-details";
|
|
@@ -8,6 +8,7 @@ import { TaskItem, TaskList } from "@tiptap/extension-list";
|
|
|
8
8
|
import { Collaboration } from "@tiptap/extension-collaboration";
|
|
9
9
|
import { CollaborationCaret } from "@tiptap/extension-collaboration-caret";
|
|
10
10
|
import { Suggestion } from "@tiptap/suggestion";
|
|
11
|
+
import { Blockquote } from "@tiptap/extension-blockquote";
|
|
11
12
|
import { TableKit } from "@tiptap/extension-table";
|
|
12
13
|
//#region src/upload.ts
|
|
13
14
|
/**
|
|
@@ -293,28 +294,28 @@ const defaultAiSlashActions = [
|
|
|
293
294
|
id: "continue-writing",
|
|
294
295
|
title: "Continue writing",
|
|
295
296
|
description: "AI extends the text above the cursor",
|
|
296
|
-
icon: "sparkles",
|
|
297
|
+
icon: "pencil-sparkles",
|
|
297
298
|
prompt: "Continue writing the document naturally, matching its tone and style. Write only the continuation, with no preamble."
|
|
298
299
|
},
|
|
299
300
|
{
|
|
300
301
|
id: "summarize",
|
|
301
302
|
title: "Summarize",
|
|
302
303
|
description: "AI summarizes the text above the cursor",
|
|
303
|
-
icon: "sparkles",
|
|
304
|
+
icon: "broom-sparkles",
|
|
304
305
|
prompt: "Summarize the following text in a few concise sentences."
|
|
305
306
|
},
|
|
306
307
|
{
|
|
307
308
|
id: "brainstorm-ideas",
|
|
308
309
|
title: "Brainstorm ideas",
|
|
309
310
|
description: "AI lists ideas related to the text above the cursor",
|
|
310
|
-
icon: "
|
|
311
|
+
icon: "brain",
|
|
311
312
|
prompt: "Brainstorm a short bullet list of ideas related to the following text."
|
|
312
313
|
},
|
|
313
314
|
{
|
|
314
315
|
id: "fix-spelling-grammar",
|
|
315
316
|
title: "Fix spelling & grammar",
|
|
316
317
|
description: "AI rewrites the text above the cursor, correcting mistakes",
|
|
317
|
-
icon: "
|
|
318
|
+
icon: "spell-check",
|
|
318
319
|
prompt: "Rewrite the following text, correcting spelling and grammar mistakes only, and preserve its meaning and tone."
|
|
319
320
|
}
|
|
320
321
|
];
|
|
@@ -1904,6 +1905,120 @@ function mention(options) {
|
|
|
1904
1905
|
return Mention.configure(options);
|
|
1905
1906
|
}
|
|
1906
1907
|
//#endregion
|
|
1908
|
+
//#region src/placeholder.ts
|
|
1909
|
+
const defaultPlaceholderText = {
|
|
1910
|
+
paragraph: "Press '/' for commands…",
|
|
1911
|
+
heading1: "Heading 1",
|
|
1912
|
+
heading2: "Heading 2",
|
|
1913
|
+
heading3: "Heading 3",
|
|
1914
|
+
listItem: "List",
|
|
1915
|
+
taskItem: "To-do",
|
|
1916
|
+
blockquote: "Quote",
|
|
1917
|
+
callout: "Callout",
|
|
1918
|
+
details: "Toggle",
|
|
1919
|
+
toggleHeading1: "Toggle heading 1",
|
|
1920
|
+
toggleHeading2: "Toggle heading 2",
|
|
1921
|
+
toggleHeading3: "Toggle heading 3"
|
|
1922
|
+
};
|
|
1923
|
+
const PARENT_KEYS = {
|
|
1924
|
+
listItem: "listItem",
|
|
1925
|
+
taskItem: "taskItem",
|
|
1926
|
+
blockquote: "blockquote",
|
|
1927
|
+
callout: "callout",
|
|
1928
|
+
detailsContent: "details"
|
|
1929
|
+
};
|
|
1930
|
+
/**
|
|
1931
|
+
* Maps an empty block to its placeholder slot, or `null` when it should stay
|
|
1932
|
+
* blank. Code blocks are excluded: their content is literal, and a hint would
|
|
1933
|
+
* read as source.
|
|
1934
|
+
*/
|
|
1935
|
+
function placeholderKeyFor(node, parent) {
|
|
1936
|
+
const name = node.type.name;
|
|
1937
|
+
if (name === "heading") {
|
|
1938
|
+
const { level } = node.attrs;
|
|
1939
|
+
return level === 1 || level === 2 || level === 3 ? `heading${level}` : null;
|
|
1940
|
+
}
|
|
1941
|
+
if (name === "detailsSummary") {
|
|
1942
|
+
const level = parent?.attrs.level;
|
|
1943
|
+
return level === 1 || level === 2 || level === 3 ? `toggleHeading${level}` : "details";
|
|
1944
|
+
}
|
|
1945
|
+
if (name !== "paragraph") return null;
|
|
1946
|
+
return parent ? PARENT_KEYS[parent.type.name] ?? "paragraph" : "paragraph";
|
|
1947
|
+
}
|
|
1948
|
+
const placeholderPluginKey = new PluginKey("placeholder");
|
|
1949
|
+
/**
|
|
1950
|
+
* Empty-block hints, Notion style: only the block holding the caret shows one.
|
|
1951
|
+
*
|
|
1952
|
+
* Renders `data-placeholder` and no class names — the UI layer styles
|
|
1953
|
+
* `[data-placeholder]::before`, matching how every other core node is styled.
|
|
1954
|
+
*
|
|
1955
|
+
* The decoration is derived from the state it is drawn against rather than
|
|
1956
|
+
* from `editor.state`: during a transaction those are different documents, and
|
|
1957
|
+
* resolving a parent in the stale one mislabels every nested block.
|
|
1958
|
+
*/
|
|
1959
|
+
const Placeholder = Extension.create({
|
|
1960
|
+
name: "placeholder",
|
|
1961
|
+
addOptions() {
|
|
1962
|
+
return {};
|
|
1963
|
+
},
|
|
1964
|
+
addProseMirrorPlugins() {
|
|
1965
|
+
const { editor } = this;
|
|
1966
|
+
const text = {
|
|
1967
|
+
...defaultPlaceholderText,
|
|
1968
|
+
...this.options.text
|
|
1969
|
+
};
|
|
1970
|
+
const { resolve } = this.options;
|
|
1971
|
+
return [new Plugin({
|
|
1972
|
+
key: placeholderPluginKey,
|
|
1973
|
+
props: { decorations: (state) => {
|
|
1974
|
+
if (!editor.isEditable) return null;
|
|
1975
|
+
const { doc, selection } = state;
|
|
1976
|
+
const $anchor = doc.resolve(selection.anchor);
|
|
1977
|
+
const node = $anchor.parent;
|
|
1978
|
+
if (!node.type.isTextblock || node.content.size > 0) return null;
|
|
1979
|
+
const parent = $anchor.depth > 0 ? $anchor.node($anchor.depth - 1) : null;
|
|
1980
|
+
const pos = $anchor.before($anchor.depth);
|
|
1981
|
+
const context = {
|
|
1982
|
+
editor,
|
|
1983
|
+
node,
|
|
1984
|
+
parent,
|
|
1985
|
+
pos
|
|
1986
|
+
};
|
|
1987
|
+
const key = placeholderKeyFor(node, parent);
|
|
1988
|
+
const value = resolve ? resolve(context) : key && text[key];
|
|
1989
|
+
if (!value) return null;
|
|
1990
|
+
return DecorationSet.create(doc, [Decoration.node(pos, pos + node.nodeSize, { "data-placeholder": value })]);
|
|
1991
|
+
} }
|
|
1992
|
+
})];
|
|
1993
|
+
}
|
|
1994
|
+
});
|
|
1995
|
+
/** Configures empty-block placeholders. */
|
|
1996
|
+
function placeholder(options = {}) {
|
|
1997
|
+
return Placeholder.configure(options);
|
|
1998
|
+
}
|
|
1999
|
+
//#endregion
|
|
2000
|
+
//#region src/quote.ts
|
|
2001
|
+
/** `"` + space at the start of a block, Notion style. */
|
|
2002
|
+
const quoteInputRegex = /^\s*"\s$/;
|
|
2003
|
+
/**
|
|
2004
|
+
* Blockquote with its markdown shorthand moved from `>` to `"`. The node name
|
|
2005
|
+
* stays `blockquote`: only the input rule changes, so stored documents,
|
|
2006
|
+
* clipboard HTML, and `Mod+Shift+B` are untouched.
|
|
2007
|
+
*
|
|
2008
|
+
* `>` belongs to the toggle (see `toggle.ts`), which is what Notion users
|
|
2009
|
+
* reach for it expecting.
|
|
2010
|
+
*/
|
|
2011
|
+
const Quote = Blockquote.extend({ addInputRules() {
|
|
2012
|
+
return [wrappingInputRule({
|
|
2013
|
+
find: quoteInputRegex,
|
|
2014
|
+
type: this.type
|
|
2015
|
+
})];
|
|
2016
|
+
} });
|
|
2017
|
+
/** Configures the quote (blockquote) node. */
|
|
2018
|
+
function quote(options = {}) {
|
|
2019
|
+
return Quote.configure(options);
|
|
2020
|
+
}
|
|
2021
|
+
//#endregion
|
|
1907
2022
|
//#region src/slash-items.ts
|
|
1908
2023
|
const TITLE_PREFIX = 100;
|
|
1909
2024
|
const TITLE_WORD_PREFIX = 80;
|
|
@@ -1933,6 +2048,7 @@ function filterSlashItems(items, query, editor) {
|
|
|
1933
2048
|
})).filter((entry) => entry.score > 0).sort((a, b) => b.score - a.score).map((entry) => entry.item);
|
|
1934
2049
|
}
|
|
1935
2050
|
const BASIC = "Basic blocks";
|
|
2051
|
+
const ADVANCED = "Advanced blocks";
|
|
1936
2052
|
const MEDIA = "Media";
|
|
1937
2053
|
const STRUCTURE = "Structure";
|
|
1938
2054
|
function hasNode(editor, name) {
|
|
@@ -1959,6 +2075,7 @@ const defaultSlashItems = [
|
|
|
1959
2075
|
description: "Large section title",
|
|
1960
2076
|
aliases: ["h1", "title"],
|
|
1961
2077
|
keywords: ["#"],
|
|
2078
|
+
shortcut: "#",
|
|
1962
2079
|
icon: "heading-1",
|
|
1963
2080
|
when: (editor) => hasNode(editor, "heading"),
|
|
1964
2081
|
run: ({ editor, range }) => {
|
|
@@ -1972,6 +2089,7 @@ const defaultSlashItems = [
|
|
|
1972
2089
|
description: "Medium section title",
|
|
1973
2090
|
aliases: ["h2", "subtitle"],
|
|
1974
2091
|
keywords: ["##"],
|
|
2092
|
+
shortcut: "##",
|
|
1975
2093
|
icon: "heading-2",
|
|
1976
2094
|
when: (editor) => hasNode(editor, "heading"),
|
|
1977
2095
|
run: ({ editor, range }) => {
|
|
@@ -1985,6 +2103,7 @@ const defaultSlashItems = [
|
|
|
1985
2103
|
description: "Small section title",
|
|
1986
2104
|
aliases: ["h3"],
|
|
1987
2105
|
keywords: ["###"],
|
|
2106
|
+
shortcut: "###",
|
|
1988
2107
|
icon: "heading-3",
|
|
1989
2108
|
when: (editor) => hasNode(editor, "heading"),
|
|
1990
2109
|
run: ({ editor, range }) => {
|
|
@@ -1998,6 +2117,7 @@ const defaultSlashItems = [
|
|
|
1998
2117
|
description: "Unordered list",
|
|
1999
2118
|
aliases: ["ul", "bullet"],
|
|
2000
2119
|
keywords: ["-", "*"],
|
|
2120
|
+
shortcut: "-",
|
|
2001
2121
|
icon: "list",
|
|
2002
2122
|
when: (editor) => hasNode(editor, "bulletList"),
|
|
2003
2123
|
run: ({ editor, range }) => {
|
|
@@ -2011,6 +2131,7 @@ const defaultSlashItems = [
|
|
|
2011
2131
|
description: "Ordered list",
|
|
2012
2132
|
aliases: ["ol", "numbered"],
|
|
2013
2133
|
keywords: ["1."],
|
|
2134
|
+
shortcut: "1.",
|
|
2014
2135
|
icon: "list-ordered",
|
|
2015
2136
|
when: (editor) => hasNode(editor, "orderedList"),
|
|
2016
2137
|
run: ({ editor, range }) => {
|
|
@@ -2028,6 +2149,7 @@ const defaultSlashItems = [
|
|
|
2028
2149
|
"checkbox"
|
|
2029
2150
|
],
|
|
2030
2151
|
keywords: ["[]", "[ ]"],
|
|
2152
|
+
shortcut: "[]",
|
|
2031
2153
|
icon: "list-checks",
|
|
2032
2154
|
when: (editor) => hasNode(editor, "taskList"),
|
|
2033
2155
|
run: ({ editor, range }) => {
|
|
@@ -2040,7 +2162,8 @@ const defaultSlashItems = [
|
|
|
2040
2162
|
group: BASIC,
|
|
2041
2163
|
description: "Capture a quotation",
|
|
2042
2164
|
aliases: ["quote", "citation"],
|
|
2043
|
-
keywords: ["
|
|
2165
|
+
keywords: ["\""],
|
|
2166
|
+
shortcut: "\"",
|
|
2044
2167
|
icon: "quote",
|
|
2045
2168
|
when: (editor) => hasNode(editor, "blockquote"),
|
|
2046
2169
|
run: ({ editor, range }) => {
|
|
@@ -2075,6 +2198,7 @@ const defaultSlashItems = [
|
|
|
2075
2198
|
"dropdown"
|
|
2076
2199
|
],
|
|
2077
2200
|
keywords: ["toggle"],
|
|
2201
|
+
shortcut: ">",
|
|
2078
2202
|
icon: "chevron-right",
|
|
2079
2203
|
when: (editor) => hasNode(editor, "details"),
|
|
2080
2204
|
run: ({ editor, range }) => {
|
|
@@ -2088,6 +2212,7 @@ const defaultSlashItems = [
|
|
|
2088
2212
|
description: "Monospaced code",
|
|
2089
2213
|
aliases: ["code", "snippet"],
|
|
2090
2214
|
keywords: ["```"],
|
|
2215
|
+
shortcut: "```",
|
|
2091
2216
|
icon: "code",
|
|
2092
2217
|
when: (editor) => hasNode(editor, "codeBlock"),
|
|
2093
2218
|
run: ({ editor, range }) => {
|
|
@@ -2105,12 +2230,55 @@ const defaultSlashItems = [
|
|
|
2105
2230
|
"rule"
|
|
2106
2231
|
],
|
|
2107
2232
|
keywords: ["---"],
|
|
2233
|
+
shortcut: "---",
|
|
2108
2234
|
icon: "minus",
|
|
2109
2235
|
when: (editor) => hasNode(editor, "horizontalRule"),
|
|
2110
2236
|
run: ({ editor, range }) => {
|
|
2111
2237
|
editor.chain().focus().deleteRange(range).setHorizontalRule().run();
|
|
2112
2238
|
}
|
|
2113
2239
|
},
|
|
2240
|
+
{
|
|
2241
|
+
id: "toggle-heading-1",
|
|
2242
|
+
title: "Toggle heading 1",
|
|
2243
|
+
group: ADVANCED,
|
|
2244
|
+
description: "Collapsible large title",
|
|
2245
|
+
aliases: ["th1", "toggleheading1"],
|
|
2246
|
+
keywords: ["collapsible", "details"],
|
|
2247
|
+
shortcut: "# >",
|
|
2248
|
+
icon: "heading-1",
|
|
2249
|
+
when: (editor) => hasNode(editor, "details"),
|
|
2250
|
+
run: ({ editor, range }) => {
|
|
2251
|
+
editor.chain().focus().deleteRange(range).setToggle(1).run();
|
|
2252
|
+
}
|
|
2253
|
+
},
|
|
2254
|
+
{
|
|
2255
|
+
id: "toggle-heading-2",
|
|
2256
|
+
title: "Toggle heading 2",
|
|
2257
|
+
group: ADVANCED,
|
|
2258
|
+
description: "Collapsible medium title",
|
|
2259
|
+
aliases: ["th2", "toggleheading2"],
|
|
2260
|
+
keywords: ["collapsible", "details"],
|
|
2261
|
+
shortcut: "## >",
|
|
2262
|
+
icon: "heading-2",
|
|
2263
|
+
when: (editor) => hasNode(editor, "details"),
|
|
2264
|
+
run: ({ editor, range }) => {
|
|
2265
|
+
editor.chain().focus().deleteRange(range).setToggle(2).run();
|
|
2266
|
+
}
|
|
2267
|
+
},
|
|
2268
|
+
{
|
|
2269
|
+
id: "toggle-heading-3",
|
|
2270
|
+
title: "Toggle heading 3",
|
|
2271
|
+
group: ADVANCED,
|
|
2272
|
+
description: "Collapsible small title",
|
|
2273
|
+
aliases: ["th3", "toggleheading3"],
|
|
2274
|
+
keywords: ["collapsible", "details"],
|
|
2275
|
+
shortcut: "### >",
|
|
2276
|
+
icon: "heading-3",
|
|
2277
|
+
when: (editor) => hasNode(editor, "details"),
|
|
2278
|
+
run: ({ editor, range }) => {
|
|
2279
|
+
editor.chain().focus().deleteRange(range).setToggle(3).run();
|
|
2280
|
+
}
|
|
2281
|
+
},
|
|
2114
2282
|
{
|
|
2115
2283
|
id: "image",
|
|
2116
2284
|
title: "Image",
|
|
@@ -2222,6 +2390,7 @@ const SlashCommand = Extension.create({
|
|
|
2222
2390
|
addOptions() {
|
|
2223
2391
|
return {
|
|
2224
2392
|
char: "/",
|
|
2393
|
+
hint: "Type to search",
|
|
2225
2394
|
items: defaultSlashItems
|
|
2226
2395
|
};
|
|
2227
2396
|
},
|
|
@@ -2283,6 +2452,7 @@ const SlashCommand = Extension.create({
|
|
|
2283
2452
|
return [Suggestion({
|
|
2284
2453
|
editor,
|
|
2285
2454
|
char: this.options.char,
|
|
2455
|
+
decorationContent: this.options.hint,
|
|
2286
2456
|
pluginKey: slashCommandPluginKey,
|
|
2287
2457
|
allowSpaces: false,
|
|
2288
2458
|
allow: ({ state, range }) => !state.doc.resolve(range.from).parent.type.spec.code,
|
|
@@ -2348,6 +2518,182 @@ function table(options = {}) {
|
|
|
2348
2518
|
});
|
|
2349
2519
|
}
|
|
2350
2520
|
//#endregion
|
|
2521
|
+
//#region src/toggle.ts
|
|
2522
|
+
/** `>` + space: the toggle shorthand. */
|
|
2523
|
+
const toggleInputRegex = /^>\s$/;
|
|
2524
|
+
/** `#`…`###` + space inside a toggle title: the toggle-heading shorthand. */
|
|
2525
|
+
const toggleHeadingInputRegex = /^(#{1,3})\s$/;
|
|
2526
|
+
function asToggleLevel(value) {
|
|
2527
|
+
return value === 1 || value === 2 || value === 3 ? value : 0;
|
|
2528
|
+
}
|
|
2529
|
+
function canReplaceBlockWithToggle($pos, detailsType) {
|
|
2530
|
+
if ($pos.depth === 0 || !$pos.parent.isTextblock) return false;
|
|
2531
|
+
const index = $pos.index($pos.depth - 1);
|
|
2532
|
+
return $pos.node($pos.depth - 1).canReplaceWith(index, index + 1, detailsType);
|
|
2533
|
+
}
|
|
2534
|
+
/**
|
|
2535
|
+
* Replaces the textblock holding `pos` with a toggle: that block's inline
|
|
2536
|
+
* content becomes the title, the body starts as one empty paragraph, and the
|
|
2537
|
+
* caret lands at the end of the title.
|
|
2538
|
+
*
|
|
2539
|
+
* Titles are `text*`, so inline nodes a summary cannot hold (a mention chip)
|
|
2540
|
+
* degrade to their text rather than failing the whole conversion.
|
|
2541
|
+
*/
|
|
2542
|
+
function replaceBlockWithToggle(tr, pos, level) {
|
|
2543
|
+
const $pos = tr.doc.resolve(pos);
|
|
2544
|
+
const { schema } = $pos.parent.type;
|
|
2545
|
+
const detailsType = schema.nodes.details;
|
|
2546
|
+
const summaryType = schema.nodes.detailsSummary;
|
|
2547
|
+
const contentType = schema.nodes.detailsContent;
|
|
2548
|
+
const paragraphType = schema.nodes.paragraph;
|
|
2549
|
+
if (!detailsType || !summaryType || !contentType || !paragraphType) return false;
|
|
2550
|
+
if (!canReplaceBlockWithToggle($pos, detailsType)) return false;
|
|
2551
|
+
const inline = $pos.parent.content;
|
|
2552
|
+
const text = inline.textBetween(0, inline.size);
|
|
2553
|
+
const title = summaryType.contentMatch.matchFragment(inline)?.validEnd ? inline : text ? Fragment.from(schema.text(text)) : Fragment.empty;
|
|
2554
|
+
const summary = summaryType.create(null, title);
|
|
2555
|
+
const body = contentType.create(null, paragraphType.create());
|
|
2556
|
+
const from = $pos.before($pos.depth);
|
|
2557
|
+
tr.replaceWith(from, $pos.after($pos.depth), detailsType.create({ level }, [summary, body]));
|
|
2558
|
+
tr.setSelection(TextSelection.create(tr.doc, from + 2 + summary.content.size));
|
|
2559
|
+
return true;
|
|
2560
|
+
}
|
|
2561
|
+
/**
|
|
2562
|
+
* Tiptap's `Details` with a `level` attribute, the `>` shorthand, and the
|
|
2563
|
+
* toggle-heading shorthands.
|
|
2564
|
+
*
|
|
2565
|
+
* `level` lives on the container rather than the title because the node view
|
|
2566
|
+
* renders the disclosure button as a *sibling* of the summary: with
|
|
2567
|
+
* `data-level` on the wrapper, one selector sizes both, and the marker stays
|
|
2568
|
+
* centred on a title of any size.
|
|
2569
|
+
*/
|
|
2570
|
+
const Toggle = Details.extend({
|
|
2571
|
+
addAttributes() {
|
|
2572
|
+
return {
|
|
2573
|
+
...this.parent?.(),
|
|
2574
|
+
level: {
|
|
2575
|
+
default: 0,
|
|
2576
|
+
parseHTML: (element) => asToggleLevel(Number(element.getAttribute("data-level"))),
|
|
2577
|
+
renderHTML: ({ level }) => level ? { "data-level": String(level) } : {}
|
|
2578
|
+
}
|
|
2579
|
+
};
|
|
2580
|
+
},
|
|
2581
|
+
renderHTML({ HTMLAttributes }) {
|
|
2582
|
+
return [
|
|
2583
|
+
"details",
|
|
2584
|
+
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
|
|
2585
|
+
0
|
|
2586
|
+
];
|
|
2587
|
+
},
|
|
2588
|
+
addNodeView() {
|
|
2589
|
+
const parent = this.parent?.();
|
|
2590
|
+
if (!parent) return null;
|
|
2591
|
+
return (props) => {
|
|
2592
|
+
const view = parent(props);
|
|
2593
|
+
const dom = view.dom;
|
|
2594
|
+
const applyLevel = (node) => {
|
|
2595
|
+
const level = asToggleLevel(node.attrs.level);
|
|
2596
|
+
if (level) dom.setAttribute("data-level", String(level));
|
|
2597
|
+
else dom.removeAttribute("data-level");
|
|
2598
|
+
};
|
|
2599
|
+
applyLevel(props.node);
|
|
2600
|
+
if (this.options.persist) dom.addEventListener("click", (event) => {
|
|
2601
|
+
const { editor, getPos } = props;
|
|
2602
|
+
const target = event.target;
|
|
2603
|
+
if (!editor.isEditable || target?.closest("button")?.parentElement !== dom) return;
|
|
2604
|
+
event.stopPropagation();
|
|
2605
|
+
const pos = getPos();
|
|
2606
|
+
const node = typeof pos === "number" ? editor.state.doc.nodeAt(pos) : null;
|
|
2607
|
+
if (!node || node.type !== this.type) return;
|
|
2608
|
+
const { from, to } = editor.state.selection;
|
|
2609
|
+
editor.chain().command(({ tr }) => {
|
|
2610
|
+
tr.setNodeMarkup(pos, void 0, {
|
|
2611
|
+
...node.attrs,
|
|
2612
|
+
open: !node.attrs.open
|
|
2613
|
+
});
|
|
2614
|
+
return true;
|
|
2615
|
+
}).setTextSelection({
|
|
2616
|
+
from,
|
|
2617
|
+
to
|
|
2618
|
+
}).focus(void 0, { scrollIntoView: false }).run();
|
|
2619
|
+
}, true);
|
|
2620
|
+
return {
|
|
2621
|
+
...view,
|
|
2622
|
+
update: (node, decorations, innerDecorations) => {
|
|
2623
|
+
const updated = view.update?.(node, decorations, innerDecorations) ?? true;
|
|
2624
|
+
if (updated) applyLevel(node);
|
|
2625
|
+
return updated;
|
|
2626
|
+
}
|
|
2627
|
+
};
|
|
2628
|
+
};
|
|
2629
|
+
},
|
|
2630
|
+
addCommands() {
|
|
2631
|
+
return {
|
|
2632
|
+
...this.parent?.(),
|
|
2633
|
+
setToggle: (level = 0) => ({ state, tr, dispatch }) => {
|
|
2634
|
+
const detailsType = state.schema.nodes.details;
|
|
2635
|
+
if (!detailsType) return false;
|
|
2636
|
+
const details = findParentNode((node) => node.type === detailsType)(state.selection);
|
|
2637
|
+
if (details) {
|
|
2638
|
+
if (dispatch) tr.setNodeMarkup(details.pos, void 0, {
|
|
2639
|
+
...details.node.attrs,
|
|
2640
|
+
level
|
|
2641
|
+
});
|
|
2642
|
+
return true;
|
|
2643
|
+
}
|
|
2644
|
+
if (!canReplaceBlockWithToggle(state.selection.$from, detailsType)) return false;
|
|
2645
|
+
return dispatch ? replaceBlockWithToggle(tr, state.selection.from, level) : true;
|
|
2646
|
+
},
|
|
2647
|
+
setToggleLevel: (level) => ({ state, tr, dispatch }) => {
|
|
2648
|
+
const detailsType = state.schema.nodes.details;
|
|
2649
|
+
const details = detailsType ? findParentNode((node) => node.type === detailsType)(state.selection) : void 0;
|
|
2650
|
+
if (!details) return false;
|
|
2651
|
+
if (dispatch) tr.setNodeMarkup(details.pos, void 0, {
|
|
2652
|
+
...details.node.attrs,
|
|
2653
|
+
level
|
|
2654
|
+
});
|
|
2655
|
+
return true;
|
|
2656
|
+
}
|
|
2657
|
+
};
|
|
2658
|
+
},
|
|
2659
|
+
addInputRules() {
|
|
2660
|
+
return [
|
|
2661
|
+
...this.parent?.() ?? [],
|
|
2662
|
+
new InputRule({
|
|
2663
|
+
find: toggleInputRegex,
|
|
2664
|
+
handler: ({ state, range }) => {
|
|
2665
|
+
const { tr } = state;
|
|
2666
|
+
const block = tr.doc.resolve(range.from).parent;
|
|
2667
|
+
const name = block.type.name;
|
|
2668
|
+
if (name !== "paragraph" && name !== "heading") return null;
|
|
2669
|
+
const level = name === "heading" ? asToggleLevel(block.attrs.level) : 0;
|
|
2670
|
+
tr.delete(range.from, range.to);
|
|
2671
|
+
return replaceBlockWithToggle(tr, range.from, level) ? void 0 : null;
|
|
2672
|
+
}
|
|
2673
|
+
}),
|
|
2674
|
+
new InputRule({
|
|
2675
|
+
find: toggleHeadingInputRegex,
|
|
2676
|
+
handler: ({ state, range, match }) => {
|
|
2677
|
+
const { tr } = state;
|
|
2678
|
+
const $from = tr.doc.resolve(range.from);
|
|
2679
|
+
if ($from.parent.type.name !== "detailsSummary") return null;
|
|
2680
|
+
const details = $from.node($from.depth - 1);
|
|
2681
|
+
const level = asToggleLevel(match[1]?.length);
|
|
2682
|
+
tr.delete(range.from, range.to);
|
|
2683
|
+
tr.setNodeMarkup($from.before($from.depth - 1), void 0, {
|
|
2684
|
+
...details.attrs,
|
|
2685
|
+
level
|
|
2686
|
+
});
|
|
2687
|
+
}
|
|
2688
|
+
})
|
|
2689
|
+
];
|
|
2690
|
+
}
|
|
2691
|
+
});
|
|
2692
|
+
/** Configures the toggle (details) node. */
|
|
2693
|
+
function toggle(options = {}) {
|
|
2694
|
+
return Toggle.configure(options);
|
|
2695
|
+
}
|
|
2696
|
+
//#endregion
|
|
2351
2697
|
//#region src/video.ts
|
|
2352
2698
|
function initialAttrs(id, options) {
|
|
2353
2699
|
if (options && "file" in options) return {
|
|
@@ -2467,7 +2813,7 @@ const DEFAULT_HEADING_LEVELS = [
|
|
|
2467
2813
|
* the `data-*` attributes rendered by slash-editor nodes.
|
|
2468
2814
|
*/
|
|
2469
2815
|
function createBlockKit(options = {}) {
|
|
2470
|
-
const { headingLevels = DEFAULT_HEADING_LEVELS, history = true, slash, blockId: blockIdOptions, drag, bubbleToolbar: bubbleToolbarOptions, image: imageOptions, file: fileOptions, video: videoOptions, embed: embedOptions, table: tableOptions, columns: columnsOptions, linkEditor: linkEditorOptions, mention: mentionOptions, ai: aiOptions, collaboration: collaborationOptions, comment: commentOptions, extend = [] } = options;
|
|
2816
|
+
const { headingLevels = DEFAULT_HEADING_LEVELS, history = true, slash, placeholder: placeholderOptions, blockId: blockIdOptions, drag, bubbleToolbar: bubbleToolbarOptions, image: imageOptions, file: fileOptions, video: videoOptions, embed: embedOptions, table: tableOptions, columns: columnsOptions, linkEditor: linkEditorOptions, mention: mentionOptions, ai: aiOptions, collaboration: collaborationOptions, comment: commentOptions, toggle: toggleOptions, extend = [] } = options;
|
|
2471
2817
|
const resolvedAi = aiOptions ? {
|
|
2472
2818
|
actions: defaultAiSlashActions,
|
|
2473
2819
|
node: true,
|
|
@@ -2481,12 +2827,17 @@ function createBlockKit(options = {}) {
|
|
|
2481
2827
|
link: {
|
|
2482
2828
|
openOnClick: false,
|
|
2483
2829
|
enableClickSelection: true
|
|
2484
|
-
}
|
|
2830
|
+
},
|
|
2831
|
+
blockquote: false
|
|
2485
2832
|
}),
|
|
2833
|
+
quote(),
|
|
2486
2834
|
TaskList,
|
|
2487
2835
|
TaskItem.configure({ nested: true }),
|
|
2488
2836
|
Callout,
|
|
2489
|
-
|
|
2837
|
+
toggle({
|
|
2838
|
+
persist: true,
|
|
2839
|
+
...toggleOptions
|
|
2840
|
+
}),
|
|
2490
2841
|
DetailsSummary,
|
|
2491
2842
|
DetailsContent,
|
|
2492
2843
|
...imageOptions === false ? [] : [image(imageOptions)],
|
|
@@ -2501,6 +2852,7 @@ function createBlockKit(options = {}) {
|
|
|
2501
2852
|
...slash,
|
|
2502
2853
|
items: slash?.items ?? (() => [...defaultSlashItems, ...resolvedAi ? createAiSlashItems(resolvedAi) : []])()
|
|
2503
2854
|
})],
|
|
2855
|
+
...placeholderOptions === false ? [] : [placeholder(placeholderOptions)],
|
|
2504
2856
|
...blockIdOptions === false ? [] : [blockId(blockIdOptions)],
|
|
2505
2857
|
...drag === false ? [] : [blockDrag(drag)],
|
|
2506
2858
|
...bubbleToolbarOptions === false ? [] : [bubbleToolbar(bubbleToolbarOptions)],
|
|
@@ -2511,4 +2863,4 @@ function createBlockKit(options = {}) {
|
|
|
2511
2863
|
];
|
|
2512
2864
|
}
|
|
2513
2865
|
//#endregion
|
|
2514
|
-
export { AiBlock, BLOCK_ID_REMOTE_META, BlockDrag, BlockId, BubbleToolbar, Callout, Column, Columns, Comment, Embed, File, Image, LinkEditor, Mention, PendingAiRegistry, PendingUploadRegistry, SlashCommand, TableKit, Video, 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 };
|
|
2866
|
+
export { AiBlock, BLOCK_ID_REMOTE_META, BlockDrag, BlockId, BubbleToolbar, Callout, Column, Columns, Comment, Embed, File, Image, LinkEditor, Mention, PendingAiRegistry, PendingUploadRegistry, Placeholder, Quote, SlashCommand, TableKit, Toggle, Video, activeThreadIds, aiBlock, blockDrag, blockDragPluginKey, blockId, blockIdPluginKey, bubbleToolbar, callout, canAppendChild, canOpenLinkEditor, collaboration, column, columns, comment, createAiSlashItems, createBlockKit, defaultAiSlashActions, defaultBubbleToolbarItems, defaultPlaceholderText, defaultSlashItems, embed, file, filterBubbleToolbarItems, filterSlashItems, findNodeById, image, linkEditor, mention, mentionPluginKey, placeholder, placeholderKeyFor, placeholderPluginKey, quote, quoteInputRegex, resolveDropTarget, retryUpload, runUpload, slashCommand, slashCommandPluginKey, table, toggle, toggleHeadingInputRegex, toggleInputRegex, video };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slash-editor/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "Headless block-editor core: ProseMirror/Tiptap extensions, schema, commands.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"dev": "vp pack --watch"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
+
"@tiptap/extension-blockquote": "^3.31.3",
|
|
27
28
|
"@tiptap/extension-collaboration": "^3.31.3",
|
|
28
29
|
"@tiptap/extension-collaboration-caret": "^3.31.3",
|
|
29
30
|
"@tiptap/extension-details": "^3.31.3",
|