tetrons 2.3.33 → 2.3.35

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 (75) hide show
  1. package/dist/index.cjs +47 -8
  2. package/dist/index.d.mts +2 -1
  3. package/dist/index.d.ts +2 -1
  4. package/dist/index.mjs +46 -8
  5. package/dist/src/index.d.ts +7 -0
  6. package/dist/src/index.js +61 -0
  7. package/package.json +1 -1
  8. package/dist/app/api/export/route.js +0 -4
  9. package/dist/app/api/register/route.js +0 -32
  10. package/dist/app/api/save/route.js +0 -15
  11. package/dist/app/api/validate/route.js +0 -58
  12. package/dist/app/layout.d.ts +0 -6
  13. package/dist/app/layout.jsx +0 -30
  14. package/dist/app/page.jsx +0 -51
  15. package/dist/components/UI/Button.d.ts +0 -0
  16. package/dist/components/UI/Button.jsx +0 -1
  17. package/dist/components/UI/Dropdown.d.ts +0 -0
  18. package/dist/components/UI/Dropdown.jsx +0 -1
  19. package/dist/components/tetrons/EditorContent.jsx +0 -209
  20. package/dist/components/tetrons/ResizableVideo.d.ts +0 -12
  21. package/dist/components/tetrons/ResizableVideo.js +0 -61
  22. package/dist/components/tetrons/ResizableVideoComponent.d.ts +0 -4
  23. package/dist/components/tetrons/ResizableVideoComponent.jsx +0 -32
  24. package/dist/components/tetrons/helpers.d.ts +0 -0
  25. package/dist/components/tetrons/helpers.js +0 -1
  26. package/dist/components/tetrons/toolbar/ActionGroup.d.ts +0 -7
  27. package/dist/components/tetrons/toolbar/ActionGroup.jsx +0 -167
  28. package/dist/components/tetrons/toolbar/ClipboardGroup.d.ts +0 -5
  29. package/dist/components/tetrons/toolbar/ClipboardGroup.jsx +0 -36
  30. package/dist/components/tetrons/toolbar/FileGroup.d.ts +0 -7
  31. package/dist/components/tetrons/toolbar/FileGroup.jsx +0 -40
  32. package/dist/components/tetrons/toolbar/FontStyleGroup.d.ts +0 -7
  33. package/dist/components/tetrons/toolbar/FontStyleGroup.jsx +0 -104
  34. package/dist/components/tetrons/toolbar/InsertGroup.d.ts +0 -5
  35. package/dist/components/tetrons/toolbar/InsertGroup.jsx +0 -163
  36. package/dist/components/tetrons/toolbar/ListAlignGroup.d.ts +0 -5
  37. package/dist/components/tetrons/toolbar/ListAlignGroup.jsx +0 -16
  38. package/dist/components/tetrons/toolbar/MiscGroup.d.ts +0 -7
  39. package/dist/components/tetrons/toolbar/MiscGroup.jsx +0 -31
  40. package/dist/components/tetrons/toolbar/TableContextMenu.d.ts +0 -7
  41. package/dist/components/tetrons/toolbar/TableContextMenu.jsx +0 -52
  42. package/dist/components/tetrons/toolbar/TetronsToolbar.d.ts +0 -6
  43. package/dist/components/tetrons/toolbar/TetronsToolbar.jsx +0 -46
  44. package/dist/components/tetrons/toolbar/ToolbarButton.d.ts +0 -12
  45. package/dist/components/tetrons/toolbar/ToolbarButton.jsx +0 -8
  46. package/dist/components/tetrons/toolbar/extensions/Comment.d.ts +0 -17
  47. package/dist/components/tetrons/toolbar/extensions/Comment.js +0 -45
  48. package/dist/components/tetrons/toolbar/extensions/Embed.d.ts +0 -2
  49. package/dist/components/tetrons/toolbar/extensions/Embed.js +0 -90
  50. package/dist/components/tetrons/toolbar/extensions/FontFamily.d.ts +0 -9
  51. package/dist/components/tetrons/toolbar/extensions/FontFamily.js +0 -28
  52. package/dist/components/tetrons/toolbar/extensions/FontSize.d.ts +0 -9
  53. package/dist/components/tetrons/toolbar/extensions/FontSize.js +0 -28
  54. package/dist/components/tetrons/toolbar/extensions/ResizableTable.d.ts +0 -1
  55. package/dist/components/tetrons/toolbar/extensions/ResizableTable.js +0 -11
  56. package/dist/components/tetrons/toolbar/marks/Subscript.d.ts +0 -2
  57. package/dist/components/tetrons/toolbar/marks/Subscript.js +0 -35
  58. package/dist/components/tetrons/toolbar/marks/Superscript.d.ts +0 -2
  59. package/dist/components/tetrons/toolbar/marks/Superscript.js +0 -35
  60. package/dist/lib/db.d.ts +0 -1
  61. package/dist/lib/db.js +0 -15
  62. package/dist/lib/export.d.ts +0 -0
  63. package/dist/lib/export.js +0 -1
  64. package/dist/lib/tiptap-extensions.d.ts +0 -0
  65. package/dist/lib/tiptap-extensions.js +0 -1
  66. package/dist/models/ApiKey.d.ts +0 -2
  67. package/dist/models/ApiKey.js +0 -14
  68. package/dist/src/app/page.d.ts +0 -2
  69. package/dist/src/app/page.jsx +0 -51
  70. package/dist/src/components/tetrons/toolbar/AIGroup.d.ts +0 -5
  71. package/dist/src/components/tetrons/toolbar/AIGroup.jsx +0 -140
  72. package/dist/utils/apiKeyUtils.d.ts +0 -11
  73. package/dist/utils/apiKeyUtils.js +0 -33
  74. package/dist/utils/loadEmojiPicker.d.ts +0 -1
  75. package/dist/utils/loadEmojiPicker.js +0 -12
