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
@@ -0,0 +1,218 @@
1
+ import { ReactRenderer, ReactNodeViewRenderer } from "@tiptap/react";
2
+ import Mention from "@tiptap/extension-mention";
3
+ import { MentionCommand } from "./mention-command";
4
+ import { MentionNodeView } from "./mention-node-view";
5
+ /**
6
+ * Create the mention extension with custom suggestion rendering
7
+ */
8
+ export const createMentionExtension = (options) => {
9
+ const extensionName = options?.name ?? "mention";
10
+ return Mention.extend({
11
+ name: extensionName,
12
+ addAttributes() {
13
+ return {
14
+ id: {
15
+ default: null,
16
+ parseHTML: (element) => element.getAttribute("data-id"),
17
+ renderHTML: (attributes) => {
18
+ if (!attributes.id) {
19
+ return {};
20
+ }
21
+ return {
22
+ "data-id": attributes.id,
23
+ };
24
+ },
25
+ },
26
+ label: {
27
+ default: null,
28
+ parseHTML: (element) => element.getAttribute("data-label"),
29
+ renderHTML: (attributes) => {
30
+ if (!attributes.label) {
31
+ return {};
32
+ }
33
+ return {
34
+ "data-label": attributes.label,
35
+ };
36
+ },
37
+ },
38
+ avatar: {
39
+ default: null,
40
+ parseHTML: (element) => element.getAttribute("data-avatar"),
41
+ renderHTML: (attributes) => {
42
+ if (!attributes.avatar) {
43
+ return {};
44
+ }
45
+ return {
46
+ "data-avatar": attributes.avatar,
47
+ };
48
+ },
49
+ },
50
+ type: {
51
+ default: null,
52
+ parseHTML: (element) => element.getAttribute("data-ref-type"),
53
+ renderHTML: (attributes) => {
54
+ if (!attributes.type) {
55
+ return {};
56
+ }
57
+ return {
58
+ "data-ref-type": attributes.type,
59
+ };
60
+ },
61
+ },
62
+ nodeId: {
63
+ default: null,
64
+ parseHTML: (element) => element.getAttribute("data-node-id"),
65
+ renderHTML: (attributes) => {
66
+ if (!attributes.nodeId) {
67
+ return {};
68
+ }
69
+ return {
70
+ "data-node-id": attributes.nodeId,
71
+ };
72
+ },
73
+ },
74
+ slug: {
75
+ default: null,
76
+ parseHTML: (element) => element.getAttribute("data-slug"),
77
+ renderHTML: (attributes) => {
78
+ if (!attributes.slug) {
79
+ return {};
80
+ }
81
+ return {
82
+ "data-slug": attributes.slug,
83
+ };
84
+ },
85
+ },
86
+ };
87
+ },
88
+ addNodeView() {
89
+ return ReactNodeViewRenderer(MentionNodeView);
90
+ },
91
+ }).configure({
92
+ HTMLAttributes: {
93
+ class: "mention",
94
+ },
95
+ suggestion: {
96
+ char: options?.char ?? "@",
97
+ items: async ({ query }) => {
98
+ if (!options?.items)
99
+ return [];
100
+ const items = await options.items(query);
101
+ return items;
102
+ },
103
+ command: ({ editor, range, props: item }) => {
104
+ editor
105
+ .chain()
106
+ .focus()
107
+ .insertContentAt(range, [
108
+ {
109
+ type: extensionName,
110
+ attrs: {
111
+ id: item.id,
112
+ label: item.label,
113
+ avatar: item.avatar,
114
+ type: item.type,
115
+ nodeId: item.nodeId,
116
+ slug: item.slug,
117
+ },
118
+ },
119
+ { type: "text", text: " " },
120
+ ])
121
+ .run();
122
+ },
123
+ render: renderMentionSuggestion,
124
+ },
125
+ renderLabel: options?.renderLabel ?? ((props) => {
126
+ return `@${props.node.attrs.label ?? props.node.attrs.id}`;
127
+ }),
128
+ });
129
+ };
130
+ /**
131
+ * Render function for mention suggestions (autocomplete dropdown)
132
+ */
133
+ export const renderMentionSuggestion = () => {
134
+ let component = null;
135
+ let container = null;
136
+ const destroy = () => {
137
+ component?.destroy();
138
+ component = null;
139
+ if (container) {
140
+ container.remove();
141
+ container = null;
142
+ }
143
+ };
144
+ const updatePosition = (clientRect) => {
145
+ if (!container || !clientRect)
146
+ return;
147
+ const gap = 8;
148
+ const maxDropdownHeight = 300; // Match the maxHeight from MentionCommand
149
+ const spaceBelow = window.innerHeight - clientRect.bottom;
150
+ const spaceAbove = clientRect.top;
151
+ // Position above if not enough space below, otherwise position below
152
+ const shouldPositionAbove = spaceBelow < maxDropdownHeight && spaceAbove > spaceBelow;
153
+ const left = Math.round(clientRect.left);
154
+ if (shouldPositionAbove) {
155
+ const bottom = Math.round(window.innerHeight - clientRect.top + gap);
156
+ container.style.bottom = `${bottom}px`;
157
+ container.style.top = 'auto';
158
+ }
159
+ else {
160
+ const top = Math.round(clientRect.bottom + gap);
161
+ container.style.top = `${top}px`;
162
+ container.style.bottom = 'auto';
163
+ }
164
+ container.style.left = `${left}px`;
165
+ };
166
+ return {
167
+ onStart: (props) => {
168
+ component = new ReactRenderer(MentionCommand, {
169
+ props: {
170
+ items: props.items ?? [],
171
+ command: props.command ?? (() => { }),
172
+ query: props.query ?? "",
173
+ },
174
+ editor: props.editor,
175
+ });
176
+ container = document.createElement("div");
177
+ container.style.position = "fixed";
178
+ container.style.zIndex = "9999";
179
+ document.body.appendChild(container);
180
+ container.appendChild(component.element);
181
+ const rect = typeof props.clientRect === "function" ? props.clientRect() : null;
182
+ if (rect)
183
+ updatePosition(rect);
184
+ },
185
+ onUpdate: (props) => {
186
+ component?.updateProps({
187
+ items: props.items ?? [],
188
+ command: props.command ?? (() => { }),
189
+ query: props.query ?? "",
190
+ });
191
+ const rect = typeof props.clientRect === "function" ? props.clientRect() : null;
192
+ if (rect)
193
+ updatePosition(rect);
194
+ },
195
+ onKeyDown: ({ event }) => {
196
+ if (!component)
197
+ return false;
198
+ if (event.key === "Escape") {
199
+ event.preventDefault();
200
+ event.stopPropagation();
201
+ destroy();
202
+ return true;
203
+ }
204
+ // Handle arrow keys and enter
205
+ if (["ArrowUp", "ArrowDown", "Enter"].includes(event.key)) {
206
+ event.preventDefault();
207
+ event.stopPropagation();
208
+ // Let the MentionList component handle keyboard navigation
209
+ return component.ref?.onKeyDown?.({ event }) ?? false;
210
+ }
211
+ return false;
212
+ },
213
+ onExit: () => {
214
+ destroy();
215
+ },
216
+ };
217
+ };
218
+ export default createMentionExtension;
@@ -0,0 +1,2 @@
1
+ export { TableKit } from "@tiptap/extension-table";
2
+ export { Table, TableCell, TableHeader, TableRow } from "@tiptap/extension-table";
@@ -0,0 +1,2 @@
1
+ export { TableKit } from "@tiptap/extension-table";
2
+ export { Table, TableCell, TableHeader, TableRow } from "@tiptap/extension-table";
@@ -0,0 +1,17 @@
1
+ import { Node } from "@tiptap/core";
2
+ export interface VideoBlockOptions {
3
+ nodeView?: any;
4
+ }
5
+ declare module "@tiptap/core" {
6
+ interface Commands<ReturnType> {
7
+ videoBlock: {
8
+ setVideoBlock: (attributes: {
9
+ src: string;
10
+ }) => ReturnType;
11
+ setVideoBlockAlign: (align: "left" | "center" | "right") => ReturnType;
12
+ setVideoBlockWidth: (width: number) => ReturnType;
13
+ };
14
+ }
15
+ }
16
+ export declare const VideoBlock: Node<VideoBlockOptions, any>;
17
+ export default VideoBlock;
@@ -0,0 +1,73 @@
1
+ import { mergeAttributes, Node } from "@tiptap/core";
2
+ import { ReactNodeViewRenderer } from "@tiptap/react";
3
+ export const VideoBlock = Node.create({
4
+ name: "videoBlock",
5
+ group: "block",
6
+ defining: true,
7
+ isolating: true,
8
+ atom: true,
9
+ addOptions() {
10
+ return {
11
+ nodeView: undefined,
12
+ };
13
+ },
14
+ addAttributes() {
15
+ return {
16
+ src: {
17
+ default: "",
18
+ parseHTML: (element) => element.getAttribute("data-src"),
19
+ renderHTML: (attributes) => ({
20
+ "data-src": attributes.src,
21
+ }),
22
+ },
23
+ width: {
24
+ default: "100%",
25
+ parseHTML: (element) => element.getAttribute("data-width"),
26
+ renderHTML: (attributes) => ({
27
+ "data-width": attributes.width,
28
+ }),
29
+ },
30
+ align: {
31
+ default: "center",
32
+ parseHTML: (element) => element.getAttribute("data-align"),
33
+ renderHTML: (attributes) => ({
34
+ "data-align": attributes.align,
35
+ }),
36
+ },
37
+ };
38
+ },
39
+ parseHTML() {
40
+ return [
41
+ {
42
+ tag: 'div[data-type="video-block"]',
43
+ },
44
+ ];
45
+ },
46
+ renderHTML({ HTMLAttributes }) {
47
+ return [
48
+ "div",
49
+ mergeAttributes(HTMLAttributes, { "data-type": "video-block" }),
50
+ ];
51
+ },
52
+ addCommands() {
53
+ return {
54
+ setVideoBlock: (attrs) => ({ commands }) => {
55
+ return commands.insertContent({
56
+ type: "videoBlock",
57
+ attrs: { src: attrs.src },
58
+ });
59
+ },
60
+ setVideoBlockAlign: (align) => ({ commands }) => commands.updateAttributes("videoBlock", { align }),
61
+ setVideoBlockWidth: (width) => ({ commands }) => commands.updateAttributes("videoBlock", {
62
+ width: `${Math.max(0, Math.min(100, width))}%`,
63
+ }),
64
+ };
65
+ },
66
+ addNodeView() {
67
+ if (this.options.nodeView) {
68
+ return ReactNodeViewRenderer(this.options.nodeView);
69
+ }
70
+ return undefined;
71
+ },
72
+ });
73
+ export default VideoBlock;
@@ -0,0 +1,2 @@
1
+ export { VideoBlock } from "./VideoBlock";
2
+ export type { VideoBlockOptions } from "./VideoBlock";
@@ -0,0 +1 @@
1
+ export { VideoBlock } from "./VideoBlock";
@@ -0,0 +1,29 @@
1
+ import type { MentionOptions } from "./Mention";
2
+ import type { DragHandleCallbacks } from "./DragHandle";
3
+ export interface ExtensionKitOptions {
4
+ uploadImage?: (file: File) => Promise<string>;
5
+ browseAssets?: (onSelect: (url: string) => void) => void;
6
+ collaboration?: {
7
+ doc: any;
8
+ field: string;
9
+ awareness?: any;
10
+ provider?: any;
11
+ user?: {
12
+ name: string;
13
+ color: string;
14
+ [key: string]: any;
15
+ };
16
+ };
17
+ imageBlockView?: any;
18
+ videoBlockView?: any;
19
+ taskItemView?: any;
20
+ mention?: MentionOptions;
21
+ reference?: MentionOptions;
22
+ slashCommand?: boolean;
23
+ dragHandle?: boolean;
24
+ dragHandleCallbacks?: DragHandleCallbacks;
25
+ table?: boolean;
26
+ placeholder?: string;
27
+ }
28
+ export declare const ExtensionKit: (options?: ExtensionKitOptions) => (import("@tiptap/core").Node<import("@tiptap/extension-code-block-lowlight").CodeBlockLowlightOptions, any> | import("@tiptap/core").Mark<import("@tiptap/extension-link").LinkOptions, any> | import("@tiptap/core").Node<import("./ImageBlock").ImageBlockOptions, any> | import("@tiptap/core").Extension<any, any> | import("@tiptap/core").Extension<any, import("./Markdown").MarkdownStorage> | import("@tiptap/core").Node<import("./VideoBlock").VideoBlockOptions, any> | import("@tiptap/core").Node<import("@tiptap/extension-list").TaskItemOptions, any> | import("@tiptap/core").Extension<import("@tiptap/starter-kit").StarterKitOptions, any> | import("@tiptap/core").Mark<import("@tiptap/extension-underline").UnderlineOptions, any> | import("@tiptap/core").Node<import("@tiptap/extension-list").TaskListOptions, any> | import("@tiptap/core").Extension<import("@tiptap/extensions").PlaceholderOptions, any>)[];
29
+ export default ExtensionKit;
@@ -0,0 +1,132 @@
1
+ import Collaboration from "@tiptap/extension-collaboration";
2
+ import CollaborationCaret from "@tiptap/extension-collaboration-caret";
3
+ import { StarterKit, Placeholder, CodeBlock, Link } from ".";
4
+ import Underline from "@tiptap/extension-underline";
5
+ import { TaskList, TaskItem as BaseTaskItem } from "@tiptap/extension-list";
6
+ import { ReactNodeViewRenderer } from "@tiptap/react";
7
+ const TaskItem = BaseTaskItem.extend({
8
+ addOptions() {
9
+ return {
10
+ ...this.parent?.(),
11
+ nodeView: null,
12
+ };
13
+ },
14
+ addNodeView() {
15
+ const custom = this.options.nodeView;
16
+ if (custom) {
17
+ return ReactNodeViewRenderer(custom);
18
+ }
19
+ return this.parent?.();
20
+ },
21
+ });
22
+ import { Command as SlashCommand, } from "./slash-command";
23
+ import { ImageBlock } from "./ImageBlock/ImageBlock";
24
+ import { VideoBlock } from "./VideoBlock/VideoBlock";
25
+ import { createMentionExtension } from "./Mention";
26
+ import { DragHandle, setDragHandleCallbacks } from "./DragHandle";
27
+ import { TableKit } from "./Table";
28
+ import { MarkdownPaste } from "./MarkdownPaste";
29
+ import { Markdown } from "./Markdown";
30
+ export const ExtensionKit = (options) => {
31
+ const enableSlashCommand = options?.slashCommand !== false; // Default to true
32
+ const extensions = [
33
+ StarterKit.configure({ codeBlock: false, link: false }),
34
+ CodeBlock,
35
+ Link,
36
+ Underline,
37
+ TaskList,
38
+ TaskItem.configure({ nested: true, nodeView: options?.taskItemView }),
39
+ ImageBlock.configure({
40
+ uploadImage: options?.uploadImage,
41
+ browseAssets: options?.browseAssets,
42
+ nodeView: options?.imageBlockView,
43
+ }),
44
+ VideoBlock.configure({
45
+ nodeView: options?.videoBlockView,
46
+ }),
47
+ Placeholder.configure({
48
+ placeholder: ({ node }) => {
49
+ if (node.type.name === "heading") {
50
+ return `Heading ${node.attrs.level}`;
51
+ }
52
+ // Use custom placeholder if provided, otherwise show slash command hint if enabled
53
+ if (options?.placeholder) {
54
+ return options.placeholder;
55
+ }
56
+ return enableSlashCommand ? "Press '/' for commands" : "";
57
+ },
58
+ includeChildren: true,
59
+ }),
60
+ MarkdownPaste,
61
+ Markdown,
62
+ ];
63
+ // Add Table support if enabled
64
+ if (options?.table !== false) {
65
+ extensions.push(TableKit.configure({
66
+ resizable: true,
67
+ lastColumnResizable: true,
68
+ allowTableNodeSelection: true,
69
+ }));
70
+ }
71
+ // Add DragHandle if enabled
72
+ if (options?.dragHandle !== false) {
73
+ extensions.push(DragHandle);
74
+ if (options?.dragHandleCallbacks) {
75
+ setDragHandleCallbacks(options.dragHandleCallbacks);
76
+ }
77
+ }
78
+ // Add SlashCommand if enabled
79
+ if (enableSlashCommand) {
80
+ extensions.push(SlashCommand.configure({
81
+ suggestion: {
82
+ char: "/",
83
+ allowSpaces: true,
84
+ allowedPrefixes: null,
85
+ },
86
+ }));
87
+ }
88
+ // Add Mention extension if configured
89
+ if (options?.mention) {
90
+ const mentionExt = createMentionExtension(options.mention);
91
+ extensions.push(mentionExt);
92
+ }
93
+ // Add Reference extension if configured (uses same Mention extension with different config)
94
+ if (options?.reference) {
95
+ const referenceExt = createMentionExtension({
96
+ ...options.reference,
97
+ name: "reference", // Use unique name to avoid conflicts
98
+ });
99
+ extensions.push(referenceExt);
100
+ }
101
+ if (options?.collaboration?.doc) {
102
+ extensions.push(Collaboration.configure({
103
+ document: options.collaboration.doc,
104
+ field: options.collaboration.field,
105
+ }));
106
+ // Add collaboration carets if provider and user are available
107
+ if (options.collaboration.provider && options.collaboration.user) {
108
+ extensions.push(CollaborationCaret.configure({
109
+ provider: options.collaboration.provider,
110
+ user: options.collaboration.user,
111
+ render: (user) => {
112
+ const cursor = document.createElement("span");
113
+ cursor.classList.add("nph-collab-caret");
114
+ cursor.setAttribute("style", `border-color: ${user.color || "#3b82f6"}`);
115
+ const label = document.createElement("div");
116
+ label.classList.add("nph-collab-caret__label");
117
+ label.setAttribute("style", `background-color: ${user.color || "#3b82f6"}`);
118
+ label.insertBefore(document.createTextNode(user.name || "Anonymous"), null);
119
+ cursor.insertBefore(label, null);
120
+ return cursor;
121
+ },
122
+ selectionRender: (user) => ({
123
+ nodeName: "span",
124
+ class: "nph-collab-selection",
125
+ style: `background-color: ${user.color || "#3b82f6"}20`,
126
+ }),
127
+ }));
128
+ }
129
+ }
130
+ return extensions;
131
+ };
132
+ export default ExtensionKit;
@@ -0,0 +1,16 @@
1
+ export { StarterKit } from "@tiptap/starter-kit";
2
+ export { Placeholder } from "@tiptap/extension-placeholder";
3
+ export { CodeBlock } from "./CodeBlock";
4
+ export { Link } from "./Link";
5
+ export { ImageBlock } from "./ImageBlock";
6
+ export type { ImageBlockOptions } from "./ImageBlock";
7
+ export { AISuggestion, AISuggestionPluginKey } from "./AISuggestion";
8
+ export type { AISuggestionOptions } from "./AISuggestion";
9
+ export { createMentionExtension, renderMentionSuggestion, MentionCommand } from "./Mention";
10
+ export type { MentionItem, MentionOptions } from "./Mention";
11
+ export { DragHandle, setDragHandleCallbacks } from "./DragHandle";
12
+ export type { DragHandleCallbacks } from "./DragHandle";
13
+ export { TableKit, Table, TableCell, TableHeader, TableRow } from "./Table";
14
+ export { MarkdownPaste } from "./MarkdownPaste";
15
+ export { Markdown, markdownToHtml } from "./Markdown";
16
+ export type { MarkdownStorage } from "./Markdown";
@@ -0,0 +1,12 @@
1
+ export { StarterKit } from "@tiptap/starter-kit";
2
+ export { Placeholder } from "@tiptap/extension-placeholder";
3
+ // Custom
4
+ export { CodeBlock } from "./CodeBlock";
5
+ export { Link } from "./Link";
6
+ export { ImageBlock } from "./ImageBlock";
7
+ export { AISuggestion, AISuggestionPluginKey } from "./AISuggestion";
8
+ export { createMentionExtension, renderMentionSuggestion, MentionCommand } from "./Mention";
9
+ export { DragHandle, setDragHandleCallbacks } from "./DragHandle";
10
+ export { TableKit, Table, TableCell, TableHeader, TableRow } from "./Table";
11
+ export { MarkdownPaste } from "./MarkdownPaste";
12
+ export { Markdown, markdownToHtml } from "./Markdown";
@@ -0,0 +1,24 @@
1
+ import { Extension } from "@tiptap/core";
2
+ import type { ReactNode } from "react";
3
+ export declare const Command: Extension<any, any>;
4
+ export declare const renderItems: () => {
5
+ onStart: () => void;
6
+ onUpdate: () => void;
7
+ onKeyDown: () => boolean;
8
+ onExit: () => void;
9
+ };
10
+ export interface SuggestionItem {
11
+ title: string;
12
+ description: string;
13
+ icon: ReactNode;
14
+ searchTerms?: string[];
15
+ command?: (props: {
16
+ editor: any;
17
+ range: {
18
+ from: number;
19
+ to: number;
20
+ };
21
+ }) => void;
22
+ }
23
+ export declare const createSuggestionItems: (items: SuggestionItem[]) => SuggestionItem[];
24
+ export declare const handleCommandNavigation: (event: KeyboardEvent) => true | undefined;
@@ -0,0 +1,99 @@
1
+ import Suggestion from "@tiptap/suggestion";
2
+ import { Extension } from "@tiptap/core";
3
+ import { queryAtom, rangeAtom, slashMenuOpenAtom, slashMenuRectAtom } from "../utils/atoms";
4
+ import { novelStore } from "../utils/store";
5
+ export const Command = Extension.create({
6
+ name: "slash-command",
7
+ addOptions() {
8
+ return {
9
+ suggestion: {
10
+ char: "/",
11
+ command: (ctx) => {
12
+ ctx.props.command({ editor: ctx.editor, range: ctx.range });
13
+ },
14
+ },
15
+ };
16
+ },
17
+ addProseMirrorPlugins() {
18
+ const base = this.options.suggestion ?? {};
19
+ return [
20
+ Suggestion({
21
+ editor: this.editor,
22
+ char: base.char ?? "/",
23
+ startOfLine: base.startOfLine ?? true,
24
+ items: base.items ?? (() => ["/"]),
25
+ command: (ctx) => {
26
+ if (typeof ctx?.props?.command === "function") {
27
+ ctx.props.command({ editor: ctx.editor, range: ctx.range });
28
+ }
29
+ },
30
+ ...base,
31
+ render: () => {
32
+ return {
33
+ onStart: (props) => {
34
+ const { selection } = props.editor.state;
35
+ const parentNode = selection.$from.node(selection.$from.depth);
36
+ const blockType = parentNode.type.name;
37
+ if (blockType === "codeBlock")
38
+ return false;
39
+ const { $from } = selection;
40
+ const marks = $from.marks();
41
+ if (marks.some((mark) => mark.type.name === "code" || mark.type.name === "link")) {
42
+ return false;
43
+ }
44
+ novelStore.set(queryAtom, props.query ?? "");
45
+ novelStore.set(rangeAtom, props.range ?? null);
46
+ novelStore.set(slashMenuOpenAtom, true);
47
+ const rect = typeof props.clientRect === "function" ? props.clientRect() : null;
48
+ novelStore.set(slashMenuRectAtom, rect);
49
+ },
50
+ onUpdate: (props) => {
51
+ novelStore.set(queryAtom, props.query ?? "");
52
+ novelStore.set(rangeAtom, props.range ?? null);
53
+ const rect = typeof props.clientRect === "function" ? props.clientRect() : null;
54
+ novelStore.set(slashMenuRectAtom, rect);
55
+ },
56
+ onKeyDown: ({ event }) => {
57
+ if (event.key === "Escape") {
58
+ novelStore.set(slashMenuOpenAtom, false);
59
+ return true;
60
+ }
61
+ if (["ArrowUp", "ArrowDown", "Enter"].includes(event.key)) {
62
+ const slashCommand = document.querySelector("#slash-command");
63
+ if (slashCommand) {
64
+ slashCommand.dispatchEvent(new KeyboardEvent("keydown", {
65
+ key: event.key,
66
+ cancelable: true,
67
+ bubbles: true,
68
+ }));
69
+ return true;
70
+ }
71
+ }
72
+ return false;
73
+ },
74
+ onExit: () => {
75
+ novelStore.set(slashMenuOpenAtom, false);
76
+ novelStore.set(queryAtom, "");
77
+ novelStore.set(rangeAtom, null);
78
+ novelStore.set(slashMenuRectAtom, null);
79
+ },
80
+ };
81
+ },
82
+ }),
83
+ ];
84
+ },
85
+ });
86
+ export const renderItems = () => ({
87
+ onStart: () => { },
88
+ onUpdate: () => { },
89
+ onKeyDown: () => false,
90
+ onExit: () => { },
91
+ });
92
+ export const createSuggestionItems = (items) => items;
93
+ export const handleCommandNavigation = (event) => {
94
+ if (["ArrowUp", "ArrowDown", "Enter"].includes(event.key)) {
95
+ const slashCommand = document.querySelector("#slash-command");
96
+ if (slashCommand)
97
+ return true;
98
+ }
99
+ };