@collabchron/notiq 0.2.0 → 1.0.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/LICENSE +21 -0
- package/README.md +230 -39
- package/dist/CodeActionMenuPlugin-EINOY4U4.mjs +15 -0
- package/dist/DynamicBlockComponent-NRQJ4WW4.mjs +161 -0
- package/dist/EquationComponent-CB6DFIHV.mjs +154 -0
- package/dist/ExcalidrawComponent-XW6646OH.mjs +528 -0
- package/dist/ExcalidrawPlugin-ZFHT62IF.mjs +14 -0
- package/dist/ExportPlugin-V2RLM63S.mjs +11 -0
- package/dist/FloatingLinkEditorPlugin-TRTCMSP4.mjs +12 -0
- package/dist/FloatingTextFormatToolbarPlugin-F2GY6LMI.mjs +30 -0
- package/dist/HintComponet-BRL6EAMS.mjs +217 -0
- package/dist/InlineImageComponent-UWIUWBHI.mjs +453 -0
- package/dist/MobileToolbar-BOOZAMQE.mjs +268 -0
- package/dist/SlashCommand-GMT5JI33.mjs +28 -0
- package/dist/StoryBuilderComponent-JGDBM5JU.mjs +562 -0
- package/{src/components/editor/plugins/TableCellActionMenuPlugin/index.tsx → dist/TableCellActionMenuPlugin-PGK2K3VG.mjs} +667 -759
- package/{src/components/editor/plugins/TableHoverActionsPlugin/index.tsx → dist/TableHoverActionsPlugin-GJVE6VRW.mjs} +258 -314
- package/dist/TemplatePlugin-ZD3QEVTI.mjs +9 -0
- package/dist/ToolbarPlugin-7TOZRD2R.mjs +1547 -0
- package/dist/babel-JZ2EV6AX.mjs +7233 -0
- package/dist/background-color-XZTYLGO2.mjs +362 -0
- package/dist/block-format-YJCV2DIY.mjs +15 -0
- package/dist/chunk-2FNEAMSP.mjs +127 -0
- package/dist/chunk-3CPBODXA.mjs +84 -0
- package/dist/chunk-3G37YKTV.mjs +83 -0
- package/dist/chunk-3JVFG7ER.mjs +184 -0
- package/dist/chunk-456TN7IM.mjs +110 -0
- package/dist/chunk-4EXYCTGJ.mjs +27 -0
- package/{src/utils/getSelectedNode.ts → dist/chunk-4HBCVSE6.mjs} +26 -27
- package/dist/chunk-4MEDW3T6.mjs +125 -0
- package/dist/chunk-4VWFVWYP.mjs +36 -0
- package/dist/chunk-5BAKY5KN.mjs +84 -0
- package/dist/chunk-5QSNIVIG.mjs +333 -0
- package/dist/chunk-64Z3FI7T.mjs +37 -0
- package/{src/components/editor/nodes/Stepper/index.tsx → dist/chunk-6RNZQOH2.mjs} +214 -260
- package/dist/chunk-77KXU36M.mjs +64 -0
- package/dist/chunk-77UA6HYR.mjs +165 -0
- package/dist/chunk-7NZAPJ4G.mjs +102 -0
- package/dist/chunk-7VUMHWWL.mjs +152 -0
- package/dist/chunk-AMMKBSST.mjs +1256 -0
- package/dist/chunk-BIU7WTLX.mjs +95 -0
- package/dist/chunk-EGMI62PP.mjs +83 -0
- package/dist/chunk-EHNQD5KO.mjs +88 -0
- package/dist/chunk-FSM26655.mjs +37 -0
- package/{src/components/editor/nodes/Hint/index.tsx → dist/chunk-G53GLEAY.mjs} +158 -190
- package/dist/chunk-GK35L7UY.mjs +28 -0
- package/dist/chunk-GXYD4VZM.mjs +193 -0
- package/dist/chunk-GYIOYVCN.mjs +538 -0
- package/dist/chunk-GZPNVR7L.mjs +157 -0
- package/dist/chunk-JXDPPUJI.mjs +52 -0
- package/dist/chunk-K36V4SIW.mjs +141 -0
- package/dist/chunk-KJ6AJ44Q.mjs +128 -0
- package/dist/chunk-KJV3FAZ7.mjs +142 -0
- package/{src/components/editor/plugins/ImagesPlugin/index.tsx → dist/chunk-LGG4IUIA.mjs} +189 -222
- package/dist/chunk-LQN3CMKV.mjs +1906 -0
- package/dist/chunk-N3WN46VL.mjs +236 -0
- package/dist/chunk-PBD6LMLC.mjs +366 -0
- package/dist/chunk-POGRR73N.mjs +33 -0
- package/{src/components/editor/utils/editorFormatting.ts → dist/chunk-PZSUSXQG.mjs} +238 -282
- package/dist/chunk-QEIFVK5M.mjs +29 -0
- package/dist/chunk-QHIQKMVN.mjs +427 -0
- package/dist/chunk-TCYK7DM7.mjs +36 -0
- package/dist/chunk-TTHQCW5F.mjs +47 -0
- package/dist/chunk-U47ABU5Z.mjs +53 -0
- package/dist/chunk-WDG7J2DY.mjs +116 -0
- package/dist/chunk-WJRHXI2C.mjs +733 -0
- package/dist/chunk-XLER2DHM.mjs +357 -0
- package/dist/chunk-XWC4TK2N.mjs +315 -0
- package/dist/chunk-YHPNOWFH.mjs +15 -0
- package/dist/chunk-YKC3SO4Z.mjs +32 -0
- package/dist/chunk-YMBXLRW5.mjs +374 -0
- package/dist/chunk-YPHOEJ46.mjs +64 -0
- package/dist/chunk-YUDCJRJM.mjs +25 -0
- package/dist/chunk-Z4EWP7BI.mjs +65 -0
- package/dist/chunk-ZB5LZQKC.mjs +191 -0
- package/dist/chunk-ZJRKATOJ.mjs +65 -0
- package/dist/color-BPKOPQKN.mjs +12 -0
- package/dist/estree-XC56IUFX.mjs +4414 -0
- package/dist/font-FEZ3GKSF.mjs +13 -0
- package/dist/font-size-EK775WRH.mjs +15 -0
- package/dist/html-S3ACX7NI.mjs +2738 -0
- package/dist/image-2PJIAYAT.mjs +993 -0
- package/dist/index.d.mts +145 -0
- package/dist/index.d.ts +145 -0
- package/dist/index.js +57855 -0
- package/dist/index.mjs +1790 -0
- package/dist/insert-gif-SAIDYURE.mjs +100 -0
- package/dist/insert-image-U3RJN3OW.mjs +259 -0
- package/dist/insert-node-5P2CRJ7S.mjs +201 -0
- package/dist/insert-poll-HCPM7MO6.mjs +33 -0
- package/dist/insert-table-24XYUS2W.mjs +66 -0
- package/dist/markdown-SNVBOSRA.mjs +3487 -0
- package/dist/poll-component-2R4MDLHS.mjs +303 -0
- package/dist/postcss-ONF3VDIM.mjs +5051 -0
- package/dist/standalone-EOIALU3M.mjs +2373 -0
- package/dist/stepper-FSARL6X6.mjs +304 -0
- package/dist/styles/notiq.css +1149 -0
- package/dist/text-align-VLECWO4H.mjs +118 -0
- package/dist/text-format-BG5WOOPZ.mjs +16 -0
- package/dist/typescript-AMPI6OVS.mjs +13135 -0
- package/package.json +94 -10
- package/src/styles/notiq.css +1149 -0
- package/src/styles/tailwind-plugin.ts +134 -0
- package/components.json +0 -21
- package/eslint.config.mjs +0 -16
- package/next.config.ts +0 -12
- package/postcss.config.mjs +0 -5
- package/public/file.svg +0 -1
- package/public/globe.svg +0 -1
- package/public/images/icons/plus.svg +0 -10
- package/public/next.svg +0 -1
- package/public/vercel.svg +0 -1
- package/public/window.svg +0 -1
- package/src/app/actions.ts +0 -2
- package/src/app/api/ai/route.ts +0 -175
- package/src/app/api/edgestore/[...edgestore]/route.ts +0 -28
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +0 -205
- package/src/app/layout.tsx +0 -38
- package/src/app/page.tsx +0 -12
- package/src/components/editor/Core.tsx +0 -220
- package/src/components/editor/hooks/instructions-messages.ts +0 -300
- package/src/components/editor/hooks/use-mobile.ts +0 -19
- package/src/components/editor/hooks/useReport.ts +0 -67
- package/src/components/editor/hooks/useResizeObservert.ts +0 -22
- package/src/components/editor/index.tsx +0 -39
- package/src/components/editor/lexical-on-change.tsx +0 -28
- package/src/components/editor/nodes/CollapsibleNode/CollapsibleContainerNode.ts +0 -92
- package/src/components/editor/nodes/CollapsibleNode/CollapsibleContentNode.ts +0 -65
- package/src/components/editor/nodes/CollapsibleNode/CollapsibleTitleNode.ts +0 -105
- package/src/components/editor/nodes/EquationNode/EquationComponent.tsx +0 -143
- package/src/components/editor/nodes/EquationNode/EquationNode.tsx +0 -170
- package/src/components/editor/nodes/ExcalidrawNode/ExcalidrawComponent.tsx +0 -228
- package/src/components/editor/nodes/ExcalidrawNode/ExcalidrawImage.tsx +0 -137
- package/src/components/editor/nodes/ExcalidrawNode/ImageResizer.tsx +0 -317
- package/src/components/editor/nodes/ExcalidrawNode/index.tsx +0 -204
- package/src/components/editor/nodes/FigmaNode/FigmaNode.tsx +0 -134
- package/src/components/editor/nodes/Hint/HintComponet.tsx +0 -221
- package/src/components/editor/nodes/ImageNode/index.tsx +0 -328
- package/src/components/editor/nodes/InlineImageNode/InlineImageComponent.tsx +0 -383
- package/src/components/editor/nodes/InlineImageNode/InlineImageNode.css +0 -94
- package/src/components/editor/nodes/InlineImageNode/InlineImageNode.tsx +0 -309
- package/src/components/editor/nodes/LayoutNode/LayoutContainerNode.ts +0 -146
- package/src/components/editor/nodes/LayoutNode/LayoutItemNode.ts +0 -79
- package/src/components/editor/nodes/PollNode/index.tsx +0 -204
- package/src/components/editor/nodes/TweetNode/index.tsx +0 -214
- package/src/components/editor/nodes/index.ts +0 -81
- package/src/components/editor/plugins/AutoEmbedPlugin/index.tsx +0 -350
- package/src/components/editor/plugins/AutoLinkPlugin/index.tsx +0 -56
- package/src/components/editor/plugins/CodeActionMenuPlugin/components/CopyButton.tsx +0 -70
- package/src/components/editor/plugins/CodeActionMenuPlugin/components/PrettierButton.tsx +0 -192
- package/src/components/editor/plugins/CodeActionMenuPlugin/index.tsx +0 -217
- package/src/components/editor/plugins/CodeActionMenuPlugin/utils.ts +0 -26
- package/src/components/editor/plugins/CodeHighlightPlugin/index.ts +0 -21
- package/src/components/editor/plugins/CollapsiblePlugin/Collapsible.css +0 -76
- package/src/components/editor/plugins/CollapsiblePlugin/index.ts +0 -228
- package/src/components/editor/plugins/DragDropPastePlugin/index.tsx +0 -44
- package/src/components/editor/plugins/DraggableBlockPlugin/index.tsx +0 -52
- package/src/components/editor/plugins/EquationsPlugin/index.tsx +0 -85
- package/src/components/editor/plugins/ExcalidrawPlugin/index.tsx +0 -98
- package/src/components/editor/plugins/FigmaPlugin/index.tsx +0 -42
- package/src/components/editor/plugins/FloatingLinkEditorPlugin/index.tsx +0 -445
- package/src/components/editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx +0 -275
- package/src/components/editor/plugins/InlineImagePlugin/index.tsx +0 -351
- package/src/components/editor/plugins/LayoutPlugin/index.tsx +0 -238
- package/src/components/editor/plugins/LinkPlugin/index.tsx +0 -36
- package/src/components/editor/plugins/LinkWithMetaData/index.tsx +0 -271
- package/src/components/editor/plugins/MarkdownShortcutPlugin/index.tsx +0 -11
- package/src/components/editor/plugins/MarkdownTransformers/index.tsx +0 -304
- package/src/components/editor/plugins/PollPlugin/index.tsx +0 -49
- package/src/components/editor/plugins/ShortcutsPlugin/index.tsx +0 -180
- package/src/components/editor/plugins/ShortcutsPlugin/shortcuts.ts +0 -253
- package/src/components/editor/plugins/SlashCommand/index.tsx +0 -621
- package/src/components/editor/plugins/SpeechToTextPlugin/index.ts +0 -127
- package/src/components/editor/plugins/TabFocusPlugin/index.ts +0 -58
- package/src/components/editor/plugins/TableCellResizer/index.tsx +0 -438
- package/src/components/editor/plugins/TablePlugin/index.tsx +0 -99
- package/src/components/editor/plugins/ToolbarPlugin/index.tsx +0 -522
- package/src/components/editor/plugins/TwitterPlugin/index.ts +0 -35
- package/src/components/editor/plugins/YouTubeNode/index.tsx +0 -179
- package/src/components/editor/plugins/YouTubePlugin/index.ts +0 -41
- package/src/components/editor/themes/editor-theme.ts +0 -113
- package/src/components/editor/themes/theme.css +0 -377
- package/src/components/editor/utils/ai.ts +0 -291
- package/src/components/editor/utils/canUseDOM.ts +0 -12
- package/src/components/editor/utils/environment.ts +0 -50
- package/src/components/editor/utils/extract-data.ts +0 -166
- package/src/components/editor/utils/getAllLexicalChildren.ts +0 -13
- package/src/components/editor/utils/getDOMRangeRect.ts +0 -27
- package/src/components/editor/utils/getSelectedNode.ts +0 -27
- package/src/components/editor/utils/gif.ts +0 -29
- package/src/components/editor/utils/invariant.ts +0 -15
- package/src/components/editor/utils/setFloatingElemPosition.ts +0 -51
- package/src/components/editor/utils/setFloatingElemPositionForLinkEditor.ts +0 -40
- package/src/components/editor/utils/setNodePlaceholderFromSelection/getNodePlaceholder.ts +0 -51
- package/src/components/editor/utils/setNodePlaceholderFromSelection/setNodePlaceholderFromSelection.ts +0 -15
- package/src/components/editor/utils/setNodePlaceholderFromSelection/setPlaceholderOnSelection.ts +0 -114
- package/src/components/editor/utils/setNodePlaceholderFromSelection/styles.css +0 -6
- package/src/components/editor/utils/url.ts +0 -109
- package/src/components/editor/utils/useLayoutEffect.ts +0 -13
- package/src/components/providers/QueryProvider.tsx +0 -15
- package/src/components/providers/SharedHistoryContext.tsx +0 -28
- package/src/components/providers/ToolbarContext.tsx +0 -123
- package/src/components/providers/theme-provider.tsx +0 -11
- package/src/components/theme/ModeToggle.tsx +0 -40
- package/src/components/ui/FileInput.tsx +0 -40
- package/src/components/ui/Input.css +0 -32
- package/src/components/ui/Select.css +0 -42
- package/src/components/ui/Select.tsx +0 -36
- package/src/components/ui/TextInput.tsx +0 -48
- package/src/components/ui/ai/ai-button.tsx +0 -574
- package/src/components/ui/ai/border.tsx +0 -99
- package/src/components/ui/ai/placeholder-input-vanish.tsx +0 -282
- package/src/components/ui/button.tsx +0 -89
- package/src/components/ui/card.tsx +0 -76
- package/src/components/ui/checkbox.tsx +0 -30
- package/src/components/ui/command.tsx +0 -153
- package/src/components/ui/dialog/Dialog.css +0 -25
- package/src/components/ui/dialog/Dialog.tsx +0 -34
- package/src/components/ui/dialog.tsx +0 -122
- package/src/components/ui/drop-downs/background-color.tsx +0 -183
- package/src/components/ui/drop-downs/block-format.tsx +0 -159
- package/src/components/ui/drop-downs/code.tsx +0 -42
- package/src/components/ui/drop-downs/color.tsx +0 -177
- package/src/components/ui/drop-downs/font-size.tsx +0 -138
- package/src/components/ui/drop-downs/font.tsx +0 -155
- package/src/components/ui/drop-downs/index.tsx +0 -122
- package/src/components/ui/drop-downs/insert-node.tsx +0 -213
- package/src/components/ui/drop-downs/text-align.tsx +0 -123
- package/src/components/ui/drop-downs/text-format.tsx +0 -104
- package/src/components/ui/dropdown-menu.tsx +0 -201
- package/src/components/ui/equation/EquationEditor.css +0 -38
- package/src/components/ui/equation/EquationEditor.tsx +0 -56
- package/src/components/ui/equation/KatexEquationAlterer.css +0 -41
- package/src/components/ui/equation/KatexEquationAlterer.tsx +0 -83
- package/src/components/ui/equation/KatexRenderer.tsx +0 -66
- package/src/components/ui/excalidraw/ExcalidrawModal.css +0 -64
- package/src/components/ui/excalidraw/ExcalidrawModal.tsx +0 -234
- package/src/components/ui/excalidraw/Modal.css +0 -62
- package/src/components/ui/excalidraw/Modal.tsx +0 -110
- package/src/components/ui/hover-card.tsx +0 -29
- package/src/components/ui/image/error-image.tsx +0 -17
- package/src/components/ui/image/file-upload.tsx +0 -240
- package/src/components/ui/image/image-resizer.tsx +0 -297
- package/src/components/ui/image/image-toolbar.tsx +0 -264
- package/src/components/ui/image/index.tsx +0 -408
- package/src/components/ui/image/lazy-image.tsx +0 -68
- package/src/components/ui/image/lazy-video.tsx +0 -71
- package/src/components/ui/input.tsx +0 -22
- package/src/components/ui/models/custom-dialog.tsx +0 -320
- package/src/components/ui/models/insert-gif.tsx +0 -90
- package/src/components/ui/models/insert-image.tsx +0 -52
- package/src/components/ui/models/insert-poll.tsx +0 -29
- package/src/components/ui/models/insert-table.tsx +0 -62
- package/src/components/ui/models/use-model.tsx +0 -91
- package/src/components/ui/poll/poll-component.tsx +0 -304
- package/src/components/ui/popover.tsx +0 -33
- package/src/components/ui/progress.tsx +0 -28
- package/src/components/ui/scroll-area.tsx +0 -48
- package/src/components/ui/separator.tsx +0 -31
- package/src/components/ui/skeleton.tsx +0 -15
- package/src/components/ui/sonner.tsx +0 -31
- package/src/components/ui/stepper/step.tsx +0 -179
- package/src/components/ui/stepper/stepper.tsx +0 -89
- package/src/components/ui/textarea.tsx +0 -22
- package/src/components/ui/toggle.tsx +0 -71
- package/src/components/ui/tooltip.tsx +0 -32
- package/src/components/ui/write/text-format-floting-toolbar.tsx +0 -346
- package/src/lib/edgestore.ts +0 -9
- package/src/lib/pinecone-client.ts +0 -0
- package/src/lib/utils.ts +0 -6
- package/src/utils/docSerialization.ts +0 -77
- package/src/utils/emoji-list.ts +0 -16615
- package/src/utils/getDOMRangeRect.ts +0 -27
- package/src/utils/getThemeSelector.ts +0 -25
- package/src/utils/isMobileWidth.ts +0 -7
- package/src/utils/joinClasses.ts +0 -13
- package/src/utils/setFloatingElemPosition.ts +0 -74
- package/src/utils/setFloatingElemPositionForLinkEditor.ts +0 -46
- package/src/utils/swipe.ts +0 -127
- package/src/utils/url.ts +0 -38
- package/tsconfig.json +0 -27
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Chinonso Chikelue (fluantiX)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,71 +1,262 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="public/logo.png" alt="Notiq Logo" width="120" />
|
|
3
|
+
<h1>Notiq</h1>
|
|
4
|
+
<p>
|
|
5
|
+
<strong>A powerful, AI-enhanced rich text editor built with Lexical, Next.js, TypeScript, and Tailwind CSS.</strong>
|
|
6
|
+
</p>
|
|
7
|
+
<p>
|
|
8
|
+
Create beautiful documents with intelligent writing assistance and advanced content blocks.
|
|
9
|
+
</p>
|
|
10
|
+
</div>
|
|
2
11
|
|
|
3
|
-
|
|
12
|
+

