neuphlo-editor 1.2.0 → 1.3.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 +54 -0
- package/dist/{chunk-2CI535YH.js → chunk-RXTFDBJQ.js} +4 -1
- package/dist/chunk-RXTFDBJQ.js.map +1 -0
- package/dist/{chunk-7L2HLBM2.js → chunk-TPFBGHW3.js} +67 -53
- package/dist/chunk-TPFBGHW3.js.map +1 -0
- package/dist/headless/components/editor-bubble-item.d.ts +9 -0
- package/dist/headless/components/editor-bubble-item.js +29 -0
- package/dist/headless/components/editor-bubble.d.ts +9 -0
- package/dist/headless/components/editor-bubble.js +9 -0
- package/dist/headless/components/editor-command-item.d.ts +3 -0
- package/dist/headless/components/editor-command-item.js +18 -0
- package/dist/headless/components/editor-command.d.ts +10 -0
- package/dist/headless/components/editor-command.js +48 -0
- package/dist/headless/components/editor.d.ts +24 -0
- package/dist/headless/components/editor.js +13 -0
- package/dist/headless/extensions/CodeBlock/CodeBlock.d.ts +1 -0
- package/dist/headless/extensions/CodeBlock/CodeBlock.js +6 -0
- package/dist/headless/extensions/CodeBlock/index.d.ts +1 -0
- package/dist/headless/extensions/CodeBlock/index.js +1 -0
- package/dist/headless/extensions/Image/Image.d.ts +6 -0
- package/dist/headless/extensions/Image/Image.js +197 -0
- package/dist/headless/extensions/ImageBlock/ImageBlock.d.ts +21 -0
- package/dist/headless/extensions/ImageBlock/ImageBlock.js +240 -0
- package/dist/headless/extensions/ImageBlock/index.d.ts +2 -0
- package/dist/headless/extensions/ImageBlock/index.js +1 -0
- package/dist/headless/extensions/Link/Link.d.ts +2 -0
- package/dist/headless/extensions/Link/Link.js +40 -0
- package/dist/headless/extensions/Link/index.d.ts +1 -0
- package/dist/headless/extensions/Link/index.js +1 -0
- package/dist/headless/extensions/extension-kit.d.ts +5 -0
- package/dist/headless/extensions/extension-kit.js +29 -0
- package/dist/headless/extensions/index.d.ts +6 -0
- package/dist/headless/extensions/index.js +6 -0
- package/dist/headless/extensions/slash-command.d.ts +36 -0
- package/dist/headless/extensions/slash-command.js +105 -0
- package/dist/headless/index.cjs +4 -0
- package/dist/headless/index.cjs.map +1 -1
- package/dist/headless/index.d.cts +2 -1
- package/dist/headless/index.d.ts +2 -1
- package/dist/headless/index.js +3 -1
- package/dist/headless/utils/atoms.d.ts +7 -0
- package/dist/headless/utils/atoms.js +3 -0
- package/dist/headless/utils/store.d.ts +2 -0
- package/dist/headless/utils/store.js +4 -0
- package/dist/react/Editor.d.ts +27 -0
- package/dist/react/Editor.js +33 -0
- package/dist/react/index.cjs +62 -15
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +18 -5
- package/dist/react/index.d.ts +18 -5
- package/dist/react/index.js +55 -9
- package/dist/react/index.js.map +1 -1
- package/dist/react/menus/ImageBlock/ImageBlockLoading.d.ts +2 -0
- package/dist/react/menus/ImageBlock/ImageBlockLoading.js +6 -0
- package/dist/react/menus/ImageBlock/ImageBlockMenu.d.ts +7 -0
- package/dist/react/menus/ImageBlock/ImageBlockMenu.js +100 -0
- package/dist/react/menus/ImageBlock/ImageBlockView.d.ts +10 -0
- package/dist/react/menus/ImageBlock/ImageBlockView.js +44 -0
- package/dist/react/menus/ImageBlock/ImageBlockWidth.d.ts +6 -0
- package/dist/react/menus/ImageBlock/ImageBlockWidth.js +29 -0
- package/dist/react/menus/ImageBlock/ImageUploader.d.ts +7 -0
- package/dist/react/menus/ImageBlock/ImageUploader.js +63 -0
- package/dist/react/menus/ImageBlock/index.d.ts +4 -0
- package/dist/react/menus/ImageBlock/index.js +4 -0
- package/dist/react/menus/ImageMenu.d.ts +10 -0
- package/dist/react/menus/ImageMenu.js +79 -0
- package/dist/react/menus/ImagePopover.d.ts +8 -0
- package/dist/react/menus/ImagePopover.js +146 -0
- package/dist/react/menus/LinkPopover.d.ts +9 -0
- package/dist/react/menus/LinkPopover.js +113 -0
- package/dist/react/menus/MenuList.d.ts +10 -0
- package/dist/react/menus/MenuList.js +94 -0
- package/dist/react/menus/SlashMenu.d.ts +5 -0
- package/dist/react/menus/SlashMenu.js +79 -0
- package/dist/react/menus/TextMenu.d.ts +10 -0
- package/dist/react/menus/TextMenu.js +94 -0
- package/dist/react/menus/bubble-menu-extensions.d.ts +19 -0
- package/dist/react/menus/bubble-menu-extensions.js +17 -0
- package/dist/react/menus/index.d.ts +9 -0
- package/dist/react/menus/index.js +5 -0
- package/package.json +9 -11
- package/dist/chunk-2CI535YH.js.map +0 -1
- package/dist/chunk-3AD4UBZA.js +0 -1164
- package/dist/chunk-3AD4UBZA.js.map +0 -1
- package/dist/chunk-565WQB6C.js +0 -1226
- package/dist/chunk-565WQB6C.js.map +0 -1
- package/dist/chunk-6JRIOPA5.js +0 -1226
- package/dist/chunk-6JRIOPA5.js.map +0 -1
- package/dist/chunk-6OCCPGY7.js +0 -1172
- package/dist/chunk-6OCCPGY7.js.map +0 -1
- package/dist/chunk-7L2HLBM2.js.map +0 -1
- package/dist/chunk-EQHURHL2.js +0 -1226
- package/dist/chunk-EQHURHL2.js.map +0 -1
- package/dist/chunk-FW3S5SLJ.js +0 -366
- package/dist/chunk-FW3S5SLJ.js.map +0 -1
- package/dist/chunk-TGPB2LFU.js +0 -1056
- package/dist/chunk-TGPB2LFU.js.map +0 -1
- package/dist/chunk-ZWSMKLQY.js +0 -1043
- package/dist/chunk-ZWSMKLQY.js.map +0 -1
- package/dist/editor-DI3_SEDt.d.cts +0 -29
- package/dist/editor-DI3_SEDt.d.ts +0 -29
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Neuphlo
|
|
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
|
@@ -228,6 +228,7 @@ const handleImageUpload = async (file: File): Promise<string> => {
|
|
|
228
228
|
| `showImageMenu` | `boolean` | `true` | Show image controls bubble menu |
|
|
229
229
|
| `showSlashMenu` | `boolean` | `true` | Show slash command menu |
|
|
230
230
|
| `extensions` | `Extension[]` | `[]` | Additional Tiptap extensions |
|
|
231
|
+
| `bubbleMenuExtras` | `{ text?: BubbleMenuExtra \| BubbleMenuExtra[]; image?: BubbleMenuExtra \| BubbleMenuExtra[] }` | `undefined` | Append custom UI to bubble menus |
|
|
231
232
|
| `uploadImage` | `(file: File) => Promise<string>` | `undefined` | Image upload handler |
|
|
232
233
|
| `onUpdate` | `({ editor }) => void` | `undefined` | Called when content changes |
|
|
233
234
|
| `onCreate` | `({ editor }) => void` | `undefined` | Called when editor is created |
|
|
@@ -253,6 +254,59 @@ const handleImageUpload = async (file: File): Promise<string> => {
|
|
|
253
254
|
/>
|
|
254
255
|
```
|
|
255
256
|
|
|
257
|
+
### Bubble Menu Extras
|
|
258
|
+
|
|
259
|
+
Use the `bubbleMenuExtras` prop when you need to sprinkle in project-specific controls (AI helpers, analytics buttons, etc.) without editing this package.
|
|
260
|
+
|
|
261
|
+
```tsx
|
|
262
|
+
import type { Editor } from "@tiptap/react"
|
|
263
|
+
|
|
264
|
+
const bubbleMenuExtras = {
|
|
265
|
+
text: {
|
|
266
|
+
align: "start", // show on the left side of the menu
|
|
267
|
+
render: (editor: Editor) => (
|
|
268
|
+
<button
|
|
269
|
+
type="button"
|
|
270
|
+
className="nph-btn nph-btn-ghost nph-btn-xs nph-btn-icon"
|
|
271
|
+
onMouseDown={(e) => e.preventDefault()}
|
|
272
|
+
onClick={() => {
|
|
273
|
+
if (editor.state.selection.empty) return
|
|
274
|
+
const note = window.prompt("Add note", "Needs review")
|
|
275
|
+
if (!note) return
|
|
276
|
+
const { to } = editor.state.selection
|
|
277
|
+
editor.chain().focus().insertContentAt(to, ` [Note: ${note}]`).run()
|
|
278
|
+
}}
|
|
279
|
+
>
|
|
280
|
+
Add note
|
|
281
|
+
</button>
|
|
282
|
+
),
|
|
283
|
+
},
|
|
284
|
+
image: {
|
|
285
|
+
// Default align is "end" (right side). You can pass an array for multiple buttons.
|
|
286
|
+
render: (editor: Editor) => (
|
|
287
|
+
<button
|
|
288
|
+
type="button"
|
|
289
|
+
className="nph-btn nph-btn-ghost nph-btn-xs nph-btn-icon"
|
|
290
|
+
onMouseDown={(e) => e.preventDefault()}
|
|
291
|
+
onClick={() =>
|
|
292
|
+
editor
|
|
293
|
+
.chain()
|
|
294
|
+
.focus()
|
|
295
|
+
.updateAttributes("image", { align: "left" })
|
|
296
|
+
.run()
|
|
297
|
+
}
|
|
298
|
+
>
|
|
299
|
+
Pin left
|
|
300
|
+
</button>
|
|
301
|
+
),
|
|
302
|
+
},
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
<Editor bubbleMenuExtras={bubbleMenuExtras} />
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Each render callback receives the live Tiptap editor so you can check selection state, trigger commands, or early-return `null` to hide your custom control. The optional `align` flag lets you position the control on the left (`"start"`) or right (`"end"`, default) side of the bubble menu.
|
|
309
|
+
|
|
256
310
|
## Styling
|
|
257
311
|
|
|
258
312
|
### Basic Styling
|
|
@@ -600,6 +600,7 @@ import { useCurrentEditor as useCurrentEditor3 } from "@tiptap/react";
|
|
|
600
600
|
import { useAtomValue } from "jotai";
|
|
601
601
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
602
602
|
var CommandItemAny = CommandItem;
|
|
603
|
+
var CommandEmptyAny = CommandEmpty;
|
|
603
604
|
var EditorCommandItem = forwardRef4(({ children, onCommand, ...rest }, ref) => {
|
|
604
605
|
const { editor } = useCurrentEditor3();
|
|
605
606
|
const range = useAtomValue(rangeAtom);
|
|
@@ -615,6 +616,7 @@ var EditorCommandItem = forwardRef4(({ children, onCommand, ...rest }, ref) => {
|
|
|
615
616
|
);
|
|
616
617
|
});
|
|
617
618
|
EditorCommandItem.displayName = "EditorCommandItem";
|
|
619
|
+
var EditorCommandEmpty = CommandEmptyAny;
|
|
618
620
|
|
|
619
621
|
// src/headless/extensions/index.ts
|
|
620
622
|
import { StarterKit } from "@tiptap/starter-kit";
|
|
@@ -1024,6 +1026,7 @@ export {
|
|
|
1024
1026
|
EditorCommand,
|
|
1025
1027
|
EditorCommandList,
|
|
1026
1028
|
EditorCommandItem,
|
|
1029
|
+
EditorCommandEmpty,
|
|
1027
1030
|
CodeBlock,
|
|
1028
1031
|
Link,
|
|
1029
1032
|
ImageBlock,
|
|
@@ -1035,4 +1038,4 @@ export {
|
|
|
1035
1038
|
handleCommandNavigation,
|
|
1036
1039
|
useCurrentEditor4 as useCurrentEditor
|
|
1037
1040
|
};
|
|
1038
|
-
//# sourceMappingURL=chunk-
|
|
1041
|
+
//# sourceMappingURL=chunk-RXTFDBJQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/react/menus/ImageBlock/ImageBlockWidth.tsx","../src/react/menus/ImageBlock/ImageBlockMenu.tsx","../src/react/menus/ImageBlock/ImageBlockLoading.tsx","../src/react/menus/ImageBlock/ImageUploader.tsx","../src/react/menus/ImageBlock/ImageBlockView.tsx","../src/headless/index.ts","../src/headless/components/editor.tsx","../src/headless/utils/store.ts","../src/headless/components/editor-bubble.tsx","../src/headless/components/editor-bubble-item.tsx","../src/headless/components/editor-command.tsx","../src/headless/utils/atoms.ts","../src/headless/components/editor-command-item.tsx","../src/headless/extensions/index.ts","../src/headless/extensions/CodeBlock/CodeBlock.ts","../src/headless/extensions/Link/Link.ts","../src/headless/extensions/ImageBlock/ImageBlock.ts","../src/headless/extensions/slash-command.tsx"],"sourcesContent":["import { memo, useCallback, useEffect, useState } from \"react\"\n\nexport type ImageBlockWidthProps = {\n onChange: (value: number) => void\n value: number\n}\n\nexport const ImageBlockWidth = memo(\n ({ onChange, value }: ImageBlockWidthProps) => {\n const [currentValue, setCurrentValue] = useState(value)\n\n useEffect(() => {\n setCurrentValue(value)\n }, [value])\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const nextValue = parseInt(e.target.value)\n onChange(nextValue)\n setCurrentValue(nextValue)\n },\n [onChange]\n )\n\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n minWidth: 140,\n }}\n >\n <span style={{ fontSize: \"12px\", whiteSpace: \"nowrap\", width: 40 }}>\n {currentValue}%\n </span>\n <input\n type=\"range\"\n min=\"25\"\n max=\"100\"\n step=\"25\"\n value={currentValue}\n onChange={handleChange}\n onMouseDown={(e) => e.stopPropagation()}\n style={{\n flex: 1,\n height: 3,\n borderRadius: 9999,\n appearance: \"none\",\n background: \"linear-gradient(to right, #333 0%, #333 \" + currentValue + \"%, #ddd \" + currentValue + \"%, #ddd 100%)\",\n outline: \"none\",\n cursor: \"pointer\",\n }}\n className=\"nph-image-width-slider\"\n />\n </div>\n )\n }\n)\n\nImageBlockWidth.displayName = \"ImageBlockWidth\"\n\nexport default ImageBlockWidth\n","import { Editor } from \"@tiptap/react\"\nimport { BubbleMenu } from \"@tiptap/react/menus\"\nimport { useCallback, useRef, useState, useEffect } from \"react\"\nimport { ImageBlockWidth } from \"./ImageBlockWidth\"\nimport {\n IconAlignLeft,\n IconAlignCenter,\n IconAlignRight,\n IconTrash,\n} from \"@tabler/icons-react\"\n\nexport type ImageBlockMenuProps = {\n editor: Editor\n appendTo?: React.RefObject<HTMLElement | null>\n}\n\nexport const ImageBlockMenu = ({ editor, appendTo }: ImageBlockMenuProps) => {\n const menuRef = useRef<HTMLDivElement>(null)\n const [align, setAlign] = useState<\"left\" | \"center\" | \"right\">(\"center\")\n const [width, setWidth] = useState<number>(100)\n\n useEffect(() => {\n if (!editor) return\n const update = () => {\n if (!editor.isActive(\"imageBlock\")) return\n const attrs = editor.getAttributes(\"imageBlock\")\n setAlign(attrs.align || \"center\")\n const widthStr = attrs.width || \"100%\"\n setWidth(parseInt(widthStr) || 100)\n }\n update()\n editor.on(\"selectionUpdate\", update)\n editor.on(\"transaction\", update)\n return () => {\n editor.off(\"selectionUpdate\", update)\n editor.off(\"transaction\", update)\n }\n }, [editor])\n\n const getReferenceClientRect = useCallback(() => {\n if (!editor) return new DOMRect(-1000, -1000, 0, 0)\n\n const { view } = editor\n const { state } = view\n const { selection } = state\n\n // Get the node at the current selection\n const node = selection instanceof (window as any).ProseMirror?.state?.NodeSelection\n ? (selection as any).node\n : null\n\n if (node && node.type.name === \"imageBlock\") {\n const nodePos = (selection as any).from\n const domNode = view.nodeDOM(nodePos)\n if (domNode && domNode instanceof HTMLElement) {\n return domNode.getBoundingClientRect()\n }\n }\n\n // Fallback: try to find the image block element\n const imageBlockElements = document.querySelectorAll('[data-node-view-wrapper]')\n for (const el of Array.from(imageBlockElements)) {\n if (el.querySelector(\"img\")) {\n return el.getBoundingClientRect()\n }\n }\n\n return new DOMRect(-1000, -1000, 0, 0)\n }, [editor])\n\n const shouldShow = useCallback(() => {\n if (!editor) return false\n const isActive = editor.isActive(\"imageBlock\")\n if (!isActive) return false\n\n // Check if it's a node selection\n const { state } = editor\n const { selection } = state\n const isNodeSelection = selection.constructor.name === \"NodeSelection\"\n\n return isNodeSelection\n }, [editor])\n\n const onAlignImageLeft = useCallback(() => {\n editor\n .chain()\n .focus(undefined, { scrollIntoView: false })\n .setImageBlockAlign(\"left\")\n .run()\n }, [editor])\n\n const onAlignImageCenter = useCallback(() => {\n editor\n .chain()\n .focus(undefined, { scrollIntoView: false })\n .setImageBlockAlign(\"center\")\n .run()\n }, [editor])\n\n const onAlignImageRight = useCallback(() => {\n editor\n .chain()\n .focus(undefined, { scrollIntoView: false })\n .setImageBlockAlign(\"right\")\n .run()\n }, [editor])\n\n const onWidthChange = useCallback(\n (value: number) => {\n editor\n .chain()\n .focus(undefined, { scrollIntoView: false })\n .setImageBlockWidth(value)\n .run()\n },\n [editor]\n )\n\n const onRemoveImage = useCallback(() => {\n editor.chain().focus(undefined, { scrollIntoView: false }).deleteSelection().run()\n }, [editor])\n\n return (\n <BubbleMenu\n editor={editor}\n shouldShow={shouldShow}\n updateDelay={0}\n >\n <div className=\"bubble-menu\" ref={menuRef}>\n <button\n type=\"button\"\n className={`nph-btn nph-btn-ghost nph-btn-xs nph-btn-icon${align === \"left\" ? \" is-active\" : \"\"}`}\n title=\"Align left\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={onAlignImageLeft}\n >\n <IconAlignLeft size={16} />\n </button>\n <button\n type=\"button\"\n className={`nph-btn nph-btn-ghost nph-btn-xs nph-btn-icon${align === \"center\" ? \" is-active\" : \"\"}`}\n title=\"Align center\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={onAlignImageCenter}\n >\n <IconAlignCenter size={16} />\n </button>\n <button\n type=\"button\"\n className={`nph-btn nph-btn-ghost nph-btn-xs nph-btn-icon${align === \"right\" ? \" is-active\" : \"\"}`}\n title=\"Align right\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={onAlignImageRight}\n >\n <IconAlignRight size={16} />\n </button>\n <div\n className=\"nph-link-popover__divider\"\n style={{ margin: \"0 4px\" }}\n />\n <ImageBlockWidth onChange={onWidthChange} value={width} />\n <div\n className=\"nph-link-popover__divider\"\n style={{ margin: \"0 4px\" }}\n />\n <button\n type=\"button\"\n className=\"nph-btn nph-btn-ghost nph-btn-xs nph-btn-icon\"\n title=\"Remove image\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={onRemoveImage}\n >\n <IconTrash size={16} />\n </button>\n </div>\n </BubbleMenu>\n )\n}\n\nexport default ImageBlockMenu\n","import { IconLoader2 } from \"@tabler/icons-react\"\n\nexport const ImageBlockLoading = () => {\n return (\n <div className=\"nph-image-block-loading\">\n <div className=\"nph-image-block-loading__overlay\">\n <div className=\"nph-image-block-loading__content\">\n <IconLoader2 size={24} className=\"nph-image-block-loading__spinner\" />\n <p className=\"nph-image-block-loading__text\">Uploading image...</p>\n </div>\n </div>\n <div className=\"nph-image-block-loading__placeholder\" />\n </div>\n )\n}\n\nexport default ImageBlockLoading\n","import { IconPhoto, IconUpload } from \"@tabler/icons-react\"\nimport { ChangeEvent, useCallback, useRef, useState, DragEvent } from \"react\"\nimport { Editor } from \"@tiptap/react\"\nimport { ImageBlockLoading } from \"./ImageBlockLoading\"\n\nexport type ImageUploaderProps = {\n onUpload: (url: string) => void\n editor: Editor\n}\n\nexport const ImageUploader = ({ onUpload, editor }: ImageUploaderProps) => {\n const [loading, setLoading] = useState(false)\n const [draggedInside, setDraggedInside] = useState(false)\n const fileInputRef = useRef<HTMLInputElement>(null)\n\n const uploadFile = useCallback(\n async (file: File) => {\n setLoading(true)\n try {\n // Get the upload handler from the editor\n const imageExtension = editor.extensionManager.extensions.find(\n (ext) => ext.name === \"imageBlock\"\n )\n const uploadImage = (imageExtension?.options as any)?.uploadImage\n\n if (uploadImage) {\n const url = await uploadImage(file)\n onUpload(url)\n } else {\n console.error(\"No uploadImage handler provided\")\n }\n } catch (error) {\n console.error(\"Failed to upload image:\", error)\n } finally {\n setLoading(false)\n }\n },\n [editor, onUpload]\n )\n\n const handleUploadClick = useCallback(() => {\n fileInputRef.current?.click()\n }, [])\n\n const onFileChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n if (file) {\n uploadFile(file)\n }\n },\n [uploadFile]\n )\n\n const onDrop = useCallback(\n (e: DragEvent<HTMLDivElement>) => {\n e.preventDefault()\n e.stopPropagation()\n setDraggedInside(false)\n\n const file = e.dataTransfer.files[0]\n if (file && /image/i.test(file.type)) {\n uploadFile(file)\n }\n },\n [uploadFile]\n )\n\n const onDragEnter = useCallback((e: DragEvent<HTMLDivElement>) => {\n e.preventDefault()\n e.stopPropagation()\n setDraggedInside(true)\n }, [])\n\n const onDragLeave = useCallback((e: DragEvent<HTMLDivElement>) => {\n e.preventDefault()\n e.stopPropagation()\n setDraggedInside(false)\n }, [])\n\n if (loading) {\n return <ImageBlockLoading />\n }\n\n return (\n <div\n className={`nph-image-uploader${draggedInside ? \" nph-image-uploader--dragging\" : \"\"}`}\n onDrop={onDrop}\n onDragOver={onDragEnter}\n onDragLeave={onDragLeave}\n contentEditable={false}\n >\n <IconPhoto size={48} className=\"nph-image-uploader__icon\" />\n <div className=\"nph-image-uploader__content\">\n <div className=\"nph-image-uploader__text\">\n {draggedInside ? \"Drop image here\" : \"Drag and drop or\"}\n </div>\n <div>\n <button\n type=\"button\"\n disabled={draggedInside}\n onClick={handleUploadClick}\n className=\"nph-btn nph-btn-ghost nph-btn-sm nph-image-uploader__button\"\n >\n <IconUpload size={16} />\n Upload an image\n </button>\n </div>\n </div>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".jpg,.jpeg,.png,.webp,.gif\"\n onChange={onFileChange}\n className=\"nph-image-uploader__input\"\n />\n </div>\n )\n}\n\nexport default ImageUploader\n","import { Node } from \"@tiptap/pm/model\"\nimport { Editor, NodeViewWrapper } from \"@tiptap/react\"\nimport { useCallback, useRef } from \"react\"\nimport { ImageBlockMenu } from \"./ImageBlockMenu\"\nimport { ImageUploader } from \"./ImageUploader\"\nimport { ImageBlockLoading } from \"./ImageBlockLoading\"\n\ninterface ImageBlockViewProps {\n editor: Editor\n getPos: () => number\n node: Node\n updateAttributes: (attrs: Record<string, any>) => void\n}\n\nexport const ImageBlockView = (props: ImageBlockViewProps) => {\n const { editor, getPos, node, updateAttributes } = props as ImageBlockViewProps & {\n node: Node & {\n attrs: {\n src: string\n width: string\n align: \"left\" | \"center\" | \"right\"\n alt?: string\n loading?: boolean\n }\n }\n }\n const imageWrapperRef = useRef<HTMLDivElement>(null)\n const { src, width, align, alt, loading } = node.attrs\n\n const handleUpload = useCallback(\n (url: string) => {\n updateAttributes({ src: url, loading: false })\n },\n [updateAttributes]\n )\n\n const onClick = useCallback(() => {\n editor.commands.setNodeSelection(getPos())\n }, [getPos, editor.commands])\n\n // Calculate wrapper class based on alignment\n const getWrapperStyle = (): React.CSSProperties => {\n const baseStyle: React.CSSProperties = {\n width: width || \"100%\",\n maxWidth: \"100%\",\n }\n\n if (align === \"left\") {\n return { ...baseStyle, marginLeft: 0, marginRight: \"auto\" }\n } else if (align === \"right\") {\n return { ...baseStyle, marginLeft: \"auto\", marginRight: 0 }\n } else {\n return { ...baseStyle, marginLeft: \"auto\", marginRight: \"auto\" }\n }\n }\n\n // Show uploader if no src\n if (!src || src === \"\") {\n return (\n <NodeViewWrapper>\n <div style={getWrapperStyle()}>\n <div ref={imageWrapperRef}>\n <ImageUploader onUpload={handleUpload} editor={editor} />\n </div>\n </div>\n </NodeViewWrapper>\n )\n }\n\n // Show loading placeholder\n if (loading) {\n return (\n <NodeViewWrapper>\n <div style={getWrapperStyle()}>\n <div ref={imageWrapperRef}>\n <ImageBlockLoading />\n </div>\n </div>\n </NodeViewWrapper>\n )\n }\n\n // Show the actual image\n return (\n <NodeViewWrapper>\n <div style={getWrapperStyle()}>\n <div contentEditable={false} ref={imageWrapperRef} style={{ position: \"relative\" }}>\n <img\n src={src}\n alt={alt || \"\"}\n onClick={onClick}\n className=\"nph-image-block\"\n />\n </div>\n </div>\n <ImageBlockMenu editor={editor} appendTo={imageWrapperRef} />\n </NodeViewWrapper>\n )\n}\n\nexport default ImageBlockView\n","export { useCurrentEditor as useEditor } from \"@tiptap/react\"\n\nexport {\n EditorRoot,\n EditorContent,\n type EditorContentProps,\n} from \"./components/editor\"\n\nexport { EditorBubble } from \"./components/editor-bubble\"\nexport { EditorBubbleItem } from \"./components/editor-bubble-item\"\nexport {\n EditorCommand,\n EditorCommandList,\n EditorCommandOut,\n} from \"./components/editor-command\"\nexport {\n EditorCommandItem,\n EditorCommandEmpty,\n} from \"./components/editor-command-item\"\n\nexport { Placeholder, StarterKit } from \"./extensions\"\nexport {\n Command as SlashCommand,\n renderItems as renderSlashCommandItems,\n createSuggestionItems,\n handleCommandNavigation,\n} from \"./extensions/slash-command\"\n// Path without extension to satisfy TS/tsup\n// (the file is at ./extensions/slash-command.tsx)\n// eslint-disable-next-line\n","import { EditorProvider } from \"@tiptap/react\"\nimport type { EditorProviderProps } from \"@tiptap/react\"\nimport { forwardRef } from \"react\"\nimport type { FC, ReactNode } from \"react\"\nimport { Provider } from \"jotai\"\nimport { novelStore } from \"../utils/store\"\n\nexport interface EditorRootProps {\n readonly children: ReactNode\n}\n\nexport const EditorRoot: FC<EditorRootProps> = ({ children }) => {\n return (\n <Provider store={novelStore as any}>\n {children as any}\n </Provider>\n )\n}\n\nexport type EditorContentProps = EditorProviderProps & {\n readonly children?: ReactNode\n readonly className?: string\n readonly initialContent?: any\n}\n\nexport const EditorContent = forwardRef<HTMLDivElement, EditorContentProps>(\n ({ className, children, initialContent, content, ...rest }, ref) => {\n const effectiveContent = content ?? initialContent\n return (\n <div ref={ref} className={className}>\n <EditorProvider {...rest} content={effectiveContent}>\n {children}\n </EditorProvider>\n </div>\n )\n }\n)\n\nEditorContent.displayName = \"EditorContent\"\n","import { createStore } from \"jotai\";\n\n// biome-ignore lint/suspicious/noExplicitAny: store is opaque to consumers\nexport const novelStore: any = createStore();\nexport * from \"jotai\";\n\n","import { useCurrentEditor } from \"@tiptap/react\";\nimport { BubbleMenu as BubbleMenuReact } from \"@tiptap/react/menus\";\nimport type { BubbleMenuProps } from \"@tiptap/react/menus\";\nimport type { ReactNode } from \"react\";\n\ntype ForwardedBubbleProps = Omit<BubbleMenuProps, \"editor\" | \"children\" | \"className\">;\n\nexport interface EditorBubbleProps extends ForwardedBubbleProps {\n readonly className?: string;\n readonly children: ReactNode;\n}\n\nexport function EditorBubble({ className, children, ...rest }: EditorBubbleProps) {\n const { editor } = useCurrentEditor();\n if (!editor) return null;\n\n return (\n <BubbleMenuReact editor={editor} {...rest}>\n <div className={className}>{children}</div>\n </BubbleMenuReact>\n );\n}\n","import { forwardRef, isValidElement, cloneElement } from \"react\"\nimport type { ComponentPropsWithoutRef, ReactElement, ReactNode } from \"react\"\nimport { useCurrentEditor } from \"@tiptap/react\"\nimport type { Editor as TiptapEditor } from \"@tiptap/react\"\n\ninterface EditorBubbleItemProps {\n readonly children: ReactNode\n readonly asChild?: boolean\n readonly onSelect?: (editor: TiptapEditor) => void\n}\n\nexport const EditorBubbleItem = forwardRef<\n HTMLDivElement,\n EditorBubbleItemProps & Omit<ComponentPropsWithoutRef<\"div\">, \"onSelect\">\n>(({ children, asChild, onSelect, ...rest }, ref) => {\n const { editor } = useCurrentEditor()\n\n if (!editor) return null\n\n const handleClick = (e: React.MouseEvent) => {\n e.preventDefault()\n onSelect?.(editor)\n }\n\n if (asChild && isValidElement(children)) {\n const child = children as ReactElement<any>\n const childOnClick = (child.props as any)?.onClick as\n | ((e: any) => void)\n | undefined\n const mergedOnClick = (e: any) => {\n childOnClick?.(e)\n if (!e?.defaultPrevented) onSelect?.(editor)\n }\n\n return cloneElement(child, {\n ...rest,\n ref: (child as any).ref ?? ref,\n onClick: mergedOnClick,\n })\n }\n\n return (\n <div ref={ref} {...rest} onClick={handleClick}>\n {children}\n </div>\n )\n})\n\nEditorBubbleItem.displayName = \"EditorBubbleItem\"\n\nexport default EditorBubbleItem\n","import { useAtom, useSetAtom } from \"jotai\"\nimport { useEffect, forwardRef } from \"react\"\nimport { Command } from \"cmdk\"\nimport { queryAtom, rangeAtom } from \"../utils/atoms\"\nimport { novelStore } from \"../utils/store\"\nimport type { FC } from \"react\"\nimport type { Range } from \"@tiptap/core\"\nimport tunnel from \"tunnel-rat\"\n\nconst commandTunnel: any = (tunnel as any)()\n\ninterface EditorCommandOutProps {\n readonly query: string\n readonly range: Range\n}\n\nexport const EditorCommandOut: FC<EditorCommandOutProps> = ({\n query,\n range,\n}) => {\n const setQuery = useSetAtom(queryAtom, { store: novelStore })\n const setRange = useSetAtom(rangeAtom, { store: novelStore })\n\n useEffect(() => {\n setQuery(query)\n }, [query, setQuery])\n\n useEffect(() => {\n setRange(range)\n }, [range, setRange])\n\n useEffect(() => {\n const navigationKeys = [\"ArrowUp\", \"ArrowDown\", \"Enter\"]\n const onKeyDown = (e: KeyboardEvent) => {\n if (navigationKeys.includes(e.key)) {\n e.preventDefault()\n const commandRef = document.querySelector(\"#slash-command\")\n\n if (commandRef)\n commandRef.dispatchEvent(\n new KeyboardEvent(\"keydown\", {\n key: e.key,\n cancelable: true,\n bubbles: true,\n })\n )\n\n return false\n }\n }\n document.addEventListener(\"keydown\", onKeyDown)\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown)\n }\n }, [])\n\n return <commandTunnel.Out />\n}\n\nconst CommandAny: any = Command\nexport const EditorCommand = forwardRef<HTMLDivElement, any>(\n ({ children, className, ...rest }, ref) => {\n const [query, setQuery] = useAtom(queryAtom)\n\n return (\n <commandTunnel.In>\n <CommandAny\n ref={ref}\n onKeyDown={(e: any) => {\n e.stopPropagation()\n }}\n id=\"slash-command\"\n className={className}\n {...rest}\n >\n <CommandAny.Input\n value={query}\n onValueChange={setQuery}\n style={{ display: \"none\" }}\n />\n {children}\n </CommandAny>\n </commandTunnel.In>\n )\n }\n)\nexport const EditorCommandList: any = Command.List\n\nEditorCommand.displayName = \"EditorCommand\"\n","import { atom } from \"jotai\"\nimport type { Range } from \"@tiptap/core\"\n\nexport const queryAtom = atom(\"\")\nexport const rangeAtom = atom<Range | null>(null)\n\n","import { forwardRef } from \"react\"\nimport { CommandEmpty, CommandItem } from \"cmdk\"\nimport { useCurrentEditor } from \"@tiptap/react\"\nimport { useAtomValue } from \"jotai\"\nimport { rangeAtom } from \"../utils/atoms\"\nimport type { Editor, Range } from \"@tiptap/core\"\n\ninterface EditorCommandItemProps {\n readonly onCommand: ({\n editor,\n range,\n }: {\n editor: Editor\n range: Range\n }) => void\n}\n\nconst CommandItemAny: any = CommandItem\nconst CommandEmptyAny: any = CommandEmpty\n\nexport const EditorCommandItem = forwardRef<\n HTMLDivElement,\n EditorCommandItemProps & any\n>(({ children, onCommand, ...rest }, ref) => {\n const { editor } = useCurrentEditor()\n const range = useAtomValue(rangeAtom)\n\n if (!editor || !range) return null\n\n return (\n <CommandItemAny\n ref={ref}\n {...(rest as any)}\n onSelect={() => onCommand({ editor, range })}\n >\n {children}\n </CommandItemAny>\n )\n})\n\nEditorCommandItem.displayName = \"EditorCommandItem\"\n\nexport const EditorCommandEmpty: any = CommandEmptyAny\n\nexport default EditorCommandItem\n","export { StarterKit } from \"@tiptap/starter-kit\"\nexport { Placeholder } from \"@tiptap/extension-placeholder\"\n\n// Custom\nexport { CodeBlock } from \"./CodeBlock\"\nexport { Link } from \"./Link\"\nexport { ImageBlock } from \"./ImageBlock\"\nexport type { ImageBlockOptions } from \"./ImageBlock\"\n","import { CodeBlockLowlight } from \"@tiptap/extension-code-block-lowlight\"\nimport { all, createLowlight } from \"lowlight\"\n\nconst lowlight = createLowlight(all)\n\nexport const CodeBlock = CodeBlockLowlight.configure({\n lowlight,\n})\n","import { mergeAttributes } from \"@tiptap/core\"\nimport TiptapLink from \"@tiptap/extension-link\"\nimport { Plugin } from \"@tiptap/pm/state\"\nimport { EditorView } from \"@tiptap/pm/view\"\n\nexport const Link = TiptapLink.extend({\n inclusive: false,\n\n parseHTML() {\n return [\n {\n tag: 'a[href]:not([data-type=\"button\"]):not([href *= \"javascript:\" i])',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }: any) {\n return [\n \"a\",\n mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {\n class: \"link\",\n }),\n 0,\n ]\n },\n\n addProseMirrorPlugins() {\n const { editor } = this\n\n return [\n ...(((this as any).parent?.() as any[]) || []),\n new Plugin({\n props: {\n handleKeyDown: (view: EditorView, event: KeyboardEvent) => {\n const { selection } = editor.state\n\n if (event.key === \"Escape\" && selection.empty !== true) {\n editor.commands.focus(selection.to, { scrollIntoView: false })\n }\n\n return false\n },\n },\n }),\n ]\n },\n})\n\nexport default Link\n","import { mergeAttributes, Range } from \"@tiptap/core\"\nimport { Image as TiptapImage } from \"@tiptap/extension-image\"\nimport { ReactNodeViewRenderer } from \"@tiptap/react\"\nimport { Plugin, PluginKey } from \"@tiptap/pm/state\"\nimport { EditorView } from \"@tiptap/pm/view\"\n\nexport interface ImageBlockOptions {\n uploadImage?: (file: File) => Promise<string>\n}\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n imageBlock: {\n setImageBlock: (attributes: { src: string }) => ReturnType\n setImageBlockAt: (attributes: {\n src: string\n pos: number | Range\n }) => ReturnType\n setImageBlockAlign: (align: \"left\" | \"center\" | \"right\") => ReturnType\n setImageBlockWidth: (width: number) => ReturnType\n }\n }\n}\n\nexport const ImageBlock = TiptapImage.extend<ImageBlockOptions>({\n name: \"imageBlock\",\n\n group: \"block\",\n\n defining: true,\n\n isolating: true,\n\n addOptions() {\n return {\n ...this.parent?.(),\n uploadImage: undefined,\n inline: false,\n }\n },\n\n addAttributes() {\n return {\n src: {\n default: \"\",\n parseHTML: (element) => element.getAttribute(\"src\"),\n renderHTML: (attributes) => ({\n src: attributes.src,\n }),\n },\n width: {\n default: \"100%\",\n parseHTML: (element) => element.getAttribute(\"data-width\"),\n renderHTML: (attributes) => ({\n \"data-width\": attributes.width,\n }),\n },\n align: {\n default: \"center\",\n parseHTML: (element) => element.getAttribute(\"data-align\"),\n renderHTML: (attributes) => ({\n \"data-align\": attributes.align,\n }),\n },\n alt: {\n default: undefined,\n parseHTML: (element) => element.getAttribute(\"alt\"),\n renderHTML: (attributes) => ({\n alt: attributes.alt,\n }),\n },\n loading: {\n default: false,\n parseHTML: () => false,\n renderHTML: () => ({}),\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'img[src]:not([src^=\"data:\"])',\n getAttrs: (element) => {\n const el = element as HTMLElement\n return {\n src: el.getAttribute(\"src\"),\n alt: el.getAttribute(\"alt\"),\n width: el.getAttribute(\"data-width\") || \"100%\",\n align: el.getAttribute(\"data-align\") || \"center\",\n }\n },\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\"img\", mergeAttributes(HTMLAttributes)]\n },\n\n addCommands() {\n return {\n setImageBlock:\n (attrs) =>\n ({ commands }) => {\n return commands.insertContent({\n type: \"imageBlock\",\n attrs: { src: attrs.src },\n })\n },\n\n setImageBlockAt:\n (attrs) =>\n ({ commands }) => {\n return commands.insertContentAt(attrs.pos, {\n type: \"imageBlock\",\n attrs: { src: attrs.src },\n })\n },\n\n setImageBlockAlign:\n (align) =>\n ({ commands }) =>\n commands.updateAttributes(\"imageBlock\", { align }),\n\n setImageBlockWidth:\n (width) =>\n ({ commands }) =>\n commands.updateAttributes(\"imageBlock\", {\n width: `${Math.max(0, Math.min(100, width))}%`,\n }),\n }\n },\n\n addNodeView() {\n // We'll import this dynamically to avoid circular dependencies\n // The view will be registered from the React side\n return ReactNodeViewRenderer(\n require(\"../../../react/menus/ImageBlock/ImageBlockView\").ImageBlockView\n )\n },\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: new PluginKey(\"imageBlockDrop\"),\n props: {\n handleDOMEvents: {\n drop: (view: EditorView, event: DragEvent) => {\n const hasFiles =\n event.dataTransfer &&\n event.dataTransfer.files &&\n event.dataTransfer.files.length\n\n if (!hasFiles) {\n return false\n }\n\n const images = Array.from(event.dataTransfer.files).filter(\n (file) => /image/i.test(file.type)\n )\n\n if (images.length === 0) {\n return false\n }\n\n event.preventDefault()\n\n const { schema } = view.state\n const coordinates = view.posAtCoords({\n left: event.clientX,\n top: event.clientY,\n })\n\n if (!coordinates) return false\n\n images.forEach(async (image) => {\n if (this.options.uploadImage) {\n try {\n // Insert placeholder first\n const placeholderNode = schema.nodes.imageBlock.create({\n src: \"\",\n loading: true,\n })\n const placeholderTr = view.state.tr.insert(\n coordinates.pos,\n placeholderNode\n )\n view.dispatch(placeholderTr)\n\n // Upload and replace\n const url = await this.options.uploadImage(image)\n const node = schema.nodes.imageBlock.create({ src: url })\n\n // Find and replace the placeholder\n const currentState = view.state\n let foundPos = -1\n currentState.doc.descendants((node, pos) => {\n if (\n node.type.name === \"imageBlock\" &&\n node.attrs.loading\n ) {\n foundPos = pos\n return false\n }\n })\n\n if (foundPos !== -1) {\n const transaction = view.state.tr.replaceWith(\n foundPos,\n foundPos + 1,\n node\n )\n view.dispatch(transaction)\n }\n } catch (error) {\n console.error(\"Failed to upload image:\", error)\n // Remove placeholder on error\n const currentState = view.state\n let foundPos = -1\n currentState.doc.descendants((node, pos) => {\n if (\n node.type.name === \"imageBlock\" &&\n node.attrs.loading\n ) {\n foundPos = pos\n return false\n }\n })\n\n if (foundPos !== -1) {\n const transaction = view.state.tr.delete(\n foundPos,\n foundPos + 1\n )\n view.dispatch(transaction)\n }\n }\n }\n })\n\n return true\n },\n paste: (view: EditorView, event: ClipboardEvent) => {\n const hasFiles =\n event.clipboardData &&\n event.clipboardData.files &&\n event.clipboardData.files.length\n\n if (!hasFiles) {\n return false\n }\n\n const images = Array.from(event.clipboardData.files).filter(\n (file) => /image/i.test(file.type)\n )\n\n if (images.length === 0) {\n return false\n }\n\n event.preventDefault()\n\n images.forEach(async (image) => {\n if (this.options.uploadImage) {\n try {\n // Insert placeholder first\n const placeholderNode =\n view.state.schema.nodes.imageBlock.create({\n src: \"\",\n loading: true,\n })\n view.dispatch(\n view.state.tr.replaceSelectionWith(placeholderNode)\n )\n\n // Upload and replace\n const url = await this.options.uploadImage(image)\n const node = view.state.schema.nodes.imageBlock.create({\n src: url,\n })\n\n // Find and replace the placeholder\n const currentState = view.state\n let foundPos = -1\n currentState.doc.descendants((node, pos) => {\n if (\n node.type.name === \"imageBlock\" &&\n node.attrs.loading\n ) {\n foundPos = pos\n return false\n }\n })\n\n if (foundPos !== -1) {\n const transaction = view.state.tr.replaceWith(\n foundPos,\n foundPos + 1,\n node\n )\n view.dispatch(transaction)\n }\n } catch (error) {\n console.error(\"Failed to upload image:\", error)\n // Remove placeholder on error\n const currentState = view.state\n let foundPos = -1\n currentState.doc.descendants((node, pos) => {\n if (\n node.type.name === \"imageBlock\" &&\n node.attrs.loading\n ) {\n foundPos = pos\n return false\n }\n })\n\n if (foundPos !== -1) {\n const transaction = view.state.tr.delete(\n foundPos,\n foundPos + 1\n )\n view.dispatch(transaction)\n }\n }\n }\n })\n\n return true\n },\n },\n },\n }),\n ]\n },\n})\n\nexport default ImageBlock\n","import { ReactRenderer } from \"@tiptap/react\"\nimport Suggestion from \"@tiptap/suggestion\"\nimport { Extension } from \"@tiptap/core\"\nimport type { RefObject, ReactNode } from \"react\"\nimport { EditorCommandOut } from \"../components/editor-command\"\n\nexport const Command = Extension.create({\n name: \"slash-command\",\n addOptions() {\n return {\n suggestion: {\n char: \"/\",\n command: (ctx: any) => {\n ctx.props.command({ editor: ctx.editor, range: ctx.range })\n },\n } as any,\n }\n },\n addProseMirrorPlugins() {\n const base: any = this.options.suggestion ?? {}\n return [\n Suggestion({\n editor: this.editor,\n char: base.char ?? \"/\",\n items: base.items ?? (() => [\"/\"] as any),\n command: (ctx: any) => {\n if (typeof ctx?.props?.command === \"function\") {\n ctx.props.command({ editor: ctx.editor, range: ctx.range })\n }\n },\n ...base,\n }),\n ]\n },\n})\n\nexport const renderItems = (elementRef?: RefObject<Element> | null) => {\n let component: ReactRenderer | null = null\n let container: HTMLElement | null = null\n\n const destroy = () => {\n component?.destroy()\n component = null\n if (container) {\n container.remove()\n container = null\n }\n }\n\n const updatePosition = (clientRect?: DOMRect | null) => {\n if (!container || !clientRect) return\n const top = Math.round(clientRect.bottom + 8)\n const left = Math.round(clientRect.left)\n container.style.top = `${top}px`\n container.style.left = `${left}px`\n }\n\n return {\n onStart: (props: {\n editor: any\n clientRect: (() => DOMRect | null) | null\n query?: string\n range?: any\n }) => {\n const { selection } = props.editor.state\n const parentNode = selection.$from.node(selection.$from.depth)\n const blockType = parentNode.type.name\n if (blockType === \"codeBlock\") return false\n\n component = new ReactRenderer(EditorCommandOut, {\n props: {\n query: (props as any).query ?? \"\",\n range: (props as any).range,\n },\n editor: props.editor,\n })\n\n container = document.createElement(\"div\")\n container.style.position = \"fixed\"\n container.style.zIndex = \"9999\"\n container.style.minWidth = \"240px\"\n ;(elementRef?.current ?? document.body).appendChild(container)\n container.appendChild(component.element)\n\n const rect =\n typeof props.clientRect === \"function\" ? props.clientRect() : null\n if (rect) updatePosition(rect)\n },\n onUpdate: (props: {\n editor: any\n clientRect: (() => DOMRect | null) | null\n query?: string\n range?: any\n }) => {\n component?.updateProps({\n query: (props as any).query ?? \"\",\n range: (props as any).range,\n })\n const rect =\n typeof props.clientRect === \"function\" ? props.clientRect() : null\n if (rect) updatePosition(rect)\n },\n onKeyDown: ({ event }: { event: KeyboardEvent }) => {\n if (event.key === \"Escape\") {\n destroy()\n return true\n }\n return false\n },\n onExit: () => {\n destroy()\n },\n }\n}\n\nexport interface SuggestionItem {\n title: string\n description: string\n icon: ReactNode\n searchTerms?: string[]\n command?: (props: {\n editor: any\n range: { from: number; to: number }\n }) => void\n}\n\nexport const createSuggestionItems = (items: SuggestionItem[]) => items\n\nexport const handleCommandNavigation = (event: KeyboardEvent) => {\n if ([\"ArrowUp\", \"ArrowDown\", \"Enter\"].includes(event.key)) {\n const slashCommand = document.querySelector(\"#slash-command\")\n if (slashCommand) return true\n }\n}\n"],"mappings":"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","names":["useEffect","jsx","jsxs","useCallback","useState","useEffect","jsx","jsxs","jsx","jsxs","useCallback","useRef","useState","jsx","jsxs","useCallback","useRef","jsx","jsxs","useCurrentEditor","jsx","forwardRef","useCurrentEditor","jsx","forwardRef","jsx","forwardRef","forwardRef","useCurrentEditor","jsx","forwardRef","useCurrentEditor","mergeAttributes","Plugin","node","Command"]}
|
|
@@ -86,25 +86,51 @@ var init_ImageBlockWidth = __esm({
|
|
|
86
86
|
}
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
+
// src/react/menus/bubble-menu-extensions.tsx
|
|
90
|
+
import { createContext, useContext, useMemo } from "react";
|
|
91
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
92
|
+
var BubbleMenuExtensionsContext, BubbleMenuExtensionsProvider, useBubbleMenuExtensions;
|
|
93
|
+
var init_bubble_menu_extensions = __esm({
|
|
94
|
+
"src/react/menus/bubble-menu-extensions.tsx"() {
|
|
95
|
+
"use strict";
|
|
96
|
+
BubbleMenuExtensionsContext = createContext([]);
|
|
97
|
+
BubbleMenuExtensionsProvider = ({
|
|
98
|
+
extensions,
|
|
99
|
+
children
|
|
100
|
+
}) => {
|
|
101
|
+
return /* @__PURE__ */ jsx7(BubbleMenuExtensionsContext.Provider, { value: extensions ?? [], children });
|
|
102
|
+
};
|
|
103
|
+
useBubbleMenuExtensions = (target, editor) => {
|
|
104
|
+
const extensions = useContext(BubbleMenuExtensionsContext);
|
|
105
|
+
return useMemo(() => {
|
|
106
|
+
if (!editor) return [];
|
|
107
|
+
return extensions.filter((extension) => extension.target === target).filter((extension) => extension.when ? extension.when({ editor }) : true).sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
108
|
+
}, [editor, extensions, target]);
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
89
113
|
// src/react/menus/ImageBlock/ImageBlockMenu.tsx
|
|
90
114
|
import { BubbleMenu } from "@tiptap/react/menus";
|
|
91
|
-
import { useCallback as useCallback2, useRef, useState as useState2, useEffect as useEffect3 } from "react";
|
|
115
|
+
import { Fragment, useCallback as useCallback2, useRef, useState as useState2, useEffect as useEffect3 } from "react";
|
|
92
116
|
import {
|
|
93
117
|
IconAlignLeft,
|
|
94
118
|
IconAlignCenter,
|
|
95
119
|
IconAlignRight,
|
|
96
120
|
IconTrash
|
|
97
121
|
} from "@tabler/icons-react";
|
|
98
|
-
import { jsx as
|
|
122
|
+
import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
99
123
|
var ImageBlockMenu;
|
|
100
124
|
var init_ImageBlockMenu = __esm({
|
|
101
125
|
"src/react/menus/ImageBlock/ImageBlockMenu.tsx"() {
|
|
102
126
|
"use strict";
|
|
103
127
|
init_ImageBlockWidth();
|
|
128
|
+
init_bubble_menu_extensions();
|
|
104
129
|
ImageBlockMenu = ({ editor, appendTo }) => {
|
|
105
130
|
const menuRef = useRef(null);
|
|
106
131
|
const [align, setAlign] = useState2("center");
|
|
107
132
|
const [width, setWidth] = useState2(100);
|
|
133
|
+
const extensions = useBubbleMenuExtensions("imageBlock", editor);
|
|
108
134
|
useEffect3(() => {
|
|
109
135
|
if (!editor) return;
|
|
110
136
|
const update = () => {
|
|
@@ -170,14 +196,14 @@ var init_ImageBlockMenu = __esm({
|
|
|
170
196
|
const onRemoveImage = useCallback2(() => {
|
|
171
197
|
editor.chain().focus(void 0, { scrollIntoView: false }).deleteSelection().run();
|
|
172
198
|
}, [editor]);
|
|
173
|
-
return /* @__PURE__ */
|
|
199
|
+
return /* @__PURE__ */ jsx8(
|
|
174
200
|
BubbleMenu,
|
|
175
201
|
{
|
|
176
202
|
editor,
|
|
177
203
|
shouldShow,
|
|
178
204
|
updateDelay: 0,
|
|
179
205
|
children: /* @__PURE__ */ jsxs3("div", { className: "bubble-menu", ref: menuRef, children: [
|
|
180
|
-
/* @__PURE__ */
|
|
206
|
+
/* @__PURE__ */ jsx8(
|
|
181
207
|
"button",
|
|
182
208
|
{
|
|
183
209
|
type: "button",
|
|
@@ -185,10 +211,10 @@ var init_ImageBlockMenu = __esm({
|
|
|
185
211
|
title: "Align left",
|
|
186
212
|
onMouseDown: (e) => e.preventDefault(),
|
|
187
213
|
onClick: onAlignImageLeft,
|
|
188
|
-
children: /* @__PURE__ */
|
|
214
|
+
children: /* @__PURE__ */ jsx8(IconAlignLeft, { size: 16 })
|
|
189
215
|
}
|
|
190
216
|
),
|
|
191
|
-
/* @__PURE__ */
|
|
217
|
+
/* @__PURE__ */ jsx8(
|
|
192
218
|
"button",
|
|
193
219
|
{
|
|
194
220
|
type: "button",
|
|
@@ -196,10 +222,10 @@ var init_ImageBlockMenu = __esm({
|
|
|
196
222
|
title: "Align center",
|
|
197
223
|
onMouseDown: (e) => e.preventDefault(),
|
|
198
224
|
onClick: onAlignImageCenter,
|
|
199
|
-
children: /* @__PURE__ */
|
|
225
|
+
children: /* @__PURE__ */ jsx8(IconAlignCenter, { size: 16 })
|
|
200
226
|
}
|
|
201
227
|
),
|
|
202
|
-
/* @__PURE__ */
|
|
228
|
+
/* @__PURE__ */ jsx8(
|
|
203
229
|
"button",
|
|
204
230
|
{
|
|
205
231
|
type: "button",
|
|
@@ -207,25 +233,25 @@ var init_ImageBlockMenu = __esm({
|
|
|
207
233
|
title: "Align right",
|
|
208
234
|
onMouseDown: (e) => e.preventDefault(),
|
|
209
235
|
onClick: onAlignImageRight,
|
|
210
|
-
children: /* @__PURE__ */
|
|
236
|
+
children: /* @__PURE__ */ jsx8(IconAlignRight, { size: 16 })
|
|
211
237
|
}
|
|
212
238
|
),
|
|
213
|
-
/* @__PURE__ */
|
|
239
|
+
/* @__PURE__ */ jsx8(
|
|
214
240
|
"div",
|
|
215
241
|
{
|
|
216
242
|
className: "nph-link-popover__divider",
|
|
217
243
|
style: { margin: "0 4px" }
|
|
218
244
|
}
|
|
219
245
|
),
|
|
220
|
-
/* @__PURE__ */
|
|
221
|
-
/* @__PURE__ */
|
|
246
|
+
/* @__PURE__ */ jsx8(ImageBlockWidth, { onChange: onWidthChange, value: width }),
|
|
247
|
+
/* @__PURE__ */ jsx8(
|
|
222
248
|
"div",
|
|
223
249
|
{
|
|
224
250
|
className: "nph-link-popover__divider",
|
|
225
251
|
style: { margin: "0 4px" }
|
|
226
252
|
}
|
|
227
253
|
),
|
|
228
|
-
/* @__PURE__ */
|
|
254
|
+
/* @__PURE__ */ jsx8(
|
|
229
255
|
"button",
|
|
230
256
|
{
|
|
231
257
|
type: "button",
|
|
@@ -233,9 +259,10 @@ var init_ImageBlockMenu = __esm({
|
|
|
233
259
|
title: "Remove image",
|
|
234
260
|
onMouseDown: (e) => e.preventDefault(),
|
|
235
261
|
onClick: onRemoveImage,
|
|
236
|
-
children: /* @__PURE__ */
|
|
262
|
+
children: /* @__PURE__ */ jsx8(IconTrash, { size: 16 })
|
|
237
263
|
}
|
|
238
|
-
)
|
|
264
|
+
),
|
|
265
|
+
extensions.map((extension) => /* @__PURE__ */ jsx8(Fragment, { children: extension.render({ editor }) }, extension.id))
|
|
239
266
|
] })
|
|
240
267
|
}
|
|
241
268
|
);
|
|
@@ -245,18 +272,18 @@ var init_ImageBlockMenu = __esm({
|
|
|
245
272
|
|
|
246
273
|
// src/react/menus/ImageBlock/ImageBlockLoading.tsx
|
|
247
274
|
import { IconLoader2 } from "@tabler/icons-react";
|
|
248
|
-
import { jsx as
|
|
275
|
+
import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
249
276
|
var ImageBlockLoading;
|
|
250
277
|
var init_ImageBlockLoading = __esm({
|
|
251
278
|
"src/react/menus/ImageBlock/ImageBlockLoading.tsx"() {
|
|
252
279
|
"use strict";
|
|
253
280
|
ImageBlockLoading = () => {
|
|
254
281
|
return /* @__PURE__ */ jsxs4("div", { className: "nph-image-block-loading", children: [
|
|
255
|
-
/* @__PURE__ */
|
|
256
|
-
/* @__PURE__ */
|
|
257
|
-
/* @__PURE__ */
|
|
282
|
+
/* @__PURE__ */ jsx9("div", { className: "nph-image-block-loading__overlay", children: /* @__PURE__ */ jsxs4("div", { className: "nph-image-block-loading__content", children: [
|
|
283
|
+
/* @__PURE__ */ jsx9(IconLoader2, { size: 24, className: "nph-image-block-loading__spinner" }),
|
|
284
|
+
/* @__PURE__ */ jsx9("p", { className: "nph-image-block-loading__text", children: "Uploading image..." })
|
|
258
285
|
] }) }),
|
|
259
|
-
/* @__PURE__ */
|
|
286
|
+
/* @__PURE__ */ jsx9("div", { className: "nph-image-block-loading__placeholder" })
|
|
260
287
|
] });
|
|
261
288
|
};
|
|
262
289
|
}
|
|
@@ -265,7 +292,7 @@ var init_ImageBlockLoading = __esm({
|
|
|
265
292
|
// src/react/menus/ImageBlock/ImageUploader.tsx
|
|
266
293
|
import { IconPhoto, IconUpload } from "@tabler/icons-react";
|
|
267
294
|
import { useCallback as useCallback3, useRef as useRef2, useState as useState3 } from "react";
|
|
268
|
-
import { jsx as
|
|
295
|
+
import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
269
296
|
var ImageUploader;
|
|
270
297
|
var init_ImageUploader = __esm({
|
|
271
298
|
"src/react/menus/ImageBlock/ImageUploader.tsx"() {
|
|
@@ -332,7 +359,7 @@ var init_ImageUploader = __esm({
|
|
|
332
359
|
setDraggedInside(false);
|
|
333
360
|
}, []);
|
|
334
361
|
if (loading) {
|
|
335
|
-
return /* @__PURE__ */
|
|
362
|
+
return /* @__PURE__ */ jsx10(ImageBlockLoading, {});
|
|
336
363
|
}
|
|
337
364
|
return /* @__PURE__ */ jsxs5(
|
|
338
365
|
"div",
|
|
@@ -343,10 +370,10 @@ var init_ImageUploader = __esm({
|
|
|
343
370
|
onDragLeave,
|
|
344
371
|
contentEditable: false,
|
|
345
372
|
children: [
|
|
346
|
-
/* @__PURE__ */
|
|
373
|
+
/* @__PURE__ */ jsx10(IconPhoto, { size: 48, className: "nph-image-uploader__icon" }),
|
|
347
374
|
/* @__PURE__ */ jsxs5("div", { className: "nph-image-uploader__content", children: [
|
|
348
|
-
/* @__PURE__ */
|
|
349
|
-
/* @__PURE__ */
|
|
375
|
+
/* @__PURE__ */ jsx10("div", { className: "nph-image-uploader__text", children: draggedInside ? "Drop image here" : "Drag and drop or" }),
|
|
376
|
+
/* @__PURE__ */ jsx10("div", { children: /* @__PURE__ */ jsxs5(
|
|
350
377
|
"button",
|
|
351
378
|
{
|
|
352
379
|
type: "button",
|
|
@@ -354,13 +381,13 @@ var init_ImageUploader = __esm({
|
|
|
354
381
|
onClick: handleUploadClick,
|
|
355
382
|
className: "nph-btn nph-btn-ghost nph-btn-sm nph-image-uploader__button",
|
|
356
383
|
children: [
|
|
357
|
-
/* @__PURE__ */
|
|
384
|
+
/* @__PURE__ */ jsx10(IconUpload, { size: 16 }),
|
|
358
385
|
"Upload an image"
|
|
359
386
|
]
|
|
360
387
|
}
|
|
361
388
|
) })
|
|
362
389
|
] }),
|
|
363
|
-
/* @__PURE__ */
|
|
390
|
+
/* @__PURE__ */ jsx10(
|
|
364
391
|
"input",
|
|
365
392
|
{
|
|
366
393
|
ref: fileInputRef,
|
|
@@ -385,14 +412,14 @@ __export(ImageBlockView_exports, {
|
|
|
385
412
|
});
|
|
386
413
|
import { NodeViewWrapper } from "@tiptap/react";
|
|
387
414
|
import { useCallback as useCallback4, useRef as useRef3 } from "react";
|
|
388
|
-
import {
|
|
389
|
-
import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
415
|
+
import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
390
416
|
var ImageBlockView, ImageBlockView_default;
|
|
391
417
|
var init_ImageBlockView = __esm({
|
|
392
418
|
"src/react/menus/ImageBlock/ImageBlockView.tsx"() {
|
|
393
419
|
"use strict";
|
|
394
420
|
init_ImageBlockMenu();
|
|
395
421
|
init_ImageUploader();
|
|
422
|
+
init_ImageBlockLoading();
|
|
396
423
|
ImageBlockView = (props) => {
|
|
397
424
|
const { editor, getPos, node, updateAttributes } = props;
|
|
398
425
|
const imageWrapperRef = useRef3(null);
|
|
@@ -420,32 +447,13 @@ var init_ImageBlockView = __esm({
|
|
|
420
447
|
}
|
|
421
448
|
};
|
|
422
449
|
if (!src || src === "") {
|
|
423
|
-
return /* @__PURE__ */
|
|
450
|
+
return /* @__PURE__ */ jsx11(NodeViewWrapper, { children: /* @__PURE__ */ jsx11("div", { style: getWrapperStyle(), children: /* @__PURE__ */ jsx11("div", { ref: imageWrapperRef, children: /* @__PURE__ */ jsx11(ImageUploader, { onUpload: handleUpload, editor }) }) }) });
|
|
424
451
|
}
|
|
425
452
|
if (loading) {
|
|
426
|
-
return /* @__PURE__ */
|
|
427
|
-
"div",
|
|
428
|
-
{
|
|
429
|
-
ref: imageWrapperRef,
|
|
430
|
-
className: "nph-image-block-loading",
|
|
431
|
-
children: [
|
|
432
|
-
/* @__PURE__ */ jsx10("div", { className: "nph-image-block-loading__overlay", children: /* @__PURE__ */ jsxs6("div", { className: "nph-image-block-loading__content", children: [
|
|
433
|
-
/* @__PURE__ */ jsx10(
|
|
434
|
-
IconLoader22,
|
|
435
|
-
{
|
|
436
|
-
size: 24,
|
|
437
|
-
className: "nph-image-block-loading__spinner"
|
|
438
|
-
}
|
|
439
|
-
),
|
|
440
|
-
/* @__PURE__ */ jsx10("p", { className: "nph-image-block-loading__text", children: "Uploading image..." })
|
|
441
|
-
] }) }),
|
|
442
|
-
/* @__PURE__ */ jsx10("div", { className: "nph-image-block-loading__placeholder" })
|
|
443
|
-
]
|
|
444
|
-
}
|
|
445
|
-
) }) });
|
|
453
|
+
return /* @__PURE__ */ jsx11(NodeViewWrapper, { children: /* @__PURE__ */ jsx11("div", { style: getWrapperStyle(), children: /* @__PURE__ */ jsx11("div", { ref: imageWrapperRef, children: /* @__PURE__ */ jsx11(ImageBlockLoading, {}) }) }) });
|
|
446
454
|
}
|
|
447
455
|
return /* @__PURE__ */ jsxs6(NodeViewWrapper, { children: [
|
|
448
|
-
/* @__PURE__ */
|
|
456
|
+
/* @__PURE__ */ jsx11("div", { style: getWrapperStyle(), children: /* @__PURE__ */ jsx11("div", { contentEditable: false, ref: imageWrapperRef, style: { position: "relative" }, children: /* @__PURE__ */ jsx11(
|
|
449
457
|
"img",
|
|
450
458
|
{
|
|
451
459
|
src,
|
|
@@ -454,7 +462,7 @@ var init_ImageBlockView = __esm({
|
|
|
454
462
|
className: "nph-image-block"
|
|
455
463
|
}
|
|
456
464
|
) }) }),
|
|
457
|
-
/* @__PURE__ */
|
|
465
|
+
/* @__PURE__ */ jsx11(ImageBlockMenu, { editor, appendTo: imageWrapperRef })
|
|
458
466
|
] });
|
|
459
467
|
};
|
|
460
468
|
ImageBlockView_default = ImageBlockView;
|
|
@@ -619,6 +627,7 @@ import { useCurrentEditor as useCurrentEditor3 } from "@tiptap/react";
|
|
|
619
627
|
import { useAtomValue } from "jotai";
|
|
620
628
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
621
629
|
var CommandItemAny = CommandItem;
|
|
630
|
+
var CommandEmptyAny = CommandEmpty;
|
|
622
631
|
var EditorCommandItem = forwardRef4(({ children, onCommand, ...rest }, ref) => {
|
|
623
632
|
const { editor } = useCurrentEditor3();
|
|
624
633
|
const range = useAtomValue(rangeAtom);
|
|
@@ -634,6 +643,7 @@ var EditorCommandItem = forwardRef4(({ children, onCommand, ...rest }, ref) => {
|
|
|
634
643
|
);
|
|
635
644
|
});
|
|
636
645
|
EditorCommandItem.displayName = "EditorCommandItem";
|
|
646
|
+
var EditorCommandEmpty = CommandEmptyAny;
|
|
637
647
|
|
|
638
648
|
// src/headless/extensions/index.ts
|
|
639
649
|
import { StarterKit } from "@tiptap/starter-kit";
|
|
@@ -1043,8 +1053,12 @@ export {
|
|
|
1043
1053
|
EditorCommand,
|
|
1044
1054
|
EditorCommandList,
|
|
1045
1055
|
EditorCommandItem,
|
|
1056
|
+
EditorCommandEmpty,
|
|
1046
1057
|
CodeBlock,
|
|
1047
1058
|
Link,
|
|
1059
|
+
BubbleMenuExtensionsProvider,
|
|
1060
|
+
useBubbleMenuExtensions,
|
|
1061
|
+
init_bubble_menu_extensions,
|
|
1048
1062
|
ImageBlock,
|
|
1049
1063
|
StarterKit,
|
|
1050
1064
|
Placeholder,
|
|
@@ -1054,4 +1068,4 @@ export {
|
|
|
1054
1068
|
handleCommandNavigation,
|
|
1055
1069
|
useCurrentEditor4 as useCurrentEditor
|
|
1056
1070
|
};
|
|
1057
|
-
//# sourceMappingURL=chunk-
|
|
1071
|
+
//# sourceMappingURL=chunk-TPFBGHW3.js.map
|