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.
Files changed (42) hide show
  1. package/dist/QuillEditor.d.ts +8 -0
  2. package/dist/QuillEditor.js +34 -0
  3. package/dist/app.d.ts +6 -0
  4. package/dist/app.js +6 -0
  5. package/dist/blots/CommentBlot.d.ts +8 -0
  6. package/dist/blots/CommentBlot.js +17 -0
  7. package/dist/blots/FormulaBlot.d.ts +12 -0
  8. package/dist/blots/FormulaBlot.js +36 -0
  9. package/dist/blots/MediaBlot.d.ts +11 -0
  10. package/dist/blots/MediaBlot.js +37 -0
  11. package/dist/blots/TableBlot.d.ts +10 -0
  12. package/dist/blots/TableBlot.js +54 -0
  13. package/dist/blots/index.d.ts +5 -0
  14. package/dist/blots/index.js +12 -0
  15. package/dist/components/ClassicEditor.d.ts +10 -0
  16. package/dist/components/ClassicEditor.js +1066 -0
  17. package/dist/components/DiagramEditor.d.ts +5 -0
  18. package/dist/components/DiagramEditor.js +73 -0
  19. package/dist/components/FormulaEditor.d.ts +6 -0
  20. package/dist/components/FormulaEditor.js +86 -0
  21. package/dist/components/InfoBox.d.ts +7 -0
  22. package/dist/components/InfoBox.js +18 -0
  23. package/dist/components/MCQBlock.d.ts +13 -0
  24. package/dist/components/MCQBlock.js +29 -0
  25. package/dist/components/SmartEditor.d.ts +0 -0
  26. package/dist/components/SmartEditor.js +1 -0
  27. package/dist/components/SmartTable.d.ts +22 -0
  28. package/dist/components/SmartTable.js +629 -0
  29. package/dist/components/TableContextMenu.d.ts +11 -0
  30. package/dist/components/TableContextMenu.js +15 -0
  31. package/dist/components/TableInsertDialog.d.ts +7 -0
  32. package/dist/components/TableInsertDialog.js +42 -0
  33. package/dist/hooks/useEditorSync.d.ts +5 -0
  34. package/dist/hooks/useEditorSync.js +53 -0
  35. package/dist/index.d.ts +1 -0
  36. package/dist/index.js +1 -0
  37. package/dist/smart-editor.d.ts +0 -0
  38. package/dist/smart-editor.js +1 -0
  39. package/dist/standalone/classic-editor-embed.d.ts +12 -0
  40. package/dist/standalone/classic-editor-embed.js +108 -0
  41. package/dist/standalone/editor.js +241 -0
  42. package/package.json +46 -0
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ export const TableInsertDialog = ({ onInsert, onClose, }) => {
4
+ const [hoverRows, setHoverRows] = useState(0);
5
+ const [hoverCols, setHoverCols] = useState(0);
6
+ const maxRows = 10;
7
+ const maxCols = 10;
8
+ return (_jsxs("div", { style: {
9
+ position: "absolute",
10
+ top: 60,
11
+ left: 100,
12
+ background: "#fff",
13
+ border: "1px solid #ddd",
14
+ padding: 12,
15
+ zIndex: 1000,
16
+ boxShadow: "0 4px 10px rgba(0,0,0,0.15)",
17
+ }, children: [_jsx("div", { style: {
18
+ display: "grid",
19
+ gridTemplateColumns: `repeat(${maxCols}, 20px)`,
20
+ gap: 4,
21
+ }, children: Array.from({ length: maxRows }).map((_, r) => Array.from({ length: maxCols }).map((_, c) => {
22
+ const active = r < hoverRows && c < hoverCols;
23
+ return (_jsx("div", { style: {
24
+ width: 20,
25
+ height: 20,
26
+ border: "1px solid #ccc",
27
+ background: active ? "#3399ff" : "#f9f9f9",
28
+ cursor: "pointer",
29
+ }, onMouseEnter: () => {
30
+ setHoverRows(r + 1);
31
+ setHoverCols(c + 1);
32
+ }, onClick: () => {
33
+ onInsert(r + 1, c + 1);
34
+ onClose();
35
+ } }, `${r}-${c}`));
36
+ })) }), _jsxs("div", { style: { marginTop: 8, textAlign: "center", fontSize: 12 }, children: [hoverRows, " \u00D7 ", hoverCols] }), _jsx("button", { style: {
37
+ marginTop: 8,
38
+ padding: "4px 8px",
39
+ fontSize: 12,
40
+ cursor: "pointer",
41
+ }, onClick: onClose, children: "Cancel" })] }));
42
+ };
@@ -0,0 +1,5 @@
1
+ export declare function useEditorSync(editor: any): {
2
+ doc: any;
3
+ setDoc: import("react").Dispatch<any>;
4
+ sync: () => void;
5
+ };
@@ -0,0 +1,53 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ export function useEditorSync(editor) {
3
+ const [doc, setDoc] = useState({ nodes: [] });
4
+ const retryRef = useRef(null);
5
+ const sync = useCallback(() => {
6
+ if (!editor)
7
+ return;
8
+ // Skip if the wasm Editor was freed (HMR/unmount). __wbg_ptr === 0 means invalid.
9
+ try {
10
+ if (typeof editor.__wbg_ptr === 'number' && editor.__wbg_ptr === 0)
11
+ return;
12
+ }
13
+ catch { }
14
+ // Defer to next tick to avoid wasm RefCell re-entrancy when calling
15
+ // multiple &mut self methods back-to-back in the same event loop turn.
16
+ setTimeout(() => {
17
+ try {
18
+ if (typeof editor.__wbg_ptr === 'number' && editor.__wbg_ptr === 0)
19
+ return;
20
+ const json = editor.to_json();
21
+ const parsed = JSON.parse(json);
22
+ setDoc(parsed);
23
+ }
24
+ catch (err) {
25
+ // Avoid noisy logs during HMR/refresh when wasm may be temporarily invalid
26
+ // Retry once shortly after in case module just reloaded
27
+ if (retryRef.current)
28
+ window.clearTimeout(retryRef.current);
29
+ retryRef.current = window.setTimeout(() => {
30
+ try {
31
+ if (typeof editor.__wbg_ptr === 'number' && editor.__wbg_ptr !== 0) {
32
+ const j = editor.to_json();
33
+ setDoc(JSON.parse(j));
34
+ }
35
+ }
36
+ catch { }
37
+ retryRef.current = null;
38
+ }, 100);
39
+ }
40
+ }, 0);
41
+ }, [editor]);
42
+ useEffect(() => {
43
+ if (!editor)
44
+ return;
45
+ try {
46
+ if (typeof editor.__wbg_ptr === 'number' && editor.__wbg_ptr === 0)
47
+ return;
48
+ }
49
+ catch { }
50
+ sync();
51
+ }, [editor, sync]);
52
+ return { doc, setDoc, sync };
53
+ }
@@ -0,0 +1 @@
1
+ export { ClassicEditor } from './components/ClassicEditor';
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { ClassicEditor } from './components/ClassicEditor';
File without changes
@@ -0,0 +1 @@
1
+ // Removed: SmartEditor shim no longer needed
@@ -0,0 +1,12 @@
1
+ export type ClassicEditorController = {
2
+ setHtml: (html: string) => void;
3
+ getHtml: () => string;
4
+ focus: () => void;
5
+ blur: () => void;
6
+ destroy: () => void;
7
+ };
8
+ declare global {
9
+ interface Window {
10
+ SmartRTE?: any;
11
+ }
12
+ }
@@ -0,0 +1,108 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React, { useImperativeHandle, useRef, useState } from "react";
3
+ import { createRoot } from "react-dom/client";
4
+ import { ClassicEditor as ClassicEditorComponent } from "../components/ClassicEditor";
5
+ function ClassicEditorHost(props, ref) {
6
+ const [html, setHtml] = useState(props.value || "");
7
+ const containerRef = useRef(null);
8
+ useImperativeHandle(ref, () => ({
9
+ setHtml(next) {
10
+ setHtml(next ?? "");
11
+ },
12
+ getHtml() {
13
+ return (containerRef.current?.querySelector('[contenteditable="true"]')
14
+ ?.innerHTML ?? html);
15
+ },
16
+ focus() {
17
+ const el = containerRef.current?.querySelector('[contenteditable="true"]');
18
+ el?.focus();
19
+ },
20
+ blur() {
21
+ const el = containerRef.current?.querySelector('[contenteditable="true"]');
22
+ el?.blur();
23
+ },
24
+ destroy() {
25
+ // No-op here; actual unmount happens in init
26
+ },
27
+ }), [html]);
28
+ return (_jsx("div", { ref: containerRef, style: { height: "100%", width: "100%" }, children: _jsx(ClassicEditorComponent, { value: html, onChange: (v) => {
29
+ setHtml(v);
30
+ props.onChange?.(v);
31
+ try {
32
+ // Bridge to Flutter if present
33
+ // @ts-ignore
34
+ const ch = window.ToFlutter;
35
+ if (ch && typeof ch.postMessage === "function") {
36
+ ch.postMessage(JSON.stringify({ type: "change", html: v }));
37
+ }
38
+ }
39
+ catch { }
40
+ }, placeholder: props.placeholder, minHeight: props.minHeight, maxHeight: props.maxHeight, readOnly: props.readOnly }) }));
41
+ }
42
+ const ClassicEditorHostWithRef = React.forwardRef(ClassicEditorHost);
43
+ function initClassicEditor(opts) {
44
+ const { target, onChange, ...rest } = opts;
45
+ const root = createRoot(target);
46
+ const ref = React.createRef();
47
+ root.render(_jsx(ClassicEditorHostWithRef, { ref: ref, onChange: onChange, ...rest }));
48
+ const controller = {
49
+ setHtml: (html) => ref.current?.setHtml(html),
50
+ getHtml: () => ref.current?.getHtml() ?? "",
51
+ focus: () => ref.current?.focus?.(),
52
+ blur: () => ref.current?.blur?.(),
53
+ destroy: () => {
54
+ try {
55
+ root.unmount();
56
+ }
57
+ catch { }
58
+ },
59
+ };
60
+ // Attach controller globally for simple bridges
61
+ try {
62
+ const g = window;
63
+ g.SmartRTE = g.SmartRTE || {};
64
+ g.SmartRTE.__controller = controller;
65
+ g.SmartBridge = g.SmartBridge || {};
66
+ if (typeof g.SmartBridge.handle !== "function") {
67
+ g.SmartBridge.handle = (msg) => {
68
+ try {
69
+ if (!msg || typeof msg !== "object")
70
+ return;
71
+ const t = msg.type;
72
+ if (t === "setHtml")
73
+ controller.setHtml(String(msg.html ?? ""));
74
+ else if (t === "focus")
75
+ controller.focus();
76
+ else if (t === "blur")
77
+ controller.blur();
78
+ else if (t === "getHtml") {
79
+ const html = controller.getHtml();
80
+ const ch = g.ToFlutter;
81
+ if (ch && typeof ch.postMessage === "function") {
82
+ ch.postMessage(JSON.stringify({ type: "getHtmlResult", html }));
83
+ }
84
+ }
85
+ }
86
+ catch { }
87
+ };
88
+ }
89
+ }
90
+ catch { }
91
+ // Inform Flutter bridge we are ready
92
+ try {
93
+ // @ts-ignore
94
+ const ch = window.ToFlutter;
95
+ if (ch && typeof ch.postMessage === "function") {
96
+ ch.postMessage(JSON.stringify({ type: "ready" }));
97
+ }
98
+ }
99
+ catch { }
100
+ return controller;
101
+ }
102
+ (function attachGlobal() {
103
+ const g = window;
104
+ g.SmartRTE = g.SmartRTE || {};
105
+ g.SmartRTE.ClassicEditor = {
106
+ init: initClassicEditor,
107
+ };
108
+ })();