|
|
4
13
|
|
|
5
|
-
##
|
|
14
|
+
## 📸 Screenshots
|
|
6
15
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- 🎨 Customizable themes with Tailwind CSS
|
|
12
|
-
- 🗂️ Modular plugin architecture
|
|
13
|
-
- 🌐 Next.js app with API routes
|
|
16
|
+
<div align="center">
|
|
17
|
+
<h3>Desktop View</h3>
|
|
18
|
+
<img src="public/screenshots/desktop.png" alt="Desktop Screenshot" width="100%" />
|
|
19
|
+
</div>
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
<div align="center">
|
|
22
|
+
<h3>Mobile View</h3>
|
|
23
|
+
<img src="public/screenshots/mobile.png" alt="Mobile Screenshot" width="300" />
|
|
24
|
+
</div>
|
|
16
25
|
|
|
17
|
-
|
|
26
|
+
## ✨ Features
|
|
18
27
|
|
|
19
|
-
-
|
|
20
|
-
-
|
|
28
|
+
### 🤖 AI-Powered Writing Assistant
|
|
29
|
+
- **Smart Writing**: GPT-4 integration for content improvement, grammar fixes, and style adjustments
|
|
30
|
+
- **AI Chat**: Ask questions about your document content and get contextual responses
|
|
31
|
+
- **Auto-completion**: Intelligent text suggestions and completions
|
|
32
|
+
- **Content Enhancement**: Make text longer/shorter, create step-by-step guides, simplify language
|
|
33
|
+
|
|
34
|
+
### ✏️ Rich Text Editor
|
|
35
|
+
- **Lexical Framework**: Built on Facebook's modern Lexical editor framework
|
|
36
|
+
- **WYSIWYG Editing**: What-you-see-is-what-you-get editing experience
|
|
37
|
+
- **Markdown Support**: Full markdown shortcuts and live transformers
|
|
38
|
+
- **Slash Commands**: Type "/" for quick content insertion and formatting
|
|
39
|
+
- **Floating Toolbars**: Context-sensitive formatting tools
|
|
40
|
+
|
|
41
|
+
### 🧩 Advanced Content Blocks
|
|
42
|
+
- **Media**: Images, inline images, YouTube videos, Twitter embeds
|
|
43
|
+
- **Interactive**: Polls, step-by-step guides, collapsible sections
|
|
44
|
+
- **Technical**: Code blocks with syntax highlighting, mathematical equations (KaTeX)
|
|
45
|
+
- **Design**: Excalidraw drawings, Figma embeds
|
|
46
|
+
- **Layout**: Multi-column layouts, resizable panels, tables
|
|
47
|
+
- **Callouts**: Hint blocks and special callout sections
|
|
48
|
+
|
|
49
|
+
### 🎨 User Experience
|
|
50
|
+
- **Drag & Drop**: Draggable blocks and content reordering
|
|
51
|
+
- **Speech-to-Text**: Voice input capabilities
|
|
52
|
+
- **Link Previews**: Rich link previews with metadata
|
|
53
|
+
- **Theme Support**: Dark/light mode with seamless switching
|
|
54
|
+
- **Keyboard Shortcuts**: Comprehensive shortcut system
|
|
55
|
+
- **Real-time Collaboration**: Shared editing context
|
|
56
|
+
|
|
57
|
+
## 🚀 Library Usage
|
|
58
|
+
|
|
59
|
+
Notiq can be used as a standalone editor in your React/Next.js projects.
|
|
21
60
|
|
|
22
61
|
### Installation
|
|
23
62
|
|
|
24
63
|
```bash
|
|
64
|
+
npm install @collabchron/notiq
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Integration
|
|
68
|
+
|
|
69
|
+
#### 1. Configure Tailwind CSS
|
|
70
|
+
|
|
71
|
+
Add the Notiq plugin to your `tailwind.config.js`:
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
import { notiqPlugin } from '@collabchron/notiq';
|
|
75
|
+
|
|
76
|
+
export default {
|
|
77
|
+
content: [
|
|
78
|
+
// ... your content paths
|
|
79
|
+
"./node_modules/@collabchron/notiq/dist/**/*.{js,mjs}",
|
|
80
|
+
],
|
|
81
|
+
plugins: [
|
|
82
|
+
notiqPlugin,
|
|
83
|
+
require('@tailwindcss/typography'),
|
|
84
|
+
],
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### 2. Usage in your component
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
"use client";
|
|
92
|
+
|
|
93
|
+
import { Editor } from "@collabchron/notiq";
|
|
94
|
+
|
|
95
|
+
export default function MyEditorPage() {
|
|
96
|
+
return (
|
|
97
|
+
<Editor
|
|
98
|
+
isEditable={true}
|
|
99
|
+
aiConfig={{
|
|
100
|
+
apiEndpoint: "/api/ai", // Your AI completion endpoint
|
|
101
|
+
}}
|
|
102
|
+
uploadConfig={{
|
|
103
|
+
uploadHandler: async (file) => {
|
|
104
|
+
// Your custom upload logic (e.g., S3, Cloudinary)
|
|
105
|
+
return { url: "https://your-storage.com/file.png" };
|
|
106
|
+
}
|
|
107
|
+
}}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## 🛠️ Local Development
|
|
114
|
+
|
|
115
|
+
If you want to contribute or run the development environment:
|
|
116
|
+
|
|
117
|
+
### Installation
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npm install
|
|
121
|
+
|
|
122
|
+
# or
|
|
123
|
+
|
|
124
|
+
yarn install
|
|
125
|
+
|
|
126
|
+
# or
|
|
127
|
+
|
|
25
128
|
pnpm install
|
|
26
129
|
```
|
|
27
130
|
|
|
131
|
+
### Environment Setup
|
|
132
|
+
|
|
133
|
+
Create a `.env.local` file with your API keys:
|
|
134
|
+
|
|
135
|
+
```env
|
|
136
|
+
OPENAI_API_KEY=your_openai_api_key_here
|
|
137
|
+
|
|
138
|
+
NEXT_PUBLIC_EDGESTORE_ACCESS_KEY=your_edgestore_key
|
|
139
|
+
|
|
140
|
+
NEXT_PUBLIC_EDGESTORE_SECRET_KEY=your_edgestore_secret
|
|
141
|
+
```
|
|
142
|
+
|
|
28
143
|
### Development
|
|
29
144
|
|
|
30
145
|
```bash
|
|
146
|
+
npm run dev
|
|
147
|
+
|
|
148
|
+
# or
|
|
149
|
+
|
|
150
|
+
yarn dev
|
|
151
|
+
|
|
152
|
+
# or
|
|
153
|
+
|
|
31
154
|
pnpm dev
|
|
32
155
|
```
|
|
33
156
|
|
|
34
|
-
Open [http://localhost:3000](http://localhost:3000)
|
|
157
|
+
Open [http://localhost:3000](http://localhost:3000) to start writing!
|
|
35
158
|
|
|
36
|
-
|
|
159
|
+
## 🏗️ Architecture
|
|
37
160
|
|
|
38
|
-
|
|
39
|
-
|
|
161
|
+
### Core Components
|
|
162
|
+
|
|
163
|
+
- **Editor Core** (`/src/components/editor/Core.tsx`) - Main editor container with Lexical integration
|
|
164
|
+
- **Plugins** (`/src/components/editor/plugins/`) - 40+ feature plugins for rich functionality
|
|
165
|
+
- **Nodes** (`/src/components/editor/nodes/`) - 20+ custom content block types
|
|
166
|
+
- **AI Integration** (`/src/components/ui/ai/`) - AI-powered writing assistance
|
|
167
|
+
- **Toolbar System** - Rich formatting toolbar with contextual actions
|
|
168
|
+
|
|
169
|
+
### Plugin System
|
|
170
|
+
|
|
171
|
+
Notiq uses an extensible plugin architecture:
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
import { Editor } from '@/components/editor'
|
|
175
|
+
|
|
176
|
+
function MyApp() {
|
|
177
|
+
return (
|
|
178
|
+
<Editor
|
|
179
|
+
plugins={[
|
|
180
|
+
// Built-in plugins
|
|
181
|
+
'toolbar',
|
|
182
|
+
'slash-commands',
|
|
183
|
+
'ai-assistant',
|
|
184
|
+
'drag-drop',
|
|
185
|
+
// Custom plugins
|
|
186
|
+
MyCustomPlugin
|
|
187
|
+
]}
|
|
188
|
+
/>
|
|
189
|
+
)
|
|
190
|
+
}
|
|
40
191
|
```
|
|
41
192
|
|
|
42
|
-
##
|
|
193
|
+
## 🎯 Use Cases
|
|
194
|
+
|
|
195
|
+
- **Documentation**: Technical docs, API references, user guides
|
|
196
|
+
- **Content Creation**: Blog posts, articles, marketing content
|
|
197
|
+
- **Note-taking**: Personal notes, meeting minutes, research
|
|
198
|
+
- **Collaborative Writing**: Team documents, shared knowledge bases
|
|
199
|
+
- **Educational Content**: Tutorials, courses, interactive lessons
|
|
200
|
+
|
|
201
|
+
## 🛠️ Development
|
|
202
|
+
|
|
203
|
+
### Adding Custom Nodes
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
import { DecoratorNode } from 'lexical'
|
|
207
|
+
|
|
208
|
+
export class MyCustomNode extends DecoratorNode<JSX.Element> {
|
|
209
|
+
static getType(): string {
|
|
210
|
+
return 'my-custom-node'
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
createDOM(): HTMLElement {
|
|
214
|
+
return document.createElement('div')
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
decorate(): JSX.Element {
|
|
218
|
+
return <MyCustomComponent />
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Creating Plugins
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
|
227
|
+
|
|
228
|
+
export function MyPlugin() {
|
|
229
|
+
const [editor] = useLexicalComposerContext()
|
|
230
|
+
|
|
231
|
+
// Plugin logic here
|
|
232
|
+
|
|
233
|
+
return null
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## 📦 Building for Production
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
npm run build
|
|
241
|
+
npm run start
|
|
242
|
+
```
|
|
43
243
|
|
|
44
|
-
|
|
45
|
-
- `src/components/editor/` — Editor core, plugins, nodes, and UI
|
|
46
|
-
- `src/components/ui/` — Reusable UI components
|
|
47
|
-
- `src/lib/` — Utility libraries (EdgeStore, Pinecone, etc.)
|
|
48
|
-
- `public/` — Static assets
|
|
244
|
+
## 🤝 Contributing
|
|
49
245
|
|
|
50
|
-
|
|
246
|
+
We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING.md) for details on how to get started, submitting bug reports, and suggesting enhancements.
|
|
51
247
|
|
|
52
|
-
|
|
53
|
-
- **Nodes:** ImageNode, InlineImageNode, EquationNode, ExcalidrawNode, PollNode, etc.
|
|
248
|
+
Please note that this project is released with a [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
|
|
54
249
|
|
|
55
|
-
##
|
|
250
|
+
## 📄 License
|
|
56
251
|
|
|
57
|
-
-
|
|
58
|
-
- ESLint config: `eslint.config.mjs`
|
|
59
|
-
- Editor themes: `src/components/editor/themes/`
|
|
252
|
+
MIT License - see the [LICENSE](LICENSE) file for details.
|
|
60
253
|
|
|
61
|
-
##
|
|
254
|
+
## 🆘 Support
|
|
62
255
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
4. Push to the branch (`git push origin feature/foo`)
|
|
67
|
-
5. Create a Pull Request
|
|
256
|
+
- 📖 [Documentation](https://github.com/chinonsochikelue/notiq)
|
|
257
|
+
- 🐛 [Report Issues](https://github.com/chinonsochikelue/notiq/issues)
|
|
258
|
+
- 💬 [Discussions](https://github.com/chinonsochikelue/notiq/discussions)
|
|
68
259
|
|
|
69
|
-
|
|
260
|
+
---
|
|
70
261
|
|
|
71
|
-
|
|
262
|
+
Built with ❤️ using [Lexical](https://lexical.dev/), [Next.js](https://nextjs.org/), and [OpenAI](https://openai.com/)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CodeActionMenuPlugin
|
|
3
|
+
} from "./chunk-PBD6LMLC.mjs";
|
|
4
|
+
import "./chunk-TTHQCW5F.mjs";
|
|
5
|
+
import "./chunk-GK35L7UY.mjs";
|
|
6
|
+
import "./chunk-EGMI62PP.mjs";
|
|
7
|
+
import "./chunk-KJ6AJ44Q.mjs";
|
|
8
|
+
import "./chunk-64Z3FI7T.mjs";
|
|
9
|
+
import "./chunk-WDG7J2DY.mjs";
|
|
10
|
+
import "./chunk-BIU7WTLX.mjs";
|
|
11
|
+
import "./chunk-YHPNOWFH.mjs";
|
|
12
|
+
import "./chunk-77KXU36M.mjs";
|
|
13
|
+
export {
|
|
14
|
+
CodeActionMenuPlugin as default
|
|
15
|
+
};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
DynamicBlockNode
|
|
4
|
+
} from "./chunk-5BAKY5KN.mjs";
|
|
5
|
+
import {
|
|
6
|
+
Badge
|
|
7
|
+
} from "./chunk-FSM26655.mjs";
|
|
8
|
+
import {
|
|
9
|
+
Card,
|
|
10
|
+
CardContent,
|
|
11
|
+
CardHeader,
|
|
12
|
+
CardTitle
|
|
13
|
+
} from "./chunk-3G37YKTV.mjs";
|
|
14
|
+
import {
|
|
15
|
+
Button
|
|
16
|
+
} from "./chunk-BIU7WTLX.mjs";
|
|
17
|
+
import {
|
|
18
|
+
cn
|
|
19
|
+
} from "./chunk-YHPNOWFH.mjs";
|
|
20
|
+
import {
|
|
21
|
+
React,
|
|
22
|
+
__spreadValues,
|
|
23
|
+
init_react_shim
|
|
24
|
+
} from "./chunk-77KXU36M.mjs";
|
|
25
|
+
|
|
26
|
+
// src/components/editor/nodes/DynamicBlockNode/DynamicBlockComponent.tsx
|
|
27
|
+
init_react_shim();
|
|
28
|
+
import { useState, useEffect, useRef } from "react";
|
|
29
|
+
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
30
|
+
import { $getNodeByKey } from "lexical";
|
|
31
|
+
import { Play, Pause, Settings, Eye, EyeOff, Zap } from "lucide-react";
|
|
32
|
+
function DynamicBlockComponent({ nodeKey, payload }) {
|
|
33
|
+
var _a;
|
|
34
|
+
const [editor] = useLexicalComposerContext();
|
|
35
|
+
const [currentBlockId, setCurrentBlockId] = useState(payload.currentBlockId || ((_a = payload.blocks[0]) == null ? void 0 : _a.id));
|
|
36
|
+
const [isPreviewMode, setIsPreviewMode] = useState(false);
|
|
37
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
38
|
+
const [showSettings, setShowSettings] = useState(false);
|
|
39
|
+
const containerRef = useRef(null);
|
|
40
|
+
const timeoutRef = useRef(void 0);
|
|
41
|
+
const currentBlock = payload.blocks.find((block) => block.id === currentBlockId);
|
|
42
|
+
const activeTriggers = payload.triggers.filter(
|
|
43
|
+
(trigger) => trigger.targetBlockId === currentBlockId || payload.blocks.some((block) => block.id === trigger.targetBlockId)
|
|
44
|
+
);
|
|
45
|
+
const executeTrigger = (trigger) => {
|
|
46
|
+
const targetBlock = payload.blocks.find((block) => block.id === trigger.targetBlockId);
|
|
47
|
+
if (!targetBlock) return;
|
|
48
|
+
switch (trigger.action) {
|
|
49
|
+
case "show":
|
|
50
|
+
case "replace":
|
|
51
|
+
setCurrentBlockId(trigger.targetBlockId);
|
|
52
|
+
break;
|
|
53
|
+
case "hide":
|
|
54
|
+
setCurrentBlockId("");
|
|
55
|
+
break;
|
|
56
|
+
case "animate":
|
|
57
|
+
setCurrentBlockId("");
|
|
58
|
+
setTimeout(() => setCurrentBlockId(trigger.targetBlockId), 100);
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (!isPreviewMode || !containerRef.current) return;
|
|
64
|
+
const container = containerRef.current;
|
|
65
|
+
const timeTriggers = activeTriggers.filter((t) => t.type === "time");
|
|
66
|
+
const clickTriggers = activeTriggers.filter((t) => t.type === "click");
|
|
67
|
+
const hoverTriggers = activeTriggers.filter((t) => t.type === "hover");
|
|
68
|
+
if (isPlaying && timeTriggers.length > 0) {
|
|
69
|
+
timeTriggers.forEach((trigger) => {
|
|
70
|
+
const delay = typeof trigger.condition === "number" ? trigger.condition * 1e3 : 3e3;
|
|
71
|
+
timeoutRef.current = setTimeout(() => executeTrigger(trigger), delay);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const handleClick = () => {
|
|
75
|
+
clickTriggers.forEach(executeTrigger);
|
|
76
|
+
};
|
|
77
|
+
const handleMouseEnter = () => {
|
|
78
|
+
hoverTriggers.forEach(executeTrigger);
|
|
79
|
+
};
|
|
80
|
+
container.addEventListener("click", handleClick);
|
|
81
|
+
container.addEventListener("mouseenter", handleMouseEnter);
|
|
82
|
+
return () => {
|
|
83
|
+
container.removeEventListener("click", handleClick);
|
|
84
|
+
container.removeEventListener("mouseenter", handleMouseEnter);
|
|
85
|
+
if (timeoutRef.current) {
|
|
86
|
+
clearTimeout(timeoutRef.current);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}, [isPreviewMode, isPlaying, activeTriggers, currentBlockId]);
|
|
90
|
+
const updatePayload = (newPayload) => {
|
|
91
|
+
editor.update(() => {
|
|
92
|
+
const node = $getNodeByKey(nodeKey);
|
|
93
|
+
if ($isDynamicBlockNode(node)) {
|
|
94
|
+
node.updatePayload(__spreadValues(__spreadValues({}, payload), newPayload));
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
const renderContentBlock = (block) => {
|
|
99
|
+
const animationClass = block.animation && block.animation !== "none" ? `animate-${block.animation === "fade" ? "fade-in" : block.animation === "slide" ? "slide-in-right" : "bounce-in"}` : "";
|
|
100
|
+
switch (block.type) {
|
|
101
|
+
case "text":
|
|
102
|
+
return /* @__PURE__ */ React.createElement(
|
|
103
|
+
"div",
|
|
104
|
+
{
|
|
105
|
+
className: cn("prose prose-sm max-w-none", animationClass),
|
|
106
|
+
style: block.styles,
|
|
107
|
+
dangerouslySetInnerHTML: { __html: block.content }
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
case "image":
|
|
111
|
+
return /* @__PURE__ */ React.createElement(
|
|
112
|
+
"img",
|
|
113
|
+
{
|
|
114
|
+
src: block.content || "/placeholder.svg",
|
|
115
|
+
alt: "Dynamic content",
|
|
116
|
+
className: cn("max-w-full h-auto rounded-lg", animationClass),
|
|
117
|
+
style: block.styles
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
case "video":
|
|
121
|
+
return /* @__PURE__ */ React.createElement(
|
|
122
|
+
"video",
|
|
123
|
+
{
|
|
124
|
+
src: block.content,
|
|
125
|
+
controls: true,
|
|
126
|
+
className: cn("max-w-full h-auto rounded-lg", animationClass),
|
|
127
|
+
style: block.styles
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
case "html":
|
|
131
|
+
return /* @__PURE__ */ React.createElement(
|
|
132
|
+
"div",
|
|
133
|
+
{
|
|
134
|
+
className: cn("w-full", animationClass),
|
|
135
|
+
style: block.styles,
|
|
136
|
+
dangerouslySetInnerHTML: { __html: block.content }
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
default:
|
|
140
|
+
return /* @__PURE__ */ React.createElement("div", { className: "text-muted-foreground" }, "Unknown content type");
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
return /* @__PURE__ */ React.createElement(Card, { className: "w-full my-4 border-2 border-dashed border-accent/30 bg-gradient-to-br from-background to-accent/5" }, /* @__PURE__ */ React.createElement(CardHeader, { className: "pb-3" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement(Zap, { className: "w-5 h-5 text-accent" }), /* @__PURE__ */ React.createElement(CardTitle, { className: "text-lg font-semibold" }, payload.title), /* @__PURE__ */ React.createElement(Badge, { variant: "secondary", className: "text-xs" }, "Dynamic Block")), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement(Button, { variant: "ghost", size: "sm", onClick: () => setIsPreviewMode(!isPreviewMode), className: "h-8 px-2" }, isPreviewMode ? /* @__PURE__ */ React.createElement(EyeOff, { className: "w-4 h-4" }) : /* @__PURE__ */ React.createElement(Eye, { className: "w-4 h-4" }), isPreviewMode ? "Edit" : "Preview"), isPreviewMode && /* @__PURE__ */ React.createElement(Button, { variant: "ghost", size: "sm", onClick: () => setIsPlaying(!isPlaying), className: "h-8 px-2" }, isPlaying ? /* @__PURE__ */ React.createElement(Pause, { className: "w-4 h-4" }) : /* @__PURE__ */ React.createElement(Play, { className: "w-4 h-4" })), /* @__PURE__ */ React.createElement(Button, { variant: "ghost", size: "sm", onClick: () => setShowSettings(!showSettings), className: "h-8 px-2" }, /* @__PURE__ */ React.createElement(Settings, { className: "w-4 h-4" }))))), /* @__PURE__ */ React.createElement(CardContent, { ref: containerRef, className: "space-y-4" }, /* @__PURE__ */ React.createElement("div", { className: "min-h-[200px] p-4 rounded-lg border bg-card/50 relative overflow-hidden" }, currentBlock ? /* @__PURE__ */ React.createElement("div", { className: "transition-all duration-300 ease-in-out" }, renderContentBlock(currentBlock)) : /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-center h-full text-muted-foreground" }, /* @__PURE__ */ React.createElement("div", { className: "text-center" }, /* @__PURE__ */ React.createElement(Zap, { className: "w-12 h-12 mx-auto mb-2 opacity-50" }), /* @__PURE__ */ React.createElement("p", null, "No content block selected"), /* @__PURE__ */ React.createElement("p", { className: "text-sm" }, "Configure blocks and triggers below")))), !isPreviewMode && /* @__PURE__ */ React.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React.createElement("h4", { className: "font-medium text-sm" }, "Content Blocks (", payload.blocks.length, ")"), /* @__PURE__ */ React.createElement(Button, { size: "sm", variant: "outline", className: "h-7 text-xs bg-transparent" }, "Add Block")), /* @__PURE__ */ React.createElement("div", { className: "grid grid-cols-2 md:grid-cols-3 gap-2" }, payload.blocks.map((block) => /* @__PURE__ */ React.createElement(
|
|
144
|
+
Button,
|
|
145
|
+
{
|
|
146
|
+
key: block.id,
|
|
147
|
+
variant: currentBlockId === block.id ? "default" : "outline",
|
|
148
|
+
size: "sm",
|
|
149
|
+
onClick: () => setCurrentBlockId(block.id),
|
|
150
|
+
className: "h-auto p-2 flex flex-col items-start text-left"
|
|
151
|
+
},
|
|
152
|
+
/* @__PURE__ */ React.createElement("div", { className: "font-medium text-xs capitalize" }, block.type),
|
|
153
|
+
/* @__PURE__ */ React.createElement("div", { className: "text-xs text-muted-foreground truncate w-full" }, block.content.substring(0, 30), "...")
|
|
154
|
+
)))), !isPreviewMode && activeTriggers.length > 0 && /* @__PURE__ */ React.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React.createElement("h4", { className: "font-medium text-sm" }, "Active Triggers (", activeTriggers.length, ")"), /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap gap-2" }, activeTriggers.map((trigger) => /* @__PURE__ */ React.createElement(Badge, { key: trigger.id, variant: "outline", className: "text-xs" }, trigger.type, ": ", trigger.action, trigger.type === "time" && ` (${trigger.condition}s)`)))), isPreviewMode && /* @__PURE__ */ React.createElement("div", { className: "text-center p-3 bg-accent/10 rounded-lg border border-accent/20" }, /* @__PURE__ */ React.createElement("p", { className: "text-sm text-accent font-medium" }, "Preview Mode Active"), /* @__PURE__ */ React.createElement("p", { className: "text-xs text-muted-foreground mt-1" }, activeTriggers.some((t) => t.type === "click") && "Click to trigger interactions \u2022 ", activeTriggers.some((t) => t.type === "hover") && "Hover to trigger interactions \u2022 ", activeTriggers.some((t) => t.type === "time") && "Press play for time-based triggers"))));
|
|
155
|
+
}
|
|
156
|
+
function $isDynamicBlockNode(node) {
|
|
157
|
+
return node instanceof DynamicBlockNode;
|
|
158
|
+
}
|
|
159
|
+
export {
|
|
160
|
+
DynamicBlockComponent as default
|
|
161
|
+
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import {
|
|
2
|
+
$isEquationNode,
|
|
3
|
+
KatexRenderer
|
|
4
|
+
} from "./chunk-3JVFG7ER.mjs";
|
|
5
|
+
import {
|
|
6
|
+
React,
|
|
7
|
+
init_react_shim
|
|
8
|
+
} from "./chunk-77KXU36M.mjs";
|
|
9
|
+
|
|
10
|
+
// src/components/editor/nodes/EquationNode/EquationComponent.tsx
|
|
11
|
+
init_react_shim();
|
|
12
|
+
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
13
|
+
import { useLexicalEditable } from "@lexical/react/useLexicalEditable";
|
|
14
|
+
import { mergeRegister } from "@lexical/utils";
|
|
15
|
+
import {
|
|
16
|
+
$getNodeByKey,
|
|
17
|
+
$getSelection,
|
|
18
|
+
$isNodeSelection,
|
|
19
|
+
COMMAND_PRIORITY_HIGH,
|
|
20
|
+
KEY_ESCAPE_COMMAND,
|
|
21
|
+
SELECTION_CHANGE_COMMAND
|
|
22
|
+
} from "lexical";
|
|
23
|
+
import * as React2 from "react";
|
|
24
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
25
|
+
import { ErrorBoundary } from "react-error-boundary";
|
|
26
|
+
|
|
27
|
+
// src/components/ui/equation/EquationEditor.tsx
|
|
28
|
+
init_react_shim();
|
|
29
|
+
import { isHTMLElement } from "lexical";
|
|
30
|
+
import { forwardRef } from "react";
|
|
31
|
+
function EquationEditor({ equation, setEquation, inline }, forwardedRef) {
|
|
32
|
+
const onChange = (event) => {
|
|
33
|
+
setEquation(event.target.value);
|
|
34
|
+
};
|
|
35
|
+
return inline && isHTMLElement(forwardedRef) ? /* @__PURE__ */ React.createElement("span", { className: "EquationEditor_inputBackground" }, /* @__PURE__ */ React.createElement("span", { className: "EquationEditor_dollarSign" }, "$"), /* @__PURE__ */ React.createElement(
|
|
36
|
+
"input",
|
|
37
|
+
{
|
|
38
|
+
className: "EquationEditor_inlineEditor",
|
|
39
|
+
value: equation,
|
|
40
|
+
onChange,
|
|
41
|
+
autoFocus: true,
|
|
42
|
+
ref: forwardedRef
|
|
43
|
+
}
|
|
44
|
+
), /* @__PURE__ */ React.createElement("span", { className: "EquationEditor_dollarSign" }, "$")) : /* @__PURE__ */ React.createElement("div", { className: "EquationEditor_inputBackground" }, /* @__PURE__ */ React.createElement("span", { className: "EquationEditor_dollarSign" }, "$$\n"), /* @__PURE__ */ React.createElement(
|
|
45
|
+
"textarea",
|
|
46
|
+
{
|
|
47
|
+
className: "EquationEditor_blockEditor",
|
|
48
|
+
value: equation,
|
|
49
|
+
onChange,
|
|
50
|
+
ref: forwardedRef
|
|
51
|
+
}
|
|
52
|
+
), /* @__PURE__ */ React.createElement("span", { className: "EquationEditor_dollarSign" }, "\n$$"));
|
|
53
|
+
}
|
|
54
|
+
var EquationEditor_default = forwardRef(EquationEditor);
|
|
55
|
+
|
|
56
|
+
// src/components/editor/nodes/EquationNode/EquationComponent.tsx
|
|
57
|
+
function EquationComponent({
|
|
58
|
+
equation,
|
|
59
|
+
inline,
|
|
60
|
+
nodeKey
|
|
61
|
+
}) {
|
|
62
|
+
const [editor] = useLexicalComposerContext();
|
|
63
|
+
const isEditable = useLexicalEditable();
|
|
64
|
+
const [equationValue, setEquationValue] = useState(equation);
|
|
65
|
+
const [showEquationEditor, setShowEquationEditor] = useState(false);
|
|
66
|
+
const inputRef = useRef(null);
|
|
67
|
+
const onHide = useCallback(
|
|
68
|
+
(restoreSelection) => {
|
|
69
|
+
setShowEquationEditor(false);
|
|
70
|
+
editor.update(() => {
|
|
71
|
+
const node = $getNodeByKey(nodeKey);
|
|
72
|
+
if ($isEquationNode(node)) {
|
|
73
|
+
node.setEquation(equationValue);
|
|
74
|
+
if (restoreSelection) {
|
|
75
|
+
node.selectNext(0, 0);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
[editor, equationValue, nodeKey]
|
|
81
|
+
);
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (!showEquationEditor && equationValue !== equation) {
|
|
84
|
+
setEquationValue(equation);
|
|
85
|
+
}
|
|
86
|
+
}, [showEquationEditor, equation, equationValue]);
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
if (!isEditable) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (showEquationEditor) {
|
|
92
|
+
return mergeRegister(
|
|
93
|
+
editor.registerCommand(
|
|
94
|
+
SELECTION_CHANGE_COMMAND,
|
|
95
|
+
(payload) => {
|
|
96
|
+
const activeElement = document.activeElement;
|
|
97
|
+
const inputElem = inputRef.current;
|
|
98
|
+
if (inputElem !== activeElement) {
|
|
99
|
+
onHide();
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
},
|
|
103
|
+
COMMAND_PRIORITY_HIGH
|
|
104
|
+
),
|
|
105
|
+
editor.registerCommand(
|
|
106
|
+
KEY_ESCAPE_COMMAND,
|
|
107
|
+
(payload) => {
|
|
108
|
+
const activeElement = document.activeElement;
|
|
109
|
+
const inputElem = inputRef.current;
|
|
110
|
+
if (inputElem === activeElement) {
|
|
111
|
+
onHide(true);
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
return false;
|
|
115
|
+
},
|
|
116
|
+
COMMAND_PRIORITY_HIGH
|
|
117
|
+
)
|
|
118
|
+
);
|
|
119
|
+
} else {
|
|
120
|
+
return editor.registerUpdateListener(({ editorState }) => {
|
|
121
|
+
const isSelected = editorState.read(() => {
|
|
122
|
+
const selection = $getSelection();
|
|
123
|
+
return $isNodeSelection(selection) && selection.has(nodeKey) && selection.getNodes().length === 1;
|
|
124
|
+
});
|
|
125
|
+
if (isSelected) {
|
|
126
|
+
setShowEquationEditor(true);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}, [editor, nodeKey, onHide, showEquationEditor, isEditable]);
|
|
131
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, showEquationEditor && isEditable ? /* @__PURE__ */ React2.createElement(
|
|
132
|
+
EquationEditor_default,
|
|
133
|
+
{
|
|
134
|
+
equation: equationValue,
|
|
135
|
+
setEquation: setEquationValue,
|
|
136
|
+
inline,
|
|
137
|
+
ref: inputRef
|
|
138
|
+
}
|
|
139
|
+
) : /* @__PURE__ */ React2.createElement(ErrorBoundary, { onError: (e) => editor._onError(e), fallback: null }, /* @__PURE__ */ React2.createElement(
|
|
140
|
+
KatexRenderer,
|
|
141
|
+
{
|
|
142
|
+
equation: equationValue,
|
|
143
|
+
inline,
|
|
144
|
+
onDoubleClick: () => {
|
|
145
|
+
if (isEditable) {
|
|
146
|
+
setShowEquationEditor(true);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
)));
|
|
151
|
+
}
|
|
152
|
+
export {
|
|
153
|
+
EquationComponent as default
|
|
154
|
+
};
|