tetrons 2.2.2 → 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/app/layout.d.ts +2 -1
  2. package/dist/app/{layout.jsx → layout.js} +2 -5
  3. package/dist/app/page.d.ts +1 -1
  4. package/dist/app/page.js +6 -0
  5. package/dist/components/tetrons/EditorContent.d.ts +1 -2
  6. package/dist/components/tetrons/{EditorContent.jsx → EditorContent.js} +2 -22
  7. package/dist/components/tetrons/{ResizableImageComponent.jsx → ResizableImageComponent.js} +10 -12
  8. package/dist/components/tetrons/{ResizableVideoComponent.jsx → ResizableVideoComponent.js} +7 -8
  9. package/dist/components/tetrons/toolbar/ActionGroup.d.ts +1 -2
  10. package/dist/components/tetrons/toolbar/{ActionGroup.jsx → ActionGroup.js} +12 -35
  11. package/dist/components/tetrons/toolbar/ClipboardGroup.d.ts +1 -2
  12. package/dist/components/tetrons/toolbar/ClipboardGroup.js +31 -0
  13. package/dist/components/tetrons/toolbar/FileGroup.d.ts +1 -2
  14. package/dist/components/tetrons/toolbar/{FileGroup.jsx → FileGroup.js} +3 -6
  15. package/dist/components/tetrons/toolbar/FontStyleGroup.d.ts +1 -2
  16. package/dist/components/tetrons/toolbar/FontStyleGroup.js +63 -0
  17. package/dist/components/tetrons/toolbar/InsertGroup.d.ts +1 -2
  18. package/dist/components/tetrons/toolbar/InsertGroup.js +138 -0
  19. package/dist/components/tetrons/toolbar/ListAlignGroup.d.ts +1 -2
  20. package/dist/components/tetrons/toolbar/ListAlignGroup.js +7 -0
  21. package/dist/components/tetrons/toolbar/MiscGroup.d.ts +1 -2
  22. package/dist/components/tetrons/toolbar/MiscGroup.js +25 -0
  23. package/dist/components/tetrons/toolbar/TableContextMenu.d.ts +1 -2
  24. package/dist/components/tetrons/toolbar/{TableContextMenu.jsx → TableContextMenu.js} +3 -21
  25. package/dist/components/tetrons/toolbar/TetronsToolbar.d.ts +1 -2
  26. package/dist/components/tetrons/toolbar/{TetronsToolbar.jsx → TetronsToolbar.js} +2 -14
  27. package/dist/components/tetrons/toolbar/ToolbarButton.js +7 -0
  28. package/dist/index.d.mts +2 -2
  29. package/dist/index.d.ts +0 -1
  30. package/dist/index.js +1 -1
  31. package/dist/index.mjs +749 -629
  32. package/dist/styles/styles/tetrons.css +371 -0
  33. package/dist/styles/tetrons.css +42 -0
  34. package/package.json +5 -3
  35. package/dist/app/page.jsx +0 -9
  36. package/dist/components/tetrons/toolbar/ClipboardGroup.jsx +0 -36
  37. package/dist/components/tetrons/toolbar/FontStyleGroup.jsx +0 -104
  38. package/dist/components/tetrons/toolbar/InsertGroup.jsx +0 -163
  39. package/dist/components/tetrons/toolbar/ListAlignGroup.jsx +0 -16
  40. package/dist/components/tetrons/toolbar/MiscGroup.jsx +0 -31
  41. package/dist/components/tetrons/toolbar/ToolbarButton.jsx +0 -8
  42. /package/dist/components/UI/{Button.jsx → Button.js} +0 -0
  43. /package/dist/components/UI/{Dropdown.jsx → Dropdown.js} +0 -0
@@ -1,6 +1,7 @@
1
+ /// <reference types="react" />
1
2
  import type { Metadata } from "next";
2
3
  import "./globals.css";
3
4
  export declare const metadata: Metadata;
4
5
  export default function RootLayout({ children, }: {
5
6
  children: React.ReactNode;
6
- }): import("react").JSX.Element;
7
+ }): import("react/jsx-runtime").JSX.Element;
@@ -1,3 +1,4 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
1
2
  import { Geist, Geist_Mono } from "next/font/google";
2
3
  import "./globals.css";
