smartrte-react 0.1.2
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/QuillEditor.d.ts +8 -0
- package/dist/QuillEditor.js +34 -0
- package/dist/app.d.ts +6 -0
- package/dist/app.js +6 -0
- package/dist/blots/CommentBlot.d.ts +8 -0
- package/dist/blots/CommentBlot.js +17 -0
- package/dist/blots/FormulaBlot.d.ts +12 -0
- package/dist/blots/FormulaBlot.js +36 -0
- package/dist/blots/MediaBlot.d.ts +11 -0
- package/dist/blots/MediaBlot.js +37 -0
- package/dist/blots/TableBlot.d.ts +10 -0
- package/dist/blots/TableBlot.js +54 -0
- package/dist/blots/index.d.ts +5 -0
- package/dist/blots/index.js +12 -0
- package/dist/components/ClassicEditor.d.ts +10 -0
- package/dist/components/ClassicEditor.js +1066 -0
- package/dist/components/DiagramEditor.d.ts +5 -0
- package/dist/components/DiagramEditor.js +73 -0
- package/dist/components/FormulaEditor.d.ts +6 -0
- package/dist/components/FormulaEditor.js +86 -0
- package/dist/components/InfoBox.d.ts +7 -0
- package/dist/components/InfoBox.js +18 -0
- package/dist/components/MCQBlock.d.ts +13 -0
- package/dist/components/MCQBlock.js +29 -0
- package/dist/components/SmartEditor.d.ts +0 -0
- package/dist/components/SmartEditor.js +1 -0
- package/dist/components/SmartTable.d.ts +22 -0
- package/dist/components/SmartTable.js +629 -0
- package/dist/components/TableContextMenu.d.ts +11 -0
- package/dist/components/TableContextMenu.js +15 -0
- package/dist/components/TableInsertDialog.d.ts +7 -0
- package/dist/components/TableInsertDialog.js +42 -0
- package/dist/hooks/useEditorSync.d.ts +5 -0
- package/dist/hooks/useEditorSync.js +53 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/smart-editor.d.ts +0 -0
- package/dist/smart-editor.js +1 -0
- package/dist/standalone/classic-editor-embed.d.ts +12 -0
- package/dist/standalone/classic-editor-embed.js +108 -0
- package/dist/standalone/editor.js +241 -0
- package/package.json +46 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import "quill/dist/quill.snow.css";
|
|
2
|
+
import "./blots";
|
|
3
|
+
type QuillEditorProps = {
|
|
4
|
+
value?: any;
|
|
5
|
+
onChange?: (delta: any) => void;
|
|
6
|
+
};
|
|
7
|
+
export declare function QuillEditor({ value, onChange }: QuillEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
import Quill from "quill";
|
|
4
|
+
import "quill/dist/quill.snow.css";
|
|
5
|
+
import "./blots"; // registers custom blots
|
|
6
|
+
export function QuillEditor({ value, onChange }) {
|
|
7
|
+
const ref = useRef(null);
|
|
8
|
+
const quillRef = useRef();
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (!ref.current)
|
|
11
|
+
return;
|
|
12
|
+
if (quillRef.current)
|
|
13
|
+
return;
|
|
14
|
+
quillRef.current = new Quill(ref.current, {
|
|
15
|
+
theme: "snow",
|
|
16
|
+
modules: {
|
|
17
|
+
toolbar: [
|
|
18
|
+
["bold", "italic", "underline"],
|
|
19
|
+
[{ header: [1, 2, 3, false] }],
|
|
20
|
+
["formula", "image"],
|
|
21
|
+
["clean"],
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
quillRef.current.on("text-change", () => {
|
|
26
|
+
const delta = quillRef.current?.getContents();
|
|
27
|
+
onChange?.(delta);
|
|
28
|
+
});
|
|
29
|
+
if (value) {
|
|
30
|
+
quillRef.current.setContents(value);
|
|
31
|
+
}
|
|
32
|
+
}, [value, onChange]);
|
|
33
|
+
return _jsx("div", { ref: ref, style: { minHeight: 300 } });
|
|
34
|
+
}
|
package/dist/app.d.ts
ADDED
package/dist/app.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { QuillEditor } from "./QuillEditor";
|
|
3
|
+
export default function App() {
|
|
4
|
+
const [delta, setDelta] = useState(null);
|
|
5
|
+
return React.createElement("div", { style: { padding: 20 } }, React.createElement("h1", null, "Smart RTE – Quill Demo"), React.createElement(QuillEditor, { value: delta, onChange: setDelta }), React.createElement("pre", null, JSON.stringify(delta, null, 2)));
|
|
6
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import Quill from "quill";
|
|
2
|
+
const Inline = Quill.import("blots/inline");
|
|
3
|
+
export class CommentBlot extends Inline {
|
|
4
|
+
static create(value) {
|
|
5
|
+
const node = super.create();
|
|
6
|
+
node.setAttribute("data-comment", value);
|
|
7
|
+
node.classList.add("comment-anchor");
|
|
8
|
+
node.style.background = "rgba(255, 229, 100, 0.6)";
|
|
9
|
+
node.innerText = "💬"; // you can replace with thread number or icon
|
|
10
|
+
return node;
|
|
11
|
+
}
|
|
12
|
+
static value(domNode) {
|
|
13
|
+
return domNode.getAttribute("data-comment") || "";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
CommentBlot.blotName = "comment";
|
|
17
|
+
CommentBlot.tagName = "sup";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare const Embed: any;
|
|
2
|
+
export declare class FormulaBlot extends Embed {
|
|
3
|
+
static blotName: string;
|
|
4
|
+
static tagName: string;
|
|
5
|
+
static className: string;
|
|
6
|
+
static create(value: any): any;
|
|
7
|
+
static value(node: HTMLElement): {
|
|
8
|
+
tex: string;
|
|
9
|
+
displayMode: boolean;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import Quill from "quill";
|
|
2
|
+
const Embed = Quill.import("blots/embed");
|
|
3
|
+
export class FormulaBlot extends Embed {
|
|
4
|
+
static create(value) {
|
|
5
|
+
const node = super.create();
|
|
6
|
+
node.setAttribute("data-formula", value.tex);
|
|
7
|
+
try {
|
|
8
|
+
// @ts-ignore
|
|
9
|
+
const katex = window.katex;
|
|
10
|
+
if (katex) {
|
|
11
|
+
node.innerHTML = "";
|
|
12
|
+
katex.render(value.tex, node, {
|
|
13
|
+
displayMode: !!value.displayMode,
|
|
14
|
+
throwOnError: false,
|
|
15
|
+
strict: "ignore",
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
node.textContent = value.tex;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
node.textContent = value.tex;
|
|
24
|
+
}
|
|
25
|
+
return node;
|
|
26
|
+
}
|
|
27
|
+
static value(node) {
|
|
28
|
+
return {
|
|
29
|
+
tex: node.getAttribute("data-formula") || "",
|
|
30
|
+
displayMode: node.classList.contains("formula-block"),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
FormulaBlot.blotName = "formula";
|
|
35
|
+
FormulaBlot.tagName = "span";
|
|
36
|
+
FormulaBlot.className = "formula-inline";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare const BlockEmbed: any;
|
|
2
|
+
export declare class MediaBlot extends BlockEmbed {
|
|
3
|
+
static blotName: string;
|
|
4
|
+
static tagName: string;
|
|
5
|
+
static create(value: any): HTMLElement;
|
|
6
|
+
static value(domNode: HTMLElement): {
|
|
7
|
+
key: string;
|
|
8
|
+
content_type: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import Quill from "quill";
|
|
2
|
+
const BlockEmbed = Quill.import("blots/block/embed");
|
|
3
|
+
export class MediaBlot extends BlockEmbed {
|
|
4
|
+
static create(value) {
|
|
5
|
+
const node = super.create();
|
|
6
|
+
node.setAttribute("data-media-key", value.key);
|
|
7
|
+
node.setAttribute("data-type", value.content_type);
|
|
8
|
+
node.classList.add("smart-media");
|
|
9
|
+
node.innerHTML = `<div style="border:1px dashed #aaa;padding:4px;">Media: ${value.key}</div>`;
|
|
10
|
+
if (value.content_type.startsWith("image/")) {
|
|
11
|
+
const img = document.createElement("img");
|
|
12
|
+
img.src = value.url || `/media/${value.key}`;
|
|
13
|
+
node.appendChild(img);
|
|
14
|
+
}
|
|
15
|
+
else if (value.content_type.startsWith("video/")) {
|
|
16
|
+
const video = document.createElement("video");
|
|
17
|
+
video.controls = true;
|
|
18
|
+
video.src = value.url || `/media/${value.key}`;
|
|
19
|
+
node.appendChild(video);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
const link = document.createElement("a");
|
|
23
|
+
link.href = value.url || `/media/${value.key}`;
|
|
24
|
+
link.innerText = `Download ${value.key}`;
|
|
25
|
+
node.appendChild(link);
|
|
26
|
+
}
|
|
27
|
+
return node;
|
|
28
|
+
}
|
|
29
|
+
static value(domNode) {
|
|
30
|
+
return {
|
|
31
|
+
key: domNode.getAttribute("data-media-key"),
|
|
32
|
+
content_type: domNode.getAttribute("data-type") || "application/octet-stream",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
MediaBlot.blotName = "media";
|
|
37
|
+
MediaBlot.tagName = "div";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import Quill from "quill";
|
|
2
|
+
const BlockEmbed = Quill.import("blots/block/embed");
|
|
3
|
+
export class TableBlot extends BlockEmbed {
|
|
4
|
+
static create(value) {
|
|
5
|
+
const node = super.create();
|
|
6
|
+
node.setAttribute("contenteditable", "false");
|
|
7
|
+
node.classList.add("smart-table");
|
|
8
|
+
// Render rows & cells
|
|
9
|
+
if (value && value.rows) {
|
|
10
|
+
value.rows.forEach((row) => {
|
|
11
|
+
const tr = document.createElement("tr");
|
|
12
|
+
row.cells.forEach((cell) => {
|
|
13
|
+
if (cell.placeholder)
|
|
14
|
+
return;
|
|
15
|
+
const td = document.createElement("td");
|
|
16
|
+
if (cell.colspan && cell.colspan > 1)
|
|
17
|
+
td.colSpan = cell.colspan;
|
|
18
|
+
if (cell.rowspan && cell.rowspan > 1)
|
|
19
|
+
td.rowSpan = cell.rowspan;
|
|
20
|
+
if (cell.style?.background)
|
|
21
|
+
td.style.background = cell.style.background;
|
|
22
|
+
if (cell.style?.border)
|
|
23
|
+
td.style.border = `${cell.style.border.width_px}px solid ${cell.style.border.color}`;
|
|
24
|
+
td.innerText = cell.text;
|
|
25
|
+
tr.appendChild(td);
|
|
26
|
+
});
|
|
27
|
+
node.appendChild(tr);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return node;
|
|
31
|
+
}
|
|
32
|
+
static value(domNode) {
|
|
33
|
+
// Store the JSON representation in Delta
|
|
34
|
+
const rows = [];
|
|
35
|
+
domNode.querySelectorAll("tr").forEach((tr) => {
|
|
36
|
+
const cells = [];
|
|
37
|
+
tr.querySelectorAll("td").forEach((td) => {
|
|
38
|
+
cells.push({
|
|
39
|
+
text: td.innerText,
|
|
40
|
+
colspan: td.colSpan || 1,
|
|
41
|
+
rowspan: td.rowSpan || 1,
|
|
42
|
+
style: td.style.background
|
|
43
|
+
? { background: td.style.background }
|
|
44
|
+
: {},
|
|
45
|
+
placeholder: false,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
rows.push({ cells });
|
|
49
|
+
});
|
|
50
|
+
return { rows };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
TableBlot.blotName = "table";
|
|
54
|
+
TableBlot.tagName = "TABLE";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import Quill from "quill";
|
|
2
|
+
import { TableBlot } from "./TableBlot";
|
|
3
|
+
import { FormulaBlot } from "./FormulaBlot";
|
|
4
|
+
import { MediaBlot } from "./MediaBlot";
|
|
5
|
+
import { CommentBlot } from "./CommentBlot";
|
|
6
|
+
Quill.register({
|
|
7
|
+
"formats/table": TableBlot,
|
|
8
|
+
"formats/formula": FormulaBlot,
|
|
9
|
+
"formats/media": MediaBlot,
|
|
10
|
+
"formats/comment": CommentBlot,
|
|
11
|
+
});
|
|
12
|
+
export { TableBlot, FormulaBlot, MediaBlot, CommentBlot };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type ClassicEditorProps = {
|
|
2
|
+
value?: string;
|
|
3
|
+
onChange?: (html: string) => void;
|
|
4
|
+
placeholder?: string;
|
|
5
|
+
minHeight?: number | string;
|
|
6
|
+
maxHeight?: number | string;
|
|
7
|
+
readOnly?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare function ClassicEditor({ value, onChange, placeholder, minHeight, maxHeight, readOnly, }: ClassicEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|