tetrons 2.3.1 → 2.3.21
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/dist/components/components/tetrons/EditorContent.tsx +282 -0
- package/dist/components/components/tetrons/ResizableImageComponent.tsx +77 -0
- package/dist/components/components/tetrons/ResizableVideoComponent.tsx +56 -0
- package/dist/index.d.mts +5 -1
- package/dist/index.d.ts +12 -7
- package/dist/index.js +17254 -21
- package/dist/index.mjs +54 -11
- package/dist/tetrons-UCHWNATC.css +372 -0
- package/package.json +3 -3
- package/dist/app/api/export/route.d.ts +0 -1
- package/dist/app/api/export/route.js +0 -4
- package/dist/app/api/register/route.d.ts +0 -7
- package/dist/app/api/register/route.js +0 -32
- package/dist/app/api/save/route.d.ts +0 -6
- package/dist/app/api/save/route.js +0 -15
- package/dist/app/api/validate/route.d.ts +0 -10
- package/dist/app/api/validate/route.js +0 -58
- package/dist/app/layout.d.ts +0 -6
- package/dist/app/layout.jsx +0 -30
- package/dist/app/page.d.ts +0 -2
- package/dist/app/page.jsx +0 -51
- package/dist/components/UI/Button.jsx +0 -1
- package/dist/components/UI/Dropdown.jsx +0 -1
- package/dist/components/tetrons/EditorContent.d.ts +0 -6
- package/dist/components/tetrons/EditorContent.jsx +0 -209
- package/dist/components/tetrons/ResizableImage.d.ts +0 -1
- package/dist/components/tetrons/ResizableImage.js +0 -40
- package/dist/components/tetrons/ResizableImageComponent.d.ts +0 -11
- package/dist/components/tetrons/ResizableImageComponent.jsx +0 -37
- package/dist/components/tetrons/ResizableVideo.d.ts +0 -12
- package/dist/components/tetrons/ResizableVideo.js +0 -61
- package/dist/components/tetrons/ResizableVideoComponent.d.ts +0 -4
- package/dist/components/tetrons/ResizableVideoComponent.jsx +0 -32
- package/dist/components/tetrons/helpers.d.ts +0 -0
- package/dist/components/tetrons/helpers.js +0 -1
- package/dist/components/tetrons/toolbar/ActionGroup.d.ts +0 -7
- package/dist/components/tetrons/toolbar/ActionGroup.jsx +0 -167
- package/dist/components/tetrons/toolbar/ClipboardGroup.d.ts +0 -5
- package/dist/components/tetrons/toolbar/ClipboardGroup.jsx +0 -36
- package/dist/components/tetrons/toolbar/FileGroup.d.ts +0 -7
- package/dist/components/tetrons/toolbar/FileGroup.jsx +0 -40
- package/dist/components/tetrons/toolbar/FontStyleGroup.d.ts +0 -7
- package/dist/components/tetrons/toolbar/FontStyleGroup.jsx +0 -104
- package/dist/components/tetrons/toolbar/InsertGroup.d.ts +0 -5
- package/dist/components/tetrons/toolbar/InsertGroup.jsx +0 -163
- package/dist/components/tetrons/toolbar/ListAlignGroup.d.ts +0 -5
- package/dist/components/tetrons/toolbar/ListAlignGroup.jsx +0 -16
- package/dist/components/tetrons/toolbar/MiscGroup.d.ts +0 -7
- package/dist/components/tetrons/toolbar/MiscGroup.jsx +0 -31
- package/dist/components/tetrons/toolbar/TableContextMenu.d.ts +0 -7
- package/dist/components/tetrons/toolbar/TableContextMenu.jsx +0 -52
- package/dist/components/tetrons/toolbar/TetronsToolbar.d.ts +0 -6
- package/dist/components/tetrons/toolbar/TetronsToolbar.jsx +0 -46
- package/dist/components/tetrons/toolbar/ToolbarButton.d.ts +0 -12
- package/dist/components/tetrons/toolbar/ToolbarButton.jsx +0 -8
- package/dist/components/tetrons/toolbar/extensions/Comment.d.ts +0 -17
- package/dist/components/tetrons/toolbar/extensions/Comment.js +0 -45
- package/dist/components/tetrons/toolbar/extensions/Embed.d.ts +0 -2
- package/dist/components/tetrons/toolbar/extensions/Embed.js +0 -90
- package/dist/components/tetrons/toolbar/extensions/FontFamily.d.ts +0 -9
- package/dist/components/tetrons/toolbar/extensions/FontFamily.js +0 -28
- package/dist/components/tetrons/toolbar/extensions/FontSize.d.ts +0 -9
- package/dist/components/tetrons/toolbar/extensions/FontSize.js +0 -28
- package/dist/components/tetrons/toolbar/extensions/ResizableTable.d.ts +0 -1
- package/dist/components/tetrons/toolbar/extensions/ResizableTable.js +0 -11
- package/dist/components/tetrons/toolbar/marks/Subscript.d.ts +0 -2
- package/dist/components/tetrons/toolbar/marks/Subscript.js +0 -35
- package/dist/components/tetrons/toolbar/marks/Superscript.d.ts +0 -2
- package/dist/components/tetrons/toolbar/marks/Superscript.js +0 -35
- package/dist/lib/db.d.ts +0 -1
- package/dist/lib/db.js +0 -15
- package/dist/lib/export.d.ts +0 -0
- package/dist/lib/export.js +0 -1
- package/dist/lib/tiptap-extensions.d.ts +0 -0
- package/dist/lib/tiptap-extensions.js +0 -1
- package/dist/models/ApiKey.d.ts +0 -2
- package/dist/models/ApiKey.js +0 -14
- package/dist/utils/apiKeyUtils.d.ts +0 -11
- package/dist/utils/apiKeyUtils.js +0 -33
- package/dist/utils/loadEmojiPicker.d.ts +0 -1
- package/dist/utils/loadEmojiPicker.js +0 -12
- /package/dist/components/{UI/Button.d.ts → components/UI/Button.tsx} +0 -0
- /package/dist/components/{UI/Dropdown.d.ts → components/UI/Dropdown.tsx} +0 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { Comment } from "./toolbar/extensions/Comment";
|
|
5
|
+
import { useEffect, useRef } from "react";
|
|
6
|
+
import {
|
|
7
|
+
useEditor,
|
|
8
|
+
EditorContent as TiptapEditorContent,
|
|
9
|
+
Editor,
|
|
10
|
+
} from "@tiptap/react";
|
|
11
|
+
|
|
12
|
+
import Document from "@tiptap/extension-document";
|
|
13
|
+
import Paragraph from "@tiptap/extension-paragraph";
|
|
14
|
+
import Text from "@tiptap/extension-text";
|
|
15
|
+
import History from "@tiptap/extension-history";
|
|
16
|
+
import Bold from "@tiptap/extension-bold";
|
|
17
|
+
import Italic from "@tiptap/extension-italic";
|
|
18
|
+
import Underline from "@tiptap/extension-underline";
|
|
19
|
+
import Strike from "@tiptap/extension-strike";
|
|
20
|
+
import Code from "@tiptap/extension-code";
|
|
21
|
+
import Blockquote from "@tiptap/extension-blockquote";
|
|
22
|
+
import HardBreak from "@tiptap/extension-hard-break";
|
|
23
|
+
import Heading from "@tiptap/extension-heading";
|
|
24
|
+
import HorizontalRule from "@tiptap/extension-horizontal-rule";
|
|
25
|
+
|
|
26
|
+
import TextAlign from "@tiptap/extension-text-align";
|
|
27
|
+
import Color from "@tiptap/extension-color";
|
|
28
|
+
import Highlight from "@tiptap/extension-highlight";
|
|
29
|
+
import Image from "@tiptap/extension-image";
|
|
30
|
+
import Link from "@tiptap/extension-link";
|
|
31
|
+
import TextStyle from "@tiptap/extension-text-style";
|
|
32
|
+
|
|
33
|
+
import ListItem from "@tiptap/extension-list-item";
|
|
34
|
+
import BulletList from "@tiptap/extension-bullet-list";
|
|
35
|
+
import OrderedList from "@tiptap/extension-ordered-list";
|
|
36
|
+
import { Subscript } from "./toolbar/marks/Subscript";
|
|
37
|
+
import { Superscript } from "./toolbar/marks/Superscript";
|
|
38
|
+
|
|
39
|
+
import { ResizableTable } from "./toolbar/extensions/ResizableTable";
|
|
40
|
+
import { Embed } from "./toolbar/extensions/Embed";
|
|
41
|
+
import TableRow from "@tiptap/extension-table-row";
|
|
42
|
+
import TableCell from "@tiptap/extension-table-cell";
|
|
43
|
+
import TableHeader from "@tiptap/extension-table-header";
|
|
44
|
+
|
|
45
|
+
import { FontFamily } from "./toolbar/extensions/FontFamily";
|
|
46
|
+
import { FontSize } from "./toolbar/extensions/FontSize";
|
|
47
|
+
import TetronsToolbar from "./toolbar/TetronsToolbar";
|
|
48
|
+
|
|
49
|
+
import { ResizableImage } from "./ResizableImage";
|
|
50
|
+
import { ResizableVideo } from "./ResizableVideo";
|
|
51
|
+
import TableContextMenu from "./toolbar/TableContextMenu";
|
|
52
|
+
import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
|
|
53
|
+
import { createLowlight } from "lowlight";
|
|
54
|
+
|
|
55
|
+
import js from "highlight.js/lib/languages/javascript";
|
|
56
|
+
import ts from "highlight.js/lib/languages/typescript";
|
|
57
|
+
|
|
58
|
+
const lowlight = createLowlight();
|
|
59
|
+
|
|
60
|
+
lowlight.register("js", js);
|
|
61
|
+
lowlight.register("ts", ts);
|
|
62
|
+
|
|
63
|
+
type EditorContentProps = {
|
|
64
|
+
apiKey: string;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default function EditorContent({ apiKey }: EditorContentProps) {
|
|
68
|
+
const [isValid, setIsValid] = React.useState<boolean | null>(null);
|
|
69
|
+
const [error, setError] = React.useState<string | null>(null);
|
|
70
|
+
const [versions, setVersions] = React.useState<string[]>([]);
|
|
71
|
+
const [userVersion, setUserVersion] = React.useState<
|
|
72
|
+
"free" | "pro" | "premium" | "platinum" | null
|
|
73
|
+
>(null);
|
|
74
|
+
|
|
75
|
+
const [currentVersionIndex, setCurrentVersionIndex] = React.useState<
|
|
76
|
+
number | null
|
|
77
|
+
>(null);
|
|
78
|
+
|
|
79
|
+
function getApiBaseUrl(): string {
|
|
80
|
+
if (
|
|
81
|
+
typeof import.meta !== "undefined" &&
|
|
82
|
+
import.meta.env?.VITE_TETRONS_API_URL
|
|
83
|
+
) {
|
|
84
|
+
return import.meta.env.VITE_TETRONS_API_URL;
|
|
85
|
+
}
|
|
86
|
+
if (
|
|
87
|
+
typeof process !== "undefined" &&
|
|
88
|
+
process.env?.NEXT_PUBLIC_TETRONS_API_URL
|
|
89
|
+
) {
|
|
90
|
+
return process.env.NEXT_PUBLIC_TETRONS_API_URL;
|
|
91
|
+
}
|
|
92
|
+
return "https://staging.tetrons.com";
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const API_BASE_URL = getApiBaseUrl();
|
|
96
|
+
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
const validateKey = async () => {
|
|
99
|
+
try {
|
|
100
|
+
const res = await fetch(`${API_BASE_URL}/api/validate`, {
|
|
101
|
+
method: "POST",
|
|
102
|
+
headers: {
|
|
103
|
+
"Content-Type": "application/json",
|
|
104
|
+
},
|
|
105
|
+
body: JSON.stringify({ apiKey }),
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const data = await res.json();
|
|
109
|
+
if (!res.ok) throw new Error(data.error || "Invalid API Key");
|
|
110
|
+
|
|
111
|
+
setIsValid(true);
|
|
112
|
+
setUserVersion(data.version);
|
|
113
|
+
} catch (err: unknown) {
|
|
114
|
+
if (err instanceof Error) {
|
|
115
|
+
setError(err.message || "Invalid API Key");
|
|
116
|
+
} else {
|
|
117
|
+
setError("Invalid API Key");
|
|
118
|
+
}
|
|
119
|
+
setIsValid(false);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
validateKey();
|
|
124
|
+
}, [apiKey]);
|
|
125
|
+
|
|
126
|
+
const editor: Editor | null = useEditor({
|
|
127
|
+
extensions: [
|
|
128
|
+
Document,
|
|
129
|
+
Paragraph,
|
|
130
|
+
Text,
|
|
131
|
+
History,
|
|
132
|
+
Bold,
|
|
133
|
+
Italic,
|
|
134
|
+
Underline,
|
|
135
|
+
Strike,
|
|
136
|
+
Code,
|
|
137
|
+
Blockquote,
|
|
138
|
+
HardBreak,
|
|
139
|
+
Heading.configure({ levels: [1, 2, 3, 4, 5, 6] }),
|
|
140
|
+
HorizontalRule,
|
|
141
|
+
|
|
142
|
+
TextStyle,
|
|
143
|
+
Color,
|
|
144
|
+
Highlight.configure({ multicolor: true }),
|
|
145
|
+
FontFamily,
|
|
146
|
+
FontSize,
|
|
147
|
+
TextAlign.configure({ types: ["heading", "paragraph"] }),
|
|
148
|
+
|
|
149
|
+
ListItem,
|
|
150
|
+
BulletList,
|
|
151
|
+
OrderedList,
|
|
152
|
+
Subscript,
|
|
153
|
+
Superscript,
|
|
154
|
+
|
|
155
|
+
Image,
|
|
156
|
+
Link.configure({
|
|
157
|
+
openOnClick: false,
|
|
158
|
+
autolink: true,
|
|
159
|
+
linkOnPaste: true,
|
|
160
|
+
}),
|
|
161
|
+
|
|
162
|
+
ResizableTable.configure({
|
|
163
|
+
resizable: true,
|
|
164
|
+
}),
|
|
165
|
+
TableRow,
|
|
166
|
+
TableCell,
|
|
167
|
+
TableHeader,
|
|
168
|
+
Embed,
|
|
169
|
+
|
|
170
|
+
ResizableImage,
|
|
171
|
+
ResizableVideo,
|
|
172
|
+
Comment,
|
|
173
|
+
CodeBlockLowlight.configure({
|
|
174
|
+
lowlight,
|
|
175
|
+
HTMLAttributes: {
|
|
176
|
+
class: "bg-gray-100 p-2 rounded font-mono text-sm overflow-auto",
|
|
177
|
+
},
|
|
178
|
+
}),
|
|
179
|
+
],
|
|
180
|
+
content: "",
|
|
181
|
+
editorProps: {
|
|
182
|
+
attributes: {
|
|
183
|
+
class: "min-h-full focus:outline-none p-0",
|
|
184
|
+
"data-placeholder": "Start typing here...",
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
immediatelyRender: false,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
191
|
+
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
return () => {
|
|
194
|
+
editor?.destroy();
|
|
195
|
+
};
|
|
196
|
+
}, [editor]);
|
|
197
|
+
|
|
198
|
+
const handleEditorClick = () => {
|
|
199
|
+
if (editor && !editor.isFocused) {
|
|
200
|
+
editor.commands.focus();
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const saveVersion = () => {
|
|
205
|
+
if (!editor) return;
|
|
206
|
+
const content = editor.getJSON();
|
|
207
|
+
setVersions((prev) => [...prev, JSON.stringify(content)]);
|
|
208
|
+
setCurrentVersionIndex(versions.length);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const restoreVersion = (index: number) => {
|
|
212
|
+
if (!editor) return;
|
|
213
|
+
const versionContent = versions[index];
|
|
214
|
+
if (versionContent) {
|
|
215
|
+
editor.commands.setContent(JSON.parse(versionContent));
|
|
216
|
+
setCurrentVersionIndex(index);
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
if (isValid === false) {
|
|
221
|
+
return <div className="editor-error">⚠️ {error}</div>;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (isValid === null) {
|
|
225
|
+
return <div className="editor-loading">🔍 Validating license...</div>;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
<div className="editor-container">
|
|
230
|
+
{userVersion !== "free" && (
|
|
231
|
+
<div className="editor-toolbar">
|
|
232
|
+
<button
|
|
233
|
+
type="button"
|
|
234
|
+
onClick={saveVersion}
|
|
235
|
+
disabled={!editor}
|
|
236
|
+
className="editor-save-btn"
|
|
237
|
+
>
|
|
238
|
+
Save Version
|
|
239
|
+
</button>
|
|
240
|
+
|
|
241
|
+
<div className="editor-versions-wrapper">
|
|
242
|
+
{versions.length === 0 && (
|
|
243
|
+
<span className="editor-no-versions">No saved versions</span>
|
|
244
|
+
)}
|
|
245
|
+
{versions.map((_, idx) => (
|
|
246
|
+
<button
|
|
247
|
+
type="button"
|
|
248
|
+
key={idx}
|
|
249
|
+
onClick={() => restoreVersion(idx)}
|
|
250
|
+
className={`editor-version-btn ${
|
|
251
|
+
idx === currentVersionIndex ? "active" : ""
|
|
252
|
+
}`}
|
|
253
|
+
title={`Restore Version ${idx + 1}`}
|
|
254
|
+
>
|
|
255
|
+
{`V${idx + 1}`}
|
|
256
|
+
</button>
|
|
257
|
+
))}
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
)}
|
|
261
|
+
|
|
262
|
+
{editor && userVersion && (
|
|
263
|
+
<TetronsToolbar editor={editor} version={userVersion} />
|
|
264
|
+
)}
|
|
265
|
+
|
|
266
|
+
<div
|
|
267
|
+
ref={wrapperRef}
|
|
268
|
+
className="editor-content-wrapper"
|
|
269
|
+
onClick={handleEditorClick}
|
|
270
|
+
>
|
|
271
|
+
{editor ? (
|
|
272
|
+
<>
|
|
273
|
+
<TiptapEditorContent editor={editor} />
|
|
274
|
+
{editor && <TableContextMenu editor={editor} />}
|
|
275
|
+
</>
|
|
276
|
+
) : (
|
|
277
|
+
<div className="editor-loading">Loading editor...</div>
|
|
278
|
+
)}
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import React, { useRef, useEffect } from "react";
|
|
2
|
+
import { NodeViewWrapper, NodeViewRendererProps } from "@tiptap/react";
|
|
3
|
+
|
|
4
|
+
interface ResizableImageProps extends NodeViewRendererProps {
|
|
5
|
+
updateAttributes: (attrs: {
|
|
6
|
+
width?: number | null;
|
|
7
|
+
height?: number | null;
|
|
8
|
+
}) => void;
|
|
9
|
+
selected?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const ResizableImageComponent: React.FC<ResizableImageProps> = ({
|
|
13
|
+
node,
|
|
14
|
+
updateAttributes,
|
|
15
|
+
selected,
|
|
16
|
+
}) => {
|
|
17
|
+
const { src, alt, title, width, height } = node.attrs as {
|
|
18
|
+
src: string;
|
|
19
|
+
alt?: string;
|
|
20
|
+
title?: string;
|
|
21
|
+
width?: number | null;
|
|
22
|
+
height?: number | null;
|
|
23
|
+
};
|
|
24
|
+
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
25
|
+
const imgRef = useRef<HTMLImageElement>(null);
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
const img = imgRef.current;
|
|
29
|
+
if (!img) return;
|
|
30
|
+
|
|
31
|
+
const observer = new ResizeObserver(() => {
|
|
32
|
+
const w = Math.round(img.offsetWidth);
|
|
33
|
+
const h = Math.round(img.offsetHeight);
|
|
34
|
+
updateAttributes({ width: w, height: h });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
observer.observe(img);
|
|
38
|
+
return () => observer.disconnect();
|
|
39
|
+
}, [updateAttributes]);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<NodeViewWrapper
|
|
43
|
+
ref={wrapperRef}
|
|
44
|
+
contentEditable={false}
|
|
45
|
+
className={`resizable-image-wrapper ${
|
|
46
|
+
selected ? "ProseMirror-selectednode" : ""
|
|
47
|
+
}`}
|
|
48
|
+
style={{
|
|
49
|
+
resize: "both",
|
|
50
|
+
overflow: "auto",
|
|
51
|
+
border: "1px solid #ccc",
|
|
52
|
+
padding: 2,
|
|
53
|
+
display: "inline-block",
|
|
54
|
+
maxWidth: "100%",
|
|
55
|
+
}}
|
|
56
|
+
>
|
|
57
|
+
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
58
|
+
<img
|
|
59
|
+
ref={imgRef}
|
|
60
|
+
src={src}
|
|
61
|
+
alt={alt ?? ""}
|
|
62
|
+
title={title ?? ""}
|
|
63
|
+
loading="lazy"
|
|
64
|
+
style={{
|
|
65
|
+
width: width ? `${width}px` : "auto",
|
|
66
|
+
height: height ? `${height}px` : "auto",
|
|
67
|
+
display: "block",
|
|
68
|
+
userSelect: "none",
|
|
69
|
+
pointerEvents: "auto",
|
|
70
|
+
}}
|
|
71
|
+
draggable={false}
|
|
72
|
+
/>
|
|
73
|
+
</NodeViewWrapper>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export default ResizableImageComponent;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React, { useRef, useEffect } from "react";
|
|
2
|
+
import { NodeViewWrapper } from "@tiptap/react";
|
|
3
|
+
import type { NodeViewProps } from "@tiptap/core";
|
|
4
|
+
|
|
5
|
+
const ResizableVideoComponent: React.FC<NodeViewProps> = ({
|
|
6
|
+
node,
|
|
7
|
+
updateAttributes,
|
|
8
|
+
selected,
|
|
9
|
+
}) => {
|
|
10
|
+
const { src, controls, width, height } = node.attrs;
|
|
11
|
+
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
12
|
+
const videoRef = useRef<HTMLVideoElement>(null);
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
const video = videoRef.current;
|
|
16
|
+
if (!video) return;
|
|
17
|
+
|
|
18
|
+
const observer = new ResizeObserver(() => {
|
|
19
|
+
const w = Math.round(video.offsetWidth);
|
|
20
|
+
const h = Math.round(video.offsetHeight);
|
|
21
|
+
updateAttributes({ width: w, height: h });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
observer.observe(video);
|
|
25
|
+
return () => observer.disconnect();
|
|
26
|
+
}, [updateAttributes]);
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<NodeViewWrapper
|
|
30
|
+
ref={wrapperRef}
|
|
31
|
+
contentEditable={false}
|
|
32
|
+
className={`resizable-video-wrapper ${
|
|
33
|
+
selected ? "ProseMirror-selectednode" : ""
|
|
34
|
+
}`}
|
|
35
|
+
style={{
|
|
36
|
+
resize: "both",
|
|
37
|
+
overflow: "auto",
|
|
38
|
+
border: "1px solid #ccc",
|
|
39
|
+
padding: "2px",
|
|
40
|
+
display: "inline-block",
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
<video
|
|
44
|
+
ref={videoRef}
|
|
45
|
+
src={src}
|
|
46
|
+
controls={controls}
|
|
47
|
+
style={{
|
|
48
|
+
width: width ? `${width}px` : "auto",
|
|
49
|
+
height: height ? `${height}px` : "auto",
|
|
50
|
+
}}
|
|
51
|
+
/>
|
|
52
|
+
</NodeViewWrapper>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default ResizableVideoComponent;
|
package/dist/index.d.mts
CHANGED
|
@@ -5,4 +5,8 @@ type EditorContentProps = {
|
|
|
5
5
|
};
|
|
6
6
|
declare function EditorContent({ apiKey }: EditorContentProps): React.JSX.Element;
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
declare function initializeTetrons(apiKey: string): Promise<void>;
|
|
9
|
+
declare function getTetronsVersion(): "" | "free" | "pro" | "premium" | "platinum";
|
|
10
|
+
declare function isApiKeyValid(): boolean;
|
|
11
|
+
|
|
12
|
+
export { EditorContent, EditorContent as default, getTetronsVersion, initializeTetrons, isApiKeyValid };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
type EditorContentProps = {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
};
|
|
6
|
+
declare function EditorContent({ apiKey }: EditorContentProps): React.JSX.Element;
|
|
7
|
+
|
|
8
|
+
declare function initializeTetrons(apiKey: string): Promise<void>;
|
|
9
|
+
declare function getTetronsVersion(): "" | "free" | "pro" | "premium" | "platinum";
|
|
10
|
+
declare function isApiKeyValid(): boolean;
|
|
11
|
+
|
|
12
|
+
export { EditorContent, EditorContent as default, getTetronsVersion, initializeTetrons, isApiKeyValid };
|