Files
notesnook/packages/editor/src/index.ts

205 lines
6.3 KiB
TypeScript

import "./extensions";
import CharacterCount from "@tiptap/extension-character-count";
import Placeholder from "@tiptap/extension-placeholder";
import Underline from "@tiptap/extension-underline";
import StarterKit from "@tiptap/starter-kit";
import { useEffect, useMemo } from "react";
import Toolbar from "./toolbar";
import TextAlign from "@tiptap/extension-text-align";
import Subscript from "@tiptap/extension-subscript";
import Superscript from "@tiptap/extension-superscript";
import FontSize from "./extensions/font-size";
import TextDirection from "./extensions/text-direction";
import TextStyle from "@tiptap/extension-text-style";
import FontFamily from "@tiptap/extension-font-family";
import BulletList from "./extensions/bullet-list";
import OrderedList from "./extensions/ordered-list";
import Color from "@tiptap/extension-color";
import TableRow from "@tiptap/extension-table-row";
import TableCell from "./extensions/table-cell";
import TableHeader from "@tiptap/extension-table-header";
import { ImageNode } from "./extensions/image";
import { Theme } from "@notesnook/theme";
import { AttachmentNode, AttachmentOptions } from "./extensions/attachment";
import { TaskListNode } from "./extensions/task-list";
import { TaskItemNode } from "./extensions/task-item";
import { SearchReplace } from "./extensions/search-replace";
import { EmbedNode } from "./extensions/embed";
import { CodeBlock } from "./extensions/code-block";
import { ListItem } from "./extensions/list-item";
import { Link } from "@tiptap/extension-link";
import { Codemark } from "./extensions/code-mark";
import { MathInline, MathBlock } from "./extensions/math";
import {
NodeViewSelectionNotifier,
usePortalProvider
} from "./extensions/react";
import { OutlineList } from "./extensions/outline-list";
import { OutlineListItem } from "./extensions/outline-list-item";
import { KeepInView } from "./extensions/keep-in-view";
import { SelectionPersist } from "./extensions/selection-persist";
import { Table } from "./extensions/table";
import { useToolbarStore } from "./toolbar/stores/toolbar-store";
import { useEditor } from "./hooks/use-editor";
import {
EditorOptions,
extensions as TiptapCoreExtensions
} from "@tiptap/core";
import { usePermissionHandler } from "./hooks/use-permission-handler";
import { Highlight } from "./extensions/highlight";
import { Paragraph } from "./extensions/paragraph";
import { ClipboardTextSerializer } from "./extensions/clipboard-text-serializer";
import { Code } from "@tiptap/extension-code";
import { DateTime } from "./extensions/date-time";
const CoreExtensions = Object.entries(TiptapCoreExtensions)
// we will implement our own customized clipboard serializer
.filter(([name]) => name !== "ClipboardTextSerializer")
.map(([, extension]) => extension);
type TiptapOptions = EditorOptions &
AttachmentOptions & {
theme: Theme;
isMobile?: boolean;
isKeyboardOpen?: boolean;
doubleSpacedLines?: boolean;
};
const useTiptap = (
options: Partial<TiptapOptions> = {},
deps: React.DependencyList = []
) => {
const {
theme,
doubleSpacedLines = true,
isMobile,
isKeyboardOpen,
onDownloadAttachment,
onOpenAttachmentPicker,
onBeforeCreate,
...restOptions
} = options;
const PortalProviderAPI = usePortalProvider();
const setIsMobile = useToolbarStore((store) => store.setIsMobile);
const setTheme = useToolbarStore((store) => store.setTheme);
const setIsKeyboardOpen = useToolbarStore((store) => store.setIsKeyboardOpen);
useEffect(() => {
setIsMobile(isMobile || false);
setTheme(theme);
setIsKeyboardOpen(isKeyboardOpen || false);
}, [isMobile, theme, isKeyboardOpen]);
const defaultOptions = useMemo<Partial<EditorOptions>>(
() => ({
enableCoreExtensions: false,
extensions: [
...CoreExtensions,
ClipboardTextSerializer,
NodeViewSelectionNotifier,
SearchReplace,
TextStyle,
Paragraph.configure({
doubleSpaced: doubleSpacedLines
}),
StarterKit.configure({
code: false,
codeBlock: false,
listItem: false,
orderedList: false,
bulletList: false,
paragraph: false,
hardBreak: false,
history: {
depth: 200,
newGroupDelay: 1000
},
dropcursor: {
class: "drop-cursor"
}
}),
CharacterCount,
Underline,
Subscript,
Superscript,
FontSize,
TextDirection,
FontFamily,
BulletList,
OrderedList,
TaskItemNode.configure({ nested: true }),
TaskListNode,
Link.configure({
openOnClick: !isMobile,
autolink: false
}).extend({
inclusive: true
}),
Table.configure({
resizable: true,
allowTableNodeSelection: true,
cellMinWidth: 50
}),
TableRow,
TableCell,
TableHeader,
Highlight,
CodeBlock,
Color,
TextAlign.configure({
types: ["heading", "paragraph"],
alignments: ["left", "right", "center", "justify"],
defaultAlignment: "left"
}),
Placeholder.configure({
placeholder: "Start writing your note..."
}),
ImageNode.configure({ allowBase64: true }),
EmbedNode,
AttachmentNode.configure({
onDownloadAttachment,
onOpenAttachmentPicker
}),
OutlineListItem,
OutlineList,
ListItem,
Code.extend({ excludes: "" }),
Codemark,
MathInline,
MathBlock,
KeepInView,
SelectionPersist,
DateTime
],
onBeforeCreate: ({ editor }) => {
editor.storage.portalProviderAPI = PortalProviderAPI;
if (onBeforeCreate) onBeforeCreate({ editor });
},
injectCSS: false
}),
[
onDownloadAttachment,
onOpenAttachmentPicker,
PortalProviderAPI,
onBeforeCreate
]
);
const editor = useEditor(
{
...defaultOptions,
...restOptions
},
deps
);
return editor;
};
export { useTiptap, Toolbar, usePermissionHandler };
export * from "./types";
export * from "./extensions/react";
export * from "./toolbar";
export { type AttachmentType, type Attachment } from "./extensions/attachment";