3
4
  const geistSans = Geist({
@@ -22,9 +23,5 @@ export const metadata = {
22
23
  manifest: "/site.webmanifest",
23
24
  };
24
25
  export default function RootLayout({ children, }) {
25
- return (<html lang="en">
26
- <body suppressHydrationWarning className={`${geistSans.variable} ${geistMono.variable} font-sans antialiased bg-gray-50 text-gray-900`}>
27
- <main className="max-w-screen-xl mx-auto p-4">{children}</main>
28
- </body>
29
- </html>);
26
+ return (_jsx("html", { lang: "en", children: _jsx("body", { suppressHydrationWarning: true, className: `${geistSans.variable} ${geistMono.variable} font-sans antialiased bg-gray-50 text-gray-900`, children: _jsx("main", { className: "max-w-screen-xl mx-auto p-4", children: children }) }) }));
30
27
  }
@@ -1,2 +1,2 @@
1
1
  import "../styles/tetrons.css";
2
- export default function Home(): import("react").JSX.Element;
2
+ export default function Home(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import EditorContent from "../components/tetrons/EditorContent";
3
+ import "../styles/tetrons.css";
4
+ export default function Home() {
5
+ return (_jsx("main", { className: "flex flex-col h-screen overflow-hidden", children: _jsx("div", { className: "flex-1 overflow-auto flex flex-col", children: _jsx(EditorContent, {}) }) }));
6
+ }
@@ -1,2 +1 @@
1
- import React from "react";
2
- export default function EditorContent(): React.JSX.Element;
1
+ export default function EditorContent(): import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
3
  import React from "react";
3
4
  import { Comment } from "./toolbar/extensions/Comment";
4
5
  import { useEffect, useRef } from "react";
@@ -133,26 +134,5 @@ export default function EditorContent() {
133
134
  setCurrentVersionIndex(index);
134
135
  }
135
136
  };
136
- return (<div className="editor-container">
137
- <div className="editor-toolbar">
138
- <button type="button" onClick={saveVersion} disabled={!editor} className="editor-save-btn">
139
- Save Version
140
- </button>
141
-
142
- <div className="editor-versions-wrapper">
143
- {versions.length === 0 && (<span className="editor-no-versions">No saved versions</span>)}
144
- {versions.map((_, idx) => (<button type="button" key={idx} onClick={() => restoreVersion(idx)} className={`editor-version-btn ${idx === currentVersionIndex ? "active" : ""}`} title={`Restore Version ${idx + 1}`}>
145
- {`V${idx + 1}`}
146
- </button>))}
147
- </div>
148
- </div>
149
-
150
- {editor && <TetronsToolbar editor={editor}/>}
151
- <div ref={wrapperRef} className="editor-content-wrapper" onClick={handleEditorClick}>
152
- {editor ? (<>
153
- <TiptapEditorContent editor={editor}/>
154
- {editor && <TableContextMenu editor={editor}/>}
155
- </>) : (<div className="editor-loading">Loading editor...</div>)}
156
- </div>
157
- </div>);
137
+ return (_jsxs("div", { className: "editor-container", children: [_jsxs("div", { className: "editor-toolbar", children: [_jsx("button", { type: "button", onClick: saveVersion, disabled: !editor, className: "editor-save-btn", children: "Save Version" }), _jsxs("div", { className: "editor-versions-wrapper", children: [versions.length === 0 && (_jsx("span", { className: "editor-no-versions", children: "No saved versions" })), versions.map((_, idx) => (_jsx("button", { type: "button", onClick: () => restoreVersion(idx), className: `editor-version-btn ${idx === currentVersionIndex ? "active" : ""}`, title: `Restore Version ${idx + 1}`, children: `V${idx + 1}` }, idx)))] })] }), editor && _jsx(TetronsToolbar, { editor: editor }), _jsx("div", { ref: wrapperRef, className: "editor-content-wrapper", onClick: handleEditorClick, children: editor ? (_jsxs(_Fragment, { children: [_jsx(TiptapEditorContent, { editor: editor }), editor && _jsx(TableContextMenu, { editor: editor })] })) : (_jsx("div", { className: "editor-loading", children: "Loading editor..." })) })] }));
158
138
  }
@@ -1,4 +1,5 @@
1
- import React, { useRef, useEffect } from "react";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useRef, useEffect } from "react";
2
3
  import { NodeViewWrapper } from "@tiptap/react";
3
4
  const ResizableImageComponent = ({ node, updateAttributes, selected, }) => {
4
5
  const { src, alt, title, width, height } = node.attrs;
@@ -16,22 +17,19 @@ const ResizableImageComponent = ({ node, updateAttributes, selected, }) => {
16
17
  observer.observe(img);
17
18
  return () => observer.disconnect();
18
19
  }, [updateAttributes]);
19
- return (<NodeViewWrapper ref={wrapperRef} contentEditable={false} className={`resizable-image-wrapper ${selected ? "ProseMirror-selectednode" : ""}`} style={{
20
+ return (_jsx(NodeViewWrapper, { ref: wrapperRef, contentEditable: false, className: `resizable-image-wrapper ${selected ? "ProseMirror-selectednode" : ""}`, style: {
20
21
  resize: "both",
21
22
  overflow: "auto",
22
23
  border: "1px solid #ccc",
23
24
  padding: 2,
24
25
  display: "inline-block",
25
26
  maxWidth: "100%",
26
- }}>
27
- {/* eslint-disable-next-line @next/next/no-img-element */}
28
- <img ref={imgRef} src={src} alt={alt !== null && alt !== void 0 ? alt : ""} title={title !== null && title !== void 0 ? title : ""} loading="lazy" style={{
29
- width: width ? `${width}px` : "auto",
30
- height: height ? `${height}px` : "auto",
31
- display: "block",
32
- userSelect: "none",
33
- pointerEvents: "auto",
34
- }} draggable={false}/>
35
- </NodeViewWrapper>);
27
+ }, children: _jsx("img", { ref: imgRef, src: src, alt: alt !== null && alt !== void 0 ? alt : "", title: title !== null && title !== void 0 ? title : "", loading: "lazy", style: {
28
+ width: width ? `${width}px` : "auto",
29
+ height: height ? `${height}px` : "auto",
30
+ display: "block",
31
+ userSelect: "none",
32
+ pointerEvents: "auto",
33
+ }, draggable: false }) }));
36
34
  };
