@collabchron/notiq 0.2.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 (188) hide show
  1. package/README.md +71 -0
  2. package/components.json +21 -0
  3. package/eslint.config.mjs +16 -0
  4. package/next.config.ts +12 -0
  5. package/package.json +108 -0
  6. package/postcss.config.mjs +5 -0
  7. package/public/file.svg +1 -0
  8. package/public/globe.svg +1 -0
  9. package/public/images/icons/plus.svg +10 -0
  10. package/public/next.svg +1 -0
  11. package/public/vercel.svg +1 -0
  12. package/public/window.svg +1 -0
  13. package/src/app/actions.ts +2 -0
  14. package/src/app/api/ai/route.ts +175 -0
  15. package/src/app/api/edgestore/[...edgestore]/route.ts +28 -0
  16. package/src/app/favicon.ico +0 -0
  17. package/src/app/globals.css +205 -0
  18. package/src/app/layout.tsx +38 -0
  19. package/src/app/page.tsx +12 -0
  20. package/src/components/editor/Core.tsx +220 -0
  21. package/src/components/editor/hooks/instructions-messages.ts +300 -0
  22. package/src/components/editor/hooks/use-mobile.ts +19 -0
  23. package/src/components/editor/hooks/useReport.ts +67 -0
  24. package/src/components/editor/hooks/useResizeObservert.ts +22 -0
  25. package/src/components/editor/index.tsx +39 -0
  26. package/src/components/editor/lexical-on-change.tsx +28 -0
  27. package/src/components/editor/nodes/CollapsibleNode/CollapsibleContainerNode.ts +92 -0
  28. package/src/components/editor/nodes/CollapsibleNode/CollapsibleContentNode.ts +65 -0
  29. package/src/components/editor/nodes/CollapsibleNode/CollapsibleTitleNode.ts +105 -0
  30. package/src/components/editor/nodes/EquationNode/EquationComponent.tsx +143 -0
  31. package/src/components/editor/nodes/EquationNode/EquationNode.tsx +170 -0
  32. package/src/components/editor/nodes/ExcalidrawNode/ExcalidrawComponent.tsx +228 -0
  33. package/src/components/editor/nodes/ExcalidrawNode/ExcalidrawImage.tsx +137 -0
  34. package/src/components/editor/nodes/ExcalidrawNode/ImageResizer.tsx +317 -0
  35. package/src/components/editor/nodes/ExcalidrawNode/index.tsx +204 -0
  36. package/src/components/editor/nodes/FigmaNode/FigmaNode.tsx +134 -0
  37. package/src/components/editor/nodes/Hint/HintComponet.tsx +221 -0
  38. package/src/components/editor/nodes/Hint/index.tsx +190 -0
  39. package/src/components/editor/nodes/ImageNode/index.tsx +328 -0
  40. package/src/components/editor/nodes/InlineImageNode/InlineImageComponent.tsx +383 -0
  41. package/src/components/editor/nodes/InlineImageNode/InlineImageNode.css +94 -0
  42. package/src/components/editor/nodes/InlineImageNode/InlineImageNode.tsx +309 -0
  43. package/src/components/editor/nodes/LayoutNode/LayoutContainerNode.ts +146 -0
  44. package/src/components/editor/nodes/LayoutNode/LayoutItemNode.ts +79 -0
  45. package/src/components/editor/nodes/PollNode/index.tsx +204 -0
  46. package/src/components/editor/nodes/Stepper/index.tsx +260 -0
  47. package/src/components/editor/nodes/TweetNode/index.tsx +214 -0
  48. package/src/components/editor/nodes/index.ts +81 -0
  49. package/src/components/editor/plugins/AutoEmbedPlugin/index.tsx +350 -0
  50. package/src/components/editor/plugins/AutoLinkPlugin/index.tsx +56 -0
  51. package/src/components/editor/plugins/CodeActionMenuPlugin/components/CopyButton.tsx +70 -0
  52. package/src/components/editor/plugins/CodeActionMenuPlugin/components/PrettierButton.tsx +192 -0
  53. package/src/components/editor/plugins/CodeActionMenuPlugin/index.tsx +217 -0
  54. package/src/components/editor/plugins/CodeActionMenuPlugin/utils.ts +26 -0
  55. package/src/components/editor/plugins/CodeHighlightPlugin/index.ts +21 -0
  56. package/src/components/editor/plugins/CollapsiblePlugin/Collapsible.css +76 -0
  57. package/src/components/editor/plugins/CollapsiblePlugin/index.ts +228 -0
  58. package/src/components/editor/plugins/DragDropPastePlugin/index.tsx +44 -0
  59. package/src/components/editor/plugins/DraggableBlockPlugin/index.tsx +52 -0
  60. package/src/components/editor/plugins/EquationsPlugin/index.tsx +85 -0
  61. package/src/components/editor/plugins/ExcalidrawPlugin/index.tsx +98 -0
  62. package/src/components/editor/plugins/FigmaPlugin/index.tsx +42 -0
  63. package/src/components/editor/plugins/FloatingLinkEditorPlugin/index.tsx +445 -0
  64. package/src/components/editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx +275 -0
  65. package/src/components/editor/plugins/ImagesPlugin/index.tsx +222 -0
  66. package/src/components/editor/plugins/InlineImagePlugin/index.tsx +351 -0
  67. package/src/components/editor/plugins/LayoutPlugin/index.tsx +238 -0
  68. package/src/components/editor/plugins/LinkPlugin/index.tsx +36 -0
  69. package/src/components/editor/plugins/LinkWithMetaData/index.tsx +271 -0
  70. package/src/components/editor/plugins/MarkdownShortcutPlugin/index.tsx +11 -0
  71. package/src/components/editor/plugins/MarkdownTransformers/index.tsx +304 -0
  72. package/src/components/editor/plugins/PollPlugin/index.tsx +49 -0
  73. package/src/components/editor/plugins/ShortcutsPlugin/index.tsx +180 -0
  74. package/src/components/editor/plugins/ShortcutsPlugin/shortcuts.ts +253 -0
  75. package/src/components/editor/plugins/SlashCommand/index.tsx +621 -0
  76. package/src/components/editor/plugins/SpeechToTextPlugin/index.ts +127 -0
  77. package/src/components/editor/plugins/TabFocusPlugin/index.ts +58 -0
  78. package/src/components/editor/plugins/TableCellActionMenuPlugin/index.tsx +759 -0
  79. package/src/components/editor/plugins/TableCellResizer/index.tsx +438 -0
  80. package/src/components/editor/plugins/TableHoverActionsPlugin/index.tsx +314 -0
  81. package/src/components/editor/plugins/TablePlugin/index.tsx +99 -0
  82. package/src/components/editor/plugins/ToolbarPlugin/index.tsx +522 -0
  83. package/src/components/editor/plugins/TwitterPlugin/index.ts +35 -0
  84. package/src/components/editor/plugins/YouTubeNode/index.tsx +179 -0
  85. package/src/components/editor/plugins/YouTubePlugin/index.ts +41 -0
  86. package/src/components/editor/themes/editor-theme.ts +113 -0
  87. package/src/components/editor/themes/theme.css +377 -0
  88. package/src/components/editor/utils/ai.ts +291 -0
  89. package/src/components/editor/utils/canUseDOM.ts +12 -0
  90. package/src/components/editor/utils/editorFormatting.ts +282 -0
  91. package/src/components/editor/utils/environment.ts +50 -0
  92. package/src/components/editor/utils/extract-data.ts +166 -0
  93. package/src/components/editor/utils/getAllLexicalChildren.ts +13 -0
  94. package/src/components/editor/utils/getDOMRangeRect.ts +27 -0
  95. package/src/components/editor/utils/getSelectedNode.ts +27 -0
  96. package/src/components/editor/utils/gif.ts +29 -0
  97. package/src/components/editor/utils/invariant.ts +15 -0
  98. package/src/components/editor/utils/setFloatingElemPosition.ts +51 -0
  99. package/src/components/editor/utils/setFloatingElemPositionForLinkEditor.ts +40 -0
  100. package/src/components/editor/utils/setNodePlaceholderFromSelection/getNodePlaceholder.ts +51 -0
  101. package/src/components/editor/utils/setNodePlaceholderFromSelection/setNodePlaceholderFromSelection.ts +15 -0
  102. package/src/components/editor/utils/setNodePlaceholderFromSelection/setPlaceholderOnSelection.ts +114 -0
  103. package/src/components/editor/utils/setNodePlaceholderFromSelection/styles.css +6 -0
  104. package/src/components/editor/utils/url.ts +109 -0
  105. package/src/components/editor/utils/useLayoutEffect.ts +13 -0
  106. package/src/components/providers/QueryProvider.tsx +15 -0
  107. package/src/components/providers/SharedHistoryContext.tsx +28 -0
  108. package/src/components/providers/ToolbarContext.tsx +123 -0
  109. package/src/components/providers/theme-provider.tsx +11 -0
  110. package/src/components/theme/ModeToggle.tsx +40 -0
  111. package/src/components/ui/FileInput.tsx +40 -0
  112. package/src/components/ui/Input.css +32 -0
  113. package/src/components/ui/Select.css +42 -0
  114. package/src/components/ui/Select.tsx +36 -0
  115. package/src/components/ui/TextInput.tsx +48 -0
  116. package/src/components/ui/ai/ai-button.tsx +574 -0
  117. package/src/components/ui/ai/border.tsx +99 -0
  118. package/src/components/ui/ai/placeholder-input-vanish.tsx +282 -0
  119. package/src/components/ui/button.tsx +89 -0
  120. package/src/components/ui/card.tsx +76 -0
  121. package/src/components/ui/checkbox.tsx +30 -0
  122. package/src/components/ui/command.tsx +153 -0
  123. package/src/components/ui/dialog/Dialog.css +25 -0
  124. package/src/components/ui/dialog/Dialog.tsx +34 -0
  125. package/src/components/ui/dialog.tsx +122 -0
  126. package/src/components/ui/drop-downs/background-color.tsx +183 -0
  127. package/src/components/ui/drop-downs/block-format.tsx +159 -0
  128. package/src/components/ui/drop-downs/code.tsx +42 -0
  129. package/src/components/ui/drop-downs/color.tsx +177 -0
  130. package/src/components/ui/drop-downs/font-size.tsx +138 -0
  131. package/src/components/ui/drop-downs/font.tsx +155 -0
  132. package/src/components/ui/drop-downs/index.tsx +122 -0
  133. package/src/components/ui/drop-downs/insert-node.tsx +213 -0
  134. package/src/components/ui/drop-downs/text-align.tsx +123 -0
  135. package/src/components/ui/drop-downs/text-format.tsx +104 -0
  136. package/src/components/ui/dropdown-menu.tsx +201 -0
  137. package/src/components/ui/equation/EquationEditor.css +38 -0
  138. package/src/components/ui/equation/EquationEditor.tsx +56 -0
  139. package/src/components/ui/equation/KatexEquationAlterer.css +41 -0
  140. package/src/components/ui/equation/KatexEquationAlterer.tsx +83 -0
  141. package/src/components/ui/equation/KatexRenderer.tsx +66 -0
  142. package/src/components/ui/excalidraw/ExcalidrawModal.css +64 -0
  143. package/src/components/ui/excalidraw/ExcalidrawModal.tsx +234 -0
  144. package/src/components/ui/excalidraw/Modal.css +62 -0
  145. package/src/components/ui/excalidraw/Modal.tsx +110 -0
  146. package/src/components/ui/hover-card.tsx +29 -0
  147. package/src/components/ui/image/error-image.tsx +17 -0
  148. package/src/components/ui/image/file-upload.tsx +240 -0
  149. package/src/components/ui/image/image-resizer.tsx +297 -0
  150. package/src/components/ui/image/image-toolbar.tsx +264 -0
  151. package/src/components/ui/image/index.tsx +408 -0
  152. package/src/components/ui/image/lazy-image.tsx +68 -0
  153. package/src/components/ui/image/lazy-video.tsx +71 -0
  154. package/src/components/ui/input.tsx +22 -0
  155. package/src/components/ui/models/custom-dialog.tsx +320 -0
  156. package/src/components/ui/models/insert-gif.tsx +90 -0
  157. package/src/components/ui/models/insert-image.tsx +52 -0
  158. package/src/components/ui/models/insert-poll.tsx +29 -0
  159. package/src/components/ui/models/insert-table.tsx +62 -0
  160. package/src/components/ui/models/use-model.tsx +91 -0
  161. package/src/components/ui/poll/poll-component.tsx +304 -0
  162. package/src/components/ui/popover.tsx +33 -0
  163. package/src/components/ui/progress.tsx +28 -0
  164. package/src/components/ui/scroll-area.tsx +48 -0
  165. package/src/components/ui/separator.tsx +31 -0
  166. package/src/components/ui/skeleton.tsx +15 -0
  167. package/src/components/ui/sonner.tsx +31 -0
  168. package/src/components/ui/stepper/step.tsx +179 -0
  169. package/src/components/ui/stepper/stepper.tsx +89 -0
  170. package/src/components/ui/textarea.tsx +22 -0
  171. package/src/components/ui/toggle.tsx +71 -0
  172. package/src/components/ui/tooltip.tsx +32 -0
  173. package/src/components/ui/write/text-format-floting-toolbar.tsx +346 -0
  174. package/src/lib/edgestore.ts +9 -0
  175. package/src/lib/pinecone-client.ts +0 -0
  176. package/src/lib/utils.ts +6 -0
  177. package/src/utils/docSerialization.ts +77 -0
  178. package/src/utils/emoji-list.ts +16615 -0
  179. package/src/utils/getDOMRangeRect.ts +27 -0
  180. package/src/utils/getSelectedNode.ts +27 -0
  181. package/src/utils/getThemeSelector.ts +25 -0
  182. package/src/utils/isMobileWidth.ts +7 -0
  183. package/src/utils/joinClasses.ts +13 -0
  184. package/src/utils/setFloatingElemPosition.ts +74 -0
  185. package/src/utils/setFloatingElemPositionForLinkEditor.ts +46 -0
  186. package/src/utils/swipe.ts +127 -0
  187. package/src/utils/url.ts +38 -0
  188. package/tsconfig.json +27 -0