@@ -1,209 +0,0 @@
1
- "use client";
2
- import React from "react";
3
- import { Comment } from "./toolbar/extensions/Comment";
4
- import { useEffect, useRef } from "react";
5
- import { useEditor, EditorContent as TiptapEditorContent, } from "@tiptap/react";
6
- import Document from "@tiptap/extension-document";
7
- import Paragraph from "@tiptap/extension-paragraph";
8
- import Text from "@tiptap/extension-text";
9
- import History from "@tiptap/extension-history";
10
- import Bold from "@tiptap/extension-bold";
11
- import Italic from "@tiptap/extension-italic";
12
- import Underline from "@tiptap/extension-underline";
13
- import Strike from "@tiptap/extension-strike";
14
- import Code from "@tiptap/extension-code";
15
- import Blockquote from "@tiptap/extension-blockquote";
16
- import HardBreak from "@tiptap/extension-hard-break";
17
- import Heading from "@tiptap/extension-heading";
18
- import HorizontalRule from "@tiptap/extension-horizontal-rule";
19
- import TextAlign from "@tiptap/extension-text-align";
20
- import Color from "@tiptap/extension-color";
21
- import Highlight from "@tiptap/extension-highlight";
22
- import Image from "@tiptap/extension-image";
23
- import Link from "@tiptap/extension-link";
24
- import TextStyle from "@tiptap/extension-text-style";
25
- import ListItem from "@tiptap/extension-list-item";
26
- import BulletList from "@tiptap/extension-bullet-list";
27
- import OrderedList from "@tiptap/extension-ordered-list";
28
- import { Subscript } from "./toolbar/marks/Subscript";
29
- import { Superscript } from "./toolbar/marks/Superscript";
30
- import { ResizableTable } from "./toolbar/extensions/ResizableTable";
31
- import { Embed } from "./toolbar/extensions/Embed";
32
- import TableRow from "@tiptap/extension-table-row";
33
- import TableCell from "@tiptap/extension-table-cell";
34
- import TableHeader from "@tiptap/extension-table-header";
35
- import { FontFamily } from "./toolbar/extensions/FontFamily";
36
- import { FontSize } from "./toolbar/extensions/FontSize";
37
- import TetronsToolbar from "./toolbar/TetronsToolbar";
38
- import { ResizableImage } from "./ResizableImage";
39
- import { ResizableVideo } from "./ResizableVideo";
40
- import TableContextMenu from "./toolbar/TableContextMenu";
41
- import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
42
- import { createLowlight } from "lowlight";
43
- import js from "highlight.js/lib/languages/javascript";
44
- import ts from "highlight.js/lib/languages/typescript";
45
- const lowlight = createLowlight();
46
- lowlight.register("js", js);
47
- lowlight.register("ts", ts);
48
- export default function EditorContent({ apiKey }) {
49
- const [isValid, setIsValid] = React.useState(null);
50
- const [error, setError] = React.useState(null);
51
- const [versions, setVersions] = React.useState([]);
52
- const [userVersion, setUserVersion] = React.useState(null);
53
- const [currentVersionIndex, setCurrentVersionIndex] = React.useState(null);
54
- function getApiBaseUrl() {
55
- var _a, _b;
56
- if (typeof import.meta !== "undefined" &&
57
- ((_a = import.meta.env) === null || _a === void 0 ? void 0 : _a.VITE_TETRONS_API_URL)) {
58
- return import.meta.env.VITE_TETRONS_API_URL;
59
- }
60
- if (typeof process !== "undefined" &&
61
- ((_b = process.env) === null || _b === void 0 ? void 0 : _b.NEXT_PUBLIC_TETRONS_API_URL)) {
62
- return process.env.NEXT_PUBLIC_TETRONS_API_URL;
63
- }
64
- return "https://staging.tetrons.com";
65
- }
66
- const API_BASE_URL = getApiBaseUrl();
67
- useEffect(() => {
68
- const validateKey = async () => {
69
- try {
70
- const res = await fetch(`${API_BASE_URL}/api/validate`, {
71
- method: "POST",
72
- headers: {
73
- "Content-Type": "application/json",
74
- },
75
- body: JSON.stringify({ apiKey }),
76
- });
77
- const data = await res.json();
78
- if (!res.ok)
79
- throw new Error(data.error || "Invalid API Key");
80
- setIsValid(true);
81
- setUserVersion(data.version);
82
- }
83
- catch (err) {
84
- if (err instanceof Error) {
85
- setError(err.message || "Invalid API Key");
86
- }
87
- else {
88
- setError("Invalid API Key");
89
- }
90
- setIsValid(false);
91
- }
92
- };
93
- validateKey();
94
- }, [apiKey]);
95
- const editor = useEditor({
96
- extensions: [
97
- Document,
98
- Paragraph,
99
- Text,
100
- History,
101
- Bold,
102
- Italic,
103
- Underline,
104
- Strike,
105
- Code,
106
- Blockquote,
107
- HardBreak,
108
- Heading.configure({ levels: [1, 2, 3, 4, 5, 6] }),
109
- HorizontalRule,
110
- TextStyle,
111
- Color,
112
- Highlight.configure({ multicolor: true }),
113
- FontFamily,
114
- FontSize,
115
- TextAlign.configure({ types: ["heading", "paragraph"] }),
116
- ListItem,
117
- BulletList,
118
- OrderedList,
119
- Subscript,
120
- Superscript,
121
- Image,
122
- Link.configure({
123
- openOnClick: false,
124
- autolink: true,
125
- linkOnPaste: true,
126
- }),
127
- ResizableTable.configure({
128
- resizable: true,
129
- }),
130
- TableRow,
131
- TableCell,
132
- TableHeader,
133
- Embed,
134
- ResizableImage,
135
- ResizableVideo,
136
- Comment,
137
- CodeBlockLowlight.configure({
138
- lowlight,
139
- HTMLAttributes: {
140
- class: "bg-gray-100 p-2 rounded font-mono text-sm overflow-auto",
141
- },
142
- }),
143
- ],
144
- content: "",
145
- editorProps: {
146
- attributes: {
147
- class: "min-h-full focus:outline-none p-0",
148
- "data-placeholder": "Start typing here...",
149
- },
150
- },
151
- immediatelyRender: false,
152
- });
153
- const wrapperRef = useRef(null);
154
- useEffect(() => {
155
- return () => {
156
- editor === null || editor === void 0 ? void 0 : editor.destroy();
157
- };
158
- }, [editor]);
159
- const handleEditorClick = () => {
160
- if (editor && !editor.isFocused) {
161
- editor.commands.focus();
162
- }
163
- };
164
- const saveVersion = () => {
165
- if (!editor)
166
- return;
167
- const content = editor.getJSON();
168
- setVersions((prev) => [...prev, JSON.stringify(content)]);
169
- setCurrentVersionIndex(versions.length);
170
- };
171
- const restoreVersion = (index) => {
172
- if (!editor)
173
- return;
174
- const versionContent = versions[index];
175
- if (versionContent) {
176
- editor.commands.setContent(JSON.parse(versionContent));
177
- setCurrentVersionIndex(index);
178
- }
179
- };
180
- if (isValid === false) {
181
- return <div className="editor-error">⚠️ {error}</div>;
182
- }
183
- if (isValid === null) {
184
- return <div className="editor-loading">🔍 Validating license...</div>;
185
- }
186
- return (<div className="editor-container">
187
- {userVersion !== "free" && (<div className="editor-toolbar">
188
- <button type="button" onClick={saveVersion} disabled={!editor} className="editor-save-btn">
189
- Save Version
190
- </button>
191
-
192
- <div className="editor-versions-wrapper">
193
- {versions.length === 0 && (<span className="editor-no-versions">No saved versions</span>)}
194
- {versions.map((_, idx) => (<button type="button" key={idx} onClick={() => restoreVersion(idx)} className={`editor-version-btn ${idx === currentVersionIndex ? "active" : ""}`} title={`Restore Version ${idx + 1}`}>
195
- {`V${idx + 1}`}
196
- </button>))}
197
- </div>
198
- </div>)}
199
-
200
- {editor && userVersion && (<TetronsToolbar editor={editor} version={userVersion}/>)}
201
-
202
- <div ref={wrapperRef} className="editor-content-wrapper" onClick={handleEditorClick}>
203
- {editor ? (<>
204
- <TiptapEditorContent editor={editor}/>
205
- {editor && <TableContextMenu editor={editor}/>}
206
- </>) : (<div className="editor-loading">Loading editor...</div>)}
207
- </div>
208
- </div>);
209
- }
@@ -1,12 +0,0 @@
1
- import { Node } from "@tiptap/core";
2
- declare module "@tiptap/core" {
3
- interface Commands<ReturnType> {
4
- video: {
5
- setVideo: (options: {
6
- src: string;
7
- controls?: boolean;
8
- }) => ReturnType;
9
- };
10
- }
11
- }
12
- export declare const ResizableVideo: Node<any, any>;
@@ -1,61 +0,0 @@
1
- var __rest = (this && this.__rest) || function (s, e) {
2
- var t = {};
3
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
- t[p] = s[p];
5
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
- t[p[i]] = s[p[i]];
9
- }
10
- return t;
11
- };
12
- import { Node } from "@tiptap/core";
13
- import { ReactNodeViewRenderer } from "@tiptap/react";
14
- import ResizableVideoComponent from "./ResizableVideoComponent";
15
- export const ResizableVideo = Node.create({
16
- name: "video",
17
- group: "block",
18
- draggable: true,
19
- atom: true,
20
- addAttributes() {
21
- return {
22
- src: { default: null },
23
- controls: {
24
- default: true,
25
- parseHTML: (element) => element.hasAttribute("controls"),
26
- renderHTML: (attributes) => attributes.controls ? { controls: "controls" } : {},
27
- },
28
- width: {
29
- default: null,
30
- },
31
- height: {
32
- default: null,
33
- },
34
- };
35
- },
36
- parseHTML() {
37
- return [{ tag: "video[src]" }];
38
- },
39
- renderHTML({ HTMLAttributes }) {
40
- const { width, height } = HTMLAttributes, rest = __rest(HTMLAttributes, ["width", "height"]);
41
- const style = [];
42
- if (width)
43
- style.push(`width: ${width}px`);
44
- if (height)
45
- style.push(`height: ${height}px`);
46
- return ["video", Object.assign(Object.assign({}, rest), { style: style.join("; ") })];
47
- },
48
- addCommands() {
49
- return {
50
- setVideo: (attributes) => ({ commands }) => {
51
- return commands.insertContent({
52
- type: this.name,
53
- attrs: attributes,
54
- });
55
- },
56
- };
57
- },
58
- addNodeView() {
59
- return ReactNodeViewRenderer(ResizableVideoComponent);
60
- },
61
- });
@@ -1,4 +0,0 @@
1
- import React from "react";
2
- import type { NodeViewProps } from "@tiptap/core";
3
- declare const ResizableVideoComponent: React.FC<NodeViewProps>;
4
- export default ResizableVideoComponent;
@@ -1,32 +0,0 @@
1
- import React, { useRef, useEffect } from "react";
2
- import { NodeViewWrapper } from "@tiptap/react";
3
- const ResizableVideoComponent = ({ node, updateAttributes, selected, }) => {
4
- const { src, controls, width, height } = node.attrs;
5
- const wrapperRef = useRef(null);
6
- const videoRef = useRef(null);
7
- useEffect(() => {
8
- const video = videoRef.current;
9
- if (!video)
10
- return;
11
- const observer = new ResizeObserver(() => {
12
- const w = Math.round(video.offsetWidth);
13
- const h = Math.round(video.offsetHeight);
14
- updateAttributes({ width: w, height: h });
15
- });
16
- observer.observe(video);
17
- return () => observer.disconnect();
18
- }, [updateAttributes]);
19
- return (<NodeViewWrapper ref={wrapperRef} contentEditable={false} className={`resizable-video-wrapper ${selected ? "ProseMirror-selectednode" : ""}`} style={{
20
- resize: "both",
21
- overflow: "auto",
22
- border: "1px solid #ccc",
23
- padding: "2px",
24
- 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>);
31
- };
32
- export default ResizableVideoComponent;
File without changes
@@ -1 +0,0 @@
1
- "use strict";
@@ -1,7 +0,0 @@
1
- import React from "react";
2
- import { Editor } from "@tiptap/react";
3
- type ActionGroupProps = {
4
- editor: Editor;
5
- };
6
- export default function ActionGroup({ editor }: ActionGroupProps): React.JSX.Element;
7
- export {};
@@ -1,167 +0,0 @@
1
- "use client";
2
- import React, { useEffect, useRef, useState } from "react";
3
- import { MdZoomIn, MdZoomOut, MdPrint, MdSave, MdDownload, } from "react-icons/md";
4
- import ToolbarButton from "./ToolbarButton";
5
- export default function ActionGroup({ editor }) {
6
- const [dropdownOpen, setDropdownOpen] = useState(false);
7
- const dropdownRef = useRef(null);
8
- useEffect(() => {
9
- const handleClickOutside = (event) => {
10
- if (dropdownRef.current &&
11
- !dropdownRef.current.contains(event.target)) {
12
- setDropdownOpen(false);
13
- }
14
- };
15
- if (dropdownOpen) {
16
- document.addEventListener("mousedown", handleClickOutside);
17
- }
18
- else {
19
- document.removeEventListener("mousedown", handleClickOutside);
20
- }
21
- return () => {
22
- document.removeEventListener("mousedown", handleClickOutside);
23
- };
24
- }, [dropdownOpen]);
25
- const zoomIn = () => {
26
- const element = document.querySelector(".ProseMirror");
27
- if (element) {
28
- const style = element.style;
29
- const currentZoom = parseFloat(style.zoom || "1");
30
- const next = Math.min(currentZoom + 0.1, 2);
31
- style.zoom = next.toString();
32
- }
33
- };
34
- const zoomOut = () => {
35
- const element = document.querySelector(".ProseMirror");
36
- if (element) {
37
- const style = element.style;
38
- const currentZoom = parseFloat(style.zoom || "1");
39
- const next = Math.max(currentZoom - 0.1, 0.5);
40
- style.zoom = next.toString();
41
- }
42
- };
43
- const handlePrint = () => {
44
- const html = editor.getHTML();
45
- const printWindow = window.open("", "_blank");
46
- if (printWindow) {
47
- printWindow.document.write(`
48
- <html>
49
- <head>
50
- <title>Print</title>
51
- </head>
52
- <body>${html}</body>
53
- </html>
54
- `);
55
- printWindow.document.close();
56
- printWindow.focus();
57
- printWindow.print();
58
- }
59
- };
60
- const handleSave = async () => {
61
- const content = editor.getJSON();
62
- try {
63
- const response = await fetch("/api/save", {
64
- method: "POST",
65
- headers: { "Content-Type": "application/json" },
66
- body: JSON.stringify(content),
67
- });
68
- if (!response.ok)
69
- throw new Error("Failed to save file");
70
- const result = await response.json();
71
- console.log(result.message);
72
- alert("Content saved successfully!");
73
- }
74
- catch (error) {
75
- console.error("Error saving content:", error);
76
- alert("Failed to save content.");
77
- }
78
- };
79
- const handleDownloadPDF = async () => {
80
- const html = editor.getHTML();
81
- const container = document.createElement("div");
82
- container.innerHTML = html;
83
- container.classList.add("p-4", "prose");
84
- document.body.appendChild(container);
85
- try {
86
- const domToPdf = (await import("dom-to-pdf")).default;
87
- const options = {
88
- filename: "document.pdf",
89
- overrideWidth: 800,
90
- overrideHeight: 1120,
91
- };
92
- domToPdf(container, options, () => {
93
- console.log("PDF downloaded!");
94
- });
95
- }
96
- catch (error) {
97
- console.error("PDF download failed", error);
98
- alert("Failed to download PDF.");
99
- }
100
- finally {
101
- document.body.removeChild(container);
102
- }
103
- };
104
- const handleDownloadHTML = () => {
105
- const html = editor.getHTML();
106
- const blob = new Blob([html], { type: "text/html" });
107
- const link = document.createElement("a");
108
- link.href = URL.createObjectURL(blob);
109
- link.download = "document.html";
110
- document.body.appendChild(link);
111
- link.click();
112
- document.body.removeChild(link);
113
- };
114
- const handleDownloadDOCX = async () => {
115
- const { Document, Packer, Paragraph } = await import("docx");
116
- const text = editor.getText();
117
- const doc = new Document({
118
- sections: [
119
- {
120
- properties: {},
121
- children: [new Paragraph(text)],
122
- },
123
- ],
124
- });
125
- const blob = await Packer.toBlob(doc);
126
- const link = document.createElement("a");
127
- link.href = URL.createObjectURL(blob);
128
- link.download = "document.docx";
129
- document.body.appendChild(link);
130
- link.click();
131
- document.body.removeChild(link);
132
- };
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>);
167
- }
@@ -1,5 +0,0 @@
1
- import React from "react";
2
- import { Editor } from "@tiptap/react";
3
- export default function ClipboardGroup({ editor }: {
4
- editor: Editor;
5
- }): React.JSX.Element;
@@ -1,36 +0,0 @@
1
- import { MdContentPaste, MdContentCut, MdContentCopy, MdFormatPaint, } from "react-icons/md";
2
- import React from "react";
3
- import ToolbarButton from "./ToolbarButton";
4
- export default function ClipboardGroup({ editor }) {
5
- return (<div className="clipboard-group">
6
- <ToolbarButton icon={MdContentPaste} title="Paste" onClick={async () => {
7
- try {
8
- const text = await navigator.clipboard.readText();
9
- editor.chain().focus().insertContent(text).run();
10
- }
11
- catch (error) {
12
- console.error("Failed to read clipboard contents:", error);
13
- }
14
- }}/>
15
- <ToolbarButton icon={MdContentCut} title="Cut" onClick={() => {
16
- const { from, to } = editor.state.selection;
17
- if (from === to)
18
- return;
19
- const selectedText = editor.state.doc.textBetween(from, to);
20
- navigator.clipboard.writeText(selectedText).then(() => {
21
- editor.chain().focus().deleteRange({ from, to }).run();
22
- });
23
- }}/>
24
- <ToolbarButton icon={MdContentCopy} title="Copy" onClick={() => {
25
- const { from, to } = editor.state.selection;
26
- if (from === to)
27
- return;
28
- const selectedText = editor.state.doc.textBetween(from, to);
29
- navigator.clipboard.writeText(selectedText);
30
- }}/>
31
- <ToolbarButton icon={MdFormatPaint} title="Format Painter" onClick={() => {
32
- const currentMarks = editor.getAttributes("textStyle");
33
- localStorage.setItem("formatPainter", JSON.stringify(currentMarks));
34
- }}/>
35
- </div>);
36
- }
@@ -1,7 +0,0 @@
1
- import { Editor } from "@tiptap/react";
2
- import React from "react";
3
- type FileGroupProps = {
4
- editor: Editor;
5
- };
6
- export default function FileGroup({ editor }: FileGroupProps): React.JSX.Element;
7
- export {};
@@ -1,40 +0,0 @@
1
- "use client";
2
- import { FaRegFolderOpen } from "react-icons/fa";
3
- import { VscNewFile } from "react-icons/vsc";
4
- import ToolbarButton from "./ToolbarButton";
5
- import React, { useRef } from "react";
6
- export default function FileGroup({ editor }) {
7
- const fileInputRef = useRef(null);
8
- const handleNew = () => {
9
- if (confirm("Are you sure you want to create a new document? Unsaved changes will be lost.")) {
10
- editor.commands.clearContent();
11
- }
12
- };
13
- const handleOpen = () => {
14
- var _a;
15
- (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
16
- };
17
- const handleFileChange = async (e) => {
18
- var _a;
19
- const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
20
- if (!file)
21
- return;
22
- try {
23
- const text = await file.text();
24
- const json = JSON.parse(text);
25
- editor.commands.setContent(json);
26
- }
27
- catch (error) {
28
- console.error("Error reading file:", error);
29
- alert("Failed to open or parse the file. Make sure it's a valid JSON file.");
30
- }
31
- finally {
32
- e.target.value = "";
33
- }
34
- };
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>);
40
- }
@@ -1,7 +0,0 @@
1
- import { Editor } from "@tiptap/react";
2
- import React from "react";
3
- interface FontStyleGroupProps {
4
- editor: Editor;
5
- }
6
- export default function FontStyleGroup({ editor }: FontStyleGroupProps): React.JSX.Element;
7
- export {};