37
35
  export default ResizableImageComponent;
@@ -1,4 +1,5 @@
1
- import React, { useRef, useEffect } from "react";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useRef, useEffect } from "react";
2
3
  import { NodeViewWrapper } from "@tiptap/react";
3
4
  const ResizableVideoComponent = ({ node, updateAttributes, selected, }) => {
4
5
  const { src, controls, width, height } = node.attrs;
@@ -16,17 +17,15 @@ const ResizableVideoComponent = ({ node, updateAttributes, selected, }) => {
16
17
  observer.observe(video);
17
18
  return () => observer.disconnect();
18
19
  }, [updateAttributes]);
19
- return (<NodeViewWrapper ref={wrapperRef} contentEditable={false} className={`resizable-video-wrapper ${selected ? "ProseMirror-selectednode" : ""}`} style={{
20
+ return (_jsx(NodeViewWrapper, { ref: wrapperRef, contentEditable: false, className: `resizable-video-wrapper ${selected ? "ProseMirror-selectednode" : ""}`, style: {
20
21
  resize: "both",
21
22
  overflow: "auto",
22
23
  border: "1px solid #ccc",
23
24
  padding: "2px",
24
25
  display: "inline-block",
25
- }}>
26
- <video ref={videoRef} src={src} controls={controls} style={{
27
- width: width ? `${width}px` : "auto",
28
- height: height ? `${height}px` : "auto",
29
- }}/>
30
- </NodeViewWrapper>);
26
+ }, children: _jsx("video", { ref: videoRef, src: src, controls: controls, style: {
27
+ width: width ? `${width}px` : "auto",
28
+ height: height ? `${height}px` : "auto",
29
+ } }) }));
31
30
  };
32
31
  export default ResizableVideoComponent;
@@ -1,7 +1,6 @@
1
- import React from "react";
2
1
  import { Editor } from "@tiptap/react";
3
2
  type ActionGroupProps = {
4
3
  editor: Editor;
5
4
  };
6
- export default function ActionGroup({ editor }: ActionGroupProps): React.JSX.Element;
5
+ export default function ActionGroup({ editor }: ActionGroupProps): import("react/jsx-runtime").JSX.Element;
7
6
  export {};
@@ -1,5 +1,6 @@
1
1
  "use client";
2
- import React, { useEffect, useRef, useState } from "react";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useRef, useState } from "react";
3
4
  import { MdZoomIn, MdZoomOut, MdPrint, MdSave, MdDownload, } from "react-icons/md";
4
5
  import ToolbarButton from "./ToolbarButton";
5
6
  export default function ActionGroup({ editor }) {
@@ -130,38 +131,14 @@ export default function ActionGroup({ editor }) {
130
131
  link.click();
131
132
  document.body.removeChild(link);
132
133
  };
133
- return (<div className="action-group" role="group" aria-label="Editor actions">
134
- <ToolbarButton icon={MdZoomIn} onClick={zoomIn} title="Zoom In"/>
135
- <ToolbarButton icon={MdZoomOut} onClick={zoomOut} title="Zoom Out"/>
136
- <ToolbarButton icon={MdPrint} onClick={handlePrint} title="Print"/>
137
- <ToolbarButton icon={MdSave} onClick={handleSave} title="Save"/>
138
-
139
- <div className="relative" ref={dropdownRef}>
140
- <button type="button" onClick={() => setDropdownOpen((open) => !open)} aria-haspopup="menu" aria-expanded={dropdownOpen ? "true" : "false"} className="export-button" title="Export">
141
- <MdDownload />
142
- <span className="text-sm"></span>
143
- </button>
144
-
145
- {dropdownOpen && (<div className="export-dropdown">
146
- <button type="button" onClick={() => {
147
- setDropdownOpen(false);
148
- handleDownloadPDF();
149
- }}>
150
- Export as PDF
151
- </button>
152
- <button type="button" onClick={() => {
153
- setDropdownOpen(false);
154
- handleDownloadHTML();
155
- }}>
156
- Export as HTML
157
- </button>
158
- <button type="button" onClick={() => {
159
- setDropdownOpen(false);
160
- handleDownloadDOCX();
161
- }}>
162
- Export as DOCX
163
- </button>
164
- </div>)}
165
- </div>
166
- </div>);
134
+ return (_jsxs("div", { className: "action-group", role: "group", "aria-label": "Editor actions", children: [_jsx(ToolbarButton, { icon: MdZoomIn, onClick: zoomIn, title: "Zoom In" }), _jsx(ToolbarButton, { icon: MdZoomOut, onClick: zoomOut, title: "Zoom Out" }), _jsx(ToolbarButton, { icon: MdPrint, onClick: handlePrint, title: "Print" }), _jsx(ToolbarButton, { icon: MdSave, onClick: handleSave, title: "Save" }), _jsxs("div", { className: "relative", ref: dropdownRef, children: [_jsxs("button", { type: "button", onClick: () => setDropdownOpen((open) => !open), "aria-haspopup": "menu", "aria-expanded": dropdownOpen ? "true" : "false", className: "export-button", title: "Export", children: [_jsx(MdDownload, {}), _jsx("span", { className: "text-sm" })] }), dropdownOpen && (_jsxs("div", { className: "export-dropdown", children: [_jsx("button", { type: "button", onClick: () => {
135
+ setDropdownOpen(false);
136
+ handleDownloadPDF();
137
+ }, children: "Export as PDF" }), _jsx("button", { type: "button", onClick: () => {
138
+ setDropdownOpen(false);
139
+ handleDownloadHTML();
140
+ }, children: "Export as HTML" }), _jsx("button", { type: "button", onClick: () => {
141
+ setDropdownOpen(false);
142
+ handleDownloadDOCX();
143
+ }, children: "Export as DOCX" })] }))] })] }));
167
144
  }
