tetrons 2.2.4 → 2.2.6

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 (81) hide show
  1. package/dist/app/api/export/{route.js → route.ts} +2 -2
  2. package/dist/app/api/register/route.ts +36 -0
  3. package/dist/app/api/save/route.ts +18 -0
  4. package/dist/app/api/validate/route.ts +26 -0
  5. package/dist/index.d.ts +8 -3
  6. package/dist/index.js +17214 -4
  7. package/package.json +3 -4
  8. package/dist/app/api/export/route.d.ts +0 -1
  9. package/dist/app/api/register/route.d.ts +0 -6
  10. package/dist/app/api/register/route.js +0 -26
  11. package/dist/app/api/save/route.d.ts +0 -6
  12. package/dist/app/api/save/route.js +0 -15
  13. package/dist/app/api/validate/route.d.ts +0 -7
  14. package/dist/app/api/validate/route.js +0 -18
  15. package/dist/app/layout.d.ts +0 -6
  16. package/dist/app/layout.jsx +0 -30
  17. package/dist/app/page.d.ts +0 -2
  18. package/dist/app/page.jsx +0 -55
  19. package/dist/components/UI/Button.d.ts +0 -0
  20. package/dist/components/UI/Button.jsx +0 -1
  21. package/dist/components/UI/Dropdown.d.ts +0 -0
  22. package/dist/components/UI/Dropdown.jsx +0 -1
  23. package/dist/components/tetrons/EditorContent.d.ts +0 -6
  24. package/dist/components/tetrons/EditorContent.jsx +0 -193
  25. package/dist/components/tetrons/ResizableImage.d.ts +0 -1
  26. package/dist/components/tetrons/ResizableImage.js +0 -40
  27. package/dist/components/tetrons/ResizableImageComponent.d.ts +0 -11
  28. package/dist/components/tetrons/ResizableImageComponent.jsx +0 -37
  29. package/dist/components/tetrons/ResizableVideo.d.ts +0 -12
  30. package/dist/components/tetrons/ResizableVideo.js +0 -61
  31. package/dist/components/tetrons/ResizableVideoComponent.d.ts +0 -4
  32. package/dist/components/tetrons/ResizableVideoComponent.jsx +0 -32
  33. package/dist/components/tetrons/helpers.d.ts +0 -0
  34. package/dist/components/tetrons/helpers.js +0 -1
  35. package/dist/components/tetrons/toolbar/ActionGroup.d.ts +0 -7
  36. package/dist/components/tetrons/toolbar/ActionGroup.jsx +0 -167
  37. package/dist/components/tetrons/toolbar/ClipboardGroup.d.ts +0 -5
  38. package/dist/components/tetrons/toolbar/ClipboardGroup.jsx +0 -36
  39. package/dist/components/tetrons/toolbar/FileGroup.d.ts +0 -7
  40. package/dist/components/tetrons/toolbar/FileGroup.jsx +0 -40
  41. package/dist/components/tetrons/toolbar/FontStyleGroup.d.ts +0 -7
  42. package/dist/components/tetrons/toolbar/FontStyleGroup.jsx +0 -104
  43. package/dist/components/tetrons/toolbar/InsertGroup.d.ts +0 -5
  44. package/dist/components/tetrons/toolbar/InsertGroup.jsx +0 -163
  45. package/dist/components/tetrons/toolbar/ListAlignGroup.d.ts +0 -5
  46. package/dist/components/tetrons/toolbar/ListAlignGroup.jsx +0 -16
  47. package/dist/components/tetrons/toolbar/MiscGroup.d.ts +0 -7
  48. package/dist/components/tetrons/toolbar/MiscGroup.jsx +0 -31
  49. package/dist/components/tetrons/toolbar/TableContextMenu.d.ts +0 -7
  50. package/dist/components/tetrons/toolbar/TableContextMenu.jsx +0 -52
  51. package/dist/components/tetrons/toolbar/TetronsToolbar.d.ts +0 -5
  52. package/dist/components/tetrons/toolbar/TetronsToolbar.jsx +0 -44
  53. package/dist/components/tetrons/toolbar/ToolbarButton.d.ts +0 -12
  54. package/dist/components/tetrons/toolbar/ToolbarButton.jsx +0 -8
  55. package/dist/components/tetrons/toolbar/extensions/Comment.d.ts +0 -17
  56. package/dist/components/tetrons/toolbar/extensions/Comment.js +0 -45
  57. package/dist/components/tetrons/toolbar/extensions/Embed.d.ts +0 -2
  58. package/dist/components/tetrons/toolbar/extensions/Embed.js +0 -90
  59. package/dist/components/tetrons/toolbar/extensions/FontFamily.d.ts +0 -9
  60. package/dist/components/tetrons/toolbar/extensions/FontFamily.js +0 -28
  61. package/dist/components/tetrons/toolbar/extensions/FontSize.d.ts +0 -9
  62. package/dist/components/tetrons/toolbar/extensions/FontSize.js +0 -28
  63. package/dist/components/tetrons/toolbar/extensions/ResizableTable.d.ts +0 -1
  64. package/dist/components/tetrons/toolbar/extensions/ResizableTable.js +0 -11
  65. package/dist/components/tetrons/toolbar/marks/Subscript.d.ts +0 -2
  66. package/dist/components/tetrons/toolbar/marks/Subscript.js +0 -35
  67. package/dist/components/tetrons/toolbar/marks/Superscript.d.ts +0 -2
  68. package/dist/components/tetrons/toolbar/marks/Superscript.js +0 -35
  69. package/dist/lib/db.d.ts +0 -1
  70. package/dist/lib/db.js +0 -15
  71. package/dist/lib/export.d.ts +0 -0
  72. package/dist/lib/export.js +0 -1
  73. package/dist/lib/tiptap-extensions.d.ts +0 -0
  74. package/dist/lib/tiptap-extensions.js +0 -1
  75. package/dist/models/ApiKey.d.ts +0 -2
  76. package/dist/models/ApiKey.js +0 -14
  77. package/dist/styles/styles/tetrons.css +0 -371
  78. package/dist/utils/apiKeyUtils.d.ts +0 -11
  79. package/dist/utils/apiKeyUtils.js +0 -17
  80. package/dist/utils/loadEmojiPicker.d.ts +0 -1
  81. package/dist/utils/loadEmojiPicker.js +0 -12
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "tetrons",
3
- "version": "2.2.4",
3
+ "version": "2.2.6",
4
4
  "description": "A Next.js project written in TypeScript",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {
8
8
  "dev": "next dev --turbo",
9
- "build": "tsup src/index.ts --format esm,cjs --dts --out-dir dist && copyfiles -u 1 src/styles/*.css dist/styles",
9
+ "build": "tsup src/index.ts --format esm,cjs --dts --out-dir dist && copyfiles -u 2 src/styles/*.css dist/styles && copyfiles -u 3 src/app/api/**/*.ts dist/app/api",
10
10
  "start": "next start",
11
11
  "lint": "next lint"
12
12
  },
