neuphlo-editor 2.5.0 → 2.6.0

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.
Files changed (171) hide show
  1. package/dist/Markdown-BAW0cb-U.d.cts +153 -0
  2. package/dist/Markdown-BAW0cb-U.d.ts +153 -0
  3. package/dist/{chunk-4L7FHW5M.js → chunk-ABL4D65Z.js} +113 -47
  4. package/dist/chunk-ABL4D65Z.js.map +1 -0
  5. package/dist/{chunk-BVFTQKY7.js → chunk-Z2DR2FK3.js} +245 -50
  6. package/dist/chunk-Z2DR2FK3.js.map +1 -0
  7. package/dist/headless/components/editor-bubble-item.d.ts +9 -0
  8. package/dist/headless/components/editor-bubble-item.js +29 -0
  9. package/dist/headless/components/editor-bubble.d.ts +9 -0
  10. package/dist/headless/components/editor-bubble.js +9 -0
  11. package/dist/headless/components/editor-command-item.d.ts +3 -0
  12. package/dist/headless/components/editor-command-item.js +27 -0
  13. package/dist/headless/components/editor-command.d.ts +3 -0
  14. package/dist/headless/components/editor-command.js +136 -0
  15. package/dist/headless/components/editor.d.ts +24 -0
  16. package/dist/headless/components/editor.js +13 -0
  17. package/dist/headless/extensions/AISuggestion/AISuggestion.d.ts +82 -0
  18. package/dist/headless/extensions/AISuggestion/AISuggestion.js +244 -0
  19. package/dist/headless/extensions/AISuggestion/index.d.ts +2 -0
  20. package/dist/headless/extensions/AISuggestion/index.js +1 -0
  21. package/dist/headless/extensions/CodeBlock/CodeBlock.d.ts +1 -0
  22. package/dist/headless/extensions/CodeBlock/CodeBlock.js +6 -0
  23. package/dist/headless/extensions/CodeBlock/index.d.ts +1 -0
  24. package/dist/headless/extensions/CodeBlock/index.js +1 -0
  25. package/dist/headless/extensions/DragHandle/DragHandle.d.ts +9 -0
  26. package/dist/headless/extensions/DragHandle/DragHandle.js +47 -0
  27. package/dist/headless/extensions/DragHandle/index.d.ts +2 -0
  28. package/dist/headless/extensions/DragHandle/index.js +1 -0
  29. package/dist/headless/extensions/Image/Image.d.ts +6 -0
  30. package/dist/headless/extensions/Image/Image.js +197 -0
  31. package/dist/headless/extensions/ImageBlock/ImageBlock.d.ts +23 -0
  32. package/dist/headless/extensions/ImageBlock/ImageBlock.js +242 -0
  33. package/dist/headless/extensions/ImageBlock/index.d.ts +2 -0
  34. package/dist/headless/extensions/ImageBlock/index.js +1 -0
  35. package/dist/headless/extensions/Link/Link.d.ts +2 -0
  36. package/dist/headless/extensions/Link/Link.js +44 -0
  37. package/dist/headless/extensions/Link/index.d.ts +1 -0
  38. package/dist/headless/extensions/Link/index.js +1 -0
  39. package/dist/headless/extensions/Markdown.d.ts +9 -0
  40. package/dist/headless/extensions/Markdown.js +138 -0
  41. package/dist/headless/extensions/MarkdownPaste.d.ts +3 -0
  42. package/dist/headless/extensions/MarkdownPaste.js +168 -0
  43. package/dist/headless/extensions/Mention/index.d.ts +4 -0
  44. package/dist/headless/extensions/Mention/index.js +3 -0
  45. package/dist/headless/extensions/Mention/mention-command.d.ts +8 -0
  46. package/dist/headless/extensions/Mention/mention-command.js +165 -0
  47. package/dist/headless/extensions/Mention/mention-list.d.ts +8 -0
  48. package/dist/headless/extensions/Mention/mention-list.js +150 -0
  49. package/dist/headless/extensions/Mention/mention-node-view.d.ts +2 -0
  50. package/dist/headless/extensions/Mention/mention-node-view.js +92 -0
  51. package/dist/headless/extensions/Mention/mention.d.ts +46 -0
  52. package/dist/headless/extensions/Mention/mention.js +218 -0
  53. package/dist/headless/extensions/Table/index.d.ts +2 -0
  54. package/dist/headless/extensions/Table/index.js +2 -0
  55. package/dist/headless/extensions/VideoBlock/VideoBlock.d.ts +17 -0
  56. package/dist/headless/extensions/VideoBlock/VideoBlock.js +73 -0
  57. package/dist/headless/extensions/VideoBlock/index.d.ts +2 -0
  58. package/dist/headless/extensions/VideoBlock/index.js +1 -0
  59. package/dist/headless/extensions/extension-kit.d.ts +29 -0
  60. package/dist/headless/extensions/extension-kit.js +132 -0
  61. package/dist/headless/extensions/index.d.ts +16 -0
  62. package/dist/headless/extensions/index.js +12 -0
  63. package/dist/headless/extensions/slash-command.d.ts +24 -0
  64. package/dist/headless/extensions/slash-command.js +99 -0
  65. package/dist/headless/index.cjs +143 -2
  66. package/dist/headless/index.cjs.map +1 -1
  67. package/dist/headless/index.d.cts +3 -2
  68. package/dist/headless/index.d.ts +3 -2
  69. package/dist/headless/index.js +5 -1
  70. package/dist/headless/utils/atoms.d.ts +13 -0
  71. package/dist/headless/utils/atoms.js +5 -0
  72. package/dist/headless/utils/store.d.ts +2 -0
  73. package/dist/headless/utils/store.js +4 -0
  74. package/dist/highlight.css +77 -1
  75. package/dist/react/Editor.d.ts +43 -0
  76. package/dist/react/Editor.js +119 -0
  77. package/dist/react/TableOfContents.d.ts +7 -0
  78. package/dist/react/TableOfContents.js +96 -0
  79. package/dist/react/index.cjs +156 -9
  80. package/dist/react/index.cjs.map +1 -1
  81. package/dist/react/index.d.cts +5 -2
  82. package/dist/react/index.d.ts +5 -2
  83. package/dist/react/index.js +14 -4
  84. package/dist/react/index.js.map +1 -1
  85. package/dist/react/menus/DragHandle/BlockActionMenu.d.ts +7 -0
  86. package/dist/react/menus/DragHandle/BlockActionMenu.js +111 -0
  87. package/dist/react/menus/DragHandle/DragHandleMenu.d.ts +7 -0
  88. package/dist/react/menus/DragHandle/DragHandleMenu.js +97 -0
  89. package/dist/react/menus/ImageBlock/ImageBlockLoading.d.ts +2 -0
  90. package/dist/react/menus/ImageBlock/ImageBlockLoading.js +6 -0
  91. package/dist/react/menus/ImageBlock/ImageBlockMenu.d.ts +8 -0
  92. package/dist/react/menus/ImageBlock/ImageBlockMenu.js +75 -0
  93. package/dist/react/menus/ImageBlock/ImageBlockView.d.ts +10 -0
  94. package/dist/react/menus/ImageBlock/ImageBlockView.js +60 -0
  95. package/dist/react/menus/ImageBlock/ImageBlockWidth.d.ts +6 -0
  96. package/dist/react/menus/ImageBlock/ImageBlockWidth.js +29 -0
  97. package/dist/react/menus/ImageBlock/ImageResizeHandle.d.ts +8 -0
  98. package/dist/react/menus/ImageBlock/ImageResizeHandle.js +37 -0
  99. package/dist/react/menus/ImageBlock/ImageUploader.d.ts +7 -0
  100. package/dist/react/menus/ImageBlock/ImageUploader.js +73 -0
  101. package/dist/react/menus/ImageBlock/index.d.ts +4 -0
  102. package/dist/react/menus/ImageBlock/index.js +4 -0
  103. package/dist/react/menus/ImageMenu.d.ts +10 -0
  104. package/dist/react/menus/ImageMenu.js +77 -0
  105. package/dist/react/menus/ImagePopover.d.ts +8 -0
  106. package/dist/react/menus/ImagePopover.js +146 -0
  107. package/dist/react/menus/LinkMenu.d.ts +2 -0
  108. package/dist/react/menus/LinkMenu.js +69 -0
  109. package/dist/react/menus/MenuList.d.ts +10 -0
  110. package/dist/react/menus/MenuList.js +94 -0
  111. package/dist/react/menus/SlashMenu.d.ts +5 -0
  112. package/dist/react/menus/SlashMenu.js +156 -0
  113. package/dist/react/menus/TableMenu.d.ts +5 -0
  114. package/dist/react/menus/TableMenu.js +462 -0
  115. package/dist/react/menus/TaskItem/TaskItemView.d.ts +12 -0
  116. package/dist/react/menus/TaskItem/TaskItemView.js +11 -0
  117. package/dist/react/menus/TextMenu.d.ts +10 -0
  118. package/dist/react/menus/TextMenu.js +139 -0
  119. package/dist/react/menus/VideoBlock/VideoBlockMenu.d.ts +7 -0
  120. package/dist/react/menus/VideoBlock/VideoBlockMenu.js +72 -0
  121. package/dist/react/menus/VideoBlock/VideoBlockView.d.ts +10 -0
  122. package/dist/react/menus/VideoBlock/VideoBlockView.js +87 -0
  123. package/dist/react/menus/VideoBlock/index.d.ts +2 -0
  124. package/dist/react/menus/VideoBlock/index.js +2 -0
  125. package/dist/react/menus/index.d.ts +15 -0
  126. package/dist/react/menus/index.js +9 -0
  127. package/package.json +3 -1
  128. package/dist/chunk-2DWEJI45.js +0 -1296
  129. package/dist/chunk-2DWEJI45.js.map +0 -1
  130. package/dist/chunk-3CLWAYRP.js +0 -1387
  131. package/dist/chunk-3CLWAYRP.js.map +0 -1
  132. package/dist/chunk-457ETWB6.js +0 -1351
  133. package/dist/chunk-457ETWB6.js.map +0 -1
  134. package/dist/chunk-4L7FHW5M.js.map +0 -1
  135. package/dist/chunk-4MV3UUZN.js +0 -1073
  136. package/dist/chunk-4MV3UUZN.js.map +0 -1
  137. package/dist/chunk-62DYB7FY.js +0 -1305
  138. package/dist/chunk-62DYB7FY.js.map +0 -1
  139. package/dist/chunk-BVFTQKY7.js.map +0 -1
  140. package/dist/chunk-DWGPGRTQ.js +0 -1302
  141. package/dist/chunk-DWGPGRTQ.js.map +0 -1
  142. package/dist/chunk-EG7NQJRA.js +0 -1324
  143. package/dist/chunk-EG7NQJRA.js.map +0 -1
  144. package/dist/chunk-FLLPFFI5.js +0 -1296
  145. package/dist/chunk-FLLPFFI5.js.map +0 -1
  146. package/dist/chunk-FVQHB6VC.js +0 -1128
  147. package/dist/chunk-FVQHB6VC.js.map +0 -1
  148. package/dist/chunk-G5E32MLB.js +0 -1352
  149. package/dist/chunk-G5E32MLB.js.map +0 -1
  150. package/dist/chunk-GXJGZHKR.js +0 -1326
  151. package/dist/chunk-GXJGZHKR.js.map +0 -1
  152. package/dist/chunk-KCPPTLGY.js +0 -1299
  153. package/dist/chunk-KCPPTLGY.js.map +0 -1
  154. package/dist/chunk-LHG2NX6C.js +0 -1123
  155. package/dist/chunk-LHG2NX6C.js.map +0 -1
  156. package/dist/chunk-MSNTVITF.js +0 -1352
  157. package/dist/chunk-MSNTVITF.js.map +0 -1
  158. package/dist/chunk-N4RDYJ5Z.js +0 -1351
  159. package/dist/chunk-N4RDYJ5Z.js.map +0 -1
  160. package/dist/chunk-OCNM37WJ.js +0 -1289
  161. package/dist/chunk-OCNM37WJ.js.map +0 -1
  162. package/dist/chunk-P3YFYEUB.js +0 -1351
  163. package/dist/chunk-P3YFYEUB.js.map +0 -1
  164. package/dist/chunk-RW6QBMJB.js +0 -1300
  165. package/dist/chunk-RW6QBMJB.js.map +0 -1
  166. package/dist/chunk-SJQQVB3M.js +0 -1353
  167. package/dist/chunk-SJQQVB3M.js.map +0 -1
  168. package/dist/chunk-SOXTEP7H.js +0 -6705
  169. package/dist/chunk-SOXTEP7H.js.map +0 -1
  170. package/dist/chunk-VPI26I4P.js +0 -1350
  171. package/dist/chunk-VPI26I4P.js.map +0 -1