@@ -1,5 +1,4 @@
1
- import React from "react";
2
1
  import { Editor } from "@tiptap/react";
3
2
  export default function ClipboardGroup({ editor }: {
4
3
  editor: Editor;
5
- }): React.JSX.Element;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { MdContentPaste, MdContentCut, MdContentCopy, MdFormatPaint, } from "react-icons/md";
3
+ import ToolbarButton from "./ToolbarButton";
4
+ export default function ClipboardGroup({ editor }) {
5
+ return (_jsxs("div", { className: "clipboard-group", children: [_jsx(ToolbarButton, { icon: MdContentPaste, title: "Paste", onClick: async () => {
6
+ try {
7
+ const text = await navigator.clipboard.readText();
8
+ editor.chain().focus().insertContent(text).run();
9
+ }
10
+ catch (error) {
11
+ console.error("Failed to read clipboard contents:", error);
12
+ }
13
+ } }), _jsx(ToolbarButton, { icon: MdContentCut, title: "Cut", onClick: () => {
14
+ const { from, to } = editor.state.selection;
15
+ if (from === to)
16
+ return;
17
+ const selectedText = editor.state.doc.textBetween(from, to);
18
+ navigator.clipboard.writeText(selectedText).then(() => {
19
+ editor.chain().focus().deleteRange({ from, to }).run();
20
+ });
21
+ } }), _jsx(ToolbarButton, { icon: MdContentCopy, title: "Copy", onClick: () => {
22
+ const { from, to } = editor.state.selection;
23
+ if (from === to)
24
+ return;
25
+ const selectedText = editor.state.doc.textBetween(from, to);
26
+ navigator.clipboard.writeText(selectedText);
27
+ } }), _jsx(ToolbarButton, { icon: MdFormatPaint, title: "Format Painter", onClick: () => {
28
+ const currentMarks = editor.getAttributes("textStyle");
29
+ localStorage.setItem("formatPainter", JSON.stringify(currentMarks));
30
+ } })] }));
31
+ }
@@ -1,7 +1,6 @@
1
1
  import { Editor } from "@tiptap/react";
2
- import React from "react";
3
2
  type FileGroupProps = {
4
3
  editor: Editor;
5
4
  };
6
- export default function FileGroup({ editor }: FileGroupProps): React.JSX.Element;
5
+ export default function FileGroup({ editor }: FileGroupProps): import("react/jsx-runtime").JSX.Element;
7
6
  export {};
@@ -1,8 +1,9 @@
1
1
  "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { FaRegFolderOpen } from "react-icons/fa";
3
4
  import { VscNewFile } from "react-icons/vsc";
4
5
  import ToolbarButton from "./ToolbarButton";
5
- import React, { useRef } from "react";
6
+ import { useRef } from "react";
6
7
  export default function FileGroup({ editor }) {
7
8
  const fileInputRef = useRef(null);
8
9
  const handleNew = () => {
@@ -32,9 +33,5 @@ export default function FileGroup({ editor }) {
32
33
  e.target.value = "";
33
34
  }
34
35
  };
35
- return (<div className="file-group" role="group" aria-label="File actions">
36
- <input type="file" accept=".json" ref={fileInputRef} onChange={handleFileChange} className="hidden" aria-label="Open JSON file"/>
37
- <ToolbarButton icon={VscNewFile} onClick={handleNew} title="New"/>
38
- <ToolbarButton icon={FaRegFolderOpen} onClick={handleOpen} title="Open File"/>
39
- </div>);
36
+ return (_jsxs("div", { className: "file-group", role: "group", "aria-label": "File actions", children: [_jsx("input", { type: "file", accept: ".json", ref: fileInputRef, onChange: handleFileChange, className: "hidden", "aria-label": "Open JSON file" }), _jsx(ToolbarButton, { icon: VscNewFile, onClick: handleNew, title: "New" }), _jsx(ToolbarButton, { icon: FaRegFolderOpen, onClick: handleOpen, title: "Open File" })] }));
40
37
  }
@@ -1,7 +1,6 @@
1
1
  import { Editor } from "@tiptap/react";
2
- import React from "react";
3
2
  interface FontStyleGroupProps {
4
3
  editor: Editor;
5
4
  }
6
- export default function FontStyleGroup({ editor }: FontStyleGroupProps): React.JSX.Element;
5
+ export default function FontStyleGroup({ editor }: FontStyleGroupProps): import("react/jsx-runtime").JSX.Element;
7
6
  export {};
