@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,314 @@
1
+ import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
2
+ import { useLexicalEditable } from "@lexical/react/useLexicalEditable";
3
+ import {
4
+ $getTableAndElementByKey,
5
+ $getTableColumnIndexFromTableCellNode,
6
+ $getTableRowIndexFromTableCellNode,
7
+ $insertTableColumn__EXPERIMENTAL,
8
+ $insertTableRow__EXPERIMENTAL,
9
+ $isTableCellNode,
10
+ $isTableNode,
11
+ getTableElement,
12
+ TableCellNode,
13
+ TableNode,
14
+ TableRowNode,
15
+ } from "@lexical/table";
16
+ import { $findMatchingParent, mergeRegister } from "@lexical/utils";
17
+ import { $getNearestNodeFromDOMNode, isHTMLElement, NodeKey } from "lexical";
18
+ import { useEffect, useMemo, useRef, useState } from "react";
19
+ import * as React from "react";
20
+ import { createPortal } from "react-dom";
21
+
22
+ import { useDebounce } from "../CodeActionMenuPlugin/utils";
23
+ import { Button } from "@/components/ui/button";
24
+ import { Plus } from "lucide-react";
25
+
26
+ const BUTTON_WIDTH_PX = 20;
27
+
28
+ function TableHoverActionsContainer({
29
+ anchorElem,
30
+ }: {
31
+ anchorElem: HTMLElement;
32
+ }): React.JSX.Element | null {
33
+ const [editor] = useLexicalComposerContext();
34
+ const isEditable = useLexicalEditable();
35
+ const [isShownRow, setShownRow] = useState<boolean>(false);
36
+ const [isShownColumn, setShownColumn] = useState<boolean>(false);
37
+ const [shouldListenMouseMove, setShouldListenMouseMove] =
38
+ useState<boolean>(false);
39
+ const [position, setPosition] = useState({});
40
+ const tableSetRef = useRef<Set<NodeKey>>(new Set());
41
+ const tableCellDOMNodeRef = useRef<HTMLElement | null>(null);
42
+
43
+ const debouncedOnMouseMove = useDebounce(
44
+ (event: MouseEvent) => {
45
+ const { isOutside, tableDOMNode } = getMouseInfo(event);
46
+
47
+ if (isOutside) {
48
+ setShownRow(false);
49
+ setShownColumn(false);
50
+ return;
51
+ }
52
+
53
+ if (!tableDOMNode) {
54
+ return;
55
+ }
56
+
57
+ tableCellDOMNodeRef.current = tableDOMNode;
58
+
59
+ let hoveredRowNode: TableCellNode | null = null;
60
+ let hoveredColumnNode: TableCellNode | null = null;
61
+ let tableDOMElement: HTMLElement | null = null;
62
+
63
+ editor.getEditorState().read(
64
+ () => {
65
+ const maybeTableCell = $getNearestNodeFromDOMNode(tableDOMNode);
66
+
67
+ if ($isTableCellNode(maybeTableCell)) {
68
+ const table = $findMatchingParent(maybeTableCell, (node) =>
69
+ $isTableNode(node)
70
+ );
71
+ if (!$isTableNode(table)) {
72
+ return;
73
+ }
74
+
75
+ tableDOMElement = getTableElement(
76
+ table,
77
+ editor.getElementByKey(table.getKey())
78
+ );
79
+
80
+ if (tableDOMElement) {
81
+ const rowCount = table.getChildrenSize();
82
+ const colCount = (
83
+ (table as TableNode).getChildAtIndex(0) as TableRowNode
84
+ )?.getChildrenSize();
85
+
86
+ const rowIndex =
87
+ $getTableRowIndexFromTableCellNode(maybeTableCell);
88
+ const colIndex =
89
+ $getTableColumnIndexFromTableCellNode(maybeTableCell);
90
+
91
+ if (rowIndex === rowCount - 1) {
92
+ hoveredRowNode = maybeTableCell;
93
+ } else if (colIndex === colCount - 1) {
94
+ hoveredColumnNode = maybeTableCell;
95
+ }
96
+ }
97
+ }
98
+ },
99
+ { editor }
100
+ );
101
+
102
+ if (tableDOMElement) {
103
+ const {
104
+ width: tableElemWidth,
105
+ y: tableElemY,
106
+ right: tableElemRight,
107
+ left: tableElemLeft,
108
+ bottom: tableElemBottom,
109
+ height: tableElemHeight,
110
+ } = (tableDOMElement as HTMLTableElement).getBoundingClientRect();
111
+
112
+ // Adjust for using the scrollable table container
113
+ const parentElement = (tableDOMElement as HTMLTableElement)
114
+ .parentElement;
115
+ let tableHasScroll = false;
116
+ if (
117
+ parentElement &&
118
+ parentElement.classList.contains(
119
+ "PlaygroundEditorTheme__tableScrollableWrapper"
120
+ )
121
+ ) {
122
+ tableHasScroll =
123
+ parentElement.scrollWidth > parentElement.clientWidth;
124
+ }
125
+ const { y: editorElemY, left: editorElemLeft } =
126
+ anchorElem.getBoundingClientRect();
127
+
128
+ if (hoveredRowNode) {
129
+ setShownColumn(false);
130
+ setShownRow(true);
131
+ setPosition({
132
+ height: BUTTON_WIDTH_PX,
133
+ left:
134
+ tableHasScroll && parentElement
135
+ ? parentElement.offsetLeft
136
+ : tableElemLeft - editorElemLeft,
137
+ top: tableElemBottom - editorElemY + 5,
138
+ width:
139
+ tableHasScroll && parentElement
140
+ ? parentElement.offsetWidth
141
+ : tableElemWidth,
142
+ });
143
+ } else if (hoveredColumnNode) {
144
+ setShownColumn(true);
145
+ setShownRow(false);
146
+ setPosition({
147
+ height: tableElemHeight,
148
+ left: tableElemRight - editorElemLeft + 5,
149
+ top: tableElemY - editorElemY,
150
+ width: BUTTON_WIDTH_PX,
151
+ });
152
+ }
153
+ }
154
+ },
155
+ 1000,
156
+ 500
157
+ );
158
+
159
+ // Hide the buttons on any table dimensions change to prevent last row cells
160
+ // overlap behind the 'Add Row' button when text entry changes cell height
161
+ const tableResizeObserver = useMemo(() => {
162
+ return new ResizeObserver(() => {
163
+ setShownRow(false);
164
+ setShownColumn(false);
165
+ });
166
+ }, []);
167
+
168
+ useEffect(() => {
169
+ if (!shouldListenMouseMove) {
170
+ return;
171
+ }
172
+
173
+ document.addEventListener("mousemove", debouncedOnMouseMove);
174
+
175
+ return () => {
176
+ setShownRow(false);
177
+ setShownColumn(false);
178
+ debouncedOnMouseMove.cancel();
179
+ document.removeEventListener("mousemove", debouncedOnMouseMove);
180
+ };
181
+ }, [shouldListenMouseMove, debouncedOnMouseMove]);
182
+
183
+ useEffect(() => {
184
+ return mergeRegister(
185
+ editor.registerMutationListener(
186
+ TableNode,
187
+ (mutations) => {
188
+ editor.getEditorState().read(
189
+ () => {
190
+ let resetObserver = false;
191
+ for (const [key, type] of mutations) {
192
+ switch (type) {
193
+ case "created": {
194
+ tableSetRef.current.add(key);
195
+ resetObserver = true;
196
+ break;
197
+ }
198
+ case "destroyed": {
199
+ tableSetRef.current.delete(key);
200
+ resetObserver = true;
201
+ break;
202
+ }
203
+ default:
204
+ break;
205
+ }
206
+ }
207
+ if (resetObserver) {
208
+ // Reset resize observers
209
+ tableResizeObserver.disconnect();
210
+ for (const tableKey of tableSetRef.current) {
211
+ const { tableElement } = $getTableAndElementByKey(tableKey);
212
+ tableResizeObserver.observe(tableElement);
213
+ }
214
+ setShouldListenMouseMove(tableSetRef.current.size > 0);
215
+ }
216
+ },
217
+ { editor }
218
+ );
219
+ },
220
+ { skipInitialization: false }
221
+ )
222
+ );
223
+ }, [editor, tableResizeObserver]);
224
+
225
+ const insertAction = (insertRow: boolean) => {
226
+ editor.update(() => {
227
+ if (tableCellDOMNodeRef.current) {
228
+ const maybeTableNode = $getNearestNodeFromDOMNode(
229
+ tableCellDOMNodeRef.current
230
+ );
231
+ maybeTableNode?.selectEnd();
232
+ if (insertRow) {
233
+ $insertTableRow__EXPERIMENTAL();
234
+ setShownRow(false);
235
+ } else {
236
+ $insertTableColumn__EXPERIMENTAL();
237
+ setShownColumn(false);
238
+ }
239
+ }
240
+ });
241
+ };
242
+
243
+ if (!isEditable) {
244
+ return null;
245
+ }
246
+
247
+ return (
248
+ <>
249
+ {isShownRow && (
250
+ <Button
251
+ size={"sm"}
252
+ className={"PlaygroundEditorTheme__tableAddRows"}
253
+ style={{ ...position }}
254
+ onClick={() => insertAction(true)}
255
+ >
256
+ <Plus className="text-black" />
257
+ </Button>
258
+ )}
259
+ {isShownColumn && (
260
+ <Button
261
+ size={"sm"}
262
+ className={"PlaygroundEditorTheme__tableAddColumns"}
263
+ style={{ ...position }}
264
+ onClick={() => insertAction(false)}
265
+ >
266
+ <Plus className="text-black" />
267
+ </Button>
268
+ )}
269
+ </>
270
+ );
271
+ }
272
+
273
+ function getMouseInfo(event: MouseEvent): {
274
+ tableDOMNode: HTMLElement | null;
275
+ isOutside: boolean;
276
+ } {
277
+ const target = event.target;
278
+
279
+ if (isHTMLElement(target)) {
280
+ const tableDOMNode = target.closest<HTMLElement>(
281
+ "td.PlaygroundEditorTheme__tableCell, th.PlaygroundEditorTheme__tableCell"
282
+ );
283
+
284
+ const isOutside = !(
285
+ tableDOMNode ||
286
+ target.closest<HTMLElement>(
287
+ "button.PlaygroundEditorTheme__tableAddRows"
288
+ ) ||
289
+ target.closest<HTMLElement>(
290
+ "button.PlaygroundEditorTheme__tableAddColumns"
291
+ ) ||
292
+ target.closest<HTMLElement>("div.TableCellResizer__resizer")
293
+ );
294
+
295
+ return { isOutside, tableDOMNode };
296
+ } else {
297
+ return { isOutside: true, tableDOMNode: null };
298
+ }
299
+ }
300
+
301
+ export default function TableHoverActionsPlugin({
302
+ anchorElem = document.body,
303
+ }: {
304
+ anchorElem?: HTMLElement;
305
+ }): React.ReactPortal | null {
306
+ const isEditable = useLexicalEditable();
307
+
308
+ return isEditable
309
+ ? createPortal(
310
+ <TableHoverActionsContainer anchorElem={anchorElem} />,
311
+ anchorElem
312
+ )
313
+ : null;
314
+ }
@@ -0,0 +1,99 @@
1
+
2
+ import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
3
+ import {
4
+ TableCellNode,
5
+ TableNode,
6
+ TableRowNode,
7
+ } from "@lexical/table";
8
+ import { invariant } from "framer-motion";
9
+ import { EditorThemeClasses, Klass, LexicalEditor, LexicalNode } from "lexical";
10
+ import {
11
+ createContext,
12
+ JSX,
13
+ useContext,
14
+ useEffect,
15
+ useMemo,
16
+ useState,
17
+ } from "react";
18
+
19
+ export type InsertTableCommandPayload = Readonly<{
20
+ columns: string;
21
+ rows: string;
22
+ includeHeaders?: boolean;
23
+ }>;
24
+
25
+ export type CellContextShape = {
26
+ cellEditorConfig: null | CellEditorConfig;
27
+ cellEditorPlugins: null | JSX.Element | Array<JSX.Element>;
28
+ set: (
29
+ cellEditorConfig: null | CellEditorConfig,
30
+ cellEditorPlugins: null | JSX.Element | Array<JSX.Element>
31
+ ) => void;
32
+ };
33
+
34
+ export type CellEditorConfig = Readonly<{
35
+ namespace: string;
36
+ nodes?: ReadonlyArray<Klass<LexicalNode>>;
37
+ onError: (error: Error, editor: LexicalEditor) => void;
38
+ readOnly?: boolean;
39
+ theme?: EditorThemeClasses;
40
+ }>;
41
+
42
+ export const CellContext = createContext<CellContextShape>({
43
+ cellEditorConfig: null,
44
+ cellEditorPlugins: null,
45
+ set: () => {
46
+ // Empty
47
+ },
48
+ });
49
+
50
+ export function TableContext({ children }: { children: JSX.Element }) {
51
+ const [contextValue, setContextValue] = useState<{
52
+ cellEditorConfig: null | CellEditorConfig;
53
+ cellEditorPlugins: null | JSX.Element | Array<JSX.Element>;
54
+ }>({
55
+ cellEditorConfig: null,
56
+ cellEditorPlugins: null,
57
+ });
58
+ return (
59
+ <CellContext.Provider
60
+ value={useMemo(
61
+ () => ({
62
+ cellEditorConfig: contextValue.cellEditorConfig,
63
+ cellEditorPlugins: contextValue.cellEditorPlugins,
64
+ set: (cellEditorConfig, cellEditorPlugins) => {
65
+ setContextValue({ cellEditorConfig, cellEditorPlugins });
66
+ },
67
+ }),
68
+ [contextValue.cellEditorConfig, contextValue.cellEditorPlugins]
69
+ )}
70
+ >
71
+ {children}
72
+ </CellContext.Provider>
73
+ );
74
+ }
75
+
76
+
77
+
78
+ export function TablePlugin({
79
+ cellEditorConfig,
80
+ children,
81
+ }: {
82
+ cellEditorConfig: CellEditorConfig;
83
+ children: JSX.Element | Array<JSX.Element>;
84
+ }): JSX.Element | null {
85
+ const [editor] = useLexicalComposerContext();
86
+ const cellContext = useContext(CellContext);
87
+ useEffect(() => {
88
+ if (!editor.hasNodes([TableNode, TableRowNode, TableCellNode])) {
89
+ invariant(
90
+ false,
91
+ "TablePlugin: TableNode, TableRowNode, or TableCellNode is not registered on editor"
92
+ );
93
+ }
94
+ }, [editor]);
95
+ useEffect(() => {
96
+ cellContext.set(cellEditorConfig, children);
97
+ }, [cellContext, cellEditorConfig, children]);
98
+ return null;
99
+ }