@@ -1,3 +1,79 @@
1
- /* Optional: include a default highlight.js theme for code token colors */
2
1
  @import "highlight.js/styles/github.css";
3
2
 
3
+ .dark .hljs {
4
+ color: #c9d1d9;
5
+ background: transparent;
6
+ }
7
+ .dark .hljs-doctag,
8
+ .dark .hljs-keyword,
9
+ .dark .hljs-meta .hljs-keyword,
10
+ .dark .hljs-template-tag,
11
+ .dark .hljs-template-variable,
12
+ .dark .hljs-type,
13
+ .dark .hljs-variable.language_ {
14
+ color: #ff7b72;
15
+ }
16
+ .dark .hljs-title,
17
+ .dark .hljs-title.class_,
18
+ .dark .hljs-title.class_.inherited__,
19
+ .dark .hljs-title.function_ {
20
+ color: #d2a8ff;
21
+ }
22
+ .dark .hljs-attr,
23
+ .dark .hljs-attribute,
24
+ .dark .hljs-literal,
25
+ .dark .hljs-meta,
26
+ .dark .hljs-number,
27
+ .dark .hljs-operator,
28
+ .dark .hljs-variable,
29
+ .dark .hljs-selector-attr,
30
+ .dark .hljs-selector-class,
31
+ .dark .hljs-selector-id {
32
+ color: #79c0ff;
33
+ }
34
+ .dark .hljs-regexp,
35
+ .dark .hljs-string,
36
+ .dark .hljs-meta .hljs-string {
37
+ color: #a5d6ff;
38
+ }
39
+ .dark .hljs-built_in,
40
+ .dark .hljs-symbol {
41
+ color: #ffa657;
42
+ }
43
+ .dark .hljs-comment,
44
+ .dark .hljs-code,
45
+ .dark .hljs-formula {
46
+ color: #8b949e;
47
+ }
48
+ .dark .hljs-name,
49
+ .dark .hljs-quote,
50
+ .dark .hljs-selector-tag,
51
+ .dark .hljs-selector-pseudo {
52
+ color: #7ee787;
53
+ }
54
+ .dark .hljs-subst {
55
+ color: #c9d1d9;
56
+ }
57
+ .dark .hljs-section {
58
+ color: #1f6feb;
59
+ font-weight: bold;
60
+ }
61
+ .dark .hljs-bullet {
62
+ color: #f2cc60;
63
+ }
64
+ .dark .hljs-emphasis {
65
+ color: #c9d1d9;
66
+ font-style: italic;
67
+ }
68
+ .dark .hljs-strong {
69
+ color: #c9d1d9;
70
+ font-weight: bold;
71
+ }
72
+ .dark .hljs-addition {
73
+ color: #aff5b4;
74
+ background-color: #033a16;
75
+ }
76
+ .dark .hljs-deletion {
77
+ color: #ffdcd7;
78
+ background-color: #67060c;
79
+ }
@@ -0,0 +1,43 @@
1
+ import { type EditorContentProps } from "../headless";
2
+ import type { MentionOptions } from "../headless/extensions";
3
+ import { type TaskItemCheckboxComponent } from "./menus/TaskItem/TaskItemView";
4
+ import type { ReactNode } from "react";
5
+ import type { Editor as TiptapEditor } from "@tiptap/react";
6
+ export type BubbleMenuExtraRenderer = (editor: TiptapEditor) => ReactNode;
7
+ export type BubbleMenuExtra = BubbleMenuExtraRenderer | {
8
+ render: BubbleMenuExtraRenderer;
9
+ align?: "start" | "end";
10
+ };
11
+ export type BubbleMenuExtras = Partial<{
12
+ text: BubbleMenuExtra | BubbleMenuExtra[];
13
+ image: BubbleMenuExtra | BubbleMenuExtra[];
14
+ }>;
15
+ export type NeuphloEditorProps = {
16
+ content?: string;
17
+ markdown?: boolean;
18
+ className?: string;
19
+ editable?: boolean;
20
+ immediatelyRender?: boolean;
21
+ showTextMenu?: boolean;
22
+ showSlashMenu?: boolean;
23
+ showImageMenu?: boolean;
24
+ showDragHandle?: boolean;
25
+ extensions?: any[];
26
+ bubbleMenuExtras?: BubbleMenuExtras;
27
+ onUpdate?: EditorContentProps["onUpdate"];
28
+ onCreate?: EditorContentProps["onCreate"];
29
+ uploadImage?: (file: File) => Promise<string>;
30
+ browseAssets?: (onSelect: (url: string) => void) => void;
31
+ collaboration?: {
32
+ doc: any;
33
+ field: string;
34
+ awareness?: any;
35
+ };
36
+ mentionOptions?: MentionOptions;
37
+ referenceOptions?: MentionOptions;
38
+ slashCommand?: boolean;
39
+ placeholder?: string;
40
+ taskItemView?: any;
41
+ checkboxComponent?: TaskItemCheckboxComponent;
42
+ };
43
+ export declare function Editor({ content, markdown, className, editable, immediatelyRender, showTextMenu, showSlashMenu, showImageMenu, showDragHandle, extensions, bubbleMenuExtras, onUpdate, onCreate, uploadImage, browseAssets, collaboration, mentionOptions, referenceOptions, slashCommand, placeholder, taskItemView, checkboxComponent, }: NeuphloEditorProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,119 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { EditorRoot, EditorContent, handleCommandNavigation, } from "../headless";
3
+ import ExtensionKit from "../headless/extensions/extension-kit";
4
+ import { markdownToHtml } from "../headless/extensions";
5
+ import { SlashMenu, TextMenu } from "./menus";
6
+ import { ImageMenu } from "./menus/ImageMenu";
7
+ import { LinkMenu } from "./menus/LinkMenu";
8
+ import { ImageBlockView } from "./menus/ImageBlock/ImageBlockView";
9
+ import { VideoBlockView } from "./menus/VideoBlock/VideoBlockView";
10
+ import { createTaskItemView, } from "./menus/TaskItem/TaskItemView";
11
+ import { useMemo, useState, useCallback, useRef, useEffect } from "react";
12
+ import { BlockActionMenu } from "./menus/DragHandle/BlockActionMenu";
13
+ import { TableMenu } from "./menus/TableMenu";
14
+ export function Editor({ content, markdown = false, className, editable = true, immediatelyRender = false, showTextMenu = true, showSlashMenu = true, showImageMenu = false, showDragHandle = true, extensions, bubbleMenuExtras, onUpdate, onCreate, uploadImage, browseAssets, collaboration, mentionOptions, referenceOptions, slashCommand, placeholder, taskItemView, checkboxComponent, }) {
15
+ const resolvedTaskItemView = useMemo(() => {
16
+ if (taskItemView)
17
+ return taskItemView;
18
+ if (checkboxComponent)
19
+ return createTaskItemView(checkboxComponent);
20
+ return undefined;
21
+ }, [taskItemView, checkboxComponent]);
22
+ const resolvedContent = useMemo(() => {
23
+ if (markdown && typeof content === "string")
24
+ return markdownToHtml(content);
25
+ return content;
26
+ }, [markdown, content]);
27
+ const [actionMenuAnchor, setActionMenuAnchor] = useState(null);
28
+ const [actionMenuEditor, setActionMenuEditor] = useState(null);
29
+ const actionMenuRef = useRef(null);
30
+ // Close action menu on click outside
31
+ useEffect(() => {
32
+ if (!actionMenuAnchor)
33
+ return;
34
+ const handlePointerDown = (e) => {
35
+ if (actionMenuRef.current && !actionMenuRef.current.contains(e.target)) {
36
+ setActionMenuAnchor(null);
37
+ }
38
+ };
39
+ document.addEventListener("pointerdown", handlePointerDown);
40
+ return () => document.removeEventListener("pointerdown", handlePointerDown);
41
+ }, [actionMenuAnchor]);
42
+ const dragHandleCallbacks = useMemo(() => ({
43
+ onAddBlock: (editor) => {
44
+ const { state } = editor;
45
+ const { selection } = state;
46
+ const { $anchor } = selection;
47
+ // Find the top-level block node (depth 1) and insert after it
48
+ const topDepth = Math.min($anchor.depth, 1);
49
+ const endOfBlock = $anchor.end(topDepth);
50
+ const insertPos = endOfBlock + 1;
51
+ editor
52
+ .chain()
53
+ .focus()
54
+ .insertContentAt(insertPos, { type: "paragraph" })
55
+ .focus(insertPos + 1)
56
+ .run();
57
+ // Insert "/" to trigger slash command menu after the new paragraph is focused
58
+ requestAnimationFrame(() => {
59
+ editor.commands.insertContent("/");
60
+ });
61
+ },
62
+ onGripClick: (editor, _node, element) => {
63
+ setActionMenuEditor(editor);
64
+ setActionMenuAnchor((prev) => (prev === element ? null : element));
65
+ },
66
+ }), []);
67
+ const enableDragHandle = showDragHandle && editable;
68
+ const normalizeExtras = (extras) => {
69
+ const result = {
70
+ start: [],
71
+ end: [],
72
+ };
73
+ if (!extras)
74
+ return result;
75
+ const list = Array.isArray(extras) ? extras : [extras];
76
+ list.forEach((item) => {
77
+ const config = typeof item === "function"
78
+ ? { render: item, align: "end" }
79
+ : item;
80
+ const slot = config.align === "start" ? "start" : "end";
81
+ result[slot].push(config.render);
82
+ });
83
+ return result;
84
+ };
85
+ const textExtras = normalizeExtras(bubbleMenuExtras?.text);
86
+ const imageExtras = normalizeExtras(bubbleMenuExtras?.image);
87
+ const handleCloseActionMenu = useCallback(() => {
88
+ setActionMenuAnchor(null);
89
+ }, []);
90
+ return (_jsxs("div", { className: className, children: [_jsx(EditorRoot, { children: _jsxs(EditorContent, { onUpdate: onUpdate, onCreate: onCreate, immediatelyRender: immediatelyRender, editable: editable, content: resolvedContent, extensions: [
91
+ ...ExtensionKit({
92
+ uploadImage: uploadImage,
93
+ browseAssets: browseAssets,
94
+ collaboration: collaboration,
95
+ imageBlockView: ImageBlockView,
96
+ videoBlockView: VideoBlockView,
97
+ taskItemView: resolvedTaskItemView,
98
+ mention: mentionOptions,
99
+ reference: referenceOptions,
100
+ slashCommand: slashCommand,
101
+ dragHandle: enableDragHandle,
102
+ dragHandleCallbacks: enableDragHandle ? dragHandleCallbacks : undefined,
103
+ placeholder: placeholder,
104
+ }),
105
+ ...(extensions ?? []),
106
+ ], editorProps: {
107
+ attributes: {
108
+ class: "nph-editor max-w-none outline-none",
109
+ },
110
+ handleKeyDown: (view, event) => {
111
+ return !!handleCommandNavigation?.(event);
112
+ },
113
+ }, children: [showTextMenu ? (_jsx(TextMenu, { leadingExtras: textExtras.start, trailingExtras: textExtras.end })) : null, showImageMenu ? (_jsx(ImageMenu, { leadingExtras: imageExtras.start, trailingExtras: imageExtras.end })) : null, _jsx(LinkMenu, {}), _jsx(TableMenu, {}), showSlashMenu ? _jsx(SlashMenu, {}) : null] }) }), actionMenuAnchor && actionMenuEditor && (_jsx("div", { ref: actionMenuRef, style: {
114
+ position: "fixed",
115
+ zIndex: 10000,
116
+ top: actionMenuAnchor.getBoundingClientRect().bottom + 4,
117
+ left: actionMenuAnchor.getBoundingClientRect().left,
118
+ }, children: _jsx(BlockActionMenu, { editor: actionMenuEditor, onClose: handleCloseActionMenu }) }))] }));
119
+ }
@@ -0,0 +1,7 @@
1
+ export type TableOfContentsProps = {
2
+ className?: string;
3
+ itemClassName?: string;
4
+ activeClassName?: string;
5
+ };
6
+ export declare function TableOfContents({ className, itemClassName, activeClassName, }: TableOfContentsProps): import("react/jsx-runtime").JSX.Element | null;
7
+ export default TableOfContents;
@@ -0,0 +1,96 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useCurrentEditor, useEditorState } from "@tiptap/react";
3
+ import { useCallback, useEffect, useRef, useState } from "react";
4
+ export function TableOfContents({ className, itemClassName, activeClassName, }) {
5
+ const { editor } = useCurrentEditor();
6
+ const [activeId, setActiveId] = useState(null);
7
+ const observerRef = useRef(null);
8
+ const headings = useEditorState({
9
+ editor,
10
+ selector: (ctx) => {
11
+ if (!ctx.editor)
12
+ return [];
13
+ const items = [];
14
+ ctx.editor.state.doc.descendants((node, pos) => {
15
+ if (node.type.name === "heading") {
16
+ const id = `heading-${pos}`;
17
+ items.push({
18
+ id,
19
+ level: node.attrs.level,
20
+ text: node.textContent,
21
+ pos,
22
+ });
23
+ }
24
+ });
25
+ return items;
26
+ },
27
+ });
28
+ // Set up IntersectionObserver to track which heading is in view
29
+ useEffect(() => {
30
+ if (!editor || !headings || headings.length === 0)
31
+ return;
32
+ // Clean up old observer
33
+ observerRef.current?.disconnect();
34
+ const callback = (entries) => {
35
+ // Find the first visible heading
36
+ const visibleEntries = entries.filter((e) => e.isIntersecting);
37
+ if (visibleEntries.length > 0) {
38
+ const firstVisible = visibleEntries[0];
39
+ const id = firstVisible.target.getAttribute("data-toc-id");
40
+ if (id)
41
+ setActiveId(id);
42
+ }
43
+ };
44
+ const observer = new IntersectionObserver(callback, {
45
+ rootMargin: "-80px 0px -70% 0px",
46
+ threshold: 0,
47
+ });
48
+ observerRef.current = observer;
49
+ // Observe heading DOM elements
50
+ const editorEl = editor.view.dom;
51
+ headings.forEach((heading) => {
52
+ // Find heading element by position
53
+ try {
54
+ const domNode = editor.view.nodeDOM(heading.pos);
55
+ if (domNode && domNode instanceof HTMLElement) {
56
+ domNode.setAttribute("data-toc-id", heading.id);
57
+ observer.observe(domNode);
58
+ }
59
+ }
60
+ catch {
61
+ // Position may be invalid after edits
62
+ }
63
+ });
64
+ return () => {
65
+ observer.disconnect();
66
+ };
67
+ }, [editor, headings]);
68
+ const handleClick = useCallback((pos) => {
69
+ if (!editor)
70
+ return;
71
+ editor.chain().focus().setTextSelection(pos + 1).run();
72
+ // Scroll into view
73
+ try {
74
+ const domNode = editor.view.nodeDOM(pos);
75
+ if (domNode && domNode instanceof HTMLElement) {
76
+ domNode.scrollIntoView({ behavior: "smooth", block: "start" });
77
+ }
78
+ }
79
+ catch {
80
+ // Ignore if DOM node not found
81
+ }
82
+ }, [editor]);
83
+ if (!editor || !headings || headings.length === 0)
84
+ return null;
85
+ return (_jsx("nav", { className: className ?? "nph-toc", children: headings.map((heading) => {
86
+ const isActive = activeId === heading.id;
87
+ const itemClass = [
88
+ itemClassName ?? "nph-toc__item",
89
+ isActive ? (activeClassName ?? "nph-toc__item--active") : "",
90
+ ]
91
+ .filter(Boolean)
92
+ .join(" ");
93
+ return (_jsx("button", { type: "button", className: itemClass, style: { paddingLeft: `${(heading.level - 1) * 12 + 8}px` }, onClick: () => handleClick(heading.pos), title: heading.text, children: heading.text || `Heading ${heading.level}` }, heading.id));
94
+ }) }));
95
+ }
96
+ export default TableOfContents;
@@ -32,8 +32,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
32
32
  var react_exports = {};