@@ -0,0 +1,63 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { MdFormatBold, MdFormatItalic, MdFormatUnderlined, MdStrikethroughS, MdSubscript, MdSuperscript, MdFormatClear, MdFormatPaint, } from "react-icons/md";
4
+ import { ImTextColor } from "react-icons/im";
5
+ import { BiSolidColorFill } from "react-icons/bi";
6
+ import ToolbarButton from "./ToolbarButton";
7
+ import { useEffect, useState } from "react";
8
+ export default function FontStyleGroup({ editor }) {
9
+ const [textColor, setTextColor] = useState("#000000");
10
+ const [highlightColor, setHighlightColor] = useState("#ffff00");
11
+ const [fontFamily, setFontFamily] = useState("Arial");
12
+ const [fontSize, setFontSize] = useState("16px");
13
+ useEffect(() => {
14
+ if (!editor)
15
+ return;
16
+ const updateStates = () => {
17
+ var _a, _b, _c;
18
+ const highlight = editor.getAttributes("highlight");
19
+ setHighlightColor((highlight === null || highlight === void 0 ? void 0 : highlight.color) || "#ffff00");
20
+ const color = (_a = editor.getAttributes("textStyle")) === null || _a === void 0 ? void 0 : _a.color;
21
+ setTextColor(color || "#000000");
22
+ const fontAttr = ((_b = editor.getAttributes("fontFamily")) === null || _b === void 0 ? void 0 : _b.font) || "Arial";
23
+ setFontFamily(fontAttr);
24
+ const sizeAttr = ((_c = editor.getAttributes("fontSize")) === null || _c === void 0 ? void 0 : _c.size) || "16px";
25
+ setFontSize(sizeAttr);
26
+ };
27
+ updateStates();
28
+ editor.on("selectionUpdate", updateStates);
29
+ editor.on("transaction", updateStates);
30
+ return () => {
31
+ editor.off("selectionUpdate", updateStates);
32
+ editor.off("transaction", updateStates);
33
+ };
34
+ }, [editor]);
35
+ return (_jsxs("div", { className: "font-style-group", children: [_jsxs("select", { title: "Font Family", value: fontFamily, onChange: (e) => {
36
+ const value = e.target.value;
37
+ setFontFamily(value);
38
+ editor.chain().focus().setFontFamily(value).run();
39
+ }, children: [_jsx("option", { value: "Arial", children: "Arial" }), _jsx("option", { value: "Georgia", children: "Georgia" }), _jsx("option", { value: "Times New Roman", children: "Times New Roman" }), _jsx("option", { value: "Courier New", children: "Courier New" }), _jsx("option", { value: "Verdana", children: "Verdana" })] }), _jsxs("select", { title: "Font Size", value: fontSize, onChange: (e) => {
40
+ const value = e.target.value;
41
+ setFontSize(value);
42
+ editor.chain().focus().setFontSize(value).run();
43
+ }, children: [_jsx("option", { value: "12px", children: "12" }), _jsx("option", { value: "14px", children: "14" }), _jsx("option", { value: "16px", children: "16" }), _jsx("option", { value: "18px", children: "18" }), _jsx("option", { value: "24px", children: "24" }), _jsx("option", { value: "36px", children: "36" }), _jsx("option", { value: "48px", children: "48" }), _jsx("option", { value: "64px", children: "64" }), _jsx("option", { value: "72px", children: "72" })] }), _jsx(ToolbarButton, { icon: MdFormatBold, label: "Bold", onClick: () => editor.chain().focus().toggleBold().run(), isActive: editor.isActive("bold") }), _jsx(ToolbarButton, { icon: MdFormatItalic, label: "Italic", onClick: () => editor.chain().focus().toggleItalic().run(), isActive: editor.isActive("italic") }), _jsx(ToolbarButton, { icon: MdFormatUnderlined, label: "Underline", onClick: () => editor.chain().focus().toggleUnderline().run(), isActive: editor.isActive("underline") }), _jsx(ToolbarButton, { icon: MdStrikethroughS, label: "Strikethrough", onClick: () => editor.chain().focus().toggleStrike().run(), isActive: editor.isActive("strike") }), _jsx(ToolbarButton, { icon: MdSubscript, label: "Subscript", onClick: () => editor.chain().focus().toggleSubscript().run(), isActive: editor.isActive("subscript") }), _jsx(ToolbarButton, { icon: MdSuperscript, label: "Superscript", onClick: () => editor.chain().focus().toggleSuperscript().run(), isActive: editor.isActive("superscript") }), _jsxs("label", { title: "Font Color", "aria-label": "Font Color", className: "color-label", style: { "--indicator-color": textColor }, children: [_jsx(ImTextColor, { size: 20 }), _jsx("div", { className: "color-indicator" }), _jsx("input", { type: "color", value: textColor, onChange: (e) => {
44
+ const color = e.target.value;
45
+ setTextColor(color);
46
+ editor.chain().focus().setColor(color).run();
47
+ } })] }), _jsxs("label", { title: "Highlight Color", "aria-label": "Highlight Color", className: "color-label", style: { "--indicator-color": highlightColor }, children: [_jsx(BiSolidColorFill, { size: 20 }), _jsx("div", { className: "color-indicator" }), _jsx("input", { type: "color", value: highlightColor, onChange: (e) => {
48
+ const color = e.target.value;
49
+ setHighlightColor(color);
50
+ editor.chain().focus().setHighlight({ color }).run();
51
+ } })] }), _jsx(ToolbarButton, { icon: MdFormatClear, label: "Clear Formatting", onClick: () => editor.chain().focus().unsetAllMarks().run() }), _jsx(ToolbarButton, { icon: MdFormatPaint, label: "Apply Painter Format", onClick: () => {
52
+ const format = JSON.parse(localStorage.getItem("formatPainter") || "{}");
53
+ if (format.color)
54
+ editor.chain().focus().setColor(format.color).run();
55
+ if (format.backgroundColor) {
56
+ editor
57
+ .chain()
58
+ .focus()
59
+ .setHighlight({ color: format.backgroundColor })
60
+ .run();
61
+ }
62
+ } })] }));
63
+ }
@@ -1,5 +1,4 @@
1
- import React from "react";
2
1
  import { Editor } from "@tiptap/react";
