@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.
- package/README.md +71 -0
- package/components.json +21 -0
- package/eslint.config.mjs +16 -0
- package/next.config.ts +12 -0
- package/package.json +108 -0
- package/postcss.config.mjs +5 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/images/icons/plus.svg +10 -0
- package/public/next.svg +1 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/src/app/actions.ts +2 -0
- package/src/app/api/ai/route.ts +175 -0
- package/src/app/api/edgestore/[...edgestore]/route.ts +28 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +205 -0
- package/src/app/layout.tsx +38 -0
- package/src/app/page.tsx +12 -0
- package/src/components/editor/Core.tsx +220 -0
- package/src/components/editor/hooks/instructions-messages.ts +300 -0
- package/src/components/editor/hooks/use-mobile.ts +19 -0
- package/src/components/editor/hooks/useReport.ts +67 -0
- package/src/components/editor/hooks/useResizeObservert.ts +22 -0
- package/src/components/editor/index.tsx +39 -0
- package/src/components/editor/lexical-on-change.tsx +28 -0
- package/src/components/editor/nodes/CollapsibleNode/CollapsibleContainerNode.ts +92 -0
- package/src/components/editor/nodes/CollapsibleNode/CollapsibleContentNode.ts +65 -0
- package/src/components/editor/nodes/CollapsibleNode/CollapsibleTitleNode.ts +105 -0
- package/src/components/editor/nodes/EquationNode/EquationComponent.tsx +143 -0
- package/src/components/editor/nodes/EquationNode/EquationNode.tsx +170 -0
- package/src/components/editor/nodes/ExcalidrawNode/ExcalidrawComponent.tsx +228 -0
- package/src/components/editor/nodes/ExcalidrawNode/ExcalidrawImage.tsx +137 -0
- package/src/components/editor/nodes/ExcalidrawNode/ImageResizer.tsx +317 -0
- package/src/components/editor/nodes/ExcalidrawNode/index.tsx +204 -0
- package/src/components/editor/nodes/FigmaNode/FigmaNode.tsx +134 -0
- package/src/components/editor/nodes/Hint/HintComponet.tsx +221 -0
- package/src/components/editor/nodes/Hint/index.tsx +190 -0
- package/src/components/editor/nodes/ImageNode/index.tsx +328 -0
- package/src/components/editor/nodes/InlineImageNode/InlineImageComponent.tsx +383 -0
- package/src/components/editor/nodes/InlineImageNode/InlineImageNode.css +94 -0
- package/src/components/editor/nodes/InlineImageNode/InlineImageNode.tsx +309 -0
- package/src/components/editor/nodes/LayoutNode/LayoutContainerNode.ts +146 -0
- package/src/components/editor/nodes/LayoutNode/LayoutItemNode.ts +79 -0
- package/src/components/editor/nodes/PollNode/index.tsx +204 -0
- package/src/components/editor/nodes/Stepper/index.tsx +260 -0
- package/src/components/editor/nodes/TweetNode/index.tsx +214 -0
- package/src/components/editor/nodes/index.ts +81 -0
- package/src/components/editor/plugins/AutoEmbedPlugin/index.tsx +350 -0
- package/src/components/editor/plugins/AutoLinkPlugin/index.tsx +56 -0
- package/src/components/editor/plugins/CodeActionMenuPlugin/components/CopyButton.tsx +70 -0
- package/src/components/editor/plugins/CodeActionMenuPlugin/components/PrettierButton.tsx +192 -0
- package/src/components/editor/plugins/CodeActionMenuPlugin/index.tsx +217 -0
- package/src/components/editor/plugins/CodeActionMenuPlugin/utils.ts +26 -0
- package/src/components/editor/plugins/CodeHighlightPlugin/index.ts +21 -0
- package/src/components/editor/plugins/CollapsiblePlugin/Collapsible.css +76 -0
- package/src/components/editor/plugins/CollapsiblePlugin/index.ts +228 -0
- package/src/components/editor/plugins/DragDropPastePlugin/index.tsx +44 -0
- package/src/components/editor/plugins/DraggableBlockPlugin/index.tsx +52 -0
- package/src/components/editor/plugins/EquationsPlugin/index.tsx +85 -0
- package/src/components/editor/plugins/ExcalidrawPlugin/index.tsx +98 -0
- package/src/components/editor/plugins/FigmaPlugin/index.tsx +42 -0
- package/src/components/editor/plugins/FloatingLinkEditorPlugin/index.tsx +445 -0
- package/src/components/editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx +275 -0
- package/src/components/editor/plugins/ImagesPlugin/index.tsx +222 -0
- package/src/components/editor/plugins/InlineImagePlugin/index.tsx +351 -0
- package/src/components/editor/plugins/LayoutPlugin/index.tsx +238 -0
- package/src/components/editor/plugins/LinkPlugin/index.tsx +36 -0
- package/src/components/editor/plugins/LinkWithMetaData/index.tsx +271 -0
- package/src/components/editor/plugins/MarkdownShortcutPlugin/index.tsx +11 -0
- package/src/components/editor/plugins/MarkdownTransformers/index.tsx +304 -0
- package/src/components/editor/plugins/PollPlugin/index.tsx +49 -0
- package/src/components/editor/plugins/ShortcutsPlugin/index.tsx +180 -0
- package/src/components/editor/plugins/ShortcutsPlugin/shortcuts.ts +253 -0
- package/src/components/editor/plugins/SlashCommand/index.tsx +621 -0
- package/src/components/editor/plugins/SpeechToTextPlugin/index.ts +127 -0
- package/src/components/editor/plugins/TabFocusPlugin/index.ts +58 -0
- package/src/components/editor/plugins/TableCellActionMenuPlugin/index.tsx +759 -0
- package/src/components/editor/plugins/TableCellResizer/index.tsx +438 -0
- package/src/components/editor/plugins/TableHoverActionsPlugin/index.tsx +314 -0
- package/src/components/editor/plugins/TablePlugin/index.tsx +99 -0
- package/src/components/editor/plugins/ToolbarPlugin/index.tsx +522 -0
- package/src/components/editor/plugins/TwitterPlugin/index.ts +35 -0
- package/src/components/editor/plugins/YouTubeNode/index.tsx +179 -0
- package/src/components/editor/plugins/YouTubePlugin/index.ts +41 -0
- package/src/components/editor/themes/editor-theme.ts +113 -0
- package/src/components/editor/themes/theme.css +377 -0
- package/src/components/editor/utils/ai.ts +291 -0
- package/src/components/editor/utils/canUseDOM.ts +12 -0
- package/src/components/editor/utils/editorFormatting.ts +282 -0
- package/src/components/editor/utils/environment.ts +50 -0
- package/src/components/editor/utils/extract-data.ts +166 -0
- package/src/components/editor/utils/getAllLexicalChildren.ts +13 -0
- package/src/components/editor/utils/getDOMRangeRect.ts +27 -0
- package/src/components/editor/utils/getSelectedNode.ts +27 -0
- package/src/components/editor/utils/gif.ts +29 -0
- package/src/components/editor/utils/invariant.ts +15 -0
- package/src/components/editor/utils/setFloatingElemPosition.ts +51 -0
- package/src/components/editor/utils/setFloatingElemPositionForLinkEditor.ts +40 -0
- package/src/components/editor/utils/setNodePlaceholderFromSelection/getNodePlaceholder.ts +51 -0
- package/src/components/editor/utils/setNodePlaceholderFromSelection/setNodePlaceholderFromSelection.ts +15 -0
- package/src/components/editor/utils/setNodePlaceholderFromSelection/setPlaceholderOnSelection.ts +114 -0
- package/src/components/editor/utils/setNodePlaceholderFromSelection/styles.css +6 -0
- package/src/components/editor/utils/url.ts +109 -0
- package/src/components/editor/utils/useLayoutEffect.ts +13 -0
- package/src/components/providers/QueryProvider.tsx +15 -0
- package/src/components/providers/SharedHistoryContext.tsx +28 -0
- package/src/components/providers/ToolbarContext.tsx +123 -0
- package/src/components/providers/theme-provider.tsx +11 -0
- package/src/components/theme/ModeToggle.tsx +40 -0
- package/src/components/ui/FileInput.tsx +40 -0
- package/src/components/ui/Input.css +32 -0
- package/src/components/ui/Select.css +42 -0
- package/src/components/ui/Select.tsx +36 -0
- package/src/components/ui/TextInput.tsx +48 -0
- package/src/components/ui/ai/ai-button.tsx +574 -0
- package/src/components/ui/ai/border.tsx +99 -0
- package/src/components/ui/ai/placeholder-input-vanish.tsx +282 -0
- package/src/components/ui/button.tsx +89 -0
- package/src/components/ui/card.tsx +76 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/command.tsx +153 -0
- package/src/components/ui/dialog/Dialog.css +25 -0
- package/src/components/ui/dialog/Dialog.tsx +34 -0
- package/src/components/ui/dialog.tsx +122 -0
- package/src/components/ui/drop-downs/background-color.tsx +183 -0
- package/src/components/ui/drop-downs/block-format.tsx +159 -0
- package/src/components/ui/drop-downs/code.tsx +42 -0
- package/src/components/ui/drop-downs/color.tsx +177 -0
- package/src/components/ui/drop-downs/font-size.tsx +138 -0
- package/src/components/ui/drop-downs/font.tsx +155 -0
- package/src/components/ui/drop-downs/index.tsx +122 -0
- package/src/components/ui/drop-downs/insert-node.tsx +213 -0
- package/src/components/ui/drop-downs/text-align.tsx +123 -0
- package/src/components/ui/drop-downs/text-format.tsx +104 -0
- package/src/components/ui/dropdown-menu.tsx +201 -0
- package/src/components/ui/equation/EquationEditor.css +38 -0
- package/src/components/ui/equation/EquationEditor.tsx +56 -0
- package/src/components/ui/equation/KatexEquationAlterer.css +41 -0
- package/src/components/ui/equation/KatexEquationAlterer.tsx +83 -0
- package/src/components/ui/equation/KatexRenderer.tsx +66 -0
- package/src/components/ui/excalidraw/ExcalidrawModal.css +64 -0
- package/src/components/ui/excalidraw/ExcalidrawModal.tsx +234 -0
- package/src/components/ui/excalidraw/Modal.css +62 -0
- package/src/components/ui/excalidraw/Modal.tsx +110 -0
- package/src/components/ui/hover-card.tsx +29 -0
- package/src/components/ui/image/error-image.tsx +17 -0
- package/src/components/ui/image/file-upload.tsx +240 -0
- package/src/components/ui/image/image-resizer.tsx +297 -0
- package/src/components/ui/image/image-toolbar.tsx +264 -0
- package/src/components/ui/image/index.tsx +408 -0
- package/src/components/ui/image/lazy-image.tsx +68 -0
- package/src/components/ui/image/lazy-video.tsx +71 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/models/custom-dialog.tsx +320 -0
- package/src/components/ui/models/insert-gif.tsx +90 -0
- package/src/components/ui/models/insert-image.tsx +52 -0
- package/src/components/ui/models/insert-poll.tsx +29 -0
- package/src/components/ui/models/insert-table.tsx +62 -0
- package/src/components/ui/models/use-model.tsx +91 -0
- package/src/components/ui/poll/poll-component.tsx +304 -0
- package/src/components/ui/popover.tsx +33 -0
- package/src/components/ui/progress.tsx +28 -0
- package/src/components/ui/scroll-area.tsx +48 -0
- package/src/components/ui/separator.tsx +31 -0
- package/src/components/ui/skeleton.tsx +15 -0
- package/src/components/ui/sonner.tsx +31 -0
- package/src/components/ui/stepper/step.tsx +179 -0
- package/src/components/ui/stepper/stepper.tsx +89 -0
- package/src/components/ui/textarea.tsx +22 -0
- package/src/components/ui/toggle.tsx +71 -0
- package/src/components/ui/tooltip.tsx +32 -0
- package/src/components/ui/write/text-format-floting-toolbar.tsx +346 -0
- package/src/lib/edgestore.ts +9 -0
- package/src/lib/pinecone-client.ts +0 -0
- package/src/lib/utils.ts +6 -0
- package/src/utils/docSerialization.ts +77 -0
- package/src/utils/emoji-list.ts +16615 -0
- package/src/utils/getDOMRangeRect.ts +27 -0
- package/src/utils/getSelectedNode.ts +27 -0
- package/src/utils/getThemeSelector.ts +25 -0
- package/src/utils/isMobileWidth.ts +7 -0
- package/src/utils/joinClasses.ts +13 -0
- package/src/utils/setFloatingElemPosition.ts +74 -0
- package/src/utils/setFloatingElemPositionForLinkEditor.ts +46 -0
- package/src/utils/swipe.ts +127 -0
- package/src/utils/url.ts +38 -0
- 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
|
+
}
|