@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,87 @@
1
+ import { FileHandler } from "../extensions/file-handler/extension.mjs";
2
+ import { Image } from "../extensions/image/extension.mjs";
3
+ import { Skeleton } from "../extensions/skeleton/extension.mjs";
4
+ import { createExtensionConfig } from "./extensions.mjs";
5
+ import Blockquote from "@tiptap/extension-blockquote";
6
+ import Bold from "@tiptap/extension-bold";
7
+ import Document from "@tiptap/extension-document";
8
+ import HardBreak from "@tiptap/extension-hard-break";
9
+ import Heading from "@tiptap/extension-heading";
10
+ import HorizontalRule from "@tiptap/extension-horizontal-rule";
11
+ import Italic from "@tiptap/extension-italic";
12
+ import Link from "@tiptap/extension-link";
13
+ import { BulletList, ListItem, ListKeymap, OrderedList } from "@tiptap/extension-list";
14
+ import Paragraph from "@tiptap/extension-paragraph";
15
+ import Strike from "@tiptap/extension-strike";
16
+ import Text from "@tiptap/extension-text";
17
+ import Underline from "@tiptap/extension-underline";
18
+ import Highlight from "@tiptap/extension-highlight";
19
+ import { Color, TextStyle } from "@tiptap/extension-text-style";
20
+ import { Dropcursor, Gapcursor, TrailingNode, UndoRedo } from "@tiptap/extensions";
21
+ //#region src/lib/constants.ts
22
+ const EDITOR_EXTENSIONS = {
23
+ blockquote: Blockquote,
24
+ document: Document,
25
+ hardBreak: HardBreak,
26
+ heading: Heading,
27
+ horizontalRule: HorizontalRule,
28
+ listItem: ListItem,
29
+ orderedList: OrderedList,
30
+ bulletList: BulletList,
31
+ paragraph: Paragraph,
32
+ text: Text,
33
+ image: Image,
34
+ fileHandler: FileHandler,
35
+ skeleton: Skeleton,
36
+ bold: Bold,
37
+ italic: Italic,
38
+ link: Link,
39
+ strike: Strike,
40
+ underline: Underline,
41
+ highlight: Highlight,
42
+ dropcursor: Dropcursor,
43
+ gapcursor: Gapcursor,
44
+ undoRedo: UndoRedo,
45
+ listKeymap: ListKeymap,
46
+ trailingNode: TrailingNode,
47
+ textStyle: TextStyle,
48
+ color: Color
49
+ };
50
+ const EDITOR_EXTENSIONS_KEYS = Object.keys(EDITOR_EXTENSIONS);
51
+ Object.values(EDITOR_EXTENSIONS);
52
+ const EDITOR_EXTENSIONS_CONFIG = [
53
+ createExtensionConfig("blockquote"),
54
+ createExtensionConfig("document"),
55
+ createExtensionConfig("hardBreak"),
56
+ createExtensionConfig("heading"),
57
+ createExtensionConfig("horizontalRule"),
58
+ createExtensionConfig("listItem"),
59
+ createExtensionConfig("orderedList"),
60
+ createExtensionConfig("bulletList"),
61
+ createExtensionConfig("paragraph"),
62
+ createExtensionConfig("text"),
63
+ createExtensionConfig("image", { resize: {
64
+ enabled: true,
65
+ directions: ["left", "right"],
66
+ minHeight: 50,
67
+ minWidth: 50,
68
+ alwaysPreserveAspectRatio: true
69
+ } }),
70
+ createExtensionConfig("fileHandler"),
71
+ createExtensionConfig("skeleton"),
72
+ createExtensionConfig("bold"),
73
+ createExtensionConfig("italic"),
74
+ createExtensionConfig("link"),
75
+ createExtensionConfig("strike"),
76
+ createExtensionConfig("underline"),
77
+ createExtensionConfig("highlight", { multicolor: true }),
78
+ createExtensionConfig("dropcursor"),
79
+ createExtensionConfig("gapcursor"),
80
+ createExtensionConfig("undoRedo"),
81
+ createExtensionConfig("listKeymap"),
82
+ createExtensionConfig("trailingNode"),
83
+ createExtensionConfig("textStyle"),
84
+ createExtensionConfig("color")
85
+ ];
86
+ //#endregion
87
+ export { EDITOR_EXTENSIONS, EDITOR_EXTENSIONS_CONFIG, EDITOR_EXTENSIONS_KEYS };
@@ -0,0 +1,56 @@
1
+ import { FileHandlerOptions } from "../extensions/file-handler/extension.mjs";
2
+ import { ImageOptions } from "../extensions/image/extension.mjs";
3
+ import { EditorExtensions } from "./constants.mjs";
4
+ import { BlockquoteOptions } from "@tiptap/extension-blockquote";
5
+ import { BoldOptions } from "@tiptap/extension-bold";
6
+ import { HardBreakOptions } from "@tiptap/extension-hard-break";
7
+ import { HeadingOptions } from "@tiptap/extension-heading";
8
+ import { HorizontalRuleOptions } from "@tiptap/extension-horizontal-rule";
9
+ import { ItalicOptions } from "@tiptap/extension-italic";
10
+ import { LinkOptions } from "@tiptap/extension-link";
11
+ import { BulletListOptions, ListItemOptions, ListKeymapOptions, OrderedListOptions } from "@tiptap/extension-list";
12
+ import { ParagraphOptions } from "@tiptap/extension-paragraph";
13
+ import { StrikeOptions } from "@tiptap/extension-strike";
14
+ import { UnderlineOptions } from "@tiptap/extension-underline";
15
+ import { Extension } from "@tiptap/react";
16
+ import { HighlightOptions } from "@tiptap/extension-highlight";
17
+ import { ColorOptions, TextStyleOptions } from "@tiptap/extension-text-style";
18
+ import { DropcursorOptions, TrailingNodeOptions, UndoRedoOptions } from "@tiptap/extensions";
19
+ //#region src/lib/extensions.d.ts
20
+ type EditorExtensionsConfig = {
21
+ blockquote: Partial<BlockquoteOptions> | boolean;
22
+ bulletList: Partial<BulletListOptions> | boolean;
23
+ document: boolean;
24
+ hardBreak: Partial<HardBreakOptions> | boolean;
25
+ heading: Partial<HeadingOptions> | boolean;
26
+ horizontalRule: Partial<HorizontalRuleOptions> | boolean;
27
+ listItem: Partial<ListItemOptions> | boolean;
28
+ orderedList: Partial<OrderedListOptions> | boolean;
29
+ paragraph: Partial<ParagraphOptions> | boolean;
30
+ text: Partial<TextStyleOptions> | boolean;
31
+ image: Partial<ImageOptions> | boolean;
32
+ fileHandler: Partial<FileHandlerOptions> | boolean;
33
+ skeleton: boolean;
34
+ bold: Partial<BoldOptions> | boolean;
35
+ italic: Partial<ItalicOptions> | boolean;
36
+ link: Partial<LinkOptions> | boolean;
37
+ strike: Partial<StrikeOptions> | boolean;
38
+ underline: Partial<UnderlineOptions> | boolean;
39
+ highlight: Partial<HighlightOptions> | boolean;
40
+ dropcursor: Partial<DropcursorOptions> | boolean;
41
+ gapcursor: boolean;
42
+ undoRedo: Partial<UndoRedoOptions> | boolean;
43
+ listKeymap: Partial<ListKeymapOptions> | boolean;
44
+ trailingNode: Partial<TrailingNodeOptions> | boolean;
45
+ textStyle: Partial<TextStyleOptions> | boolean;
46
+ color: Partial<ColorOptions> | boolean;
47
+ };
48
+ declare function createExtensionConfig<TName extends keyof EditorExtensionsConfig>(name: TName, defaultOptions?: Partial<Exclude<EditorExtensionsConfig[TName], boolean>>): {
49
+ name: TName;
50
+ configure: (options: EditorExtensionsConfig[TName]) => Extension<FileHandlerOptions, any> | import("@tiptap/core").Node<ImageOptions, any> | import("@tiptap/core").Node<BlockquoteOptions, any> | import("@tiptap/core").Node<any, any> | import("@tiptap/core").Node<HardBreakOptions, any> | import("@tiptap/core").Node<HeadingOptions, any> | import("@tiptap/core").Node<HorizontalRuleOptions, any> | import("@tiptap/core").Node<ListItemOptions, any> | import("@tiptap/core").Node<OrderedListOptions, any> | import("@tiptap/core").Mark<BoldOptions, any> | import("@tiptap/core").Mark<LinkOptions, any> | import("@tiptap/core").Mark<HighlightOptions, any> | Extension<DropcursorOptions, any> | Extension<any, any> | Extension<UndoRedoOptions, any> | Extension<ListKeymapOptions, any> | Extension<TrailingNodeOptions, any> | import("@tiptap/core").Mark<TextStyleOptions, any> | Extension<ColorOptions, any> | undefined;
51
+ };
52
+ declare function editorExtensionsConfigToExtensions(extensions?: Partial<EditorExtensionsConfig>): Extension<any, any>[];
53
+ declare function flattenEditorExtensionsConfig(extensions?: Partial<EditorExtensionsConfig>): EditorExtensionsConfigResult;
54
+ type EditorExtensionsConfigResult = Record<keyof EditorExtensions, boolean>;
55
+ //#endregion
56
+ export { EditorExtensionsConfig, EditorExtensionsConfigResult, createExtensionConfig, editorExtensionsConfigToExtensions, flattenEditorExtensionsConfig };
@@ -0,0 +1,35 @@
1
+ import { EDITOR_EXTENSIONS, EDITOR_EXTENSIONS_CONFIG, EDITOR_EXTENSIONS_KEYS } from "./constants.mjs";
2
+ import deepmerge from "deepmerge";
3
+ //#region src/lib/extensions.ts
4
+ function createExtensionConfig(name, defaultOptions = {}) {
5
+ return {
6
+ name,
7
+ configure: (options) => {
8
+ const extension = EDITOR_EXTENSIONS[name];
9
+ if (!options || !extension) return void 0;
10
+ if (typeof options === "boolean") return extension.configure(defaultOptions);
11
+ const extensionOptions = deepmerge(defaultOptions, options);
12
+ return extension.configure(extensionOptions);
13
+ }
14
+ };
15
+ }
16
+ function editorExtensionsConfigToExtensions(extensions) {
17
+ return EDITOR_EXTENSIONS_CONFIG.flatMap(({ name, configure }) => {
18
+ const value = extensions?.[name];
19
+ if (value === void 0) return configure(true);
20
+ return configure(value);
21
+ });
22
+ }
23
+ function flattenEditorExtensionsConfig(extensions) {
24
+ return EDITOR_EXTENSIONS_KEYS.reduce((acc, key) => {
25
+ const value = extensions?.[key];
26
+ if (value === void 0) {
27
+ acc[key] = true;
28
+ return acc;
29
+ }
30
+ acc[key] = typeof value === "boolean" ? value : true;
31
+ return acc;
32
+ }, {});
33
+ }
34
+ //#endregion
35
+ export { createExtensionConfig, editorExtensionsConfigToExtensions, flattenEditorExtensionsConfig };
@@ -0,0 +1,9 @@
1
+ import { EditorJSONContent } from "./types.mjs";
2
+ //#region src/lib/helpers.d.ts
3
+ declare function convertHTMLToEditorContent(html: string): EditorJSONContent;
4
+ declare function convertMarkdownToEditorContent(markdown: string): EditorJSONContent;
5
+ declare function convertEditorContentToHTML(content: EditorJSONContent): string;
6
+ declare function convertEditorContentToMarkdown(content: EditorJSONContent): string;
7
+ declare function convertEditorContentToPlainText(content: EditorJSONContent): string;
8
+ //#endregion
9
+ export { convertEditorContentToHTML, convertEditorContentToMarkdown, convertEditorContentToPlainText, convertHTMLToEditorContent, convertMarkdownToEditorContent };
@@ -0,0 +1,58 @@
1
+ import { markdownParser } from "./markdown.mjs";
2
+ import { generateText } from "@tiptap/core";
3
+ import Blockquote from "@tiptap/extension-blockquote";
4
+ import Bold from "@tiptap/extension-bold";
5
+ import Document from "@tiptap/extension-document";
6
+ import HardBreak from "@tiptap/extension-hard-break";
7
+ import Heading from "@tiptap/extension-heading";
8
+ import HorizontalRule from "@tiptap/extension-horizontal-rule";
9
+ import Italic from "@tiptap/extension-italic";
10
+ import Link from "@tiptap/extension-link";
11
+ import { BulletList, ListItem, OrderedList } from "@tiptap/extension-list";
12
+ import Paragraph from "@tiptap/extension-paragraph";
13
+ import Strike from "@tiptap/extension-strike";
14
+ import Text from "@tiptap/extension-text";
15
+ import Underline from "@tiptap/extension-underline";
16
+ import { generateJSON } from "@tiptap/html";
17
+ import { renderToHTMLString, renderToMarkdown } from "@tiptap/static-renderer";
18
+ //#region src/lib/helpers.ts
19
+ const EXTENSIONS_FOR_GENERATION = [
20
+ Blockquote,
21
+ BulletList,
22
+ Document,
23
+ HardBreak,
24
+ Heading,
25
+ HorizontalRule,
26
+ ListItem,
27
+ OrderedList,
28
+ Paragraph,
29
+ Text,
30
+ Bold,
31
+ Italic,
32
+ Link,
33
+ Strike,
34
+ Underline
35
+ ];
36
+ function convertHTMLToEditorContent(html) {
37
+ return generateJSON(html, EXTENSIONS_FOR_GENERATION);
38
+ }
39
+ function convertMarkdownToEditorContent(markdown) {
40
+ return convertHTMLToEditorContent(markdownParser.render(markdown));
41
+ }
42
+ function convertEditorContentToHTML(content) {
43
+ return renderToHTMLString({
44
+ content,
45
+ extensions: EXTENSIONS_FOR_GENERATION
46
+ });
47
+ }
48
+ function convertEditorContentToMarkdown(content) {
49
+ return renderToMarkdown({
50
+ content,
51
+ extensions: EXTENSIONS_FOR_GENERATION
52
+ });
53
+ }
54
+ function convertEditorContentToPlainText(content) {
55
+ return generateText(content, EXTENSIONS_FOR_GENERATION);
56
+ }
57
+ //#endregion
58
+ export { convertEditorContentToHTML, convertEditorContentToMarkdown, convertEditorContentToPlainText, convertHTMLToEditorContent, convertMarkdownToEditorContent };
@@ -0,0 +1,9 @@
1
+ import MarkdownIt from "markdown-it";
2
+ //#region src/lib/markdown.ts
3
+ const markdownParser = new MarkdownIt({
4
+ html: false,
5
+ linkify: true,
6
+ breaks: true
7
+ });
8
+ //#endregion
9
+ export { markdownParser };
@@ -0,0 +1,5 @@
1
+ import { JSONContent } from "@tiptap/react";
2
+ //#region src/lib/types.d.ts
3
+ type EditorJSONContent = JSONContent;
4
+ //#endregion
5
+ export { EditorJSONContent };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import { cn } from "@tulip-systems/ui/cn";
2
+ import { cva } from "class-variance-authority";
3
+ //#region src/lib/variants.ts
4
+ const editorProseVariants = cva(cn("prose dark:prose-invert", "prose-a:text-primary", "prose-headings:scroll-mt-20", "prose-h1:mt-6 prose-h1:mb-3", "prose-h2:mt-6 prose-h2:mb-3", "prose-h3:mt-5 prose-h3:mb-2", "prose-h4:mt-4 prose-h4:mb-2", "prose-ul:my-3 prose-ol:my-3", "prose-ul:pl-6 prose-ol:pl-6", "prose-li:my-1", "prose-li:marker:text-primary", "prose-li:p-0", "prose-img:my-0 prose-img:rounded-lg", "prose-blockquote:my-4 prose-blockquote:py-1", "prose-hr:my-6", "prose-pre:my-4"));
5
+ const editorImageVariants = cva(cn("[&_[data-resize-wrapper]]:!inline-block", "[&_[data-resize-wrapper]]:!relative", "[&_[data-resize-wrapper]]:max-w-full", "[&_[data-resize-wrapper]]:overflow-hidden", "[&_[data-resize-handle]]:absolute", "[&_[data-resize-handle]]:z-10", "[&_[data-resize-handle]]:rounded-full", "[&_[data-resize-handle]]:bg-muted/40", "[&_[data-resize-handle]]:w-1.5", "[&_[data-resize-handle]]:cursor-ew-resize", "[&_[data-resize-handle]]:opacity-0", "[&_[data-resize-handle]]:transition-opacity", "[&:hover_[data-resize-handle]]:opacity-100", "[&_[data-resize-state='true']_[data-resize-handle]]:opacity-100", "[&_[data-resize-handle]]:!top-1/2", "[&_[data-resize-handle]]:!bottom-auto", "[&_[data-resize-handle]]:!-translate-y-1/2", "[&_[data-resize-handle]]:!h-1/2", "[&_[data-resize-handle='left']]:!left-2", "[&_[data-resize-handle='right']]:!right-2", "[&_[data-resize-container]:has(img[data-pending='true'])]:[visibility:visible!important]", "[&_[data-resize-container]:has(img[data-pending='true'])]:[pointer-events:auto!important]", "[&_img[data-pending='true']]:bg-primary/10", "[&_img[data-pending='true']]:animate-pulse", "[&_img[data-pending='true']]:rounded-md", "[&_img[data-pending='true']]:opacity-0", "[&_img[data-pending='true']]:min-h-[500px]"));
6
+ //#endregion
7
+ export { editorImageVariants, editorProseVariants };
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "@tulip-systems/editor",
3
+ "version": "0.11.1",
4
+ "type": "module",
5
+ "sideEffects": true,
6
+ "license": "AGPL-3.0",
7
+ "dependencies": {
8
+ "@tiptap/core": "^3.29.2",
9
+ "@tiptap/extension-blockquote": "^3.29.2",
10
+ "@tiptap/extension-bold": "^3.29.2",
11
+ "@tiptap/extension-color": "^3.29.2",
12
+ "@tiptap/extension-document": "^3.29.2",
13
+ "@tiptap/extension-file-handler": "^3.29.2",
14
+ "@tiptap/extension-hard-break": "^3.29.2",
15
+ "@tiptap/extension-heading": "^3.29.2",
16
+ "@tiptap/extension-highlight": "^3.29.2",
17
+ "@tiptap/extension-horizontal-rule": "^3.29.2",
18
+ "@tiptap/extension-image": "^3.29.2",
19
+ "@tiptap/extension-italic": "^3.29.2",
20
+ "@tiptap/extension-link": "^3.29.2",
21
+ "@tiptap/extension-list": "^3.29.2",
22
+ "@tiptap/extension-paragraph": "^3.29.2",
23
+ "@tiptap/extension-strike": "^3.29.2",
24
+ "@tiptap/extension-text": "^3.29.2",
25
+ "@tiptap/extension-text-style": "^3.29.2",
26
+ "@tiptap/extension-underline": "^3.29.2",
27
+ "@tiptap/extensions": "^3.29.2",
28
+ "@tiptap/html": "^3.29.2",
29
+ "@tiptap/pm": "^3.29.2",
30
+ "@tiptap/react": "^3.29.2",
31
+ "@tiptap/static-renderer": "^3.29.2",
32
+ "class-variance-authority": "^0.7.1",
33
+ "deepmerge": "^4.3.1",
34
+ "lucide-react": "^1.30.0",
35
+ "markdown-it": "^14.3.0",
36
+ "@tulip-systems/ui": "0.11.1"
37
+ },
38
+ "devDependencies": {
39
+ "@arethetypeswrong/core": "^0.18.5",
40
+ "@types/markdown-it": "^14.1.2",
41
+ "@types/react": "19.2.17",
42
+ "@types/react-dom": "19.2.4",
43
+ "publint": "^0.3.23",
44
+ "tailwindcss": "^4.3.3",
45
+ "tsdown": "^0.22.14",
46
+ "typescript": "5.9.3",
47
+ "unrun": "^0.3.1",
48
+ "vitest": "^4.1.10",
49
+ "@tulip-systems/typescript-config": "0.0.0"
50
+ },
51
+ "peerDependencies": {
52
+ "@tailwindcss/typography": "^0.5.19",
53
+ "react": "19.2.8",
54
+ "react-dom": "19.2.8"
55
+ },
56
+ "publishConfig": {
57
+ "access": "public"
58
+ },
59
+ "engines": {
60
+ "node": "24.x"
61
+ },
62
+ "files": [
63
+ "dist",
64
+ "styles.css"
65
+ ],
66
+ "exports": {
67
+ ".": "./dist/index.mjs",
68
+ "./client": "./dist/client.mjs",
69
+ "./package.json": "./package.json",
70
+ "./styles.css": "./styles.css"
71
+ },
72
+ "scripts": {
73
+ "dev": "tsdown --config tsdown.config.ts --config-loader unrun --watch --no-clean",
74
+ "build": "tsdown --config tsdown.config.ts --config-loader unrun --no-clean",
75
+ "build:release": "tsdown --config tsdown.config.ts --config-loader unrun",
76
+ "lint": "biome check",
77
+ "format": "biome format --write",
78
+ "typecheck": "tsc --noEmit",
79
+ "test": "vitest",
80
+ "test:ci": "vitest run",
81
+ "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
82
+ }
83
+ }
package/styles.css ADDED
@@ -0,0 +1 @@
1
+ @source "./dist";