3
2
  export default function InsertGroup({ editor }: {
4
3
  editor: Editor;
5
- }): React.JSX.Element;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,138 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useRef, useState } from "react";
4
+ import { MdTableChart, MdInsertPhoto, MdInsertLink, MdInsertComment, MdInsertEmoticon, MdHorizontalRule, MdVideoLibrary, MdOutlineOndemandVideo, } from "react-icons/md";
5
+ import ToolbarButton from "./ToolbarButton";
6
+ import Picker from "@emoji-mart/react";
7
+ export default function InsertGroup({ editor }) {
8
+ const [showTableGrid, setShowTableGrid] = useState(false);
9
+ const [selectedRows, setSelectedRows] = useState(1);
10
+ const [selectedCols, setSelectedCols] = useState(1);
11
+ const imageInputRef = useRef(null);
12
+ const videoInputRef = useRef(null);
13
+ const [showPicker, setShowPicker] = useState(false);
14
+ const addEmoji = (emoji) => {
15
+ editor.chain().focus().insertContent(emoji.native).run();
16
+ setShowPicker(false);
17
+ };
18
+ const handleTableCellHover = (row, col) => {
19
+ setSelectedRows(row);
20
+ setSelectedCols(col);
21
+ };
22
+ const handleTableInsert = (rows, cols) => {
23
+ editor
24
+ .chain()
25
+ .focus()
26
+ .insertTable({
27
+ rows: rows || 1,
28
+ cols: cols || 1,
29
+ withHeaderRow: true,
30
+ })
31
+ .run();
32
+ setShowTableGrid(false);
33
+ setSelectedRows(1);
34
+ setSelectedCols(1);
35
+ };
36
+ const handleImageUpload = (e) => {
37
+ var _a;
38
+ const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
39
+ if (file) {
40
+ const reader = new FileReader();
41
+ reader.onload = () => {
42
+ editor
43
+ .chain()
44
+ .focus()
45
+ .setImage({ src: reader.result })
46
+ .run();
47
+ };
48
+ reader.readAsDataURL(file);
49
+ }
50
+ };
51
+ const handleVideoUpload = (e) => {
52
+ var _a;
53
+ const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
54
+ if (file) {
55
+ const reader = new FileReader();
56
+ reader.onload = () => {
57
+ editor
58
+ .chain()
59
+ .focus()
60
+ .setVideo({ src: reader.result, controls: true })
61
+ .run();
62
+ };
63
+ reader.readAsDataURL(file);
64
+ }
65
+ };
66
+ function normalizeEmbedUrl(url) {
67
+ try {
68
+ const u = new URL(url);
69
+ const hostname = u.hostname.replace("www.", "").toLowerCase();
70
+ if (hostname === "youtube.com" || hostname === "youtu.be") {
71
+ let videoId = u.searchParams.get("v");
72
+ if (!videoId && hostname === "youtu.be") {
73
+ videoId = u.pathname.slice(1);
74
+ }
75
+ if (videoId) {
76
+ return `https://www.youtube.com/embed/${videoId}`;
77
+ }
78
+ }
79
+ if (hostname === "vimeo.com") {
80
+ const videoId = u.pathname.split("/")[1];
81
+ if (videoId) {
82
+ return `https://player.vimeo.com/video/${videoId}`;
83
+ }
84
+ }
85
+ if (hostname === "google.com" ||
86
+ hostname === "maps.google.com" ||
87
+ hostname === "goo.gl") {
88
+ if (url.includes("/maps/embed")) {
89
+ return url;
90
+ }
91
+ return url.replace("/maps/", "/maps/embed/");
92
+ }
93
+ return url;
94
+ }
95
+ catch (_a) {
96
+ return url;
97
+ }
98
+ }
99
+ return (_jsxs("div", { className: "insert-group", children: [_jsx("input", { type: "file", accept: "image/*", ref: imageInputRef, className: "hidden-input", onChange: handleImageUpload, "aria-label": "Upload Image", title: "Upload Image" }), _jsx("input", { type: "file", accept: "video/*", ref: videoInputRef, className: "hidden-input", onChange: handleVideoUpload, "aria-label": "Upload Video", title: "Upload Video" }), _jsx(ToolbarButton, { icon: MdTableChart, label: "Insert Table", onClick: () => setShowTableGrid(!showTableGrid) }), showTableGrid && (_jsxs("div", { className: "table-grid-popup", onMouseLeave: () => setShowTableGrid(false), children: [_jsx("div", { className: "table-grid", children: [...Array(10)].map((_, row) => [...Array(10)].map((_, col) => {
100
+ const isSelected = row < selectedRows && col < selectedCols;
101
+ return (_jsx("div", { className: `table-grid-cell ${isSelected ? "selected" : ""}`, onMouseEnter: () => handleTableCellHover(row + 1, col + 1), onClick: () => handleTableInsert(row + 1, col + 1) }, `${row}-${col}`));
102
+ })) }), _jsxs("div", { className: "table-grid-label", children: [selectedRows, " x ", selectedCols] })] })), _jsx(ToolbarButton, { icon: MdInsertPhoto, label: "Insert Image", onClick: () => { var _a; return (_a = imageInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); } }), _jsx(ToolbarButton, { icon: MdVideoLibrary, label: "Insert Video", onClick: () => { var _a; return (_a = videoInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); } }), _jsx(ToolbarButton, { icon: MdInsertLink, label: "Insert Link", onClick: () => {
103
+ const url = prompt("Enter URL");
104
+ if (url) {
105
+ editor
106
+ .chain()
107
+ .focus()
108
+ .extendMarkRange("link")
109
+ .setLink({ href: url })
110
+ .run();
111
+ }
112
+ } }), _jsx(ToolbarButton, { icon: MdInsertComment, label: "Insert Comment", onClick: () => {
113
+ const comment = prompt("Enter your comment");
114
+ if (comment &&
115
+ editor.can().chain().focus().setComment(comment).run()) {
116
+ editor.chain().focus().setComment(comment).run();
117
+ }
118
+ else {
119
+ console.warn("Cannot apply comment — maybe no selection?");
120
+ }
121
+ } }), _jsxs("div", { className: "relative", children: [_jsx(ToolbarButton, { icon: MdInsertEmoticon, label: "Emoji", onClick: () => setShowPicker(!showPicker) }), showPicker && (_jsx("div", { className: "emoji-picker", children: _jsx(Picker, { onEmojiSelect: addEmoji, theme: "auto", emoji: "point_up", showPreview: false, showSkinTones: true, emojiTooltip: true }) }))] }), _jsx(ToolbarButton, { icon: MdHorizontalRule, label: "Horizontal Line", onClick: () => editor.chain().focus().setHorizontalRule().run() }), _jsx(ToolbarButton, { icon: MdOutlineOndemandVideo, label: "Embed", onClick: () => {
122
+ const url = prompt("Enter embed URL (YouTube, Vimeo, Google Maps, etc.)");
123
+ if (!url)
124
+ return;
125
+ const embedUrl = normalizeEmbedUrl(url);
126
+ const width = prompt("Enter width in pixels", "560");
127
+ const height = prompt("Enter height in pixels", "315");
128
+ editor
129
+ .chain()
130
+ .focus()
131
+ .setEmbed({
132
+ src: embedUrl,
133
+ width: width ? parseInt(width) : 560,
134
+ height: height ? parseInt(height) : 315,
135
+ })
136
+ .run();
137
+ } })] }));
138
+ }
@@ -1,5 +1,4 @@
1
- import React from "react";
2
1
  import { Editor } from "@tiptap/react";