33
33
  __export(react_exports, {
34
34
  Editor: () => Editor5,
35
+ Markdown: () => Markdown,
35
36
  TableOfContents: () => TableOfContents,
36
- TextMenu: () => TextMenu
37
+ TextMenu: () => TextMenu,
38
+ markdownToHtml: () => markdownToHtml
37
39
  });
38
40
  module.exports = __toCommonJS(react_exports);
39
41
 
@@ -1288,10 +1290,147 @@ var MarkdownPaste = import_core3.Extension.create({
1288
1290
  }
1289
1291
  });
1290
1292
 
1293
+ // src/headless/extensions/Markdown.ts
1294
+ var import_core4 = require("@tiptap/core");
1295
+ var import_markdown2 = require("@tiptap/pm/markdown");
1296
+ var import_model = require("@tiptap/pm/model");
1297
+ var import_markdown_it = __toESM(require("markdown-it"), 1);
1298
+ var markdownIt = new import_markdown_it.default({ html: true, linkify: false, breaks: false });
1299
+ function markdownToHtml(input) {
1300
+ if (!input) return "";
1301
+ return markdownIt.render(input);
1302
+ }
1303
+ function nodeToHtml(node, schema) {
1304
+ if (typeof document === "undefined") return "";
1305
+ const dom = import_model.DOMSerializer.fromSchema(schema).serializeNode(node);
1306
+ const container = document.createElement("div");
1307
+ container.appendChild(dom);
1308
+ return container.innerHTML;
1309
+ }
1310
+ var specificNodes = {
1311
+ text: (state, node) => {
1312
+ state.text(node.text ?? "");
1313
+ },
1314
+ paragraph: (state, node) => {
1315
+ state.renderInline(node);
1316
+ state.closeBlock(node);
1317
+ },
1318
+ heading: (state, node) => {
1319
+ state.write(`${state.repeat("#", node.attrs.level)} `);
1320
+ state.renderInline(node);
1321
+ state.closeBlock(node);
1322
+ },
1323
+ blockquote: (state, node) => {
1324
+ state.wrapBlock("> ", null, node, () => state.renderContent(node));
1325
+ },
1326
+ horizontalRule: (state, node) => {
1327
+ state.write(node.attrs.markup || "---");
1328
+ state.closeBlock(node);
1329
+ },
1330
+ bulletList: (state, node) => {
1331
+ state.renderList(node, " ", () => `${node.attrs.bullet || "-"} `);
1332
+ },
1333
+ orderedList: (state, node) => {
1334
+ const start = node.attrs.start || 1;
1335
+ const maxWidth = String(start + node.childCount - 1).length;
1336
+ const space = state.repeat(" ", maxWidth + 2);
1337
+ state.renderList(node, space, (index) => {
1338
+ const label = String(start + index);
1339
+ return `${state.repeat(" ", maxWidth - label.length)}${label}. `;
1340
+ });
1341
+ },
1342
+ listItem: (state, node) => {
1343
+ state.renderContent(node);
1344
+ },
1345
+ codeBlock: (state, node) => {
1346
+ state.write(`\`\`\`${node.attrs.language || ""}
1347
+ `);
1348
+ state.text(node.textContent, false);
1349
+ state.ensureNewLine();
1350
+ state.write("```");
1351
+ state.closeBlock(node);
1352
+ },
1353
+ hardBreak: (state, node, parent, index) => {
1354
+ for (let i = index + 1; i < parent.childCount; i += 1) {
1355
+ if (parent.child(i).type !== node.type) {
1356
+ state.write("\\\n");
1357
+ return;
1358
+ }
1359
+ }
1360
+ }
1361
+ };
1362
+ var inlineHtmlNodes = /* @__PURE__ */ new Set(["mention", "reference"]);
1363
+ var specificMarks = {
1364
+ bold: { open: "**", close: "**", mixable: true, expelEnclosingWhitespace: true },
1365
+ italic: { open: "*", close: "*", mixable: true, expelEnclosingWhitespace: true },
1366
+ strike: { open: "~~", close: "~~", mixable: true, expelEnclosingWhitespace: true },
1367
+ underline: { open: "<u>", close: "</u>", mixable: true },
1368
+ code: { open: "`", close: "`", escape: false },
1369
+ link: {
1370
+ open: "[",
1371
+ close: (_state, mark) => {
1372
+ const href = mark.attrs.href || "";
1373
+ const title = mark.attrs.title ? ` "${mark.attrs.title}"` : "";
1374
+ return `](${href}${title})`;
1375
+ }
1376
+ }
1377
+ };
1378
+ function buildSerializer(schema) {
1379
+ const nodes = {};
1380
+ for (const name of Object.keys(schema.nodes)) {
1381
+ if (specificNodes[name]) {
1382
+ nodes[name] = specificNodes[name];
1383
+ continue;
1384
+ }
1385
+ const type = schema.nodes[name];
1386
+ if (type.isText) {
1387
+ nodes[name] = specificNodes.text;
1388
+ continue;
1389
+ }
1390
+ if (type.isInline || inlineHtmlNodes.has(name)) {
1391
+ nodes[name] = (state, node) => {
1392
+ state.text(nodeToHtml(node, schema), false);
1393
+ };
1394
+ continue;
1395
+ }
1396
+ nodes[name] = (state, node) => {
1397
+ state.write(nodeToHtml(node, schema));
1398
+ state.closeBlock(node);
1399
+ };
1400
+ }
1401
+ const marks = {};
1402
+ for (const name of Object.keys(schema.marks)) {
1403
+ marks[name] = specificMarks[name] || { open: "", close: "", mixable: true };
1404
+ }
1405
+ return new import_markdown2.MarkdownSerializer(nodes, marks);
1406
+ }
1407
+ var Markdown = import_core4.Extension.create({
1408
+ name: "markdown",
1409
+ addStorage() {
1410
+ return {
1411
+ serializer: null,
1412
+ getMarkdown: () => ""
1413
+ };
1414
+ },
1415
+ onBeforeCreate() {
1416
+ const storage = this.storage;
1417
+ storage.serializer = buildSerializer(this.editor.schema);
1418
+ storage.getMarkdown = () => {
1419
+ try {
1420
+ return storage.serializer.serialize(this.editor.state.doc, {
1421
+ tightLists: true
1422
+ });
1423
+ } catch {
1424
+ return this.editor.getHTML();
1425
+ }
1426
+ };
1427
+ }
1428
+ });
1429
+
1291
1430
  // src/headless/extensions/slash-command.tsx