@@ -65,8 +65,7 @@
65
65
  "exports": {
66
66
  ".": {
67
67
  "import": "./dist/index.js",
68
- "require": "./dist/index.js",
69
- "types": "./dist/index.d.ts"
68
+ "require": "./dist/index.js"
70
69
  },
71
70
  "./style.css": "./dist/styles/tetrons.css"
72
71
  },
@@ -1 +0,0 @@
1
- export declare function GET(req: Request): Response;
@@ -1,6 +0,0 @@
1
- import { NextRequest, NextResponse } from "next/server";
2
- export declare function POST(req: NextRequest): Promise<NextResponse<{
3
- error: string;
4
- }> | NextResponse<{
5
- apiKey: string;
6
- }>>;
@@ -1,26 +0,0 @@
1
- import { NextResponse } from "next/server";
2
- import { connectDB } from "../../../lib/db";
3
- import { ApiKey } from "../../../models/ApiKey";
4
- import { generateApiKey } from "../../../utils/apiKeyUtils";
5
- export async function POST(req) {
6
- const { email, organization, version } = await req.json();
7
- if (!email || !organization || !version)
8
- return NextResponse.json({ error: "Missing fields" }, { status: 400 });
9
- await connectDB();
10
- if (version === "free") {
11
- const expiresAt = new Date(Date.now() + 14 * 24 * 60 * 60 * 1000);
12
- const apiKey = generateApiKey(48);
13
- await ApiKey.deleteMany({ email, version });
14
- await ApiKey.create({
15
- email,
16
- organization,
17
- version,
18
- apiKey,
19
- expiresAt,
20
- });
21
- return NextResponse.json({ apiKey, expiresAt });
22
- }
23
- const apiKey = generateApiKey(48);
24
- await ApiKey.create({ email, organization, version, apiKey });
25
- return NextResponse.json({ apiKey });
26
- }
@@ -1,6 +0,0 @@
1
- import { NextRequest, NextResponse } from "next/server";
2
- export declare function POST(request: NextRequest): Promise<NextResponse<{
3
- message: string;
4
- }> | NextResponse<{
5
- error: string;
6
- }>>;
@@ -1,15 +0,0 @@
1
- import { NextResponse } from "next/server";
2
- import path from "path";
3
- import fs from "fs/promises";
4
- export async function POST(request) {
5
- try {
6
- const json = await request.json();
7
- const publicDir = path.join(process.cwd(), "public");
8
- const filePath = path.join(publicDir, "editor-content.json");
9
- await fs.writeFile(filePath, JSON.stringify(json, null, 2), "utf-8");
10
- return NextResponse.json({ message: "File saved successfully" });
11
- }
12
- catch (_a) {
13
- return NextResponse.json({ error: "Failed to save file" }, { status: 500 });
14
- }
15
- }
@@ -1,7 +0,0 @@
1
- import { NextRequest, NextResponse } from "next/server";
2
- export declare function POST(req: NextRequest): Promise<NextResponse<{
3
- error: string;
4
- }> | NextResponse<{
5
- valid: boolean;
6
- version: any;
7
- }>>;
@@ -1,18 +0,0 @@
1
- import { NextResponse } from "next/server";
2
- import { connectDB } from "../../../lib/db";
3
- import { ApiKey } from "../../../models/ApiKey";
4
- export async function POST(req) {
5
- const { apiKey } = await req.json();
6
- if (!apiKey)
7
- return NextResponse.json({ error: "API key required" }, { status: 400 });
8
- await connectDB();
9
- const keyEntry = await ApiKey.findOne({ apiKey });
10
- if (!keyEntry)
11
- return NextResponse.json({ error: "Invalid key" }, { status: 401 });
12
- if (keyEntry.version === "free" &&
13
- keyEntry.expiresAt &&
14
- new Date() > new Date(keyEntry.expiresAt)) {
15
- return NextResponse.json({ error: "Free trial expired" }, { status: 403 });
16
- }
17
- return NextResponse.json({ valid: true, version: keyEntry.version });
18
- }
@@ -1,6 +0,0 @@
1
- import type { Metadata } from "next";
2
- import "./globals.css";
3
- export declare const metadata: Metadata;
4
- export default function RootLayout({ children, }: {
5
- children: React.ReactNode;
6
- }): import("react").JSX.Element;
@@ -1,30 +0,0 @@
1
- import { Geist, Geist_Mono } from "next/font/google";
2
- import "./globals.css";
3
- const geistSans = Geist({
4
- variable: "--font-geist-sans",
5
- subsets: ["latin"],
6
- });
7
- const geistMono = Geist_Mono({
8
- variable: "--font-geist-mono",
9
- subsets: ["latin"],
10
- });
11
- export const metadata = {
12
- title: "Tetrons",
13
- description: "A modern Word-style rich text editor built with Next.js",
14
- icons: {
15
- icon: [
16
- { url: "/favicon.ico", type: "image/x-icon" },
17
- { url: "/favicon-32x32.png", type: "image/png", sizes: "32x32" },
18
- { url: "/favicon-16x16.png", type: "image/png", sizes: "16x16" },
19
- ],
20
- apple: "/apple-touch-icon.png",
21
- },
22
- manifest: "/site.webmanifest",
23
- };
24
- 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>);
30
- }
@@ -1,2 +0,0 @@
1
- import "../styles/tetrons.css";
2
- export default function Home(): import("react").JSX.Element;
package/dist/app/page.jsx DELETED
@@ -1,55 +0,0 @@
1
- "use client";
2
- import { useEffect, useState } from "react";
3
- import EditorContent from "../components/tetrons/EditorContent";
4
- import "../styles/tetrons.css";
5
- export default function Home() {
6
- const [apiKey, setApiKey] = useState(null);
7
- const [loading, setLoading] = useState(true);
8
- useEffect(() => {
9
- const fetchApiKey = async () => {
10
- try {
11
- const cachedKey = localStorage.getItem("my-api-key");
12
- if (cachedKey) {
13
- setApiKey(cachedKey);
14
- setLoading(false);
15
- return;
16
- }
17
- const res = await fetch("/api/register", {
18
- method: "POST",
19
- headers: {
20
- "Content-Type": "application/json",
21
- },
22
- body: JSON.stringify({
23
- email: "mr.swastikjha@gmail.com",
24
- organization: "FCSPL",
25
- version: "free",
26
- }),
27
- });
28
- const data = await res.json();
29
- if (!res.ok || !data.apiKey) {
30
- throw new Error(data.error || "Failed to fetch API key");
31
- }
32
- localStorage.setItem("my-api-key", data.apiKey);
33
- setApiKey(data.apiKey);
34
- }
35
- catch (error) {
36
- console.error("Error fetching API key:", error);
37
- }
38
- finally {
39
- setLoading(false);
40
- }
41
- };
42
- fetchApiKey();
43
- }, []);
44
- if (loading) {
45
- return <div className="text-center p-4">⏳ Loading Editor...</div>;
46
- }
47
- if (!apiKey) {
48
- return (<div className="text-center text-red-600">❌ Failed to load API key</div>);
49
- }
50
- return (<main className="flex flex-col h-screen overflow-hidden">
51
- <div className="flex-1 overflow-auto flex flex-col">
52
- <EditorContent apiKey={apiKey}/>
53
- </div>
54
- </main>);
55
- }
File without changes
@@ -1 +0,0 @@
1
- "use strict";
File without changes
@@ -1 +0,0 @@
1
- "use strict";
@@ -1,6 +0,0 @@
1
- import React from "react";
2
- type EditorContentProps = {
3
- apiKey: string;
4
- };
5
- export default function EditorContent({ apiKey }: EditorContentProps): React.JSX.Element;
6
- export {};
@@ -1,193 +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 [currentVersionIndex, setCurrentVersionIndex] = React.useState(null);
53
- useEffect(() => {
54
- const validateKey = async () => {
55
- try {
56
- const res = await fetch("/api/validate", {
57
- method: "POST",
58
- headers: {
59
- "Content-Type": "application/json",
60
- },
61
- body: JSON.stringify({ apiKey }),
62
- });
63
- const data = await res.json();
64
- if (!res.ok)
65
- throw new Error(data.error || "Invalid API Key");
66
- setIsValid(true);
67
- }
68
- catch (err) {
69
- if (err instanceof Error) {
70
- setError(err.message || "Invalid API Key");
71
- }
72
- else {
73
- setError("Invalid API Key");
74
- }
75
- setIsValid(false);
76
- }
77
- };
78
- validateKey();
79
- }, [apiKey]);
80
- const editor = useEditor({
81
- extensions: [
82
- Document,
83
- Paragraph,
84
- Text,
85
- History,
86
- Bold,
87
- Italic,
88
- Underline,
89
- Strike,
90
- Code,
91
- Blockquote,
92
- HardBreak,
93
- Heading.configure({ levels: [1, 2, 3, 4, 5, 6] }),
94
- HorizontalRule,
95
- TextStyle,
96
- Color,
97
- Highlight.configure({ multicolor: true }),
98
- FontFamily,
99
- FontSize,
100
- TextAlign.configure({ types: ["heading", "paragraph"] }),
101
- ListItem,
102
- BulletList,
103
- OrderedList,
104
- Subscript,
105
- Superscript,
106
- Image,
107
- Link.configure({
108
- openOnClick: false,
109
- autolink: true,
110
- linkOnPaste: true,
111
- }),
112
- ResizableTable.configure({
113
- resizable: true,
114
- }),
115
- TableRow,
116
- TableCell,
117
- TableHeader,
118
- Embed,
119
- ResizableImage,
120
- ResizableVideo,
121
- Comment,
122
- CodeBlockLowlight.configure({
123
- lowlight,
124
- HTMLAttributes: {
125
- class: "bg-gray-100 p-2 rounded font-mono text-sm overflow-auto",
126
- },
127
- }),
128
- ],
129
- content: "",
130
- editorProps: {
131
- attributes: {
132
- class: "min-h-full focus:outline-none p-0",
133
- "data-placeholder": "Start typing here...",
134
- },
135
- },
136
- immediatelyRender: false,
137
- });
138
- const wrapperRef = useRef(null);
139
- useEffect(() => {
140
- return () => {
141
- editor === null || editor === void 0 ? void 0 : editor.destroy();
142
- };
143
- }, [editor]);
144
- const handleEditorClick = () => {
145
- if (editor && !editor.isFocused) {
146
- editor.commands.focus();
147
- }
148
- };
149
- const saveVersion = () => {
150
- if (!editor)
151
- return;
152
- const content = editor.getJSON();
153
- setVersions((prev) => [...prev, JSON.stringify(content)]);
154
- setCurrentVersionIndex(versions.length);
155
- };
156
- const restoreVersion = (index) => {
157
- if (!editor)
158
- return;
159
- const versionContent = versions[index];
160
- if (versionContent) {
161
- editor.commands.setContent(JSON.parse(versionContent));
162
- setCurrentVersionIndex(index);
163
- }
164
- };
165
- if (isValid === false) {
166
- return <div className="editor-error">⚠️ {error}</div>;
167
- }
168
- if (isValid === null) {
169
- return <div className="editor-loading">🔍 Validating license...</div>;
170
- }
171
- return (<div className="editor-container">
172
- <div className="editor-toolbar">
173
- <button type="button" onClick={saveVersion} disabled={!editor} className="editor-save-btn">
174
- Save Version
175
- </button>
176
-
177
- <div className="editor-versions-wrapper">
178
- {versions.length === 0 && (<span className="editor-no-versions">No saved versions</span>)}
179
- {versions.map((_, idx) => (<button type="button" key={idx} onClick={() => restoreVersion(idx)} className={`editor-version-btn ${idx === currentVersionIndex ? "active" : ""}`} title={`Restore Version ${idx + 1}`}>
180
- {`V${idx + 1}`}
181
- </button>))}
182
- </div>
183
- </div>
184
-
185
- {editor && <TetronsToolbar editor={editor}/>}
186
- <div ref={wrapperRef} className="editor-content-wrapper" onClick={handleEditorClick}>
187
- {editor ? (<>
188
- <TiptapEditorContent editor={editor}/>
189
- {editor && <TableContextMenu editor={editor}/>}
190
- </>) : (<div className="editor-loading">Loading editor...</div>)}
191
- </div>
192
- </div>);
193
- }
@@ -1 +0,0 @@
1
- export declare const ResizableImage: import("@tiptap/react").Node<import("@tiptap/extension-image").ImageOptions, any>;
@@ -1,40 +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 Image from "@tiptap/extension-image";
13
- import { ReactNodeViewRenderer } from "@tiptap/react";
14
- import ResizableImageComponent from "./ResizableImageComponent";
15
- export const ResizableImage = Image.extend({
16
- name: "resizableImage",
17
- addAttributes() {
18
- var _a;
19
- return Object.assign(Object.assign({}, (_a = this.parent) === null || _a === void 0 ? void 0 : _a.call(this)), { width: {
20
- default: null,
21
- }, height: {
22
- default: null,
23
- } });
24
- },
25
- renderHTML({ HTMLAttributes }) {
26
- const { width, height } = HTMLAttributes, rest = __rest(HTMLAttributes, ["width", "height"]);
27
- const style = [];
28
- if (width)
29
- style.push(`width: ${width}px`);
30
- if (height)
31
- style.push(`height: ${height}px`);
32
- return [
33
- "img",
34
- Object.assign(Object.assign({}, rest), { style: style.join("; ") }),
35
- ];
36
- },
37
- addNodeView() {
38
- return ReactNodeViewRenderer(ResizableImageComponent);
39
- },
40
- });
@@ -1,11 +0,0 @@
1
- import React from "react";
2
- import { NodeViewRendererProps } from "@tiptap/react";
3
- interface ResizableImageProps extends NodeViewRendererProps {
4
- updateAttributes: (attrs: {
5
- width?: number | null;
6
- height?: number | null;
7
- }) => void;
8
- selected?: boolean;
9
- }
10
- declare const ResizableImageComponent: React.FC<ResizableImageProps>;
11
- export default ResizableImageComponent;
@@ -1,37 +0,0 @@
1
- import React, { useRef, useEffect } from "react";
2
- import { NodeViewWrapper } from "@tiptap/react";
3
- const ResizableImageComponent = ({ node, updateAttributes, selected, }) => {
4
- const { src, alt, title, width, height } = node.attrs;
5
- const wrapperRef = useRef(null);
6
- const imgRef = useRef(null);
7
- useEffect(() => {
8
- const img = imgRef.current;
9
- if (!img)
10
- return;
11
- const observer = new ResizeObserver(() => {
12
- const w = Math.round(img.offsetWidth);
13
- const h = Math.round(img.offsetHeight);
14
- updateAttributes({ width: w, height: h });
15
- });
16
- observer.observe(img);
17
- return () => observer.disconnect();
18
- }, [updateAttributes]);
19
- return (<NodeViewWrapper ref={wrapperRef} contentEditable={false} className={`resizable-image-wrapper ${selected ? "ProseMirror-selectednode" : ""}`} style={{
20
- resize: "both",
21
- overflow: "auto",
22
- border: "1px solid #ccc",
23
- padding: 2,
24
- display: "inline-block",
25
- 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>);
36
- };
37
- export default ResizableImageComponent;
@@ -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 {};