3
2
  export default function ListAlignGroup({ editor }: {
4
3
  editor: Editor;
5
- }): React.JSX.Element;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { MdFormatListBulleted, MdFormatListNumbered, MdFormatIndentDecrease, MdFormatIndentIncrease, MdFormatAlignLeft, MdFormatAlignCenter, MdFormatAlignRight, MdFormatAlignJustify, } from "react-icons/md";
4
+ import ToolbarButton from "./ToolbarButton";
5
+ export default function ListAlignGroup({ editor }) {
6
+ return (_jsxs("div", { className: "list-align-group", children: [_jsx(ToolbarButton, { icon: MdFormatListBulleted, title: "Bulleted List", onClick: () => editor.chain().focus().toggleBulletList().run(), disabled: !editor.can().toggleBulletList() }), _jsx(ToolbarButton, { icon: MdFormatListNumbered, title: "Numbered List", onClick: () => editor.chain().focus().toggleOrderedList().run(), disabled: !editor.can().toggleOrderedList() }), _jsx(ToolbarButton, { icon: MdFormatIndentIncrease, title: "Increase Indent", onClick: () => editor.chain().focus().sinkListItem("listItem").run(), disabled: !editor.can().sinkListItem("listItem") }), _jsx(ToolbarButton, { icon: MdFormatIndentDecrease, title: "Decrease Indent", onClick: () => editor.chain().focus().liftListItem("listItem").run(), disabled: !editor.can().liftListItem("listItem") }), _jsx(ToolbarButton, { icon: MdFormatAlignLeft, title: "Align Left", onClick: () => editor.chain().focus().setTextAlign("left").run(), disabled: !editor.can().setTextAlign("left") }), _jsx(ToolbarButton, { icon: MdFormatAlignCenter, title: "Align Center", onClick: () => editor.chain().focus().setTextAlign("center").run(), disabled: !editor.can().setTextAlign("center") }), _jsx(ToolbarButton, { icon: MdFormatAlignRight, title: "Align Right", onClick: () => editor.chain().focus().setTextAlign("right").run(), disabled: !editor.can().setTextAlign("right") }), _jsx(ToolbarButton, { icon: MdFormatAlignJustify, title: "Justify", onClick: () => editor.chain().focus().setTextAlign("justify").run(), disabled: !editor.can().setTextAlign("justify") })] }));
7
+ }
@@ -1,7 +1,6 @@
1
- import React from "react";
2
1
  import { Editor } from "@tiptap/react";
