@tulip-systems/editor 0.11.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.
@@ -0,0 +1,8 @@
1
+ import "./lib/types.mjs";
2
+ import { FileHandler } from "./extensions/file-handler/extension.mjs";
3
+ import { Image } from "./extensions/image/extension.mjs";
4
+ import { createExtensionConfig, editorExtensionsConfigToExtensions, flattenEditorExtensionsConfig } from "./lib/extensions.mjs";
5
+ import { Editor, EditorContext, editorVariants } from "./components/editor.client.mjs";
6
+ import { EditorContent } from "./components/content.client.mjs";
7
+ import { EditorMenuBubble, EditorMenuFixed } from "./components/menu.client.mjs";
8
+ export { Editor, EditorContent, EditorContext, EditorMenuBubble, EditorMenuFixed, FileHandler, Image, createExtensionConfig, editorExtensionsConfigToExtensions, editorVariants, flattenEditorExtensionsConfig };
@@ -0,0 +1,4 @@
1
+ //#region src/components/content.client.d.ts
2
+ declare function EditorContent(): import("react").JSX.Element;
3
+ //#endregion
4
+ export { EditorContent };
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { EditorContext } from "./editor.client.mjs";
3
+ import { EditorContent } from "@tiptap/react";
4
+ import { TooltipProvider } from "@tulip-systems/ui/tooltip";
5
+ import { useContext } from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ //#region src/components/content.client.tsx
8
+ function EditorContent$1() {
9
+ const { editor } = useContext(EditorContext);
10
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(EditorContent, { editor }) });
11
+ }
12
+ //#endregion
13
+ export { EditorContent$1 as EditorContent };
@@ -0,0 +1,25 @@
1
+ import { EditorExtensionsConfig, EditorExtensionsConfigResult } from "../lib/extensions.mjs";
2
+ import { EditorJSONContent } from "../lib/types.mjs";
3
+ import { Content, Editor, EditorOptions } from "@tiptap/react";
4
+ import { PropsWithChildren } from "react";
5
+ import { VariantProps } from "class-variance-authority";
6
+ //#region src/components/editor.client.d.ts
7
+ type EditorContextValue = {
8
+ editor: Editor;
9
+ extensions: EditorExtensionsConfigResult;
10
+ };
11
+ declare const EditorContext: import("react").Context<EditorContextValue>;
12
+ declare const editorVariants: (props?: ({
13
+ variant?: "default" | "table" | "preview" | null | undefined;
14
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
15
+ type EditorProps = VariantProps<typeof editorVariants> & Pick<EditorOptions["editorProps"], "attributes"> & PropsWithChildren<{
16
+ value?: Content;
17
+ extensions?: Partial<EditorExtensionsConfig>;
18
+ onUpdate?: (value: EditorJSONContent) => void;
19
+ onBlur?: (value: EditorJSONContent) => void;
20
+ disabled?: boolean;
21
+ className?: string;
22
+ }>;
23
+ declare function Editor$1({ value, extensions, onUpdate, onBlur, disabled, variant, className, children, attributes }: EditorProps): import("react").JSX.Element | null;
24
+ //#endregion
25
+ export { Editor$1 as Editor, EditorContext, EditorProps, editorVariants };
@@ -0,0 +1,49 @@
1
+ "use client";
2
+ import { editorExtensionsConfigToExtensions, flattenEditorExtensionsConfig } from "../lib/extensions.mjs";
3
+ import { editorImageVariants, editorProseVariants } from "../lib/variants.mjs";
4
+ import { useEditor } from "@tiptap/react";
5
+ import { createContext } from "react";
6
+ import { cn } from "@tulip-systems/ui/cn";
7
+ import { cva } from "class-variance-authority";
8
+ import { jsx } from "react/jsx-runtime";
9
+ //#region src/components/editor.client.tsx
10
+ const EditorContext = createContext({});
11
+ const editorVariants = cva("", {
12
+ variants: { variant: {
13
+ default: "border-input rounded-lg border [&_.editor-content]:p-3 [&_.editor-content[contenteditable='false']]:pointer-events-none [&_.editor-content[contenteditable='false']]:cursor-not-allowed [&_.editor-content[contenteditable='false']]:opacity-50",
14
+ table: "[&_.editor-content[contenteditable='false']]:pointer-events-none [&_.editor-content[contenteditable='false']]:cursor-not-allowed [&_.editor-content[contenteditable='false']]:opacity-50",
15
+ preview: "bg-transparent [&_.editor-content]:p-0 [&_.editor-content]:min-h-0"
16
+ } },
17
+ defaultVariants: { variant: "default" }
18
+ });
19
+ function Editor$1({ value, extensions, onUpdate, onBlur, disabled, variant, className, children, attributes }) {
20
+ const editor = useEditor({
21
+ extensions: editorExtensionsConfigToExtensions(extensions),
22
+ content: value,
23
+ onUpdate: ({ editor }) => onUpdate?.(editor.getJSON()),
24
+ onBlur: ({ editor }) => onBlur?.(editor.getJSON()),
25
+ editable: !disabled,
26
+ injectCSS: false,
27
+ immediatelyRender: false,
28
+ editorProps: {
29
+ transformPastedHTML: (html) => html.replace(/<img.*?>/g, ""),
30
+ attributes: {
31
+ ...attributes,
32
+ class: cn("editor-content text-sm max-w-full focus:outline-none", editorProseVariants(), editorImageVariants(), className)
33
+ }
34
+ }
35
+ });
36
+ if (!editor) return null;
37
+ return /* @__PURE__ */ jsx(EditorContext.Provider, {
38
+ value: {
39
+ editor,
40
+ extensions: flattenEditorExtensionsConfig(extensions)
41
+ },
42
+ children: /* @__PURE__ */ jsx("div", {
43
+ className: editorVariants({ variant }),
44
+ children
45
+ })
46
+ });
47
+ }
48
+ //#endregion
49
+ export { Editor$1 as Editor, EditorContext, editorVariants };
@@ -0,0 +1,90 @@
1
+ import { EditorContext } from "./editor.client.mjs";
2
+ import { useContext } from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { Button } from "@tulip-systems/ui/button";
5
+ import { ChevronDown, Heading1Icon, Heading2Icon, Heading3Icon, Heading4Icon, Heading5Icon, ListIcon, ListOrderedIcon, TextIcon } from "lucide-react";
6
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@tulip-systems/ui/dropdown-menu";
7
+ //#region src/components/menu-nodes.client.tsx
8
+ const blocks = [
9
+ {
10
+ label: "Paragraaf",
11
+ icon: TextIcon,
12
+ selected: (editor) => editor.isActive("paragraph"),
13
+ handler: (editor) => editor.commands.setParagraph(),
14
+ hidden: (extensions) => !extensions.paragraph
15
+ },
16
+ {
17
+ label: "Titel 1",
18
+ icon: Heading1Icon,
19
+ selected: (editor) => editor.isActive("heading", { level: 1 }),
20
+ handler: (editor) => editor.commands.setHeading({ level: 1 }),
21
+ hidden: (extensions) => !extensions.heading
22
+ },
23
+ {
24
+ label: "Titel 2",
25
+ icon: Heading2Icon,
26
+ selected: (editor) => editor.isActive("heading", { level: 2 }),
27
+ handler: (editor) => editor.commands.setHeading({ level: 2 }),
28
+ hidden: (extensions) => !extensions.heading
29
+ },
30
+ {
31
+ label: "Titel 3",
32
+ icon: Heading3Icon,
33
+ selected: (editor) => editor.isActive("heading", { level: 3 }),
34
+ handler: (editor) => editor.commands.setHeading({ level: 3 }),
35
+ hidden: (extensions) => !extensions.heading
36
+ },
37
+ {
38
+ label: "Titel 4",
39
+ icon: Heading4Icon,
40
+ selected: (editor) => editor.isActive("heading", { level: 4 }),
41
+ handler: (editor) => editor.commands.setHeading({ level: 4 }),
42
+ hidden: (extensions) => !extensions.heading
43
+ },
44
+ {
45
+ label: "Titel 5",
46
+ icon: Heading5Icon,
47
+ selected: (editor) => editor.isActive("heading", { level: 5 }),
48
+ handler: (editor) => editor.commands.setHeading({ level: 5 }),
49
+ hidden: (extensions) => !extensions.heading
50
+ },
51
+ {
52
+ label: "Numbered List",
53
+ icon: ListOrderedIcon,
54
+ selected: (editor) => editor.isActive("orderedList"),
55
+ handler: (editor) => editor.commands.toggleOrderedList(),
56
+ hidden: (extensions) => !extensions.orderedList
57
+ },
58
+ {
59
+ label: "Bulleted List",
60
+ icon: ListIcon,
61
+ selected: (editor) => editor.isActive("bulletList"),
62
+ handler: (editor) => editor.commands.toggleBulletList(),
63
+ hidden: (extensions) => !extensions.bulletList
64
+ }
65
+ ];
66
+ function EditorMenuNodes() {
67
+ const { editor, extensions } = useContext(EditorContext);
68
+ const selectedBlock = blocks.find((block) => block.selected(editor));
69
+ const Icon = selectedBlock?.icon;
70
+ const filteredBlocks = blocks.filter((block) => !block.hidden(extensions));
71
+ if (filteredBlocks.length === 0) return null;
72
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
73
+ asChild: true,
74
+ children: /* @__PURE__ */ jsxs(Button, {
75
+ variant: "outline",
76
+ size: "sm",
77
+ className: "flex items-center gap-8 p-2",
78
+ children: [/* @__PURE__ */ jsxs("span", {
79
+ className: "flex items-center gap-2",
80
+ children: [Icon && /* @__PURE__ */ jsx(Icon, { className: "size-3.5" }), selectedBlock?.label ?? "Select a block"]
81
+ }), /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5" })]
82
+ })
83
+ }), /* @__PURE__ */ jsx(DropdownMenuContent, { children: filteredBlocks.map(({ label, icon: Icon, handler }) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
84
+ onClick: () => handler(editor),
85
+ className: "flex items-center gap-2",
86
+ children: [Icon && /* @__PURE__ */ jsx(Icon, { className: "size-3.5" }), label]
87
+ }, label)) })] });
88
+ }
89
+ //#endregion
90
+ export { EditorMenuNodes };
@@ -0,0 +1,7 @@
1
+ import { ComponentProps } from "react";
2
+ import { BubbleMenu } from "@tiptap/react/menus";
3
+ //#region src/components/menu.client.d.ts
4
+ declare function EditorMenuFixed(props: React.ComponentProps<"div">): import("react").JSX.Element;
5
+ declare function EditorMenuBubble(props: ComponentProps<typeof BubbleMenu>): import("react").JSX.Element;
6
+ //#endregion
7
+ export { EditorMenuBubble, EditorMenuFixed };
@@ -0,0 +1,154 @@
1
+ import { EditorContext } from "./editor.client.mjs";
2
+ import { EditorMenuNodes } from "./menu-nodes.client.mjs";
3
+ import { useContext } from "react";
4
+ import { cn } from "@tulip-systems/ui/cn";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { BubbleMenu } from "@tiptap/react/menus";
7
+ import { Button } from "@tulip-systems/ui/button";
8
+ import { ColorPicker } from "@tulip-systems/ui/color-picker";
9
+ import { Popover, PopoverContent, PopoverTrigger } from "@tulip-systems/ui/popover";
10
+ import { BaselineIcon, BoldIcon, EraserIcon, ItalicIcon, PaintBucketIcon, RedoIcon, StrikethroughIcon, UnderlineIcon, UndoIcon } from "lucide-react";
11
+ //#region src/components/menu.client.tsx
12
+ function EditorMenuFixed(props) {
13
+ return /* @__PURE__ */ jsx("div", {
14
+ ...props,
15
+ className: cn("z-10 overflow-auto border-input border-b bg-muted/30 p-2", props.className),
16
+ children: /* @__PURE__ */ jsxs(EditorMenuContent, { children: [
17
+ /* @__PURE__ */ jsx(EditorMenuUndoRedo, {}),
18
+ /* @__PURE__ */ jsx(EditorMenuNodes, {}),
19
+ /* @__PURE__ */ jsx(EditorMenuMarks, {}),
20
+ /* @__PURE__ */ jsx(EditorMenuColor, {})
21
+ ] })
22
+ });
23
+ }
24
+ function EditorMenuBubble(props) {
25
+ const { editor } = useContext(EditorContext);
26
+ return /* @__PURE__ */ jsx(BubbleMenu, {
27
+ ...props,
28
+ editor,
29
+ options: {
30
+ ...props.options,
31
+ strategy: "fixed"
32
+ },
33
+ className: cn("z-10 rounded-lg border border-input bg-muted p-2", props.className),
34
+ children: /* @__PURE__ */ jsx(EditorMenuContent, { children: /* @__PURE__ */ jsx(EditorMenuMarks, {}) })
35
+ });
36
+ }
37
+ function EditorMenuContent(props) {
38
+ return /* @__PURE__ */ jsx("div", {
39
+ className: "flex items-center gap-6",
40
+ children: props.children
41
+ });
42
+ }
43
+ function EditorMenuUndoRedo() {
44
+ const { editor, extensions } = useContext(EditorContext);
45
+ if (!extensions.undoRedo) return null;
46
+ return /* @__PURE__ */ jsxs("div", {
47
+ className: "flex items-center gap-1",
48
+ children: [/* @__PURE__ */ jsx(Button, {
49
+ onClick: () => editor.commands.undo(),
50
+ disabled: !editor?.can().undo(),
51
+ type: "button",
52
+ "aria-label": "Undo",
53
+ size: "icon",
54
+ className: "p-2",
55
+ variant: "outline",
56
+ children: /* @__PURE__ */ jsx(UndoIcon, { className: "size-3.5" })
57
+ }), /* @__PURE__ */ jsx(Button, {
58
+ onClick: () => editor.commands.redo(),
59
+ disabled: !editor?.can().redo(),
60
+ type: "button",
61
+ "aria-label": "Redo",
62
+ size: "icon",
63
+ className: "p-2",
64
+ variant: "outline",
65
+ children: /* @__PURE__ */ jsx(RedoIcon, { className: "size-3.5" })
66
+ })]
67
+ });
68
+ }
69
+ function EditorMenuMarks() {
70
+ const { editor, extensions } = useContext(EditorContext);
71
+ if (!extensions.bold && !extensions.italic && !extensions.underline && !extensions.strike) return null;
72
+ return /* @__PURE__ */ jsxs("div", {
73
+ className: "flex items-center gap-1",
74
+ children: [
75
+ extensions.bold && /* @__PURE__ */ jsx(Button, {
76
+ type: "button",
77
+ size: "icon",
78
+ variant: editor?.isActive("bold") ? "secondary" : "outline",
79
+ onClick: () => editor.chain().focus().toggleBold().run(),
80
+ className: "border",
81
+ children: /* @__PURE__ */ jsx(BoldIcon, { className: "h-3.5 w-3.5" })
82
+ }),
83
+ extensions.italic && /* @__PURE__ */ jsx(Button, {
84
+ type: "button",
85
+ size: "icon",
86
+ variant: editor?.isActive("italic") ? "secondary" : "outline",
87
+ onClick: () => editor.chain().focus().toggleItalic().run(),
88
+ className: "border",
89
+ children: /* @__PURE__ */ jsx(ItalicIcon, { className: "size-3.5" })
90
+ }),
91
+ extensions.underline && /* @__PURE__ */ jsx(Button, {
92
+ type: "button",
93
+ size: "icon",
94
+ variant: editor?.isActive("underline") ? "secondary" : "outline",
95
+ onClick: () => editor.chain().focus().toggleUnderline().run(),
96
+ className: "border",
97
+ children: /* @__PURE__ */ jsx(UnderlineIcon, { className: "size-3.5" })
98
+ }),
99
+ extensions.strike && /* @__PURE__ */ jsx(Button, {
100
+ type: "button",
101
+ size: "icon",
102
+ variant: editor?.isActive("strike") ? "secondary" : "outline",
103
+ onClick: () => editor.chain().focus().toggleStrike().run(),
104
+ className: "border",
105
+ children: /* @__PURE__ */ jsx(StrikethroughIcon, { className: "size-3.5" })
106
+ })
107
+ ]
108
+ });
109
+ }
110
+ function EditorMenuColor() {
111
+ const { editor, extensions } = useContext(EditorContext);
112
+ if (!extensions.color && !extensions.highlight) return null;
113
+ return /* @__PURE__ */ jsxs("div", {
114
+ className: "flex items-center gap-1",
115
+ children: [
116
+ extensions.color && /* @__PURE__ */ jsxs(Popover, { children: [/* @__PURE__ */ jsx(PopoverTrigger, {
117
+ asChild: true,
118
+ children: /* @__PURE__ */ jsx(Button, {
119
+ size: "icon",
120
+ variant: "outline",
121
+ children: /* @__PURE__ */ jsx(BaselineIcon, { className: "size-3.5" })
122
+ })
123
+ }), /* @__PURE__ */ jsx(PopoverContent, {
124
+ className: "w-fit p-0",
125
+ children: /* @__PURE__ */ jsx(ColorPicker, { onValueChange: (color) => editor.chain().focus().setColor(color).run() })
126
+ })] }),
127
+ extensions.highlight && /* @__PURE__ */ jsxs(Popover, { children: [/* @__PURE__ */ jsx(PopoverTrigger, {
128
+ asChild: true,
129
+ children: /* @__PURE__ */ jsx(Button, {
130
+ size: "icon",
131
+ variant: "outline",
132
+ disabled: !editor?.can().setHighlight(),
133
+ children: /* @__PURE__ */ jsx(PaintBucketIcon, { className: "size-3.5" })
134
+ })
135
+ }), /* @__PURE__ */ jsx(PopoverContent, {
136
+ className: "w-fit p-0",
137
+ children: /* @__PURE__ */ jsx(ColorPicker, { onValueChange: (color) => editor.chain().focus().setHighlight({ color }).run() })
138
+ })] }),
139
+ /* @__PURE__ */ jsx(Button, {
140
+ type: "button",
141
+ size: "icon",
142
+ variant: "outline",
143
+ className: "border",
144
+ onClick: () => {
145
+ editor.commands.unsetColor();
146
+ editor.commands.unsetHighlight();
147
+ },
148
+ children: /* @__PURE__ */ jsx(EraserIcon, { className: "h-4 w-4" })
149
+ })
150
+ ]
151
+ });
152
+ }
153
+ //#endregion
154
+ export { EditorMenuBubble, EditorMenuFixed };
@@ -0,0 +1,9 @@
1
+ import { FileHandlerOptions } from "@tiptap/extension-file-handler";
2
+ //#region src/extensions/file-handler/extension.d.ts
3
+ interface FileHandlerOptions$1 extends FileHandlerOptions {
4
+ onReferenceRemoved?: (assetId: string) => void;
5
+ onReferenceAdded?: (assetId: string) => void;
6
+ }
7
+ declare const FileHandler$1: import("@tiptap/core").Extension<FileHandlerOptions$1, any>;
8
+ //#endregion
9
+ export { FileHandler$1 as FileHandler, FileHandlerOptions$1 as FileHandlerOptions };
@@ -0,0 +1,35 @@
1
+ "use client";
2
+ import { collectImageIds, diffIds } from "./utils.mjs";
3
+ import { FileHandler } from "@tiptap/extension-file-handler";
4
+ import { Plugin, PluginKey } from "@tiptap/pm/state";
5
+ //#region src/extensions/file-handler/extension.ts
6
+ const FileHandler$1 = FileHandler.extend({
7
+ addOptions() {
8
+ return {
9
+ ...this.parent?.(),
10
+ onReferenceRemoved: void 0,
11
+ onReferenceAdded: void 0
12
+ };
13
+ },
14
+ addProseMirrorPlugins() {
15
+ const parent = this.parent?.() ?? [];
16
+ const key = new PluginKey("fileHandlerItemTracker");
17
+ return [...parent, new Plugin({
18
+ key,
19
+ appendTransaction: (trs, oldState, newState) => {
20
+ if (!trs.some((tr) => tr.docChanged)) return null;
21
+ const onReferenceRemoved = this.options.onReferenceRemoved;
22
+ const onReferenceAdded = this.options.onReferenceAdded;
23
+ if (!onReferenceRemoved && !onReferenceAdded) return null;
24
+ const before = collectImageIds(oldState.doc);
25
+ const after = collectImageIds(newState.doc);
26
+ const { removed, added } = diffIds(before, after);
27
+ for (const id of removed) onReferenceRemoved?.(id);
28
+ for (const id of added) onReferenceAdded?.(id);
29
+ return null;
30
+ }
31
+ })];
32
+ }
33
+ });
34
+ //#endregion
35
+ export { FileHandler$1 as FileHandler };
@@ -0,0 +1,28 @@
1
+ //#region src/extensions/file-handler/utils.ts
2
+ function collectImageIds(doc) {
3
+ const counts = /* @__PURE__ */ new Map();
4
+ doc.descendants((node) => {
5
+ if (node.type.name !== "image") return;
6
+ const id = node.attrs?.assetId;
7
+ if (!id) return;
8
+ counts.set(id, (counts.get(id) ?? 0) + 1);
9
+ });
10
+ return counts;
11
+ }
12
+ function diffIds(before, after) {
13
+ const removed = [];
14
+ const added = [];
15
+ const keys = /* @__PURE__ */ new Set([...before.keys(), ...after.keys()]);
16
+ for (const key of keys) {
17
+ const b = before.get(key) ?? 0;
18
+ const a = after.get(key) ?? 0;
19
+ if (a < b) removed.push(key);
20
+ if (a > b) added.push(key);
21
+ }
22
+ return {
23
+ removed,
24
+ added
25
+ };
26
+ }
27
+ //#endregion
28
+ export { collectImageIds, diffIds };
@@ -0,0 +1,9 @@
1
+ import { ImageOptions } from "@tiptap/extension-image";
2
+ //#region src/extensions/image/extension.d.ts
3
+ type ImageAttributes = Record<string, unknown>;
4
+ interface ImageOptions$1 extends ImageOptions {
5
+ resolveImageSrc?: (attrs: ImageAttributes) => string | null | undefined;
6
+ }
7
+ declare const Image$1: import("@tiptap/core").Node<ImageOptions$1, any>;
8
+ //#endregion
9
+ export { Image$1 as Image, ImageOptions$1 as ImageOptions };
@@ -0,0 +1,41 @@
1
+ "use client";
2
+ import { Image } from "@tiptap/extension-image";
3
+ //#region src/extensions/image/extension.ts
4
+ const Image$1 = Image.extend({
5
+ atom: true,
6
+ addAttributes() {
7
+ return {
8
+ ...this.parent?.(),
9
+ assetId: {
10
+ default: null,
11
+ parseHTML: (el) => el.getAttribute("data-asset-id"),
12
+ renderHTML: (attrs) => {
13
+ if (!attrs.assetId) return {};
14
+ return { "data-asset-id": attrs.assetId };
15
+ }
16
+ },
17
+ alt: { default: null },
18
+ title: { default: null },
19
+ width: { default: null },
20
+ height: { default: null },
21
+ isPending: {
22
+ default: false,
23
+ renderHTML: (attrs) => attrs.isPending ? { "data-pending": "true" } : {}
24
+ },
25
+ fileName: { default: null }
26
+ };
27
+ },
28
+ parseHTML() {
29
+ return [{ tag: "img[src]" }, { tag: "img[data-asset-id]" }];
30
+ },
31
+ renderHTML({ HTMLAttributes }) {
32
+ const { src: rawSrc, ...attrs } = HTMLAttributes;
33
+ const src = this.options.resolveImageSrc?.(HTMLAttributes) ?? rawSrc;
34
+ return ["img", {
35
+ ...attrs,
36
+ ...src && !attrs.isPending ? { src } : {}
37
+ }];
38
+ }
39
+ });
40
+ //#endregion
41
+ export { Image$1 as Image };
@@ -0,0 +1,37 @@
1
+ "use client";
2
+ import { SkeletonNodeRenderer } from "./renderer.mjs";
3
+ import { Node } from "@tiptap/core";
4
+ import { ReactNodeViewRenderer } from "@tiptap/react";
5
+ //#region src/extensions/skeleton/extension.ts
6
+ const Skeleton = Node.create({
7
+ name: "skeleton",
8
+ atom: true,
9
+ inline: true,
10
+ group: "inline",
11
+ selectable: false,
12
+ draggable: false,
13
+ addAttributes() {
14
+ return {
15
+ imageNodeId: { default: null },
16
+ width: { default: null },
17
+ height: { default: null }
18
+ };
19
+ },
20
+ addOptions() {
21
+ return { addToHistory: false };
22
+ },
23
+ parseHTML() {
24
+ return [{ tag: "span[data-skeleton]" }];
25
+ },
26
+ renderHTML({ HTMLAttributes }) {
27
+ return ["span", {
28
+ ...HTMLAttributes,
29
+ "data-skeleton": "true"
30
+ }];
31
+ },
32
+ addNodeView() {
33
+ return ReactNodeViewRenderer(SkeletonNodeRenderer);
34
+ }
35
+ });
36
+ //#endregion
37
+ export { Skeleton };
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import { NodeViewWrapper } from "@tiptap/react";
3
+ import { Skeleton } from "@tulip-systems/ui/skeleton";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/extensions/skeleton/renderer.tsx
6
+ function SkeletonNodeRenderer(props) {
7
+ const { width, height } = props.node.attrs;
8
+ return /* @__PURE__ */ jsx(NodeViewWrapper, {
9
+ as: "span",
10
+ "data-skeleton": "true",
11
+ children: /* @__PURE__ */ jsx(Skeleton, {
12
+ className: "min-h-125 w-full",
13
+ style: {
14
+ width,
15
+ height
16
+ }
17
+ })
18
+ });
19
+ }
20
+ //#endregion
21
+ export { SkeletonNodeRenderer };
@@ -0,0 +1,3 @@
1
+ import { EditorJSONContent } from "./lib/types.mjs";
2
+ import { convertEditorContentToHTML, convertEditorContentToMarkdown, convertEditorContentToPlainText, convertHTMLToEditorContent, convertMarkdownToEditorContent } from "./lib/helpers.mjs";
3
+ export { EditorJSONContent, convertEditorContentToHTML, convertEditorContentToMarkdown, convertEditorContentToPlainText, convertHTMLToEditorContent, convertMarkdownToEditorContent };
package/dist/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import { convertEditorContentToHTML, convertEditorContentToMarkdown, convertEditorContentToPlainText, convertHTMLToEditorContent, convertMarkdownToEditorContent } from "./lib/helpers.mjs";
2
+ import "./lib/types.mjs";
3
+ export { convertEditorContentToHTML, convertEditorContentToMarkdown, convertEditorContentToPlainText, convertHTMLToEditorContent, convertMarkdownToEditorContent };
@@ -0,0 +1,35 @@
1
+ import { FileHandlerOptions } from "../extensions/file-handler/extension.mjs";
2
+ import { ImageOptions } from "../extensions/image/extension.mjs";
3
+ import "../client.mjs";
4
+ //#region src/lib/constants.d.ts
5
+ declare const EDITOR_EXTENSIONS: {
6
+ blockquote: import("@tiptap/core").Node<import("@tiptap/extension-blockquote").BlockquoteOptions, any>;
7
+ document: import("@tiptap/core").Node<any, any>;
8
+ hardBreak: import("@tiptap/core").Node<import("@tiptap/extension-hard-break").HardBreakOptions, any>;
9
+ heading: import("@tiptap/core").Node<import("@tiptap/extension-heading").HeadingOptions, any>;
10
+ horizontalRule: import("@tiptap/core").Node<import("@tiptap/extension-horizontal-rule").HorizontalRuleOptions, any>;
11
+ listItem: import("@tiptap/core").Node<import("@tiptap/extension-list").ListItemOptions, any>;
12
+ orderedList: import("@tiptap/core").Node<import("@tiptap/extension-list").OrderedListOptions, any>;
13
+ bulletList: import("@tiptap/core").Node<import("@tiptap/extension-list").BulletListOptions, any>;
14
+ paragraph: import("@tiptap/core").Node<import("@tiptap/extension-paragraph").ParagraphOptions, any>;
15
+ text: import("@tiptap/core").Node<any, any>;
16
+ image: import("@tiptap/core").Node<ImageOptions, any>;
17
+ fileHandler: import("@tiptap/core").Extension<FileHandlerOptions, any>;
18
+ skeleton: import("@tiptap/core").Node<any, any>;
19
+ bold: import("@tiptap/core").Mark<import("@tiptap/extension-bold").BoldOptions, any>;
20
+ italic: import("@tiptap/core").Mark<import("@tiptap/extension-italic").ItalicOptions, any>;
21
+ link: import("@tiptap/core").Mark<import("@tiptap/extension-link").LinkOptions, any>;
22
+ strike: import("@tiptap/core").Mark<import("@tiptap/extension-strike").StrikeOptions, any>;
23
+ underline: import("@tiptap/core").Mark<import("@tiptap/extension-underline").UnderlineOptions, any>;
24
+ highlight: import("@tiptap/core").Mark<import("@tiptap/extension-highlight").HighlightOptions, any>;
25
+ dropcursor: import("@tiptap/core").Extension<import("@tiptap/extensions").DropcursorOptions, any>;
26
+ gapcursor: import("@tiptap/core").Extension<any, any>;
27
+ undoRedo: import("@tiptap/core").Extension<import("@tiptap/extensions").UndoRedoOptions, any>;
28
+ listKeymap: import("@tiptap/core").Extension<import("@tiptap/extension-list").ListKeymapOptions, any>;
29
+ trailingNode: import("@tiptap/core").Extension<import("@tiptap/extensions").TrailingNodeOptions, any>;
30
+ textStyle: import("@tiptap/core").Mark<import("@tiptap/extension-text-style").TextStyleOptions, any>;
31
+ color: import("@tiptap/core").Extension<import("@tiptap/extension-text-style").ColorOptions, any>;
32
+ };
33
+ type EditorExtensions = typeof EDITOR_EXTENSIONS;
34
+ //#endregion
35
+ export { EDITOR_EXTENSIONS, EditorExtensions };