@@ -0,0 +1,228 @@
1
+ import "./Collapsible.css";
2
+
3
+ import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
4
+ import { $findMatchingParent, mergeRegister } from "@lexical/utils";
5
+ import {
6
+ $createParagraphNode,
7
+ $getNodeByKey,
8
+ $getPreviousSelection,
9
+ $getSelection,
10
+ $isElementNode,
11
+ $isRangeSelection,
12
+ $setSelection,
13
+ COMMAND_PRIORITY_EDITOR,
14
+ COMMAND_PRIORITY_LOW,
15
+ createCommand,
16
+ DELETE_CHARACTER_COMMAND,
17
+ INSERT_PARAGRAPH_COMMAND,
18
+ KEY_ARROW_DOWN_COMMAND,
19
+ NodeKey
20
+ } from "lexical";
21
+ import { JSX, useEffect } from "react";
22
+
23
+ import {
24
+ $createCollapsibleContainerNode,
25
+ $isCollapsibleContainerNode,
26
+ CollapsibleContainerNode
27
+ } from "../../nodes/CollapsibleNode/CollapsibleContainerNode";
28
+ import {
29
+ $createCollapsibleContentNode,
30
+ $isCollapsibleContentNode,
31
+ CollapsibleContentNode
32
+ } from "../../nodes/CollapsibleNode/CollapsibleContentNode";
33
+ import {
34
+ $createCollapsibleTitleNode,
35
+ $isCollapsibleTitleNode,
36
+ CollapsibleTitleNode
37
+ } from "../../nodes/CollapsibleNode/CollapsibleTitleNode";
38
+
39
+ export const INSERT_COLLAPSIBLE_COMMAND = createCommand<void>();
40
+ export const TOGGLE_COLLAPSIBLE_COMMAND = createCommand<NodeKey>();
41
+
42
+ export default function CollapsiblePlugin(): JSX.Element | null {
43
+ const [editor] = useLexicalComposerContext();
44
+ useEffect(() => {
45
+ if (
46
+ !editor.hasNodes([
47
+ CollapsibleContainerNode,
48
+ CollapsibleTitleNode,
49
+ CollapsibleContentNode
50
+ ])
51
+ ) {
52
+ throw new Error(
53
+ "CollapsiblePlugin: CollapsibleContainerNode, CollapsibleTitleNode, or CollapsibleContentNode not registered on editor"
54
+ );
55
+ }
56
+
57
+ return mergeRegister(
58
+ // Structure enforcing transformers for each node type. In case nesting structure is not
59
+ // "Container > Title + Content" it'll unwrap nodes and convert it back
60
+ // to regular content.
61
+ editor.registerNodeTransform(CollapsibleContentNode, (node) => {
62
+ const parent = node.getParent();
63
+ if (!$isCollapsibleContainerNode(parent)) {
64
+ const children = node.getChildren();
65
+ for (const child of children) {
66
+ node.insertAfter(child);
67
+ }
68
+ node.remove();
69
+ }
70
+ }),
71
+ editor.registerNodeTransform(CollapsibleTitleNode, (node) => {
72
+ const parent = node.getParent();
73
+ if (!$isCollapsibleContainerNode(parent)) {
74
+ node.replace($createParagraphNode().append(...node.getChildren()));
75
+ }
76
+ }),
77
+ editor.registerNodeTransform(CollapsibleContainerNode, (node) => {
78
+ const children = node.getChildren();
79
+ if (
80
+ children.length !== 2 ||
81
+ !$isCollapsibleTitleNode(children[0]) ||
82
+ !$isCollapsibleContentNode(children[1])
83
+ ) {
84
+ for (const child of children) {
85
+ node.insertAfter(child);
86
+ }
87
+ node.remove();
88
+ }
89
+ }),
90
+ // This handles the case when container is collapsed and we delete its previous sibling
91
+ // into it, it would cause collapsed content deleted (since it's display: none, and selection
92
+ // swallows it when deletes single char). Instead we expand container, which is although
93
+ // not perfect, but avoids bigger problem
94
+ editor.registerCommand(
95
+ DELETE_CHARACTER_COMMAND,
96
+ () => {
97
+ const selection = $getSelection();
98
+ if (
99
+ !$isRangeSelection(selection) ||
100
+ !selection.isCollapsed() ||
101
+ selection.anchor.offset !== 0
102
+ ) {
103
+ return false;
104
+ }
105
+
106
+ const anchorNode = selection.anchor.getNode();
107
+ const topLevelElement = anchorNode.getTopLevelElement();
108
+ if (topLevelElement === null) {
109
+ return false;
110
+ }
111
+
112
+ const container = topLevelElement.getPreviousSibling();
113
+ if (!$isCollapsibleContainerNode(container) || container.getOpen()) {
114
+ return false;
115
+ }
116
+
117
+ container.setOpen(true);
118
+ return true;
119
+ },
120
+ COMMAND_PRIORITY_LOW
121
+ ),
122
+ // When collapsible is the last child pressing down arrow will insert paragraph
123
+ // below it to allow adding more content. It's similar what $insertBlockNode
124
+ // (mainly for decorators), except it'll always be possible to continue adding
125
+ // new content even if trailing paragraph is accidentally deleted
126
+ editor.registerCommand(
127
+ KEY_ARROW_DOWN_COMMAND,
128
+ () => {
129
+ const selection = $getSelection();
130
+ if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
131
+ return false;
132
+ }
133
+
134
+ const container = $findMatchingParent(
135
+ selection.anchor.getNode(),
136
+ $isCollapsibleContainerNode
137
+ );
138
+
139
+ if (container === null) {
140
+ return false;
141
+ }
142
+
143
+ const parent = container.getParent();
144
+ if (parent !== null && parent.getLastChild() === container) {
145
+ parent.append($createParagraphNode());
146
+ }
147
+ return false;
148
+ },
149
+ COMMAND_PRIORITY_LOW
150
+ ),
151
+ // Handling CMD+Enter to toggle collapsible element collapsed state
152
+ editor.registerCommand(
153
+ INSERT_PARAGRAPH_COMMAND,
154
+ () => {
155
+ // @ts-ignore
156
+ const windowEvent: KeyboardEvent | undefined = editor._window?.event;
157
+
158
+ if (
159
+ windowEvent &&
160
+ (windowEvent.ctrlKey || windowEvent.metaKey) &&
161
+ windowEvent.key === "Enter"
162
+ ) {
163
+ const selection = $getPreviousSelection();
164
+ if ($isRangeSelection(selection) && selection.isCollapsed()) {
165
+ const parent = $findMatchingParent(
166
+ selection.anchor.getNode(),
167
+ (node) => $isElementNode(node) && !node.isInline()
168
+ );
169
+
170
+ if ($isCollapsibleTitleNode(parent)) {
171
+ const container = parent.getParent();
172
+ if ($isCollapsibleContainerNode(container)) {
173
+ container.toggleOpen();
174
+ $setSelection(selection.clone());
175
+ return true;
176
+ }
177
+ }
178
+ }
179
+ }
180
+
181
+ return false;
182
+ },
183
+ COMMAND_PRIORITY_LOW
184
+ ),
185
+ editor.registerCommand(
186
+ INSERT_COLLAPSIBLE_COMMAND,
187
+ () => {
188
+ editor.update(() => {
189
+ const selection = $getSelection();
190
+
191
+ if (!$isRangeSelection(selection)) {
192
+ return;
193
+ }
194
+
195
+ const title = $createCollapsibleTitleNode();
196
+ const content = $createCollapsibleContentNode().append(
197
+ $createParagraphNode()
198
+ );
199
+ const container = $createCollapsibleContainerNode().append(
200
+ title,
201
+ content
202
+ );
203
+ selection.insertNodes([container]);
204
+ title.selectStart();
205
+ });
206
+
207
+ return true;
208
+ },
209
+ COMMAND_PRIORITY_EDITOR
210
+ ),
211
+ editor.registerCommand(
212
+ TOGGLE_COLLAPSIBLE_COMMAND,
213
+ (key: NodeKey) => {
214
+ editor.update(() => {
215
+ const containerNode = $getNodeByKey(key);
216
+ if ($isCollapsibleContainerNode(containerNode)) {
217
+ containerNode.toggleOpen();
218
+ }
219
+ });
220
+
221
+ return true;
222
+ },
223
+ COMMAND_PRIORITY_EDITOR
224
+ )
225
+ );
226
+ }, [editor]);
227
+ return null;
228
+ }
@@ -0,0 +1,44 @@
1
+
2
+ import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
3
+ import {DRAG_DROP_PASTE} from '@lexical/rich-text';
4
+ import {isMimeType, mediaFileReader} from '@lexical/utils';
5
+ import {COMMAND_PRIORITY_LOW} from 'lexical';
6
+ import {useEffect} from 'react';
7
+
8
+ import {INSERT_IMAGE_COMMAND} from '../ImagesPlugin';
9
+
10
+ const ACCEPTABLE_IMAGE_TYPES = [
11
+ 'image/',
12
+ 'image/heic',
13
+ 'image/heif',
14
+ 'image/gif',
15
+ 'image/webp',
16
+ ];
17
+
18
+ export default function DragDropPaste(): null {
19
+ const [editor] = useLexicalComposerContext();
20
+ useEffect(() => {
21
+ return editor.registerCommand(
22
+ DRAG_DROP_PASTE,
23
+ (files) => {
24
+ (async () => {
25
+ const filesResult = await mediaFileReader(
26
+ files,
27
+ [ACCEPTABLE_IMAGE_TYPES].flatMap((x) => x),
28
+ );
29
+ for (const {file, result} of filesResult) {
30
+ if (isMimeType(file, ACCEPTABLE_IMAGE_TYPES)) {
31
+ editor.dispatchCommand(INSERT_IMAGE_COMMAND, {
32
+ altText: file.name,
33
+ src: result,
34
+ });
35
+ }
36
+ }
37
+ })();
38
+ return true;
39
+ },
40
+ COMMAND_PRIORITY_LOW,
41
+ );
42
+ }, [editor]);
43
+ return null;
44
+ }
@@ -0,0 +1,52 @@
1
+ import { cn } from '@/lib/utils';
2
+ import {DraggableBlockPlugin_EXPERIMENTAL} from '@lexical/react/LexicalDraggableBlockPlugin';
3
+ import { JSX, useRef} from 'react';
4
+
5
+ const DRAGGABLE_BLOCK_MENU_CLASSNAME = 'draggable-block-menu';
6
+
7
+ export default function DraggableBlockPlugin({
8
+ anchorElem = document.body,
9
+ className
10
+ }: {
11
+ anchorElem?: HTMLElement;
12
+ className?:string
13
+ }): JSX.Element {
14
+ const menuRef = useRef<any>(null);
15
+ const targetLineRef = useRef<any>(null);
16
+
17
+ const isOnMenu = (element: HTMLElement): boolean => {
18
+
19
+ return !!element.closest(`.${DRAGGABLE_BLOCK_MENU_CLASSNAME}`);
20
+ };
21
+
22
+
23
+ return (
24
+ <DraggableBlockPlugin_EXPERIMENTAL
25
+ anchorElem={anchorElem}
26
+ menuRef={menuRef}
27
+ targetLineRef={targetLineRef}
28
+ menuComponent={
29
+ <div ref={menuRef} className={
30
+ cn("draggable-block-menu transition-all z-50 absolute top-0 -left-4",className)
31
+ }>
32
+ <svg
33
+ xmlns="http://www.w3.org/2000/svg"
34
+ className="w-4 cursor-move rounded-sm h-4 z-50"
35
+ data-name="Layer 1"
36
+ viewBox="0 0 24 24"
37
+ fill="currentColor"
38
+ >
39
+ <path stroke="currentColor" d="M8.5 10a2 2 0 1 0 2 2 2 2 0 0 0-2-2Zm0 7a2 2 0 1 0 2 2 2 2 0 0 0-2-2Zm7-10a2 2 0 1 0-2-2 2 2 0 0 0 2 2Zm-7-4a2 2 0 1 0 2 2 2 2 0 0 0-2-2Zm7 14a2 2 0 1 0 2 2 2 2 0 0 0-2-2Zm0-7a2 2 0 1 0 2 2 2 2 0 0 0-2-2Z" />
40
+ </svg>
41
+ </div>
42
+ }
43
+ targetLineComponent={
44
+ <div
45
+ ref={targetLineRef}
46
+ className="cursor-none bg-sky-600 h-1 absolute left-0 top-0 opacity-0 will-change-transform"
47
+ />
48
+ }
49
+ isOnMenu={isOnMenu}
50
+ />
51
+ );
52
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import type {JSX} from 'react';
10
+
11
+ import 'katex/dist/katex.css';
12
+
13
+ import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
14
+ import {$wrapNodeInElement} from '@lexical/utils';
15
+ import {
16
+ $createParagraphNode,
17
+ $insertNodes,
18
+ $isRootOrShadowRoot,
19
+ COMMAND_PRIORITY_EDITOR,
20
+ createCommand,
21
+ LexicalCommand,
22
+ LexicalEditor,
23
+ } from 'lexical';
24
+ import {useCallback, useEffect} from 'react';
25
+ import * as React from 'react';
26
+
27
+ import {$createEquationNode, EquationNode} from '../../nodes/EquationNode/EquationNode';
28
+ import KatexEquationAlterer from '@/components/ui/equation/KatexEquationAlterer';
29
+
30
+
31
+ type CommandPayload = {
32
+ equation: string;
33
+ inline: boolean;
34
+ };
35
+
36
+ export const INSERT_EQUATION_COMMAND: LexicalCommand<CommandPayload> =
37
+ createCommand('INSERT_EQUATION_COMMAND');
38
+
39
+ export function InsertEquationDialog({
40
+ activeEditor,
41
+ onClose,
42
+ }: {
43
+ activeEditor: LexicalEditor;
44
+ onClose: () => void;
45
+ }): JSX.Element {
46
+ const onEquationConfirm = useCallback(
47
+ (equation: string, inline: boolean) => {
48
+ activeEditor.dispatchCommand(INSERT_EQUATION_COMMAND, {equation, inline});
49
+ onClose();
50
+ },
51
+ [activeEditor, onClose],
52
+ );
53
+
54
+ return <KatexEquationAlterer onConfirm={onEquationConfirm} />;
55
+ }
56
+
57
+ export default function EquationsPlugin(): JSX.Element | null {
58
+ const [editor] = useLexicalComposerContext();
59
+
60
+ useEffect(() => {
61
+ if (!editor.hasNodes([EquationNode])) {
62
+ throw new Error(
63
+ 'EquationsPlugins: EquationsNode not registered on editor',
64
+ );
65
+ }
66
+
67
+ return editor.registerCommand<CommandPayload>(
68
+ INSERT_EQUATION_COMMAND,
69
+ (payload) => {
70
+ const {equation, inline} = payload;
71
+ const equationNode = $createEquationNode(equation, inline);
72
+
73
+ $insertNodes([equationNode]);
74
+ if ($isRootOrShadowRoot(equationNode.getParentOrThrow())) {
75
+ $wrapNodeInElement(equationNode, $createParagraphNode).selectEnd();
76
+ }
77
+
78
+ return true;
79
+ },
80
+ COMMAND_PRIORITY_EDITOR,
81
+ );
82
+ }, [editor]);
83
+
84
+ return null;
85
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+ import type {AppState, BinaryFiles} from '@excalidraw/excalidraw/types';
9
+ import type {JSX} from 'react';
10
+
11
+ import '@excalidraw/excalidraw/index.css';
12
+
13
+ import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
14
+ import {$wrapNodeInElement} from '@lexical/utils';
15
+ import {
16
+ $createParagraphNode,
17
+ $insertNodes,
18
+ $isRootOrShadowRoot,
19
+ COMMAND_PRIORITY_EDITOR,
20
+ createCommand,
21
+ LexicalCommand,
22
+ } from 'lexical';
23
+ import {useEffect, useState} from 'react';
24
+
25
+ import {
26
+ $createExcalidrawNode,
27
+ ExcalidrawNode,
28
+ } from '../../nodes/ExcalidrawNode';
29
+ import ExcalidrawModal, { ExcalidrawInitialElements } from '@/components/ui/excalidraw/ExcalidrawModal';
30
+
31
+ export const INSERT_EXCALIDRAW_COMMAND: LexicalCommand<void> = createCommand(
32
+ 'INSERT_EXCALIDRAW_COMMAND',
33
+ );
34
+
35
+ export default function ExcalidrawPlugin(): JSX.Element | null {
36
+ const [editor] = useLexicalComposerContext();
37
+ const [isModalOpen, setModalOpen] = useState<boolean>(false);
38
+
39
+ useEffect(() => {
40
+ if (!editor.hasNodes([ExcalidrawNode])) {
41
+ throw new Error(
42
+ 'ExcalidrawPlugin: ExcalidrawNode not registered on editor',
43
+ );
44
+ }
45
+
46
+ return editor.registerCommand(
47
+ INSERT_EXCALIDRAW_COMMAND,
48
+ () => {
49
+ setModalOpen(true);
50
+ return true;
51
+ },
52
+ COMMAND_PRIORITY_EDITOR,
53
+ );
54
+ }, [editor]);
55
+
56
+ const onClose = () => {
57
+ setModalOpen(false);
58
+ };
59
+
60
+ const onDelete = () => {
61
+ setModalOpen(false);
62
+ };
63
+
64
+ const onSave = (
65
+ elements: ExcalidrawInitialElements,
66
+ appState: Partial<AppState>,
67
+ files: BinaryFiles,
68
+ ) => {
69
+ editor.update(() => {
70
+ const excalidrawNode = $createExcalidrawNode();
71
+ excalidrawNode.setData(
72
+ JSON.stringify({
73
+ appState,
74
+ elements,
75
+ files,
76
+ }),
77
+ );
78
+ $insertNodes([excalidrawNode]);
79
+ if ($isRootOrShadowRoot(excalidrawNode.getParentOrThrow())) {
80
+ $wrapNodeInElement(excalidrawNode, $createParagraphNode).selectEnd();
81
+ }
82
+ });
83
+ setModalOpen(false);
84
+ };
85
+
86
+ return isModalOpen ? (
87
+ <ExcalidrawModal
88
+ initialElements={[]}
89
+ initialAppState={{} as AppState}
90
+ initialFiles={{}}
91
+ isShown={isModalOpen}
92
+ onDelete={onDelete}
93
+ onClose={onClose}
94
+ onSave={onSave}
95
+ closeOnClickOutside={false}
96
+ />
97
+ ) : null;
98
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import type {JSX} from 'react';
10
+
11
+ import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
12
+ import {$insertNodeToNearestRoot} from '@lexical/utils';
13
+ import {COMMAND_PRIORITY_EDITOR, createCommand, LexicalCommand} from 'lexical';
14
+ import {useEffect} from 'react';
15
+
16
+ import {$createFigmaNode, FigmaNode} from '../../nodes/FigmaNode/FigmaNode';
17
+
18
+ export const INSERT_FIGMA_COMMAND: LexicalCommand<string> = createCommand(
19
+ 'INSERT_FIGMA_COMMAND',
20
+ );
21
+
22
+ export default function FigmaPlugin(): JSX.Element | null {
23
+ const [editor] = useLexicalComposerContext();
24
+
25
+ useEffect(() => {
26
+ if (!editor.hasNodes([FigmaNode])) {
27
+ throw new Error('FigmaPlugin: FigmaNode not registered on editor');
28
+ }
29
+
30
+ return editor.registerCommand<string>(
31
+ INSERT_FIGMA_COMMAND,
32
+ (payload) => {
33
+ const figmaNode = $createFigmaNode(payload);
34
+ $insertNodeToNearestRoot(figmaNode);
35
+ return true;
36
+ },
37
+ COMMAND_PRIORITY_EDITOR,
38
+ );
39
+ }, [editor]);
40
+
41
+ return null;
42
+ }