3
2
  interface MiscGroupProps {
4
3
  editor: Editor;
5
4
  }
6
- export default function MiscGroup({ editor }: MiscGroupProps): React.JSX.Element;
5
+ export default function MiscGroup({ editor }: MiscGroupProps): import("react/jsx-runtime").JSX.Element;
7
6
  export {};
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { MdUndo, MdRedo, MdRefresh, MdVisibility, MdCode, } from "react-icons/md";
3
+ import ToolbarButton from "./ToolbarButton";
4
+ export default function MiscGroup({ editor }) {
5
+ const handlePreview = () => {
6
+ const html = editor.getHTML();
7
+ const previewWindow = window.open("", "_blank");
8
+ if (previewWindow) {
9
+ previewWindow.document.open();
10
+ previewWindow.document.write(`
11
+ <html>
12
+ <head>
13
+ <title>Preview</title>
14
+ <style>
15
+ body { font-family: sans-serif; padding: 2rem; line-height: 1.6; }
16
+ </style>
17
+ </head>
18
+ <body>${html}</body>
19
+ </html>
20
+ `);
21
+ previewWindow.document.close();
22
+ }
23
+ };
24
+ return (_jsxs("div", { className: "misc-group", children: [_jsx(ToolbarButton, { icon: MdUndo, label: "Undo", onClick: () => editor.chain().focus().undo().run(), disabled: !editor.can().undo() }), _jsx(ToolbarButton, { icon: MdRedo, label: "Redo", onClick: () => editor.chain().focus().redo().run(), disabled: !editor.can().redo() }), _jsx(ToolbarButton, { icon: MdRefresh, label: "Reset Formatting", onClick: () => editor.chain().focus().unsetAllMarks().clearNodes().run() }), _jsx(ToolbarButton, { icon: MdCode, label: "Toggle Code Block", onClick: () => editor.chain().focus().toggleCodeBlock().run(), isActive: editor.isActive("codeBlock") }), _jsx(ToolbarButton, { icon: MdVisibility, label: "Preview", onClick: handlePreview })] }));
25
+ }
@@ -1,7 +1,6 @@
1
- import React from "react";
2
1
  import { Editor } from "@tiptap/react";
3
2
  interface ContextMenuProps {
4
3
  editor: Editor;
5
4
  }
6
- export default function TableContextMenu({ editor }: ContextMenuProps): React.JSX.Element | null;
5
+ export default function TableContextMenu({ editor }: ContextMenuProps): import("react/jsx-runtime").JSX.Element | null;
7
6
  export {};
@@ -1,5 +1,6 @@
1
1
  "use client";
2
- import React, { useEffect, useState } from "react";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
3
4
  export default function TableContextMenu({ editor }) {
4
5
  const [menuPosition, setMenuPosition] = useState(null);
5
6
  useEffect(() => {
@@ -29,24 +30,5 @@ export default function TableContextMenu({ editor }) {
29
30
  const deleteCol = () => editor.chain().focus().deleteColumn().run();
30
31
  if (!menuPosition)
31
32
  return null;
32
- return (<ul className="absolute bg-white shadow border rounded text-sm z-50" style={{ top: menuPosition.y, left: menuPosition.x }}>
33
- <li className="px-3 py-1 hover:bg-gray-100 cursor-pointer" onClick={insertRowAbove}>
34
- Insert Row Above
35
- </li>
36
- <li className="px-3 py-1 hover:bg-gray-100 cursor-pointer" onClick={insertRowBelow}>
37
- Insert Row Below
38
- </li>
39
- <li className="px-3 py-1 hover:bg-gray-100 cursor-pointer" onClick={insertColLeft}>
40
- Insert Column Left
41
- </li>
42
- <li className="px-3 py-1 hover:bg-gray-100 cursor-pointer" onClick={insertColRight}>
43
- Insert Column Right
44
- </li>
45
- <li className="px-3 py-1 hover:bg-red-100 cursor-pointer" onClick={deleteRow}>
46
- Delete Row
47
- </li>
48
- <li className="px-3 py-1 hover:bg-red-100 cursor-pointer" onClick={deleteCol}>
49
- Delete Column
50
- </li>
51
- </ul>);
33
+ return (_jsxs("ul", { className: "absolute bg-white shadow border rounded text-sm z-50", style: { top: menuPosition.y, left: menuPosition.x }, children: [_jsx("li", { className: "px-3 py-1 hover:bg-gray-100 cursor-pointer", onClick: insertRowAbove, children: "Insert Row Above" }), _jsx("li", { className: "px-3 py-1 hover:bg-gray-100 cursor-pointer", onClick: insertRowBelow, children: "Insert Row Below" }), _jsx("li", { className: "px-3 py-1 hover:bg-gray-100 cursor-pointer", onClick: insertColLeft, children: "Insert Column Left" }), _jsx("li", { className: "px-3 py-1 hover:bg-gray-100 cursor-pointer", onClick: insertColRight, children: "Insert Column Right" }), _jsx("li", { className: "px-3 py-1 hover:bg-red-100 cursor-pointer", onClick: deleteRow, children: "Delete Row" }), _jsx("li", { className: "px-3 py-1 hover:bg-red-100 cursor-pointer", onClick: deleteCol, children: "Delete Column" })] }));
52
34
  }