1292
1431
  var import_suggestion = __toESM(require("@tiptap/suggestion"), 1);
1293
- var import_core4 = require("@tiptap/core");
1294
- var Command = import_core4.Extension.create({
1432
+ var import_core5 = require("@tiptap/core");
1433
+ var Command = import_core5.Extension.create({
1295
1434
  name: "slash-command",
1296
1435
  addOptions() {
1297
1436
  return {
@@ -1388,9 +1527,9 @@ var import_extension_list = require("@tiptap/extension-list");
1388
1527
  var import_react12 = require("@tiptap/react");
1389
1528
 
1390
1529
  // src/headless/extensions/VideoBlock/VideoBlock.ts
1391
- var import_core5 = require("@tiptap/core");
1530
+ var import_core6 = require("@tiptap/core");
1392
1531
  var import_react11 = require("@tiptap/react");
1393
- var VideoBlock = import_core5.Node.create({
1532
+ var VideoBlock = import_core6.Node.create({
1394
1533
  name: "videoBlock",
1395
1534
  group: "block",
1396
1535
  defining: true,
@@ -1436,7 +1575,7 @@ var VideoBlock = import_core5.Node.create({
1436
1575
  renderHTML({ HTMLAttributes }) {
1437
1576
  return [
1438
1577
  "div",
1439
- (0, import_core5.mergeAttributes)(HTMLAttributes, { "data-type": "video-block" })
1578
+ (0, import_core6.mergeAttributes)(HTMLAttributes, { "data-type": "video-block" })
1440
1579
  ];
1441
1580
  },
1442
1581
  addCommands() {
@@ -1506,7 +1645,8 @@ var ExtensionKit = (options) => {
1506
1645
  },
1507
1646
  includeChildren: true
1508
1647
  }),
1509
- MarkdownPaste
1648
+ MarkdownPaste,
1649
+ Markdown
1510
1650
  ];
1511
1651
  if (options?.table !== false) {
1512
1652
  extensions.push(
@@ -4076,6 +4216,7 @@ var import_react37 = require("react");
4076
4216
  var import_jsx_runtime22 = require("react/jsx-runtime");
4077
4217
  function Editor5({
4078
4218
  content,
4219
+ markdown = false,
4079
4220
  className,
4080
4221
  editable = true,
4081
4222
  immediatelyRender = false,
@@ -4102,6 +4243,10 @@ function Editor5({
4102
4243
  if (checkboxComponent) return createTaskItemView(checkboxComponent);
4103
4244
  return void 0;
4104
4245
  }, [taskItemView, checkboxComponent]);
4246
+ const resolvedContent = (0, import_react37.useMemo)(() => {
4247
+ if (markdown && typeof content === "string") return markdownToHtml(content);
4248
+ return content;
4249
+ }, [markdown, content]);
4105
4250
  const [actionMenuAnchor, setActionMenuAnchor] = (0, import_react37.useState)(null);
4106
4251
  const [actionMenuEditor, setActionMenuEditor] = (0, import_react37.useState)(null);
4107
4252
  const actionMenuRef = (0, import_react37.useRef)(null);
@@ -4164,7 +4309,7 @@ function Editor5({
4164
4309
  onCreate,
4165
4310
  immediatelyRender,
4166
4311
  editable,
4167
- content,
4312
+ content: resolvedContent,
4168
4313
  extensions: [
4169
4314
  ...extension_kit_default({
4170
4315
  uploadImage,
@@ -4333,7 +4478,9 @@ function TableOfContents({
4333
4478
  // Annotate the CommonJS export names for ESM import in node:
4334
4479
  0 && (module.exports = {
4335
4480
  Editor,
4481
+ Markdown,
4336
4482
  TableOfContents,
4337
- TextMenu
4483
+ TextMenu,
4484
+ markdownToHtml
4338
4485
  });
4339
4486
  //# sourceMappingURL=index.cjs.map