@wingleeio/ori-react 0.1.1 → 0.2.0
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/index.cjs +176 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +176 -8
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/styles.css +5 -7
package/dist/index.cjs
CHANGED
|
@@ -36,8 +36,129 @@ function useActiveMarks(editor) {
|
|
|
36
36
|
return editor.getActiveMarks();
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
// src/ce/
|
|
39
|
+
// src/ce/clipboard.ts
|
|
40
|
+
var ORI_MIME = "application/x-ori-inline";
|
|
41
|
+
function atomPlain(it) {
|
|
42
|
+
const d = it.atom?.data ?? {};
|
|
43
|
+
const label = d.label ?? d.text ?? d.name;
|
|
44
|
+
return label != null ? `@${String(label)}` : "";
|
|
45
|
+
}
|
|
46
|
+
function blockPlain(items) {
|
|
47
|
+
return items.map((it) => it.atom ? atomPlain(it) : it.text).join("");
|
|
48
|
+
}
|
|
49
|
+
var MARK_TAGS = [
|
|
50
|
+
["bold", "strong"],
|
|
51
|
+
["italic", "em"],
|
|
52
|
+
["underline", "u"],
|
|
53
|
+
["strike", "s"],
|
|
54
|
+
["code", "code"]
|
|
55
|
+
];
|
|
40
56
|
function esc(s) {
|
|
57
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
58
|
+
}
|
|
59
|
+
function runHtml(it) {
|
|
60
|
+
if (it.atom) return `<span>${esc(atomPlain(it))}</span>`;
|
|
61
|
+
let html = esc(it.text);
|
|
62
|
+
const m = it.marks ?? {};
|
|
63
|
+
for (const [k, tag] of MARK_TAGS) if (m[k]) html = `<${tag}>${html}</${tag}>`;
|
|
64
|
+
if (m.link) html = `<a href="${esc(m.link)}">${html}</a>`;
|
|
65
|
+
return html;
|
|
66
|
+
}
|
|
67
|
+
function serializeSelection(blocks) {
|
|
68
|
+
const text = blocks.map(blockPlain).join("\n");
|
|
69
|
+
const html = blocks.map((items) => `<p>${items.map(runHtml).join("") || "<br>"}</p>`).join("");
|
|
70
|
+
const json = JSON.stringify({
|
|
71
|
+
v: 1,
|
|
72
|
+
blocks: blocks.map(
|
|
73
|
+
(items) => items.map(
|
|
74
|
+
(it) => it.atom ? { embed: it.atom.data ?? { type: it.atom.type } } : { text: it.text, marks: it.marks }
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
});
|
|
78
|
+
return { text, html, json };
|
|
79
|
+
}
|
|
80
|
+
function deserializeOri(json) {
|
|
81
|
+
try {
|
|
82
|
+
const data = JSON.parse(json);
|
|
83
|
+
if (!Array.isArray(data.blocks)) return null;
|
|
84
|
+
return data.blocks.map(
|
|
85
|
+
(items) => items.map(
|
|
86
|
+
(it) => it.embed ? { text: "", start: 0, atom: { type: String(it.embed.type ?? ""), width: 0, data: it.embed } } : { text: it.text ?? "", start: 0, marks: it.marks }
|
|
87
|
+
)
|
|
88
|
+
);
|
|
89
|
+
} catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function textToBlocks(text) {
|
|
94
|
+
return text.replace(/\r\n?/g, "\n").split("\n").map((line) => line ? [{ text: line, start: 0 }] : []);
|
|
95
|
+
}
|
|
96
|
+
function htmlToBlocks(html) {
|
|
97
|
+
if (typeof DOMParser === "undefined") return [];
|
|
98
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
99
|
+
const blocks = [];
|
|
100
|
+
let cur = [];
|
|
101
|
+
const flush = () => {
|
|
102
|
+
blocks.push(cur);
|
|
103
|
+
cur = [];
|
|
104
|
+
};
|
|
105
|
+
const push = (text, marks) => {
|
|
106
|
+
if (!text) return;
|
|
107
|
+
cur.push({ text, start: 0, marks: Object.keys(marks).length ? { ...marks } : void 0 });
|
|
108
|
+
};
|
|
109
|
+
const BLOCK = /* @__PURE__ */ new Set([
|
|
110
|
+
"P",
|
|
111
|
+
"DIV",
|
|
112
|
+
"H1",
|
|
113
|
+
"H2",
|
|
114
|
+
"H3",
|
|
115
|
+
"H4",
|
|
116
|
+
"H5",
|
|
117
|
+
"H6",
|
|
118
|
+
"LI",
|
|
119
|
+
"BLOCKQUOTE",
|
|
120
|
+
"PRE",
|
|
121
|
+
"SECTION",
|
|
122
|
+
"ARTICLE",
|
|
123
|
+
"UL",
|
|
124
|
+
"OL"
|
|
125
|
+
]);
|
|
126
|
+
const walk = (node, marks) => {
|
|
127
|
+
for (const child of Array.from(node.childNodes)) {
|
|
128
|
+
if (child.nodeType === Node.TEXT_NODE) {
|
|
129
|
+
push((child.textContent ?? "").replace(/\s+/g, " "), marks);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (child.nodeType !== Node.ELEMENT_NODE) continue;
|
|
133
|
+
const el = child;
|
|
134
|
+
const tag = el.tagName;
|
|
135
|
+
if (tag === "BR") {
|
|
136
|
+
if (cur.length) flush();
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const m = { ...marks };
|
|
140
|
+
if (tag === "STRONG" || tag === "B") m.bold = true;
|
|
141
|
+
if (tag === "EM" || tag === "I") m.italic = true;
|
|
142
|
+
if (tag === "U" || tag === "INS") m.underline = true;
|
|
143
|
+
if (tag === "S" || tag === "STRIKE" || tag === "DEL") m.strike = true;
|
|
144
|
+
if (tag === "CODE" || tag === "KBD" || tag === "TT") m.code = true;
|
|
145
|
+
const href = tag === "A" ? el.getAttribute("href") : null;
|
|
146
|
+
if (href) m.link = href;
|
|
147
|
+
const isBlock = BLOCK.has(tag);
|
|
148
|
+
if (isBlock && cur.length) flush();
|
|
149
|
+
walk(el, m);
|
|
150
|
+
if (isBlock) flush();
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
walk(doc.body, {});
|
|
154
|
+
if (cur.length) flush();
|
|
155
|
+
while (blocks.length && blocks[0].length === 0) blocks.shift();
|
|
156
|
+
while (blocks.length && blocks[blocks.length - 1].length === 0) blocks.pop();
|
|
157
|
+
return blocks;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/ce/dom.ts
|
|
161
|
+
function esc2(s) {
|
|
41
162
|
return typeof CSS !== "undefined" && CSS.escape ? CSS.escape(s) : s.replace(/["\\]/g, "\\$&");
|
|
42
163
|
}
|
|
43
164
|
function blockElOf(node, root) {
|
|
@@ -82,7 +203,7 @@ function spanLen(span) {
|
|
|
82
203
|
return span.dataset.len != null ? Number(span.dataset.len) : (span.textContent ?? "").length;
|
|
83
204
|
}
|
|
84
205
|
function modelToDom(root, blockId, offset) {
|
|
85
|
-
const blockEl = root.querySelector(`[data-block-id="${
|
|
206
|
+
const blockEl = root.querySelector(`[data-block-id="${esc2(blockId)}"]`);
|
|
86
207
|
if (!blockEl) return null;
|
|
87
208
|
const spans = Array.from(blockEl.querySelectorAll("[data-off]"));
|
|
88
209
|
if (spans.length === 0) {
|
|
@@ -166,6 +287,9 @@ var EditorView = class {
|
|
|
166
287
|
this.composing = false;
|
|
167
288
|
this.onInput();
|
|
168
289
|
});
|
|
290
|
+
on("copy", (e) => this.onClipboard(e, false));
|
|
291
|
+
on("cut", (e) => this.onClipboard(e, true));
|
|
292
|
+
on("paste", (e) => this.onPaste(e));
|
|
169
293
|
const onSelChange = () => {
|
|
170
294
|
if (this.applyingModel || this.composing) return;
|
|
171
295
|
const sel = this.readSelection();
|
|
@@ -257,7 +381,7 @@ var EditorView = class {
|
|
|
257
381
|
const bot = this.root.lastElementChild;
|
|
258
382
|
if (bot && bot.style.height !== `${botH}px`) bot.style.height = `${botH}px`;
|
|
259
383
|
for (const vb of vis) {
|
|
260
|
-
const el = this.root.querySelector(`[data-block-id="${
|
|
384
|
+
const el = this.root.querySelector(`[data-block-id="${esc2(vb.id)}"]`);
|
|
261
385
|
if (!el) continue;
|
|
262
386
|
const sig = this.sig(vb.id);
|
|
263
387
|
if (el.dataset.sig !== sig) {
|
|
@@ -419,9 +543,10 @@ var EditorView = class {
|
|
|
419
543
|
e.preventDefault();
|
|
420
544
|
if (t === "deleteContentForward") ed.deleteForward();
|
|
421
545
|
else ed.deleteBackward();
|
|
422
|
-
} else if (t === "insertText" || t === "insertReplacementText"
|
|
546
|
+
} else if (t === "insertText" || t === "insertReplacementText") {
|
|
423
547
|
e.preventDefault();
|
|
424
|
-
|
|
548
|
+
if (!collapsed) ed.deleteBackward();
|
|
549
|
+
const text = e.data ?? "";
|
|
425
550
|
if (text) ed.insertText(text);
|
|
426
551
|
} else if (t === "insertLineBreak") {
|
|
427
552
|
e.preventDefault();
|
|
@@ -468,6 +593,45 @@ var EditorView = class {
|
|
|
468
593
|
off += len;
|
|
469
594
|
}
|
|
470
595
|
}
|
|
596
|
+
// --- clipboard ---------------------------------------------------------
|
|
597
|
+
/** Copy/cut: put plain, HTML and a private (mark-preserving) payload on the clipboard. */
|
|
598
|
+
onClipboard(e, isCut) {
|
|
599
|
+
const blocks = this.editor.getSelectionInline();
|
|
600
|
+
if (!blocks.length || !e.clipboardData) return;
|
|
601
|
+
e.preventDefault();
|
|
602
|
+
const { text, html, json } = serializeSelection(blocks);
|
|
603
|
+
e.clipboardData.setData("text/plain", text);
|
|
604
|
+
e.clipboardData.setData("text/html", html);
|
|
605
|
+
e.clipboardData.setData(ORI_MIME, json);
|
|
606
|
+
if (isCut && !this.opts.readOnly) {
|
|
607
|
+
this.editor.deleteBackward();
|
|
608
|
+
this.commit();
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
/** Paste: restore marks from our payload, else parse external HTML, else plain text. */
|
|
612
|
+
onPaste(e) {
|
|
613
|
+
if (this.opts.readOnly || !e.clipboardData) return;
|
|
614
|
+
e.preventDefault();
|
|
615
|
+
const sel = this.readSelection();
|
|
616
|
+
if (sel) {
|
|
617
|
+
this.editor.setSelection(sel);
|
|
618
|
+
if (!oriCore.isCollapsed(sel)) this.editor.deleteBackward();
|
|
619
|
+
}
|
|
620
|
+
const cd = e.clipboardData;
|
|
621
|
+
const ori = cd.getData(ORI_MIME);
|
|
622
|
+
const html = cd.getData("text/html");
|
|
623
|
+
let blocks = ori ? deserializeOri(ori) : null;
|
|
624
|
+
if (!blocks?.length && html) blocks = htmlToBlocks(html);
|
|
625
|
+
if (!blocks?.length) blocks = textToBlocks(cd.getData("text/plain"));
|
|
626
|
+
this.pasteBlocks(blocks);
|
|
627
|
+
this.commit();
|
|
628
|
+
}
|
|
629
|
+
pasteBlocks(blocks) {
|
|
630
|
+
blocks.forEach((items, i) => {
|
|
631
|
+
if (i > 0) this.editor.insertParagraphBreak();
|
|
632
|
+
if (items.length) this.editor.insertInline(items);
|
|
633
|
+
});
|
|
634
|
+
}
|
|
471
635
|
};
|
|
472
636
|
function caretClientRect() {
|
|
473
637
|
const s = window.getSelection();
|
|
@@ -491,6 +655,7 @@ function caretClientRect() {
|
|
|
491
655
|
var NoteEditor = react.forwardRef(function NoteEditor2({ editor, className, style, maxWidth = 720, placeholder, autoFocus, readOnly, blockRenderers, atomRenderers }, ref) {
|
|
492
656
|
const snapshot = useEditorSnapshot(editor);
|
|
493
657
|
const scrollerRef = react.useRef(null);
|
|
658
|
+
const overlayRef = react.useRef(null);
|
|
494
659
|
const contentRef = react.useRef(null);
|
|
495
660
|
const viewRef = react.useRef(null);
|
|
496
661
|
const [focused, setFocused] = react.useState(false);
|
|
@@ -512,7 +677,8 @@ var NoteEditor = react.forwardRef(function NoteEditor2({ editor, className, styl
|
|
|
512
677
|
if (!b.width && !b.height) return null;
|
|
513
678
|
return { top: b.top, left: b.left, right: b.right, bottom: b.bottom, width: b.width, height: b.height };
|
|
514
679
|
},
|
|
515
|
-
getScrollElement: () => scrollerRef.current
|
|
680
|
+
getScrollElement: () => scrollerRef.current,
|
|
681
|
+
getOverlayElement: () => overlayRef.current
|
|
516
682
|
}),
|
|
517
683
|
[]
|
|
518
684
|
);
|
|
@@ -577,7 +743,9 @@ var NoteEditor = react.forwardRef(function NoteEditor2({ editor, className, styl
|
|
|
577
743
|
};
|
|
578
744
|
const onPointerDown = (e) => {
|
|
579
745
|
if (readOnly) return;
|
|
580
|
-
|
|
746
|
+
const t = e.target;
|
|
747
|
+
const onSurface = t === scrollerRef.current || t === overlayRef.current || t.classList.contains("ori-ce") || t.dataset.spacer != null;
|
|
748
|
+
if (!onSurface) return;
|
|
581
749
|
const content = contentRef.current;
|
|
582
750
|
const blocks = content?.querySelectorAll("[data-block-id]");
|
|
583
751
|
const last = blocks && blocks[blocks.length - 1];
|
|
@@ -594,7 +762,7 @@ var NoteEditor = react.forwardRef(function NoteEditor2({ editor, className, styl
|
|
|
594
762
|
sel.addRange(range);
|
|
595
763
|
};
|
|
596
764
|
const showCaret = focused && !!caret && !readOnly;
|
|
597
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `ori-root${className ? ` ${className}` : ""}`, style, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ori-scroller", ref: scrollerRef, onScroll, onPointerDown, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ori-content", style: { maxWidth, marginInline: "auto", position: "relative" }, children: [
|
|
765
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `ori-root${className ? ` ${className}` : ""}`, style, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ori-scroller", ref: scrollerRef, onScroll, onPointerDown, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ori-content", ref: overlayRef, style: { maxWidth, marginInline: "auto", position: "relative" }, children: [
|
|
598
766
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
599
767
|
"div",
|
|
600
768
|
{
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useEditor.ts","../src/hooks.ts","../src/ce/dom.ts","../src/ce/view.ts","../src/NoteEditor.tsx","../src/renderers.tsx"],"names":["useRef","EditorController","createCanvasMeasurer","useEffect","useSyncExternalStore","textNode","isCollapsed","createRoot","forwardRef","NoteEditor","useState","useImperativeHandle","useLayoutEffect","jsx","jsxs","createContext","useContext"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n EditorController,\n createCanvasMeasurer,\n type EditorSchema,\n type Measurer,\n type Typography,\n} from \"@wingleeio/ori-core\";\nimport { useEffect, useRef } from \"react\";\nimport type * as Y from \"yjs\";\n\nexport interface UseEditorOptions {\n /** Existing note `Y.Doc`. When switching notes, remount via `key` instead. */\n doc?: Y.Doc;\n typography?: Typography;\n measurer?: Measurer;\n overscan?: number;\n blockSpacing?: number;\n /** Custom block/atom nodes, merged over the built-ins. */\n schema?: Partial<EditorSchema>;\n}\n\n/**\n * Create (once) and own an {@link EditorController} for the lifetime of the\n * component. To switch documents, give the hosting component a `key` so it\n * remounts with a fresh controller.\n *\n * The controller is reconnected on mount and disconnected on unmount rather than\n * destroyed, so React StrictMode's dev mount → unmount → remount cycle reuses the\n * same controller (with all its state) instead of leaving a torn-down one behind.\n */\nexport function useEditor(options: UseEditorOptions = {}): EditorController {\n const ref = useRef<EditorController | null>(null);\n if (ref.current === null) {\n ref.current = new EditorController({\n doc: options.doc,\n measurer: options.measurer ?? createCanvasMeasurer(),\n typography: options.typography,\n overscan: options.overscan,\n blockSpacing: options.blockSpacing,\n schema: options.schema,\n });\n }\n useEffect(() => {\n const editor = ref.current;\n editor?.connect();\n return () => editor?.disconnect();\n }, []);\n return ref.current;\n}\n","import type { EditorController, EditorSnapshot, Marks } from \"@wingleeio/ori-core\";\nimport { useSyncExternalStore } from \"react\";\n\n/** Subscribe a component to the controller's snapshot stream. */\nexport function useEditorSnapshot(editor: EditorController): EditorSnapshot {\n return useSyncExternalStore(editor.subscribe, editor.getSnapshot, editor.getSnapshot);\n}\n\n/**\n * The marks active at the current selection. Recomputed whenever the editor\n * notifies (selection move, edit, or pending-mark toggle), so toolbars stay in\n * sync without their own subscription.\n */\nexport function useActiveMarks(editor: EditorController): Marks {\n const snapshot = useEditorSnapshot(editor);\n // `revision` changes on every notify; reading it ties this to the store.\n void snapshot.revision;\n return editor.getActiveMarks();\n}\n","import type { InlineItem } from \"@wingleeio/ori-core\";\n\n/** CSS.escape with a fallback (jsdom lacks it). */\nexport function esc(s: string): string {\n return typeof CSS !== \"undefined\" && CSS.escape ? CSS.escape(s) : s.replace(/[\"\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Imperative DOM helpers for the contentEditable view. Each block is a\n * block-level element carrying `data-block-id`; its inline runs are spans\n * carrying `data-off` (their start offset in the block) so DOM positions map\n * back to {blockId, offset} and vice-versa.\n */\n\nexport const BLOCK_SEL = \"[data-block-id]\";\n\nexport function blockElOf(node: Node | null, root: HTMLElement): HTMLElement | null {\n let n: Node | null = node;\n while (n && n !== root) {\n if (n instanceof HTMLElement && n.dataset.blockId) return n;\n n = n.parentNode;\n }\n return null;\n}\n\nfunction spanOf(node: Node | null): HTMLElement | null {\n let n: Node | null = node;\n while (n) {\n if (n instanceof HTMLElement && n.dataset.off != null) return n;\n n = n.parentNode;\n }\n return null;\n}\n\n/** Map a DOM (node, offset) to a {blockId, offset} model position. */\nexport function domToModel(\n root: HTMLElement,\n node: Node | null,\n offset: number,\n): { blockId: string; offset: number } | null {\n const blockEl = blockElOf(node, root);\n if (!blockEl) return null;\n const blockId = blockEl.dataset.blockId as string;\n\n if (node && node.nodeType === Node.TEXT_NODE) {\n const span = spanOf(node);\n const base = span ? Number(span.dataset.off) : 0;\n return { blockId, offset: base + offset };\n }\n\n // node is an element; `offset` is a child index. Resolve via the child spans.\n const el = node as HTMLElement;\n if (el.dataset?.off != null) {\n // selection landed on a span boundary\n return { blockId, offset: Number(el.dataset.off) + (offset > 0 ? spanLen(el) : 0) };\n }\n const kids = Array.from(el.childNodes);\n for (let i = offset; i < kids.length; i++) {\n const k = kids[i];\n if (k instanceof HTMLElement && k.dataset.off != null) return { blockId, offset: Number(k.dataset.off) };\n }\n // past the last span → block end\n let end = 0;\n for (const k of kids) if (k instanceof HTMLElement && k.dataset.off != null) end = Math.max(end, Number(k.dataset.off) + spanLen(k));\n return { blockId, offset: end };\n}\n\nfunction spanLen(span: HTMLElement): number {\n return span.dataset.len != null ? Number(span.dataset.len) : (span.textContent ?? \"\").length;\n}\n\n/** Find the DOM (node, offset) for a {blockId, offset} model position. */\nexport function modelToDom(\n root: HTMLElement,\n blockId: string,\n offset: number,\n): { node: Node; offset: number } | null {\n const blockEl = root.querySelector(`[data-block-id=\"${esc(blockId)}\"]`) as HTMLElement | null;\n if (!blockEl) return null;\n const spans = Array.from(blockEl.querySelectorAll(\"[data-off]\")) as HTMLElement[];\n if (spans.length === 0) {\n return { node: blockEl, offset: 0 }; // empty block\n }\n for (const span of spans) {\n const start = Number(span.dataset.off);\n const len = spanLen(span);\n if (offset <= start + len) {\n if (span.dataset.atom != null) {\n // atom: place before or after it (offset is start or start+1)\n const idx = Array.prototype.indexOf.call(blockEl.childNodes, span);\n return { node: blockEl, offset: offset <= start ? idx : idx + 1 };\n }\n const textNode = span.firstChild ?? span;\n return { node: textNode, offset: Math.max(0, Math.min(offset - start, (textNode.textContent ?? \"\").length)) };\n }\n }\n // past everything → after the last span\n const last = spans[spans.length - 1];\n const textNode = last.firstChild ?? last;\n return { node: textNode, offset: (textNode.textContent ?? \"\").length };\n}\n\nfunction markClass(marks: InlineItem[\"marks\"]): string {\n const m = marks ?? {};\n const cls = [\"ori-frag\"];\n if (m.bold) cls.push(\"ori-m-bold\");\n if (m.italic) cls.push(\"ori-m-italic\");\n if (m.underline) cls.push(\"ori-m-underline\");\n if (m.strike) cls.push(\"ori-m-strike\");\n if (m.code) cls.push(\"ori-frag-code\");\n if (m.link) cls.push(\"ori-frag-link\");\n return cls.join(\" \");\n}\n\n/** Build the inline run DOM for a block (text spans only; atoms handled by the view). */\nexport function buildRun(item: InlineItem): HTMLElement {\n const span = document.createElement(\"span\");\n span.className = markClass(item.marks);\n span.dataset.off = String(item.start);\n span.dataset.len = String(item.text.length);\n span.textContent = item.text;\n return span;\n}\n","import type { EditorController } from \"@wingleeio/ori-core\";\nimport { isCollapsed } from \"@wingleeio/ori-core\";\nimport type { ReactNode } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport type { AtomRenderer, BlockRenderer } from \"../renderers\";\nimport { blockElOf, buildRun, domToModel, esc, modelToDom } from \"./dom\";\n\nconst PLACEHOLDER = \"\";\n\nexport interface ViewOptions {\n readOnly?: boolean;\n renderAtom: (type: string) => AtomRenderer | undefined;\n renderBlock: (type: string) => BlockRenderer | undefined;\n}\n\n/**\n * Imperative contentEditable view over an {@link EditorController}. The browser\n * owns caret / selection / trackpad / menus / IME on the live text; we intercept\n * structural + cross-block edits (beforeinput) and route them through the\n * controller, let smooth in-block typing flow natively and read it back, and\n * keep the DOM selection and the controller selection in lock-step.\n */\nexport class EditorView {\n private roots = new Map<HTMLElement, Root>();\n private composing = false;\n private applyingModel = false;\n private detachers: Array<() => void> = [];\n /** The model revision the DOM currently reflects (so external changes — remote\n * edits, app commands — re-render, but our own edits don't clobber the caret). */\n private lastRevision = -1;\n\n constructor(\n private root: HTMLElement,\n private editor: EditorController,\n private opts: ViewOptions,\n ) {\n root.setAttribute(\"contenteditable\", opts.readOnly ? \"false\" : \"true\");\n root.setAttribute(\"spellcheck\", opts.readOnly ? \"false\" : \"true\");\n root.setAttribute(\"role\", \"textbox\");\n root.setAttribute(\"aria-multiline\", \"true\");\n this.renderBlocks();\n this.lastRevision = this.rev();\n\n const on = <K extends keyof HTMLElementEventMap>(\n t: K,\n h: (e: HTMLElementEventMap[K]) => void,\n o?: AddEventListenerOptions,\n ) => {\n root.addEventListener(t, h as EventListener, o);\n this.detachers.push(() => root.removeEventListener(t, h as EventListener, o));\n };\n on(\"beforeinput\", (e) => this.onBeforeInput(e as InputEvent));\n on(\"input\", () => this.onInput());\n on(\"keydown\", (e) => this.onKeyDown(e as KeyboardEvent));\n on(\"blur\", () => {\n // Clicking outside the editor drops the selection (so a selection toolbar\n // hides). Defer so we can ignore a window/tab blur and focus-preserving\n // clicks (e.g. toolbar buttons that re-focus the editor).\n setTimeout(() => {\n if (document.activeElement === this.root || !document.hasFocus()) return;\n const sel = this.editor.getSelection();\n if (sel && !isCollapsed(sel)) {\n this.editor.collapse(sel.focus);\n this.lastRevision = this.rev();\n }\n }, 0);\n });\n on(\"compositionstart\", () => (this.composing = true));\n on(\"compositionend\", () => {\n this.composing = false;\n this.onInput();\n });\n\n const onSelChange = () => {\n if (this.applyingModel || this.composing) return;\n const sel = this.readSelection();\n if (!sel) return;\n this.editor.setSelection(sel);\n // DOM is already the source of truth here — record the revision so the\n // resulting React sync() doesn't write the selection back and collapse it.\n this.lastRevision = this.rev();\n };\n document.addEventListener(\"selectionchange\", onSelChange);\n this.detachers.push(() => document.removeEventListener(\"selectionchange\", onSelChange));\n }\n\n destroy() {\n this.detachers.forEach((d) => d());\n this.roots.forEach((r) => r.unmount());\n this.roots.clear();\n }\n\n focus() {\n this.root.focus();\n }\n\n // --- rendering ---------------------------------------------------------\n\n private rev(): number {\n return this.editor.getSnapshot().revision;\n }\n\n /**\n * Called by React on every model change. Only re-renders when the model moved\n * ahead of what we last drew (an *external* change — app command, undo, remote);\n * our own edits already updated the DOM and must not be clobbered.\n */\n sync() {\n const rev = this.rev();\n if (rev === this.lastRevision) return;\n // Only restore the DOM selection when the *content* changed (app command,\n // undo, remote). A selection-only change is already correct in the DOM, and\n // writing it back would fight (and collapse) the user's native selection.\n const changed = this.renderBlocks();\n if (changed) this.writeSelection();\n this.lastRevision = rev;\n }\n\n /** After a controlled (preventDefault'd) edit: re-render + restore the caret. */\n private commit() {\n this.renderBlocks();\n this.writeSelection();\n this.lastRevision = this.rev();\n }\n\n /** A content signature for a block, so unchanged blocks aren't re-rendered. */\n private sig(id: string): string {\n return this.editor.getBlockType(id) + \"|\" + JSON.stringify(this.editor.getInline(id));\n }\n\n /**\n * Reconcile the DOM to the *visible window* of blocks (virtualization): a top\n * spacer, the windowed blocks, then a bottom spacer — heights from the\n * controller's offscreen measurement. On-screen blocks are reused by id so a\n * caret inside one survives a scroll. Returns true if the DOM was mutated.\n */\n private renderBlocks(): boolean {\n let changed = false;\n const snap = this.editor.getSnapshot();\n const vis = snap.visible;\n const topH = vis.length ? vis[0].top : 0;\n const botH = vis.length\n ? Math.max(0, snap.totalHeight - (vis[vis.length - 1].top + vis[vis.length - 1].height))\n : Math.max(0, snap.totalHeight);\n\n const TOP = \"\u0000top\";\n const BOTTOM = \"\u0000bottom\";\n const want = [TOP, ...vis.map((v) => v.id), BOTTOM];\n const keyOf = (el: Element) => {\n const e = el as HTMLElement;\n return e.dataset.spacer ? \"\u0000\" + e.dataset.spacer : (e.dataset.blockId ?? \"\");\n };\n const have = new Map<string, HTMLElement>();\n for (const c of Array.from(this.root.children)) have.set(keyOf(c), c as HTMLElement);\n\n let prev: HTMLElement | null = null;\n for (const k of want) {\n let el: HTMLElement | undefined = have.get(k);\n if (el) {\n have.delete(k);\n } else {\n el = k === TOP || k === BOTTOM ? this.makeSpacer(k.slice(1)) : this.makeBlock(k);\n changed = true;\n }\n const anchor: ChildNode | null = prev ? prev.nextSibling : this.root.firstChild;\n if (anchor !== el) {\n this.root.insertBefore(el, anchor);\n changed = true;\n }\n prev = el;\n }\n for (const el of have.values()) {\n if (el.dataset.blockId) this.unmountRootsIn(el);\n el.remove();\n changed = true;\n }\n\n const top = this.root.firstElementChild as HTMLElement | null;\n if (top && top.style.height !== `${topH}px`) top.style.height = `${topH}px`;\n const bot = this.root.lastElementChild as HTMLElement | null;\n if (bot && bot.style.height !== `${botH}px`) bot.style.height = `${botH}px`;\n\n for (const vb of vis) {\n const el = this.root.querySelector(`[data-block-id=\"${esc(vb.id)}\"]`) as HTMLElement | null;\n if (!el) continue;\n const sig = this.sig(vb.id);\n if (el.dataset.sig !== sig) {\n el.dataset.sig = sig;\n this.renderBlockInner(el, vb.id);\n changed = true;\n }\n }\n return changed;\n }\n\n private makeBlock(id: string): HTMLElement {\n const el = document.createElement(\"div\");\n el.dataset.blockId = id;\n return el;\n }\n\n private makeSpacer(which: string): HTMLElement {\n const el = document.createElement(\"div\");\n el.dataset.spacer = which;\n el.setAttribute(\"contenteditable\", \"false\");\n el.setAttribute(\"aria-hidden\", \"true\");\n el.style.userSelect = \"none\";\n el.style.pointerEvents = \"none\";\n return el;\n }\n\n private renderBlockInner(el: HTMLElement, id: string) {\n this.unmountRootsIn(el);\n const type = this.editor.getBlockType(id);\n el.className = `ori-block ori-block-${type}`;\n\n const blockRenderer = this.opts.renderBlock(type);\n if (blockRenderer) {\n el.contentEditable = \"false\";\n el.textContent = \"\";\n const root = createRoot(el);\n root.render(blockRenderer({ editor: this.editor, block: { id, type, index: 0, top: 0, height: 0 }, layout: this.editor.getLayout(id)! }) as ReactNode);\n this.roots.set(el, root);\n return;\n }\n el.contentEditable = \"inherit\";\n el.textContent = \"\";\n const items = this.editor.getInline(id);\n if (items.length === 0) {\n el.appendChild(document.createElement(\"br\")); // keep an empty block selectable\n return;\n }\n for (const item of items) {\n if (item.atom) {\n const span = document.createElement(\"span\");\n span.className = \"ori-atom\";\n span.contentEditable = \"false\";\n span.dataset.atom = \"true\";\n span.dataset.off = String(item.start);\n span.dataset.len = \"1\";\n el.appendChild(span);\n const renderer = this.opts.renderAtom(item.atom.type);\n if (renderer) {\n const r = createRoot(span);\n r.render(renderer({ editor: this.editor, atom: item.atom }) as ReactNode);\n this.roots.set(span, r);\n }\n } else {\n el.appendChild(buildRun(item));\n }\n }\n }\n\n private unmountRootsIn(el: HTMLElement) {\n for (const [node, root] of this.roots) {\n if (el === node || el.contains(node)) {\n root.unmount();\n this.roots.delete(node);\n }\n }\n }\n\n // --- selection ---------------------------------------------------------\n\n private readSelection() {\n const s = window.getSelection();\n if (!s || s.rangeCount === 0 || !this.root.contains(s.anchorNode)) return null;\n const a = domToModel(this.root, s.anchorNode, s.anchorOffset);\n const f = domToModel(this.root, s.focusNode, s.focusOffset);\n if (!a || !f) return null;\n return { anchor: { blockId: a.blockId, offset: a.offset }, focus: { blockId: f.blockId, offset: f.offset } };\n }\n\n /** Push the controller's selection back into the DOM (after a model op). */\n private writeSelection() {\n const sel = this.editor.getSelection();\n if (!sel) return;\n const a = modelToDom(this.root, sel.anchor.blockId, sel.anchor.offset);\n const f = modelToDom(this.root, sel.focus.blockId, sel.focus.offset);\n if (!a || !f) return;\n const r = document.createRange();\n const s = window.getSelection();\n if (!s) return;\n this.applyingModel = true;\n try {\n r.setStart(a.node, a.offset);\n s.removeAllRanges();\n s.addRange(r);\n s.extend(f.node, f.offset);\n } catch {\n /* node detached mid-reconcile */\n } finally {\n this.applyingModel = false;\n }\n }\n\n /** The block text as the model sees it (atoms collapse to one placeholder). */\n private domBlockText(el: HTMLElement): string {\n let out = \"\";\n for (const child of Array.from(el.childNodes)) {\n if (child instanceof HTMLElement && child.dataset.atom != null) {\n out += PLACEHOLDER;\n } else {\n out += child.textContent ?? \"\";\n }\n }\n return out;\n }\n\n // --- input -------------------------------------------------------------\n\n /** Formatting + history shortcuts (the browser fires these as keydown). */\n private onKeyDown(e: KeyboardEvent) {\n if (this.opts.readOnly) return;\n const mod = e.metaKey || e.ctrlKey;\n if (!mod || e.altKey) return;\n const k = e.key.toLowerCase();\n const mark = ({ b: \"bold\", i: \"italic\", u: \"underline\", e: \"code\" } as const)[k];\n if (mark) {\n e.preventDefault();\n const sel = this.readSelection();\n if (sel) this.editor.setSelection(sel);\n this.editor.toggleMark(mark);\n this.commit();\n } else if (k === \"z\") {\n e.preventDefault();\n if (e.shiftKey) this.editor.redo();\n else this.editor.undo();\n this.commit();\n } else if (k === \"y\") {\n e.preventDefault();\n this.editor.redo();\n this.commit();\n }\n }\n\n private onBeforeInput(e: InputEvent) {\n if (this.opts.readOnly) {\n e.preventDefault();\n return;\n }\n const sel = this.readSelection();\n if (!sel) return;\n this.editor.setSelection(sel);\n const collapsed = isCollapsed(sel);\n const startOffset = this.editor.orderedSelection()?.start.offset ?? sel.focus.offset;\n const t = e.inputType;\n\n // Native fast path: collapsed in-block typing / deletion. The browser mutates\n // a single text node; onInput reads it back. Keeps autocorrect/IME native.\n if (collapsed && (t === \"insertText\" || t === \"insertCompositionText\" || t === \"insertReplacementText\")) return;\n if (collapsed && t === \"deleteContentForward\") return;\n if (collapsed && t === \"deleteContentBackward\" && startOffset > 0) return;\n\n // Everything else (structural + cross-block) is handled through the controller.\n const ed = this.editor;\n if (t === \"insertParagraph\") {\n e.preventDefault();\n ed.insertParagraphBreak();\n } else if (t.startsWith(\"delete\")) {\n e.preventDefault();\n if (t === \"deleteContentForward\") ed.deleteForward();\n else ed.deleteBackward();\n } else if (t === \"insertText\" || t === \"insertReplacementText\" || t === \"insertFromPaste\") {\n e.preventDefault();\n const text = e.data ?? e.dataTransfer?.getData(\"text/plain\") ?? \"\";\n if (text) ed.insertText(text);\n } else if (t === \"insertLineBreak\") {\n e.preventDefault();\n ed.insertText(\"\\n\");\n } else {\n return; // let the browser handle anything we don't model\n }\n this.commit();\n }\n\n private onInput() {\n if (this.composing || this.opts.readOnly) return;\n const blockEl = blockElOf(window.getSelection()?.anchorNode ?? null, this.root);\n if (!blockEl) {\n // structure changed under us (browser merged blocks) → full resync\n this.renderBlocks();\n this.lastRevision = this.rev();\n return;\n }\n const id = blockEl.dataset.blockId as string;\n const next = this.domBlockText(blockEl);\n const cur = this.editor.getBlockText(id);\n if (next === cur) return;\n\n // diff → splice through the controller (which infers marks at the caret)\n const max = Math.min(cur.length, next.length);\n let p = 0;\n while (p < max && cur[p] === next[p]) p++;\n let s = 0;\n while (s < max - p && cur[cur.length - 1 - s] === next[next.length - 1 - s]) s++;\n const from = p;\n const to = cur.length - s;\n const insert = next.slice(p, next.length - s);\n this.editor.setSelection({ anchor: { blockId: id, offset: from }, focus: { blockId: id, offset: to } });\n if (to > from) this.editor.deleteBackward();\n if (insert) this.editor.insertText(insert);\n // The browser already painted the text; just realign the run offsets.\n this.reindex(blockEl);\n this.lastRevision = this.rev();\n }\n\n /** Re-derive data-off / data-len after a native edit (no node replacement). */\n private reindex(el: HTMLElement) {\n let off = 0;\n for (const child of Array.from(el.children) as HTMLElement[]) {\n if (child.dataset.off == null) continue;\n child.dataset.off = String(off);\n const len = child.dataset.atom != null ? 1 : (child.textContent ?? \"\").length;\n child.dataset.len = String(len);\n off += len;\n }\n }\n}\n","import type { EditorController } from \"@wingleeio/ori-core\";\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type PointerEvent as ReactPointerEvent,\n} from \"react\";\nimport { EditorView } from \"./ce/view\";\nimport { useEditorSnapshot } from \"./hooks\";\nimport type { AtomRenderer, BlockRenderer } from \"./renderers\";\n\nexport interface NoteEditorProps {\n editor: EditorController;\n className?: string;\n style?: CSSProperties;\n /** Max width of the centered content column, in px. */\n maxWidth?: number;\n placeholder?: string;\n autoFocus?: boolean;\n readOnly?: boolean;\n /** Renderers for custom (atomic) block node types. */\n blockRenderers?: Record<string, BlockRenderer>;\n /** Renderers for custom inline atom types. */\n atomRenderers?: Record<string, AtomRenderer>;\n}\n\n/** A viewport-space rectangle (client coordinates). */\nexport interface ViewportRect {\n top: number;\n left: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n}\n\n/** Imperative handle for building floating UI (slash / selection menus). */\nexport interface NoteEditorHandle {\n focus(): void;\n /** Caret position in viewport coordinates, or null if unavailable. */\n getCaretRect(): { x: number; y: number; height: number } | null;\n /** Bounding box of the current selection in viewport coordinates, or null. */\n getSelectionRect(): ViewportRect | null;\n /** The scrolling element, for scroll-aware positioning. */\n getScrollElement(): HTMLElement | null;\n}\n\nfunction caretClientRect(): DOMRect | null {\n const s = window.getSelection();\n if (!s || s.rangeCount === 0) return null;\n const r = s.getRangeAt(0).cloneRange();\n r.collapse(s.focusNode === r.endContainer && s.focusOffset === r.endOffset ? false : true);\n const rects = r.getClientRects();\n if (rects.length) return rects[rects.length - 1];\n const b = r.getBoundingClientRect();\n if (b.height || b.width) return b;\n // Empty block (`<br>` only): a collapsed range there has no client rects, so\n // synthesize the caret from the block box + its line metrics. Without this the\n // custom caret would vanish on empty lines (the native caret is hidden).\n const node = r.startContainer;\n const el = (node.nodeType === Node.TEXT_NODE ? node.parentElement : (node as HTMLElement)) ?? null;\n if (!el) return null;\n const eb = el.getBoundingClientRect();\n const cs = getComputedStyle(el);\n const lh = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.4 || 18;\n const padL = parseFloat(cs.paddingLeft) || 0;\n const padT = parseFloat(cs.paddingTop) || 0;\n return new DOMRect(eb.left + padL, eb.top + padT, 0, lh);\n}\n\n/**\n * A contentEditable note editor: the browser owns caret, selection, trackpad,\n * native menus and IME on the live text, while edits are routed through the\n * {@link EditorController} (Y.Doc). A custom caret is drawn on top so it can be\n * branded/animated independently of the (hidden) native one.\n */\nexport const NoteEditor = forwardRef<NoteEditorHandle, NoteEditorProps>(function NoteEditor(\n { editor, className, style, maxWidth = 720, placeholder, autoFocus, readOnly, blockRenderers, atomRenderers },\n ref,\n) {\n const snapshot = useEditorSnapshot(editor);\n const scrollerRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n const viewRef = useRef<EditorView | null>(null);\n const [focused, setFocused] = useState(false);\n const [caret, setCaret] = useState<{ x: number; y: number; h: number } | null>(null);\n\n // Keep the latest renderers reachable without recreating the view.\n const renderersRef = useRef({ blockRenderers, atomRenderers });\n renderersRef.current = { blockRenderers, atomRenderers };\n\n useImperativeHandle(\n ref,\n (): NoteEditorHandle => ({\n focus: () => contentRef.current?.focus(),\n getCaretRect: () => {\n const r = caretClientRect();\n return r ? { x: r.left, y: r.top, height: r.height || 16 } : null;\n },\n getSelectionRect: () => {\n const s = window.getSelection();\n if (!s || s.rangeCount === 0 || s.isCollapsed) return null;\n const b = s.getRangeAt(0).getBoundingClientRect();\n if (!b.width && !b.height) return null;\n return { top: b.top, left: b.left, right: b.right, bottom: b.bottom, width: b.width, height: b.height };\n },\n getScrollElement: () => scrollerRef.current,\n }),\n [],\n );\n\n // Create the imperative contentEditable view once.\n useEffect(() => {\n const el = contentRef.current;\n if (!el) return;\n const view = new EditorView(el, editor, {\n readOnly,\n renderAtom: (t) => renderersRef.current.atomRenderers?.[t],\n renderBlock: (t) => renderersRef.current.blockRenderers?.[t],\n });\n viewRef.current = view;\n return () => {\n view.destroy();\n viewRef.current = null;\n };\n }, [editor, readOnly]);\n\n // Reconcile the view when the model changes externally (app commands, undo,\n // remote). The view ignores revisions it produced itself (native typing).\n useEffect(() => {\n viewRef.current?.sync();\n }, [snapshot.revision]);\n\n useEffect(() => {\n if (autoFocus) contentRef.current?.focus();\n }, [autoFocus]);\n\n // Position the custom caret from the live DOM selection.\n useEffect(() => {\n const update = () => {\n const content = contentRef.current;\n const s = window.getSelection();\n if (!content || !s || s.rangeCount === 0 || !s.isCollapsed || !content.contains(s.anchorNode)) {\n setCaret(null);\n return;\n }\n const r = caretClientRect();\n const box = content.getBoundingClientRect();\n if (r) setCaret({ x: r.left - box.left, y: r.top - box.top, h: r.height || 18 });\n };\n document.addEventListener(\"selectionchange\", update);\n const ro = new ResizeObserver(update);\n if (contentRef.current) ro.observe(contentRef.current);\n update();\n return () => {\n document.removeEventListener(\"selectionchange\", update);\n ro.disconnect();\n };\n }, []);\n\n // Drive virtualization: keep the controller's width + viewport in sync.\n useLayoutEffect(() => {\n const sc = scrollerRef.current;\n const content = contentRef.current;\n if (!sc || !content) return;\n const sync = () => {\n editor.setWidth(content.clientWidth);\n editor.setViewport(sc.scrollTop, sc.clientHeight);\n };\n sync();\n const ro = new ResizeObserver(sync);\n ro.observe(sc);\n ro.observe(content);\n return () => ro.disconnect();\n }, [editor]);\n\n const onScroll = () => {\n const sc = scrollerRef.current;\n if (sc) editor.setViewport(sc.scrollTop, sc.clientHeight);\n };\n\n // Clicking the empty region below the content should focus the editor and put\n // the caret at the document end (the usual \"click to keep writing\" affordance).\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>) => {\n if (readOnly) return;\n if ((e.target as HTMLElement).closest(\"[data-block-id]\")) return; // real block → browser\n const content = contentRef.current;\n const blocks = content?.querySelectorAll(\"[data-block-id]\");\n const last = blocks && (blocks[blocks.length - 1] as HTMLElement | undefined);\n if (!content || !last) return;\n if (e.clientY <= last.getBoundingClientRect().bottom) return; // beside text, not below\n e.preventDefault();\n content.focus();\n const sel = window.getSelection();\n if (!sel) return;\n const range = document.createRange();\n range.selectNodeContents(last);\n range.collapse(false);\n sel.removeAllRanges();\n sel.addRange(range);\n };\n\n const showCaret = focused && !!caret && !readOnly;\n\n return (\n <div className={`ori-root${className ? ` ${className}` : \"\"}`} style={style}>\n <div className=\"ori-scroller\" ref={scrollerRef} onScroll={onScroll} onPointerDown={onPointerDown}>\n <div className=\"ori-content\" style={{ maxWidth, marginInline: \"auto\", position: \"relative\" }}>\n <div\n className=\"ori-canvas ori-ce\"\n ref={contentRef}\n onFocus={() => setFocused(true)}\n onBlur={() => setFocused(false)}\n suppressContentEditableWarning\n />\n {showCaret && caret ? (\n <div\n className=\"ori-caret\"\n style={{ position: \"absolute\", left: caret.x, top: caret.y, height: caret.h, pointerEvents: \"none\" }}\n aria-hidden\n />\n ) : null}\n {snapshot.empty && placeholder ? (\n <div className=\"ori-placeholder\" aria-hidden>\n {placeholder}\n </div>\n ) : null}\n </div>\n </div>\n </div>\n );\n});\n","import type { BlockLayout, EditorController, InlineAtom, VisibleBlock } from \"@wingleeio/ori-core\";\nimport { createContext, useContext, type ReactNode } from \"react\";\n\n/** Props for a custom block renderer (atomic nodes: divider, image, …). */\nexport interface BlockRendererProps {\n editor: EditorController;\n block: VisibleBlock;\n /** The block's synthetic layout (atomic blocks: one line, no fragments). */\n layout: BlockLayout;\n}\nexport type BlockRenderer = (props: BlockRendererProps) => ReactNode;\n\n/** Props for a custom inline-atom renderer (mention chip, inline math, …). */\nexport interface AtomRendererProps {\n editor: EditorController;\n atom: InlineAtom;\n}\nexport type AtomRenderer = (props: AtomRendererProps) => ReactNode;\n\nexport interface Renderers {\n blocks: Record<string, BlockRenderer>;\n atoms: Record<string, AtomRenderer>;\n}\n\nconst EMPTY: Renderers = { blocks: {}, atoms: {} };\n\nconst RenderersContext = createContext<Renderers>(EMPTY);\nexport const RenderersProvider = RenderersContext.Provider;\nexport const useRenderers = (): Renderers => useContext(RenderersContext);\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/useEditor.ts","../src/hooks.ts","../src/ce/clipboard.ts","../src/ce/dom.ts","../src/ce/view.ts","../src/NoteEditor.tsx","../src/renderers.tsx"],"names":["useRef","EditorController","createCanvasMeasurer","useEffect","useSyncExternalStore","esc","textNode","isCollapsed","createRoot","forwardRef","NoteEditor","useState","useImperativeHandle","useLayoutEffect","jsx","jsxs","createContext","useContext"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n EditorController,\n createCanvasMeasurer,\n type EditorSchema,\n type Measurer,\n type Typography,\n} from \"@wingleeio/ori-core\";\nimport { useEffect, useRef } from \"react\";\nimport type * as Y from \"yjs\";\n\nexport interface UseEditorOptions {\n /** Existing note `Y.Doc`. When switching notes, remount via `key` instead. */\n doc?: Y.Doc;\n typography?: Typography;\n measurer?: Measurer;\n overscan?: number;\n blockSpacing?: number;\n /** Custom block/atom nodes, merged over the built-ins. */\n schema?: Partial<EditorSchema>;\n}\n\n/**\n * Create (once) and own an {@link EditorController} for the lifetime of the\n * component. To switch documents, give the hosting component a `key` so it\n * remounts with a fresh controller.\n *\n * The controller is reconnected on mount and disconnected on unmount rather than\n * destroyed, so React StrictMode's dev mount → unmount → remount cycle reuses the\n * same controller (with all its state) instead of leaving a torn-down one behind.\n */\nexport function useEditor(options: UseEditorOptions = {}): EditorController {\n const ref = useRef<EditorController | null>(null);\n if (ref.current === null) {\n ref.current = new EditorController({\n doc: options.doc,\n measurer: options.measurer ?? createCanvasMeasurer(),\n typography: options.typography,\n overscan: options.overscan,\n blockSpacing: options.blockSpacing,\n schema: options.schema,\n });\n }\n useEffect(() => {\n const editor = ref.current;\n editor?.connect();\n return () => editor?.disconnect();\n }, []);\n return ref.current;\n}\n","import type { EditorController, EditorSnapshot, Marks } from \"@wingleeio/ori-core\";\nimport { useSyncExternalStore } from \"react\";\n\n/** Subscribe a component to the controller's snapshot stream. */\nexport function useEditorSnapshot(editor: EditorController): EditorSnapshot {\n return useSyncExternalStore(editor.subscribe, editor.getSnapshot, editor.getSnapshot);\n}\n\n/**\n * The marks active at the current selection. Recomputed whenever the editor\n * notifies (selection move, edit, or pending-mark toggle), so toolbars stay in\n * sync without their own subscription.\n */\nexport function useActiveMarks(editor: EditorController): Marks {\n const snapshot = useEditorSnapshot(editor);\n // `revision` changes on every notify; reading it ties this to the store.\n void snapshot.revision;\n return editor.getActiveMarks();\n}\n","import type { InlineItem, Marks } from \"@wingleeio/ori-core\";\n\n/**\n * Clipboard (de)serialization for the contentEditable view. Copy writes three\n * payloads — `text/plain`, `text/html` (for other apps), and a private JSON MIME\n * that round-trips marks/atoms exactly — and paste prefers the private MIME, then\n * falls back to parsing external HTML, then plain text. Content is grouped one\n * array of inline runs per block so block boundaries survive a multi-block copy.\n */\nexport const ORI_MIME = \"application/x-ori-inline\";\n\nfunction atomPlain(it: InlineItem): string {\n const d = (it.atom?.data ?? {}) as Record<string, unknown>;\n const label = d.label ?? d.text ?? d.name;\n return label != null ? `@${String(label)}` : \"\";\n}\n\nfunction blockPlain(items: InlineItem[]): string {\n return items.map((it) => (it.atom ? atomPlain(it) : it.text)).join(\"\");\n}\n\nconst MARK_TAGS: Array<[keyof Marks, string]> = [\n [\"bold\", \"strong\"],\n [\"italic\", \"em\"],\n [\"underline\", \"u\"],\n [\"strike\", \"s\"],\n [\"code\", \"code\"],\n];\n\nfunction esc(s: string): string {\n return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n}\n\nfunction runHtml(it: InlineItem): string {\n if (it.atom) return `<span>${esc(atomPlain(it))}</span>`;\n let html = esc(it.text);\n const m = it.marks ?? {};\n for (const [k, tag] of MARK_TAGS) if (m[k]) html = `<${tag}>${html}</${tag}>`;\n if (m.link) html = `<a href=\"${esc(m.link)}\">${html}</a>`;\n return html;\n}\n\n/** Build the three clipboard payloads for a block-grouped selection. */\nexport function serializeSelection(blocks: InlineItem[][]): { text: string; html: string; json: string } {\n const text = blocks.map(blockPlain).join(\"\\n\");\n const html = blocks.map((items) => `<p>${items.map(runHtml).join(\"\") || \"<br>\"}</p>`).join(\"\");\n const json = JSON.stringify({\n v: 1,\n blocks: blocks.map((items) =>\n items.map((it) =>\n it.atom ? { embed: it.atom.data ?? { type: it.atom.type } } : { text: it.text, marks: it.marks },\n ),\n ),\n });\n return { text, html, json };\n}\n\ninterface SerItem {\n text?: string;\n marks?: Marks;\n embed?: Record<string, unknown>;\n}\n\n/** Parse our own clipboard JSON back into block-grouped inline items. */\nexport function deserializeOri(json: string): InlineItem[][] | null {\n try {\n const data = JSON.parse(json) as { v?: number; blocks?: SerItem[][] };\n if (!Array.isArray(data.blocks)) return null;\n return data.blocks.map((items) =>\n items.map((it) =>\n it.embed\n ? { text: \"\", start: 0, atom: { type: String(it.embed.type ?? \"\"), width: 0, data: it.embed } }\n : { text: it.text ?? \"\", start: 0, marks: it.marks },\n ),\n );\n } catch {\n return null;\n }\n}\n\n/** Plain text → one block per line. */\nexport function textToBlocks(text: string): InlineItem[][] {\n return text\n .replace(/\\r\\n?/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => (line ? [{ text: line, start: 0 } as InlineItem] : []));\n}\n\n/** Parse external HTML into block-grouped inline items (best-effort marks). */\nexport function htmlToBlocks(html: string): InlineItem[][] {\n if (typeof DOMParser === \"undefined\") return [];\n const doc = new DOMParser().parseFromString(html, \"text/html\");\n const blocks: InlineItem[][] = [];\n let cur: InlineItem[] = [];\n const flush = () => {\n blocks.push(cur);\n cur = [];\n };\n const push = (text: string, marks: Marks) => {\n if (!text) return;\n cur.push({ text, start: 0, marks: Object.keys(marks).length ? { ...marks } : undefined });\n };\n const BLOCK = new Set([\n \"P\", \"DIV\", \"H1\", \"H2\", \"H3\", \"H4\", \"H5\", \"H6\", \"LI\", \"BLOCKQUOTE\", \"PRE\", \"SECTION\", \"ARTICLE\", \"UL\", \"OL\",\n ]);\n const walk = (node: Node, marks: Marks) => {\n for (const child of Array.from(node.childNodes)) {\n if (child.nodeType === Node.TEXT_NODE) {\n push((child.textContent ?? \"\").replace(/\\s+/g, \" \"), marks);\n continue;\n }\n if (child.nodeType !== Node.ELEMENT_NODE) continue;\n const el = child as HTMLElement;\n const tag = el.tagName;\n if (tag === \"BR\") {\n if (cur.length) flush();\n continue;\n }\n const m: Marks = { ...marks };\n if (tag === \"STRONG\" || tag === \"B\") m.bold = true;\n if (tag === \"EM\" || tag === \"I\") m.italic = true;\n if (tag === \"U\" || tag === \"INS\") m.underline = true;\n if (tag === \"S\" || tag === \"STRIKE\" || tag === \"DEL\") m.strike = true;\n if (tag === \"CODE\" || tag === \"KBD\" || tag === \"TT\") m.code = true;\n const href = tag === \"A\" ? el.getAttribute(\"href\") : null;\n if (href) m.link = href;\n const isBlock = BLOCK.has(tag);\n if (isBlock && cur.length) flush();\n walk(el, m);\n if (isBlock) flush();\n }\n };\n walk(doc.body, {});\n if (cur.length) flush();\n // Trim leading/trailing empty blocks left by formatting whitespace.\n while (blocks.length && blocks[0].length === 0) blocks.shift();\n while (blocks.length && blocks[blocks.length - 1].length === 0) blocks.pop();\n return blocks;\n}\n","import type { InlineItem } from \"@wingleeio/ori-core\";\n\n/** CSS.escape with a fallback (jsdom lacks it). */\nexport function esc(s: string): string {\n return typeof CSS !== \"undefined\" && CSS.escape ? CSS.escape(s) : s.replace(/[\"\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Imperative DOM helpers for the contentEditable view. Each block is a\n * block-level element carrying `data-block-id`; its inline runs are spans\n * carrying `data-off` (their start offset in the block) so DOM positions map\n * back to {blockId, offset} and vice-versa.\n */\n\nexport const BLOCK_SEL = \"[data-block-id]\";\n\nexport function blockElOf(node: Node | null, root: HTMLElement): HTMLElement | null {\n let n: Node | null = node;\n while (n && n !== root) {\n if (n instanceof HTMLElement && n.dataset.blockId) return n;\n n = n.parentNode;\n }\n return null;\n}\n\nfunction spanOf(node: Node | null): HTMLElement | null {\n let n: Node | null = node;\n while (n) {\n if (n instanceof HTMLElement && n.dataset.off != null) return n;\n n = n.parentNode;\n }\n return null;\n}\n\n/** Map a DOM (node, offset) to a {blockId, offset} model position. */\nexport function domToModel(\n root: HTMLElement,\n node: Node | null,\n offset: number,\n): { blockId: string; offset: number } | null {\n const blockEl = blockElOf(node, root);\n if (!blockEl) return null;\n const blockId = blockEl.dataset.blockId as string;\n\n if (node && node.nodeType === Node.TEXT_NODE) {\n const span = spanOf(node);\n const base = span ? Number(span.dataset.off) : 0;\n return { blockId, offset: base + offset };\n }\n\n // node is an element; `offset` is a child index. Resolve via the child spans.\n const el = node as HTMLElement;\n if (el.dataset?.off != null) {\n // selection landed on a span boundary\n return { blockId, offset: Number(el.dataset.off) + (offset > 0 ? spanLen(el) : 0) };\n }\n const kids = Array.from(el.childNodes);\n for (let i = offset; i < kids.length; i++) {\n const k = kids[i];\n if (k instanceof HTMLElement && k.dataset.off != null) return { blockId, offset: Number(k.dataset.off) };\n }\n // past the last span → block end\n let end = 0;\n for (const k of kids) if (k instanceof HTMLElement && k.dataset.off != null) end = Math.max(end, Number(k.dataset.off) + spanLen(k));\n return { blockId, offset: end };\n}\n\nfunction spanLen(span: HTMLElement): number {\n return span.dataset.len != null ? Number(span.dataset.len) : (span.textContent ?? \"\").length;\n}\n\n/** Find the DOM (node, offset) for a {blockId, offset} model position. */\nexport function modelToDom(\n root: HTMLElement,\n blockId: string,\n offset: number,\n): { node: Node; offset: number } | null {\n const blockEl = root.querySelector(`[data-block-id=\"${esc(blockId)}\"]`) as HTMLElement | null;\n if (!blockEl) return null;\n const spans = Array.from(blockEl.querySelectorAll(\"[data-off]\")) as HTMLElement[];\n if (spans.length === 0) {\n return { node: blockEl, offset: 0 }; // empty block\n }\n for (const span of spans) {\n const start = Number(span.dataset.off);\n const len = spanLen(span);\n if (offset <= start + len) {\n if (span.dataset.atom != null) {\n // atom: place before or after it (offset is start or start+1)\n const idx = Array.prototype.indexOf.call(blockEl.childNodes, span);\n return { node: blockEl, offset: offset <= start ? idx : idx + 1 };\n }\n const textNode = span.firstChild ?? span;\n return { node: textNode, offset: Math.max(0, Math.min(offset - start, (textNode.textContent ?? \"\").length)) };\n }\n }\n // past everything → after the last span\n const last = spans[spans.length - 1];\n const textNode = last.firstChild ?? last;\n return { node: textNode, offset: (textNode.textContent ?? \"\").length };\n}\n\nfunction markClass(marks: InlineItem[\"marks\"]): string {\n const m = marks ?? {};\n const cls = [\"ori-frag\"];\n if (m.bold) cls.push(\"ori-m-bold\");\n if (m.italic) cls.push(\"ori-m-italic\");\n if (m.underline) cls.push(\"ori-m-underline\");\n if (m.strike) cls.push(\"ori-m-strike\");\n if (m.code) cls.push(\"ori-frag-code\");\n if (m.link) cls.push(\"ori-frag-link\");\n return cls.join(\" \");\n}\n\n/** Build the inline run DOM for a block (text spans only; atoms handled by the view). */\nexport function buildRun(item: InlineItem): HTMLElement {\n const span = document.createElement(\"span\");\n span.className = markClass(item.marks);\n span.dataset.off = String(item.start);\n span.dataset.len = String(item.text.length);\n span.textContent = item.text;\n return span;\n}\n","import type { EditorController, InlineItem } from \"@wingleeio/ori-core\";\nimport { isCollapsed } from \"@wingleeio/ori-core\";\nimport type { ReactNode } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport type { AtomRenderer, BlockRenderer } from \"../renderers\";\nimport { ORI_MIME, deserializeOri, htmlToBlocks, serializeSelection, textToBlocks } from \"./clipboard\";\nimport { blockElOf, buildRun, domToModel, esc, modelToDom } from \"./dom\";\n\nconst PLACEHOLDER = \"\";\n\nexport interface ViewOptions {\n readOnly?: boolean;\n renderAtom: (type: string) => AtomRenderer | undefined;\n renderBlock: (type: string) => BlockRenderer | undefined;\n}\n\n/**\n * Imperative contentEditable view over an {@link EditorController}. The browser\n * owns caret / selection / trackpad / menus / IME on the live text; we intercept\n * structural + cross-block edits (beforeinput) and route them through the\n * controller, let smooth in-block typing flow natively and read it back, and\n * keep the DOM selection and the controller selection in lock-step.\n */\nexport class EditorView {\n private roots = new Map<HTMLElement, Root>();\n private composing = false;\n private applyingModel = false;\n private detachers: Array<() => void> = [];\n /** The model revision the DOM currently reflects (so external changes — remote\n * edits, app commands — re-render, but our own edits don't clobber the caret). */\n private lastRevision = -1;\n\n constructor(\n private root: HTMLElement,\n private editor: EditorController,\n private opts: ViewOptions,\n ) {\n root.setAttribute(\"contenteditable\", opts.readOnly ? \"false\" : \"true\");\n root.setAttribute(\"spellcheck\", opts.readOnly ? \"false\" : \"true\");\n root.setAttribute(\"role\", \"textbox\");\n root.setAttribute(\"aria-multiline\", \"true\");\n this.renderBlocks();\n this.lastRevision = this.rev();\n\n const on = <K extends keyof HTMLElementEventMap>(\n t: K,\n h: (e: HTMLElementEventMap[K]) => void,\n o?: AddEventListenerOptions,\n ) => {\n root.addEventListener(t, h as EventListener, o);\n this.detachers.push(() => root.removeEventListener(t, h as EventListener, o));\n };\n on(\"beforeinput\", (e) => this.onBeforeInput(e as InputEvent));\n on(\"input\", () => this.onInput());\n on(\"keydown\", (e) => this.onKeyDown(e as KeyboardEvent));\n on(\"blur\", () => {\n // Clicking outside the editor drops the selection (so a selection toolbar\n // hides). Defer so we can ignore a window/tab blur and focus-preserving\n // clicks (e.g. toolbar buttons that re-focus the editor).\n setTimeout(() => {\n if (document.activeElement === this.root || !document.hasFocus()) return;\n const sel = this.editor.getSelection();\n if (sel && !isCollapsed(sel)) {\n this.editor.collapse(sel.focus);\n this.lastRevision = this.rev();\n }\n }, 0);\n });\n on(\"compositionstart\", () => (this.composing = true));\n on(\"compositionend\", () => {\n this.composing = false;\n this.onInput();\n });\n on(\"copy\", (e) => this.onClipboard(e as ClipboardEvent, false));\n on(\"cut\", (e) => this.onClipboard(e as ClipboardEvent, true));\n on(\"paste\", (e) => this.onPaste(e as ClipboardEvent));\n\n const onSelChange = () => {\n if (this.applyingModel || this.composing) return;\n const sel = this.readSelection();\n if (!sel) return;\n this.editor.setSelection(sel);\n // DOM is already the source of truth here — record the revision so the\n // resulting React sync() doesn't write the selection back and collapse it.\n this.lastRevision = this.rev();\n };\n document.addEventListener(\"selectionchange\", onSelChange);\n this.detachers.push(() => document.removeEventListener(\"selectionchange\", onSelChange));\n }\n\n destroy() {\n this.detachers.forEach((d) => d());\n this.roots.forEach((r) => r.unmount());\n this.roots.clear();\n }\n\n focus() {\n this.root.focus();\n }\n\n // --- rendering ---------------------------------------------------------\n\n private rev(): number {\n return this.editor.getSnapshot().revision;\n }\n\n /**\n * Called by React on every model change. Only re-renders when the model moved\n * ahead of what we last drew (an *external* change — app command, undo, remote);\n * our own edits already updated the DOM and must not be clobbered.\n */\n sync() {\n const rev = this.rev();\n if (rev === this.lastRevision) return;\n // Only restore the DOM selection when the *content* changed (app command,\n // undo, remote). A selection-only change is already correct in the DOM, and\n // writing it back would fight (and collapse) the user's native selection.\n const changed = this.renderBlocks();\n if (changed) this.writeSelection();\n this.lastRevision = rev;\n }\n\n /** After a controlled (preventDefault'd) edit: re-render + restore the caret. */\n private commit() {\n this.renderBlocks();\n this.writeSelection();\n this.lastRevision = this.rev();\n }\n\n /** A content signature for a block, so unchanged blocks aren't re-rendered. */\n private sig(id: string): string {\n return this.editor.getBlockType(id) + \"|\" + JSON.stringify(this.editor.getInline(id));\n }\n\n /**\n * Reconcile the DOM to the *visible window* of blocks (virtualization): a top\n * spacer, the windowed blocks, then a bottom spacer — heights from the\n * controller's offscreen measurement. On-screen blocks are reused by id so a\n * caret inside one survives a scroll. Returns true if the DOM was mutated.\n */\n private renderBlocks(): boolean {\n let changed = false;\n const snap = this.editor.getSnapshot();\n const vis = snap.visible;\n const topH = vis.length ? vis[0].top : 0;\n const botH = vis.length\n ? Math.max(0, snap.totalHeight - (vis[vis.length - 1].top + vis[vis.length - 1].height))\n : Math.max(0, snap.totalHeight);\n\n const TOP = \"\u0000top\";\n const BOTTOM = \"\u0000bottom\";\n const want = [TOP, ...vis.map((v) => v.id), BOTTOM];\n const keyOf = (el: Element) => {\n const e = el as HTMLElement;\n return e.dataset.spacer ? \"\u0000\" + e.dataset.spacer : (e.dataset.blockId ?? \"\");\n };\n const have = new Map<string, HTMLElement>();\n for (const c of Array.from(this.root.children)) have.set(keyOf(c), c as HTMLElement);\n\n let prev: HTMLElement | null = null;\n for (const k of want) {\n let el: HTMLElement | undefined = have.get(k);\n if (el) {\n have.delete(k);\n } else {\n el = k === TOP || k === BOTTOM ? this.makeSpacer(k.slice(1)) : this.makeBlock(k);\n changed = true;\n }\n const anchor: ChildNode | null = prev ? prev.nextSibling : this.root.firstChild;\n if (anchor !== el) {\n this.root.insertBefore(el, anchor);\n changed = true;\n }\n prev = el;\n }\n for (const el of have.values()) {\n if (el.dataset.blockId) this.unmountRootsIn(el);\n el.remove();\n changed = true;\n }\n\n const top = this.root.firstElementChild as HTMLElement | null;\n if (top && top.style.height !== `${topH}px`) top.style.height = `${topH}px`;\n const bot = this.root.lastElementChild as HTMLElement | null;\n if (bot && bot.style.height !== `${botH}px`) bot.style.height = `${botH}px`;\n\n for (const vb of vis) {\n const el = this.root.querySelector(`[data-block-id=\"${esc(vb.id)}\"]`) as HTMLElement | null;\n if (!el) continue;\n const sig = this.sig(vb.id);\n if (el.dataset.sig !== sig) {\n el.dataset.sig = sig;\n this.renderBlockInner(el, vb.id);\n changed = true;\n }\n }\n return changed;\n }\n\n private makeBlock(id: string): HTMLElement {\n const el = document.createElement(\"div\");\n el.dataset.blockId = id;\n return el;\n }\n\n private makeSpacer(which: string): HTMLElement {\n const el = document.createElement(\"div\");\n el.dataset.spacer = which;\n el.setAttribute(\"contenteditable\", \"false\");\n el.setAttribute(\"aria-hidden\", \"true\");\n el.style.userSelect = \"none\";\n el.style.pointerEvents = \"none\";\n return el;\n }\n\n private renderBlockInner(el: HTMLElement, id: string) {\n this.unmountRootsIn(el);\n const type = this.editor.getBlockType(id);\n el.className = `ori-block ori-block-${type}`;\n\n const blockRenderer = this.opts.renderBlock(type);\n if (blockRenderer) {\n el.contentEditable = \"false\";\n el.textContent = \"\";\n const root = createRoot(el);\n root.render(blockRenderer({ editor: this.editor, block: { id, type, index: 0, top: 0, height: 0 }, layout: this.editor.getLayout(id)! }) as ReactNode);\n this.roots.set(el, root);\n return;\n }\n el.contentEditable = \"inherit\";\n el.textContent = \"\";\n const items = this.editor.getInline(id);\n if (items.length === 0) {\n el.appendChild(document.createElement(\"br\")); // keep an empty block selectable\n return;\n }\n for (const item of items) {\n if (item.atom) {\n const span = document.createElement(\"span\");\n span.className = \"ori-atom\";\n span.contentEditable = \"false\";\n span.dataset.atom = \"true\";\n span.dataset.off = String(item.start);\n span.dataset.len = \"1\";\n el.appendChild(span);\n const renderer = this.opts.renderAtom(item.atom.type);\n if (renderer) {\n const r = createRoot(span);\n r.render(renderer({ editor: this.editor, atom: item.atom }) as ReactNode);\n this.roots.set(span, r);\n }\n } else {\n el.appendChild(buildRun(item));\n }\n }\n }\n\n private unmountRootsIn(el: HTMLElement) {\n for (const [node, root] of this.roots) {\n if (el === node || el.contains(node)) {\n root.unmount();\n this.roots.delete(node);\n }\n }\n }\n\n // --- selection ---------------------------------------------------------\n\n private readSelection() {\n const s = window.getSelection();\n if (!s || s.rangeCount === 0 || !this.root.contains(s.anchorNode)) return null;\n const a = domToModel(this.root, s.anchorNode, s.anchorOffset);\n const f = domToModel(this.root, s.focusNode, s.focusOffset);\n if (!a || !f) return null;\n return { anchor: { blockId: a.blockId, offset: a.offset }, focus: { blockId: f.blockId, offset: f.offset } };\n }\n\n /** Push the controller's selection back into the DOM (after a model op). */\n private writeSelection() {\n const sel = this.editor.getSelection();\n if (!sel) return;\n const a = modelToDom(this.root, sel.anchor.blockId, sel.anchor.offset);\n const f = modelToDom(this.root, sel.focus.blockId, sel.focus.offset);\n if (!a || !f) return;\n const r = document.createRange();\n const s = window.getSelection();\n if (!s) return;\n this.applyingModel = true;\n try {\n r.setStart(a.node, a.offset);\n s.removeAllRanges();\n s.addRange(r);\n s.extend(f.node, f.offset);\n } catch {\n /* node detached mid-reconcile */\n } finally {\n this.applyingModel = false;\n }\n }\n\n /** The block text as the model sees it (atoms collapse to one placeholder). */\n private domBlockText(el: HTMLElement): string {\n let out = \"\";\n for (const child of Array.from(el.childNodes)) {\n if (child instanceof HTMLElement && child.dataset.atom != null) {\n out += PLACEHOLDER;\n } else {\n out += child.textContent ?? \"\";\n }\n }\n return out;\n }\n\n // --- input -------------------------------------------------------------\n\n /** Formatting + history shortcuts (the browser fires these as keydown). */\n private onKeyDown(e: KeyboardEvent) {\n if (this.opts.readOnly) return;\n const mod = e.metaKey || e.ctrlKey;\n if (!mod || e.altKey) return;\n const k = e.key.toLowerCase();\n const mark = ({ b: \"bold\", i: \"italic\", u: \"underline\", e: \"code\" } as const)[k];\n if (mark) {\n e.preventDefault();\n const sel = this.readSelection();\n if (sel) this.editor.setSelection(sel);\n this.editor.toggleMark(mark);\n this.commit();\n } else if (k === \"z\") {\n e.preventDefault();\n if (e.shiftKey) this.editor.redo();\n else this.editor.undo();\n this.commit();\n } else if (k === \"y\") {\n e.preventDefault();\n this.editor.redo();\n this.commit();\n }\n }\n\n private onBeforeInput(e: InputEvent) {\n if (this.opts.readOnly) {\n e.preventDefault();\n return;\n }\n const sel = this.readSelection();\n if (!sel) return;\n this.editor.setSelection(sel);\n const collapsed = isCollapsed(sel);\n const startOffset = this.editor.orderedSelection()?.start.offset ?? sel.focus.offset;\n const t = e.inputType;\n\n // Native fast path: collapsed in-block typing / deletion. The browser mutates\n // a single text node; onInput reads it back. Keeps autocorrect/IME native.\n if (collapsed && (t === \"insertText\" || t === \"insertCompositionText\" || t === \"insertReplacementText\")) return;\n if (collapsed && t === \"deleteContentForward\") return;\n if (collapsed && t === \"deleteContentBackward\" && startOffset > 0) return;\n\n // Everything else (structural + cross-block) is handled through the controller.\n const ed = this.editor;\n if (t === \"insertParagraph\") {\n e.preventDefault();\n ed.insertParagraphBreak();\n } else if (t.startsWith(\"delete\")) {\n e.preventDefault();\n if (t === \"deleteContentForward\") ed.deleteForward();\n else ed.deleteBackward();\n } else if (t === \"insertText\" || t === \"insertReplacementText\") {\n // Non-collapsed (e.g. autocorrect replacement, or typing over a selection):\n // replace the range. Paste has its own handler (onPaste).\n e.preventDefault();\n if (!collapsed) ed.deleteBackward();\n const text = e.data ?? \"\";\n if (text) ed.insertText(text);\n } else if (t === \"insertLineBreak\") {\n e.preventDefault();\n ed.insertText(\"\\n\");\n } else {\n return; // let the browser handle anything we don't model\n }\n this.commit();\n }\n\n private onInput() {\n if (this.composing || this.opts.readOnly) return;\n const blockEl = blockElOf(window.getSelection()?.anchorNode ?? null, this.root);\n if (!blockEl) {\n // structure changed under us (browser merged blocks) → full resync\n this.renderBlocks();\n this.lastRevision = this.rev();\n return;\n }\n const id = blockEl.dataset.blockId as string;\n const next = this.domBlockText(blockEl);\n const cur = this.editor.getBlockText(id);\n if (next === cur) return;\n\n // diff → splice through the controller (which infers marks at the caret)\n const max = Math.min(cur.length, next.length);\n let p = 0;\n while (p < max && cur[p] === next[p]) p++;\n let s = 0;\n while (s < max - p && cur[cur.length - 1 - s] === next[next.length - 1 - s]) s++;\n const from = p;\n const to = cur.length - s;\n const insert = next.slice(p, next.length - s);\n this.editor.setSelection({ anchor: { blockId: id, offset: from }, focus: { blockId: id, offset: to } });\n if (to > from) this.editor.deleteBackward();\n if (insert) this.editor.insertText(insert);\n // The browser already painted the text; just realign the run offsets.\n this.reindex(blockEl);\n this.lastRevision = this.rev();\n }\n\n /** Re-derive data-off / data-len after a native edit (no node replacement). */\n private reindex(el: HTMLElement) {\n let off = 0;\n for (const child of Array.from(el.children) as HTMLElement[]) {\n if (child.dataset.off == null) continue;\n child.dataset.off = String(off);\n const len = child.dataset.atom != null ? 1 : (child.textContent ?? \"\").length;\n child.dataset.len = String(len);\n off += len;\n }\n }\n\n // --- clipboard ---------------------------------------------------------\n\n /** Copy/cut: put plain, HTML and a private (mark-preserving) payload on the clipboard. */\n private onClipboard(e: ClipboardEvent, isCut: boolean) {\n const blocks = this.editor.getSelectionInline();\n if (!blocks.length || !e.clipboardData) return;\n e.preventDefault();\n const { text, html, json } = serializeSelection(blocks);\n e.clipboardData.setData(\"text/plain\", text);\n e.clipboardData.setData(\"text/html\", html);\n e.clipboardData.setData(ORI_MIME, json);\n if (isCut && !this.opts.readOnly) {\n this.editor.deleteBackward();\n this.commit();\n }\n }\n\n /** Paste: restore marks from our payload, else parse external HTML, else plain text. */\n private onPaste(e: ClipboardEvent) {\n if (this.opts.readOnly || !e.clipboardData) return;\n e.preventDefault();\n const sel = this.readSelection();\n if (sel) {\n this.editor.setSelection(sel);\n if (!isCollapsed(sel)) this.editor.deleteBackward();\n }\n const cd = e.clipboardData;\n const ori = cd.getData(ORI_MIME);\n const html = cd.getData(\"text/html\");\n let blocks = ori ? deserializeOri(ori) : null;\n if (!blocks?.length && html) blocks = htmlToBlocks(html);\n if (!blocks?.length) blocks = textToBlocks(cd.getData(\"text/plain\"));\n this.pasteBlocks(blocks);\n this.commit();\n }\n\n private pasteBlocks(blocks: InlineItem[][]) {\n blocks.forEach((items, i) => {\n if (i > 0) this.editor.insertParagraphBreak();\n if (items.length) this.editor.insertInline(items);\n });\n }\n}\n","import type { EditorController } from \"@wingleeio/ori-core\";\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type PointerEvent as ReactPointerEvent,\n} from \"react\";\nimport { EditorView } from \"./ce/view\";\nimport { useEditorSnapshot } from \"./hooks\";\nimport type { AtomRenderer, BlockRenderer } from \"./renderers\";\n\nexport interface NoteEditorProps {\n editor: EditorController;\n className?: string;\n style?: CSSProperties;\n /** Max width of the centered content column, in px. */\n maxWidth?: number;\n placeholder?: string;\n autoFocus?: boolean;\n readOnly?: boolean;\n /** Renderers for custom (atomic) block node types. */\n blockRenderers?: Record<string, BlockRenderer>;\n /** Renderers for custom inline atom types. */\n atomRenderers?: Record<string, AtomRenderer>;\n}\n\n/** A viewport-space rectangle (client coordinates). */\nexport interface ViewportRect {\n top: number;\n left: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n}\n\n/** Imperative handle for building floating UI (slash / selection menus). */\nexport interface NoteEditorHandle {\n focus(): void;\n /** Caret position in viewport coordinates, or null if unavailable. */\n getCaretRect(): { x: number; y: number; height: number } | null;\n /** Bounding box of the current selection in viewport coordinates, or null. */\n getSelectionRect(): ViewportRect | null;\n /** The scrolling element, for scroll-aware positioning. */\n getScrollElement(): HTMLElement | null;\n /**\n * The content overlay element (a positioned layer that scrolls *with* the\n * text). Render floating UI into this with `position: absolute` and\n * content-relative coordinates so it rides the scroll natively instead of\n * trailing it (which causes a fixed-position toolbar to shake on scroll).\n */\n getOverlayElement(): HTMLElement | null;\n}\n\nfunction caretClientRect(): DOMRect | null {\n const s = window.getSelection();\n if (!s || s.rangeCount === 0) return null;\n const r = s.getRangeAt(0).cloneRange();\n r.collapse(s.focusNode === r.endContainer && s.focusOffset === r.endOffset ? false : true);\n const rects = r.getClientRects();\n if (rects.length) return rects[rects.length - 1];\n const b = r.getBoundingClientRect();\n if (b.height || b.width) return b;\n // Empty block (`<br>` only): a collapsed range there has no client rects, so\n // synthesize the caret from the block box + its line metrics. Without this the\n // custom caret would vanish on empty lines (the native caret is hidden).\n const node = r.startContainer;\n const el = (node.nodeType === Node.TEXT_NODE ? node.parentElement : (node as HTMLElement)) ?? null;\n if (!el) return null;\n const eb = el.getBoundingClientRect();\n const cs = getComputedStyle(el);\n const lh = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.4 || 18;\n const padL = parseFloat(cs.paddingLeft) || 0;\n const padT = parseFloat(cs.paddingTop) || 0;\n return new DOMRect(eb.left + padL, eb.top + padT, 0, lh);\n}\n\n/**\n * A contentEditable note editor: the browser owns caret, selection, trackpad,\n * native menus and IME on the live text, while edits are routed through the\n * {@link EditorController} (Y.Doc). A custom caret is drawn on top so it can be\n * branded/animated independently of the (hidden) native one.\n */\nexport const NoteEditor = forwardRef<NoteEditorHandle, NoteEditorProps>(function NoteEditor(\n { editor, className, style, maxWidth = 720, placeholder, autoFocus, readOnly, blockRenderers, atomRenderers },\n ref,\n) {\n const snapshot = useEditorSnapshot(editor);\n const scrollerRef = useRef<HTMLDivElement>(null);\n const overlayRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n const viewRef = useRef<EditorView | null>(null);\n const [focused, setFocused] = useState(false);\n const [caret, setCaret] = useState<{ x: number; y: number; h: number } | null>(null);\n\n // Keep the latest renderers reachable without recreating the view.\n const renderersRef = useRef({ blockRenderers, atomRenderers });\n renderersRef.current = { blockRenderers, atomRenderers };\n\n useImperativeHandle(\n ref,\n (): NoteEditorHandle => ({\n focus: () => contentRef.current?.focus(),\n getCaretRect: () => {\n const r = caretClientRect();\n return r ? { x: r.left, y: r.top, height: r.height || 16 } : null;\n },\n getSelectionRect: () => {\n const s = window.getSelection();\n if (!s || s.rangeCount === 0 || s.isCollapsed) return null;\n const b = s.getRangeAt(0).getBoundingClientRect();\n if (!b.width && !b.height) return null;\n return { top: b.top, left: b.left, right: b.right, bottom: b.bottom, width: b.width, height: b.height };\n },\n getScrollElement: () => scrollerRef.current,\n getOverlayElement: () => overlayRef.current,\n }),\n [],\n );\n\n // Create the imperative contentEditable view once.\n useEffect(() => {\n const el = contentRef.current;\n if (!el) return;\n const view = new EditorView(el, editor, {\n readOnly,\n renderAtom: (t) => renderersRef.current.atomRenderers?.[t],\n renderBlock: (t) => renderersRef.current.blockRenderers?.[t],\n });\n viewRef.current = view;\n return () => {\n view.destroy();\n viewRef.current = null;\n };\n }, [editor, readOnly]);\n\n // Reconcile the view when the model changes externally (app commands, undo,\n // remote). The view ignores revisions it produced itself (native typing).\n useEffect(() => {\n viewRef.current?.sync();\n }, [snapshot.revision]);\n\n useEffect(() => {\n if (autoFocus) contentRef.current?.focus();\n }, [autoFocus]);\n\n // Position the custom caret from the live DOM selection.\n useEffect(() => {\n const update = () => {\n const content = contentRef.current;\n const s = window.getSelection();\n if (!content || !s || s.rangeCount === 0 || !s.isCollapsed || !content.contains(s.anchorNode)) {\n setCaret(null);\n return;\n }\n const r = caretClientRect();\n const box = content.getBoundingClientRect();\n if (r) setCaret({ x: r.left - box.left, y: r.top - box.top, h: r.height || 18 });\n };\n document.addEventListener(\"selectionchange\", update);\n const ro = new ResizeObserver(update);\n if (contentRef.current) ro.observe(contentRef.current);\n update();\n return () => {\n document.removeEventListener(\"selectionchange\", update);\n ro.disconnect();\n };\n }, []);\n\n // Drive virtualization: keep the controller's width + viewport in sync.\n useLayoutEffect(() => {\n const sc = scrollerRef.current;\n const content = contentRef.current;\n if (!sc || !content) return;\n const sync = () => {\n editor.setWidth(content.clientWidth);\n editor.setViewport(sc.scrollTop, sc.clientHeight);\n };\n sync();\n const ro = new ResizeObserver(sync);\n ro.observe(sc);\n ro.observe(content);\n return () => ro.disconnect();\n }, [editor]);\n\n const onScroll = () => {\n const sc = scrollerRef.current;\n if (sc) editor.setViewport(sc.scrollTop, sc.clientHeight);\n };\n\n // Clicking the empty region below the content should focus the editor and put\n // the caret at the document end (the usual \"click to keep writing\" affordance).\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>) => {\n if (readOnly) return;\n // Only act on the editor's own empty surface — not on blocks (the browser\n // places the caret) and not on floating UI (menus) layered into the overlay.\n const t = e.target as HTMLElement;\n const onSurface =\n t === scrollerRef.current ||\n t === overlayRef.current ||\n t.classList.contains(\"ori-ce\") ||\n t.dataset.spacer != null;\n if (!onSurface) return;\n const content = contentRef.current;\n const blocks = content?.querySelectorAll(\"[data-block-id]\");\n const last = blocks && (blocks[blocks.length - 1] as HTMLElement | undefined);\n if (!content || !last) return;\n if (e.clientY <= last.getBoundingClientRect().bottom) return; // beside text, not below\n e.preventDefault();\n content.focus();\n const sel = window.getSelection();\n if (!sel) return;\n const range = document.createRange();\n range.selectNodeContents(last);\n range.collapse(false);\n sel.removeAllRanges();\n sel.addRange(range);\n };\n\n const showCaret = focused && !!caret && !readOnly;\n\n return (\n <div className={`ori-root${className ? ` ${className}` : \"\"}`} style={style}>\n <div className=\"ori-scroller\" ref={scrollerRef} onScroll={onScroll} onPointerDown={onPointerDown}>\n <div className=\"ori-content\" ref={overlayRef} style={{ maxWidth, marginInline: \"auto\", position: \"relative\" }}>\n <div\n className=\"ori-canvas ori-ce\"\n ref={contentRef}\n onFocus={() => setFocused(true)}\n onBlur={() => setFocused(false)}\n suppressContentEditableWarning\n />\n {showCaret && caret ? (\n <div\n className=\"ori-caret\"\n style={{ position: \"absolute\", left: caret.x, top: caret.y, height: caret.h, pointerEvents: \"none\" }}\n aria-hidden\n />\n ) : null}\n {snapshot.empty && placeholder ? (\n <div className=\"ori-placeholder\" aria-hidden>\n {placeholder}\n </div>\n ) : null}\n </div>\n </div>\n </div>\n );\n});\n","import type { BlockLayout, EditorController, InlineAtom, VisibleBlock } from \"@wingleeio/ori-core\";\nimport { createContext, useContext, type ReactNode } from \"react\";\n\n/** Props for a custom block renderer (atomic nodes: divider, image, …). */\nexport interface BlockRendererProps {\n editor: EditorController;\n block: VisibleBlock;\n /** The block's synthetic layout (atomic blocks: one line, no fragments). */\n layout: BlockLayout;\n}\nexport type BlockRenderer = (props: BlockRendererProps) => ReactNode;\n\n/** Props for a custom inline-atom renderer (mention chip, inline math, …). */\nexport interface AtomRendererProps {\n editor: EditorController;\n atom: InlineAtom;\n}\nexport type AtomRenderer = (props: AtomRendererProps) => ReactNode;\n\nexport interface Renderers {\n blocks: Record<string, BlockRenderer>;\n atoms: Record<string, AtomRenderer>;\n}\n\nconst EMPTY: Renderers = { blocks: {}, atoms: {} };\n\nconst RenderersContext = createContext<Renderers>(EMPTY);\nexport const RenderersProvider = RenderersContext.Provider;\nexport const useRenderers = (): Renderers => useContext(RenderersContext);\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -90,6 +90,13 @@ interface NoteEditorHandle {
|
|
|
90
90
|
getSelectionRect(): ViewportRect | null;
|
|
91
91
|
/** The scrolling element, for scroll-aware positioning. */
|
|
92
92
|
getScrollElement(): HTMLElement | null;
|
|
93
|
+
/**
|
|
94
|
+
* The content overlay element (a positioned layer that scrolls *with* the
|
|
95
|
+
* text). Render floating UI into this with `position: absolute` and
|
|
96
|
+
* content-relative coordinates so it rides the scroll natively instead of
|
|
97
|
+
* trailing it (which causes a fixed-position toolbar to shake on scroll).
|
|
98
|
+
*/
|
|
99
|
+
getOverlayElement(): HTMLElement | null;
|
|
93
100
|
}
|
|
94
101
|
/**
|
|
95
102
|
* A contentEditable note editor: the browser owns caret, selection, trackpad,
|
package/dist/index.d.ts
CHANGED
|
@@ -90,6 +90,13 @@ interface NoteEditorHandle {
|
|
|
90
90
|
getSelectionRect(): ViewportRect | null;
|
|
91
91
|
/** The scrolling element, for scroll-aware positioning. */
|
|
92
92
|
getScrollElement(): HTMLElement | null;
|
|
93
|
+
/**
|
|
94
|
+
* The content overlay element (a positioned layer that scrolls *with* the
|
|
95
|
+
* text). Render floating UI into this with `position: absolute` and
|
|
96
|
+
* content-relative coordinates so it rides the scroll natively instead of
|
|
97
|
+
* trailing it (which causes a fixed-position toolbar to shake on scroll).
|
|
98
|
+
*/
|
|
99
|
+
getOverlayElement(): HTMLElement | null;
|
|
93
100
|
}
|
|
94
101
|
/**
|
|
95
102
|
* A contentEditable note editor: the browser owns caret, selection, trackpad,
|
package/dist/index.js
CHANGED
|
@@ -35,8 +35,129 @@ function useActiveMarks(editor) {
|
|
|
35
35
|
return editor.getActiveMarks();
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
// src/ce/
|
|
38
|
+
// src/ce/clipboard.ts
|
|
39
|
+
var ORI_MIME = "application/x-ori-inline";
|
|
40
|
+
function atomPlain(it) {
|
|
41
|
+
const d = it.atom?.data ?? {};
|
|
42
|
+
const label = d.label ?? d.text ?? d.name;
|
|
43
|
+
return label != null ? `@${String(label)}` : "";
|
|
44
|
+
}
|
|
45
|
+
function blockPlain(items) {
|
|
46
|
+
return items.map((it) => it.atom ? atomPlain(it) : it.text).join("");
|
|
47
|
+
}
|
|
48
|
+
var MARK_TAGS = [
|
|
49
|
+
["bold", "strong"],
|
|
50
|
+
["italic", "em"],
|
|
51
|
+
["underline", "u"],
|
|
52
|
+
["strike", "s"],
|
|
53
|
+
["code", "code"]
|
|
54
|
+
];
|
|
39
55
|
function esc(s) {
|
|
56
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
57
|
+
}
|
|
58
|
+
function runHtml(it) {
|
|
59
|
+
if (it.atom) return `<span>${esc(atomPlain(it))}</span>`;
|
|
60
|
+
let html = esc(it.text);
|
|
61
|
+
const m = it.marks ?? {};
|
|
62
|
+
for (const [k, tag] of MARK_TAGS) if (m[k]) html = `<${tag}>${html}</${tag}>`;
|
|
63
|
+
if (m.link) html = `<a href="${esc(m.link)}">${html}</a>`;
|
|
64
|
+
return html;
|
|
65
|
+
}
|
|
66
|
+
function serializeSelection(blocks) {
|
|
67
|
+
const text = blocks.map(blockPlain).join("\n");
|
|
68
|
+
const html = blocks.map((items) => `<p>${items.map(runHtml).join("") || "<br>"}</p>`).join("");
|
|
69
|
+
const json = JSON.stringify({
|
|
70
|
+
v: 1,
|
|
71
|
+
blocks: blocks.map(
|
|
72
|
+
(items) => items.map(
|
|
73
|
+
(it) => it.atom ? { embed: it.atom.data ?? { type: it.atom.type } } : { text: it.text, marks: it.marks }
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
});
|
|
77
|
+
return { text, html, json };
|
|
78
|
+
}
|
|
79
|
+
function deserializeOri(json) {
|
|
80
|
+
try {
|
|
81
|
+
const data = JSON.parse(json);
|
|
82
|
+
if (!Array.isArray(data.blocks)) return null;
|
|
83
|
+
return data.blocks.map(
|
|
84
|
+
(items) => items.map(
|
|
85
|
+
(it) => it.embed ? { text: "", start: 0, atom: { type: String(it.embed.type ?? ""), width: 0, data: it.embed } } : { text: it.text ?? "", start: 0, marks: it.marks }
|
|
86
|
+
)
|
|
87
|
+
);
|
|
88
|
+
} catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function textToBlocks(text) {
|
|
93
|
+
return text.replace(/\r\n?/g, "\n").split("\n").map((line) => line ? [{ text: line, start: 0 }] : []);
|
|
94
|
+
}
|
|
95
|
+
function htmlToBlocks(html) {
|
|
96
|
+
if (typeof DOMParser === "undefined") return [];
|
|
97
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
98
|
+
const blocks = [];
|
|
99
|
+
let cur = [];
|
|
100
|
+
const flush = () => {
|
|
101
|
+
blocks.push(cur);
|
|
102
|
+
cur = [];
|
|
103
|
+
};
|
|
104
|
+
const push = (text, marks) => {
|
|
105
|
+
if (!text) return;
|
|
106
|
+
cur.push({ text, start: 0, marks: Object.keys(marks).length ? { ...marks } : void 0 });
|
|
107
|
+
};
|
|
108
|
+
const BLOCK = /* @__PURE__ */ new Set([
|
|
109
|
+
"P",
|
|
110
|
+
"DIV",
|
|
111
|
+
"H1",
|
|
112
|
+
"H2",
|
|
113
|
+
"H3",
|
|
114
|
+
"H4",
|
|
115
|
+
"H5",
|
|
116
|
+
"H6",
|
|
117
|
+
"LI",
|
|
118
|
+
"BLOCKQUOTE",
|
|
119
|
+
"PRE",
|
|
120
|
+
"SECTION",
|
|
121
|
+
"ARTICLE",
|
|
122
|
+
"UL",
|
|
123
|
+
"OL"
|
|
124
|
+
]);
|
|
125
|
+
const walk = (node, marks) => {
|
|
126
|
+
for (const child of Array.from(node.childNodes)) {
|
|
127
|
+
if (child.nodeType === Node.TEXT_NODE) {
|
|
128
|
+
push((child.textContent ?? "").replace(/\s+/g, " "), marks);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (child.nodeType !== Node.ELEMENT_NODE) continue;
|
|
132
|
+
const el = child;
|
|
133
|
+
const tag = el.tagName;
|
|
134
|
+
if (tag === "BR") {
|
|
135
|
+
if (cur.length) flush();
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const m = { ...marks };
|
|
139
|
+
if (tag === "STRONG" || tag === "B") m.bold = true;
|
|
140
|
+
if (tag === "EM" || tag === "I") m.italic = true;
|
|
141
|
+
if (tag === "U" || tag === "INS") m.underline = true;
|
|
142
|
+
if (tag === "S" || tag === "STRIKE" || tag === "DEL") m.strike = true;
|
|
143
|
+
if (tag === "CODE" || tag === "KBD" || tag === "TT") m.code = true;
|
|
144
|
+
const href = tag === "A" ? el.getAttribute("href") : null;
|
|
145
|
+
if (href) m.link = href;
|
|
146
|
+
const isBlock = BLOCK.has(tag);
|
|
147
|
+
if (isBlock && cur.length) flush();
|
|
148
|
+
walk(el, m);
|
|
149
|
+
if (isBlock) flush();
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
walk(doc.body, {});
|
|
153
|
+
if (cur.length) flush();
|
|
154
|
+
while (blocks.length && blocks[0].length === 0) blocks.shift();
|
|
155
|
+
while (blocks.length && blocks[blocks.length - 1].length === 0) blocks.pop();
|
|
156
|
+
return blocks;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/ce/dom.ts
|
|
160
|
+
function esc2(s) {
|
|
40
161
|
return typeof CSS !== "undefined" && CSS.escape ? CSS.escape(s) : s.replace(/["\\]/g, "\\$&");
|
|
41
162
|
}
|
|
42
163
|
function blockElOf(node, root) {
|
|
@@ -81,7 +202,7 @@ function spanLen(span) {
|
|
|
81
202
|
return span.dataset.len != null ? Number(span.dataset.len) : (span.textContent ?? "").length;
|
|
82
203
|
}
|
|
83
204
|
function modelToDom(root, blockId, offset) {
|
|
84
|
-
const blockEl = root.querySelector(`[data-block-id="${
|
|
205
|
+
const blockEl = root.querySelector(`[data-block-id="${esc2(blockId)}"]`);
|
|
85
206
|
if (!blockEl) return null;
|
|
86
207
|
const spans = Array.from(blockEl.querySelectorAll("[data-off]"));
|
|
87
208
|
if (spans.length === 0) {
|
|
@@ -165,6 +286,9 @@ var EditorView = class {
|
|
|
165
286
|
this.composing = false;
|
|
166
287
|
this.onInput();
|
|
167
288
|
});
|
|
289
|
+
on("copy", (e) => this.onClipboard(e, false));
|
|
290
|
+
on("cut", (e) => this.onClipboard(e, true));
|
|
291
|
+
on("paste", (e) => this.onPaste(e));
|
|
168
292
|
const onSelChange = () => {
|
|
169
293
|
if (this.applyingModel || this.composing) return;
|
|
170
294
|
const sel = this.readSelection();
|
|
@@ -256,7 +380,7 @@ var EditorView = class {
|
|
|
256
380
|
const bot = this.root.lastElementChild;
|
|
257
381
|
if (bot && bot.style.height !== `${botH}px`) bot.style.height = `${botH}px`;
|
|
258
382
|
for (const vb of vis) {
|
|
259
|
-
const el = this.root.querySelector(`[data-block-id="${
|
|
383
|
+
const el = this.root.querySelector(`[data-block-id="${esc2(vb.id)}"]`);
|
|
260
384
|
if (!el) continue;
|
|
261
385
|
const sig = this.sig(vb.id);
|
|
262
386
|
if (el.dataset.sig !== sig) {
|
|
@@ -418,9 +542,10 @@ var EditorView = class {
|
|
|
418
542
|
e.preventDefault();
|
|
419
543
|
if (t === "deleteContentForward") ed.deleteForward();
|
|
420
544
|
else ed.deleteBackward();
|
|
421
|
-
} else if (t === "insertText" || t === "insertReplacementText"
|
|
545
|
+
} else if (t === "insertText" || t === "insertReplacementText") {
|
|
422
546
|
e.preventDefault();
|
|
423
|
-
|
|
547
|
+
if (!collapsed) ed.deleteBackward();
|
|
548
|
+
const text = e.data ?? "";
|
|
424
549
|
if (text) ed.insertText(text);
|
|
425
550
|
} else if (t === "insertLineBreak") {
|
|
426
551
|
e.preventDefault();
|
|
@@ -467,6 +592,45 @@ var EditorView = class {
|
|
|
467
592
|
off += len;
|
|
468
593
|
}
|
|
469
594
|
}
|
|
595
|
+
// --- clipboard ---------------------------------------------------------
|
|
596
|
+
/** Copy/cut: put plain, HTML and a private (mark-preserving) payload on the clipboard. */
|
|
597
|
+
onClipboard(e, isCut) {
|
|
598
|
+
const blocks = this.editor.getSelectionInline();
|
|
599
|
+
if (!blocks.length || !e.clipboardData) return;
|
|
600
|
+
e.preventDefault();
|
|
601
|
+
const { text, html, json } = serializeSelection(blocks);
|
|
602
|
+
e.clipboardData.setData("text/plain", text);
|
|
603
|
+
e.clipboardData.setData("text/html", html);
|
|
604
|
+
e.clipboardData.setData(ORI_MIME, json);
|
|
605
|
+
if (isCut && !this.opts.readOnly) {
|
|
606
|
+
this.editor.deleteBackward();
|
|
607
|
+
this.commit();
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
/** Paste: restore marks from our payload, else parse external HTML, else plain text. */
|
|
611
|
+
onPaste(e) {
|
|
612
|
+
if (this.opts.readOnly || !e.clipboardData) return;
|
|
613
|
+
e.preventDefault();
|
|
614
|
+
const sel = this.readSelection();
|
|
615
|
+
if (sel) {
|
|
616
|
+
this.editor.setSelection(sel);
|
|
617
|
+
if (!isCollapsed(sel)) this.editor.deleteBackward();
|
|
618
|
+
}
|
|
619
|
+
const cd = e.clipboardData;
|
|
620
|
+
const ori = cd.getData(ORI_MIME);
|
|
621
|
+
const html = cd.getData("text/html");
|
|
622
|
+
let blocks = ori ? deserializeOri(ori) : null;
|
|
623
|
+
if (!blocks?.length && html) blocks = htmlToBlocks(html);
|
|
624
|
+
if (!blocks?.length) blocks = textToBlocks(cd.getData("text/plain"));
|
|
625
|
+
this.pasteBlocks(blocks);
|
|
626
|
+
this.commit();
|
|
627
|
+
}
|
|
628
|
+
pasteBlocks(blocks) {
|
|
629
|
+
blocks.forEach((items, i) => {
|
|
630
|
+
if (i > 0) this.editor.insertParagraphBreak();
|
|
631
|
+
if (items.length) this.editor.insertInline(items);
|
|
632
|
+
});
|
|
633
|
+
}
|
|
470
634
|
};
|
|
471
635
|
function caretClientRect() {
|
|
472
636
|
const s = window.getSelection();
|
|
@@ -490,6 +654,7 @@ function caretClientRect() {
|
|
|
490
654
|
var NoteEditor = forwardRef(function NoteEditor2({ editor, className, style, maxWidth = 720, placeholder, autoFocus, readOnly, blockRenderers, atomRenderers }, ref) {
|
|
491
655
|
const snapshot = useEditorSnapshot(editor);
|
|
492
656
|
const scrollerRef = useRef(null);
|
|
657
|
+
const overlayRef = useRef(null);
|
|
493
658
|
const contentRef = useRef(null);
|
|
494
659
|
const viewRef = useRef(null);
|
|
495
660
|
const [focused, setFocused] = useState(false);
|
|
@@ -511,7 +676,8 @@ var NoteEditor = forwardRef(function NoteEditor2({ editor, className, style, max
|
|
|
511
676
|
if (!b.width && !b.height) return null;
|
|
512
677
|
return { top: b.top, left: b.left, right: b.right, bottom: b.bottom, width: b.width, height: b.height };
|
|
513
678
|
},
|
|
514
|
-
getScrollElement: () => scrollerRef.current
|
|
679
|
+
getScrollElement: () => scrollerRef.current,
|
|
680
|
+
getOverlayElement: () => overlayRef.current
|
|
515
681
|
}),
|
|
516
682
|
[]
|
|
517
683
|
);
|
|
@@ -576,7 +742,9 @@ var NoteEditor = forwardRef(function NoteEditor2({ editor, className, style, max
|
|
|
576
742
|
};
|
|
577
743
|
const onPointerDown = (e) => {
|
|
578
744
|
if (readOnly) return;
|
|
579
|
-
|
|
745
|
+
const t = e.target;
|
|
746
|
+
const onSurface = t === scrollerRef.current || t === overlayRef.current || t.classList.contains("ori-ce") || t.dataset.spacer != null;
|
|
747
|
+
if (!onSurface) return;
|
|
580
748
|
const content = contentRef.current;
|
|
581
749
|
const blocks = content?.querySelectorAll("[data-block-id]");
|
|
582
750
|
const last = blocks && blocks[blocks.length - 1];
|
|
@@ -593,7 +761,7 @@ var NoteEditor = forwardRef(function NoteEditor2({ editor, className, style, max
|
|
|
593
761
|
sel.addRange(range);
|
|
594
762
|
};
|
|
595
763
|
const showCaret = focused && !!caret && !readOnly;
|
|
596
|
-
return /* @__PURE__ */ jsx("div", { className: `ori-root${className ? ` ${className}` : ""}`, style, children: /* @__PURE__ */ jsx("div", { className: "ori-scroller", ref: scrollerRef, onScroll, onPointerDown, children: /* @__PURE__ */ jsxs("div", { className: "ori-content", style: { maxWidth, marginInline: "auto", position: "relative" }, children: [
|
|
764
|
+
return /* @__PURE__ */ jsx("div", { className: `ori-root${className ? ` ${className}` : ""}`, style, children: /* @__PURE__ */ jsx("div", { className: "ori-scroller", ref: scrollerRef, onScroll, onPointerDown, children: /* @__PURE__ */ jsxs("div", { className: "ori-content", ref: overlayRef, style: { maxWidth, marginInline: "auto", position: "relative" }, children: [
|
|
597
765
|
/* @__PURE__ */ jsx(
|
|
598
766
|
"div",
|
|
599
767
|
{
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useEditor.ts","../src/hooks.ts","../src/ce/dom.ts","../src/ce/view.ts","../src/NoteEditor.tsx","../src/renderers.tsx"],"names":["textNode","NoteEditor","useRef","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import {\n EditorController,\n createCanvasMeasurer,\n type EditorSchema,\n type Measurer,\n type Typography,\n} from \"@wingleeio/ori-core\";\nimport { useEffect, useRef } from \"react\";\nimport type * as Y from \"yjs\";\n\nexport interface UseEditorOptions {\n /** Existing note `Y.Doc`. When switching notes, remount via `key` instead. */\n doc?: Y.Doc;\n typography?: Typography;\n measurer?: Measurer;\n overscan?: number;\n blockSpacing?: number;\n /** Custom block/atom nodes, merged over the built-ins. */\n schema?: Partial<EditorSchema>;\n}\n\n/**\n * Create (once) and own an {@link EditorController} for the lifetime of the\n * component. To switch documents, give the hosting component a `key` so it\n * remounts with a fresh controller.\n *\n * The controller is reconnected on mount and disconnected on unmount rather than\n * destroyed, so React StrictMode's dev mount → unmount → remount cycle reuses the\n * same controller (with all its state) instead of leaving a torn-down one behind.\n */\nexport function useEditor(options: UseEditorOptions = {}): EditorController {\n const ref = useRef<EditorController | null>(null);\n if (ref.current === null) {\n ref.current = new EditorController({\n doc: options.doc,\n measurer: options.measurer ?? createCanvasMeasurer(),\n typography: options.typography,\n overscan: options.overscan,\n blockSpacing: options.blockSpacing,\n schema: options.schema,\n });\n }\n useEffect(() => {\n const editor = ref.current;\n editor?.connect();\n return () => editor?.disconnect();\n }, []);\n return ref.current;\n}\n","import type { EditorController, EditorSnapshot, Marks } from \"@wingleeio/ori-core\";\nimport { useSyncExternalStore } from \"react\";\n\n/** Subscribe a component to the controller's snapshot stream. */\nexport function useEditorSnapshot(editor: EditorController): EditorSnapshot {\n return useSyncExternalStore(editor.subscribe, editor.getSnapshot, editor.getSnapshot);\n}\n\n/**\n * The marks active at the current selection. Recomputed whenever the editor\n * notifies (selection move, edit, or pending-mark toggle), so toolbars stay in\n * sync without their own subscription.\n */\nexport function useActiveMarks(editor: EditorController): Marks {\n const snapshot = useEditorSnapshot(editor);\n // `revision` changes on every notify; reading it ties this to the store.\n void snapshot.revision;\n return editor.getActiveMarks();\n}\n","import type { InlineItem } from \"@wingleeio/ori-core\";\n\n/** CSS.escape with a fallback (jsdom lacks it). */\nexport function esc(s: string): string {\n return typeof CSS !== \"undefined\" && CSS.escape ? CSS.escape(s) : s.replace(/[\"\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Imperative DOM helpers for the contentEditable view. Each block is a\n * block-level element carrying `data-block-id`; its inline runs are spans\n * carrying `data-off` (their start offset in the block) so DOM positions map\n * back to {blockId, offset} and vice-versa.\n */\n\nexport const BLOCK_SEL = \"[data-block-id]\";\n\nexport function blockElOf(node: Node | null, root: HTMLElement): HTMLElement | null {\n let n: Node | null = node;\n while (n && n !== root) {\n if (n instanceof HTMLElement && n.dataset.blockId) return n;\n n = n.parentNode;\n }\n return null;\n}\n\nfunction spanOf(node: Node | null): HTMLElement | null {\n let n: Node | null = node;\n while (n) {\n if (n instanceof HTMLElement && n.dataset.off != null) return n;\n n = n.parentNode;\n }\n return null;\n}\n\n/** Map a DOM (node, offset) to a {blockId, offset} model position. */\nexport function domToModel(\n root: HTMLElement,\n node: Node | null,\n offset: number,\n): { blockId: string; offset: number } | null {\n const blockEl = blockElOf(node, root);\n if (!blockEl) return null;\n const blockId = blockEl.dataset.blockId as string;\n\n if (node && node.nodeType === Node.TEXT_NODE) {\n const span = spanOf(node);\n const base = span ? Number(span.dataset.off) : 0;\n return { blockId, offset: base + offset };\n }\n\n // node is an element; `offset` is a child index. Resolve via the child spans.\n const el = node as HTMLElement;\n if (el.dataset?.off != null) {\n // selection landed on a span boundary\n return { blockId, offset: Number(el.dataset.off) + (offset > 0 ? spanLen(el) : 0) };\n }\n const kids = Array.from(el.childNodes);\n for (let i = offset; i < kids.length; i++) {\n const k = kids[i];\n if (k instanceof HTMLElement && k.dataset.off != null) return { blockId, offset: Number(k.dataset.off) };\n }\n // past the last span → block end\n let end = 0;\n for (const k of kids) if (k instanceof HTMLElement && k.dataset.off != null) end = Math.max(end, Number(k.dataset.off) + spanLen(k));\n return { blockId, offset: end };\n}\n\nfunction spanLen(span: HTMLElement): number {\n return span.dataset.len != null ? Number(span.dataset.len) : (span.textContent ?? \"\").length;\n}\n\n/** Find the DOM (node, offset) for a {blockId, offset} model position. */\nexport function modelToDom(\n root: HTMLElement,\n blockId: string,\n offset: number,\n): { node: Node; offset: number } | null {\n const blockEl = root.querySelector(`[data-block-id=\"${esc(blockId)}\"]`) as HTMLElement | null;\n if (!blockEl) return null;\n const spans = Array.from(blockEl.querySelectorAll(\"[data-off]\")) as HTMLElement[];\n if (spans.length === 0) {\n return { node: blockEl, offset: 0 }; // empty block\n }\n for (const span of spans) {\n const start = Number(span.dataset.off);\n const len = spanLen(span);\n if (offset <= start + len) {\n if (span.dataset.atom != null) {\n // atom: place before or after it (offset is start or start+1)\n const idx = Array.prototype.indexOf.call(blockEl.childNodes, span);\n return { node: blockEl, offset: offset <= start ? idx : idx + 1 };\n }\n const textNode = span.firstChild ?? span;\n return { node: textNode, offset: Math.max(0, Math.min(offset - start, (textNode.textContent ?? \"\").length)) };\n }\n }\n // past everything → after the last span\n const last = spans[spans.length - 1];\n const textNode = last.firstChild ?? last;\n return { node: textNode, offset: (textNode.textContent ?? \"\").length };\n}\n\nfunction markClass(marks: InlineItem[\"marks\"]): string {\n const m = marks ?? {};\n const cls = [\"ori-frag\"];\n if (m.bold) cls.push(\"ori-m-bold\");\n if (m.italic) cls.push(\"ori-m-italic\");\n if (m.underline) cls.push(\"ori-m-underline\");\n if (m.strike) cls.push(\"ori-m-strike\");\n if (m.code) cls.push(\"ori-frag-code\");\n if (m.link) cls.push(\"ori-frag-link\");\n return cls.join(\" \");\n}\n\n/** Build the inline run DOM for a block (text spans only; atoms handled by the view). */\nexport function buildRun(item: InlineItem): HTMLElement {\n const span = document.createElement(\"span\");\n span.className = markClass(item.marks);\n span.dataset.off = String(item.start);\n span.dataset.len = String(item.text.length);\n span.textContent = item.text;\n return span;\n}\n","import type { EditorController } from \"@wingleeio/ori-core\";\nimport { isCollapsed } from \"@wingleeio/ori-core\";\nimport type { ReactNode } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport type { AtomRenderer, BlockRenderer } from \"../renderers\";\nimport { blockElOf, buildRun, domToModel, esc, modelToDom } from \"./dom\";\n\nconst PLACEHOLDER = \"\";\n\nexport interface ViewOptions {\n readOnly?: boolean;\n renderAtom: (type: string) => AtomRenderer | undefined;\n renderBlock: (type: string) => BlockRenderer | undefined;\n}\n\n/**\n * Imperative contentEditable view over an {@link EditorController}. The browser\n * owns caret / selection / trackpad / menus / IME on the live text; we intercept\n * structural + cross-block edits (beforeinput) and route them through the\n * controller, let smooth in-block typing flow natively and read it back, and\n * keep the DOM selection and the controller selection in lock-step.\n */\nexport class EditorView {\n private roots = new Map<HTMLElement, Root>();\n private composing = false;\n private applyingModel = false;\n private detachers: Array<() => void> = [];\n /** The model revision the DOM currently reflects (so external changes — remote\n * edits, app commands — re-render, but our own edits don't clobber the caret). */\n private lastRevision = -1;\n\n constructor(\n private root: HTMLElement,\n private editor: EditorController,\n private opts: ViewOptions,\n ) {\n root.setAttribute(\"contenteditable\", opts.readOnly ? \"false\" : \"true\");\n root.setAttribute(\"spellcheck\", opts.readOnly ? \"false\" : \"true\");\n root.setAttribute(\"role\", \"textbox\");\n root.setAttribute(\"aria-multiline\", \"true\");\n this.renderBlocks();\n this.lastRevision = this.rev();\n\n const on = <K extends keyof HTMLElementEventMap>(\n t: K,\n h: (e: HTMLElementEventMap[K]) => void,\n o?: AddEventListenerOptions,\n ) => {\n root.addEventListener(t, h as EventListener, o);\n this.detachers.push(() => root.removeEventListener(t, h as EventListener, o));\n };\n on(\"beforeinput\", (e) => this.onBeforeInput(e as InputEvent));\n on(\"input\", () => this.onInput());\n on(\"keydown\", (e) => this.onKeyDown(e as KeyboardEvent));\n on(\"blur\", () => {\n // Clicking outside the editor drops the selection (so a selection toolbar\n // hides). Defer so we can ignore a window/tab blur and focus-preserving\n // clicks (e.g. toolbar buttons that re-focus the editor).\n setTimeout(() => {\n if (document.activeElement === this.root || !document.hasFocus()) return;\n const sel = this.editor.getSelection();\n if (sel && !isCollapsed(sel)) {\n this.editor.collapse(sel.focus);\n this.lastRevision = this.rev();\n }\n }, 0);\n });\n on(\"compositionstart\", () => (this.composing = true));\n on(\"compositionend\", () => {\n this.composing = false;\n this.onInput();\n });\n\n const onSelChange = () => {\n if (this.applyingModel || this.composing) return;\n const sel = this.readSelection();\n if (!sel) return;\n this.editor.setSelection(sel);\n // DOM is already the source of truth here — record the revision so the\n // resulting React sync() doesn't write the selection back and collapse it.\n this.lastRevision = this.rev();\n };\n document.addEventListener(\"selectionchange\", onSelChange);\n this.detachers.push(() => document.removeEventListener(\"selectionchange\", onSelChange));\n }\n\n destroy() {\n this.detachers.forEach((d) => d());\n this.roots.forEach((r) => r.unmount());\n this.roots.clear();\n }\n\n focus() {\n this.root.focus();\n }\n\n // --- rendering ---------------------------------------------------------\n\n private rev(): number {\n return this.editor.getSnapshot().revision;\n }\n\n /**\n * Called by React on every model change. Only re-renders when the model moved\n * ahead of what we last drew (an *external* change — app command, undo, remote);\n * our own edits already updated the DOM and must not be clobbered.\n */\n sync() {\n const rev = this.rev();\n if (rev === this.lastRevision) return;\n // Only restore the DOM selection when the *content* changed (app command,\n // undo, remote). A selection-only change is already correct in the DOM, and\n // writing it back would fight (and collapse) the user's native selection.\n const changed = this.renderBlocks();\n if (changed) this.writeSelection();\n this.lastRevision = rev;\n }\n\n /** After a controlled (preventDefault'd) edit: re-render + restore the caret. */\n private commit() {\n this.renderBlocks();\n this.writeSelection();\n this.lastRevision = this.rev();\n }\n\n /** A content signature for a block, so unchanged blocks aren't re-rendered. */\n private sig(id: string): string {\n return this.editor.getBlockType(id) + \"|\" + JSON.stringify(this.editor.getInline(id));\n }\n\n /**\n * Reconcile the DOM to the *visible window* of blocks (virtualization): a top\n * spacer, the windowed blocks, then a bottom spacer — heights from the\n * controller's offscreen measurement. On-screen blocks are reused by id so a\n * caret inside one survives a scroll. Returns true if the DOM was mutated.\n */\n private renderBlocks(): boolean {\n let changed = false;\n const snap = this.editor.getSnapshot();\n const vis = snap.visible;\n const topH = vis.length ? vis[0].top : 0;\n const botH = vis.length\n ? Math.max(0, snap.totalHeight - (vis[vis.length - 1].top + vis[vis.length - 1].height))\n : Math.max(0, snap.totalHeight);\n\n const TOP = \"\u0000top\";\n const BOTTOM = \"\u0000bottom\";\n const want = [TOP, ...vis.map((v) => v.id), BOTTOM];\n const keyOf = (el: Element) => {\n const e = el as HTMLElement;\n return e.dataset.spacer ? \"\u0000\" + e.dataset.spacer : (e.dataset.blockId ?? \"\");\n };\n const have = new Map<string, HTMLElement>();\n for (const c of Array.from(this.root.children)) have.set(keyOf(c), c as HTMLElement);\n\n let prev: HTMLElement | null = null;\n for (const k of want) {\n let el: HTMLElement | undefined = have.get(k);\n if (el) {\n have.delete(k);\n } else {\n el = k === TOP || k === BOTTOM ? this.makeSpacer(k.slice(1)) : this.makeBlock(k);\n changed = true;\n }\n const anchor: ChildNode | null = prev ? prev.nextSibling : this.root.firstChild;\n if (anchor !== el) {\n this.root.insertBefore(el, anchor);\n changed = true;\n }\n prev = el;\n }\n for (const el of have.values()) {\n if (el.dataset.blockId) this.unmountRootsIn(el);\n el.remove();\n changed = true;\n }\n\n const top = this.root.firstElementChild as HTMLElement | null;\n if (top && top.style.height !== `${topH}px`) top.style.height = `${topH}px`;\n const bot = this.root.lastElementChild as HTMLElement | null;\n if (bot && bot.style.height !== `${botH}px`) bot.style.height = `${botH}px`;\n\n for (const vb of vis) {\n const el = this.root.querySelector(`[data-block-id=\"${esc(vb.id)}\"]`) as HTMLElement | null;\n if (!el) continue;\n const sig = this.sig(vb.id);\n if (el.dataset.sig !== sig) {\n el.dataset.sig = sig;\n this.renderBlockInner(el, vb.id);\n changed = true;\n }\n }\n return changed;\n }\n\n private makeBlock(id: string): HTMLElement {\n const el = document.createElement(\"div\");\n el.dataset.blockId = id;\n return el;\n }\n\n private makeSpacer(which: string): HTMLElement {\n const el = document.createElement(\"div\");\n el.dataset.spacer = which;\n el.setAttribute(\"contenteditable\", \"false\");\n el.setAttribute(\"aria-hidden\", \"true\");\n el.style.userSelect = \"none\";\n el.style.pointerEvents = \"none\";\n return el;\n }\n\n private renderBlockInner(el: HTMLElement, id: string) {\n this.unmountRootsIn(el);\n const type = this.editor.getBlockType(id);\n el.className = `ori-block ori-block-${type}`;\n\n const blockRenderer = this.opts.renderBlock(type);\n if (blockRenderer) {\n el.contentEditable = \"false\";\n el.textContent = \"\";\n const root = createRoot(el);\n root.render(blockRenderer({ editor: this.editor, block: { id, type, index: 0, top: 0, height: 0 }, layout: this.editor.getLayout(id)! }) as ReactNode);\n this.roots.set(el, root);\n return;\n }\n el.contentEditable = \"inherit\";\n el.textContent = \"\";\n const items = this.editor.getInline(id);\n if (items.length === 0) {\n el.appendChild(document.createElement(\"br\")); // keep an empty block selectable\n return;\n }\n for (const item of items) {\n if (item.atom) {\n const span = document.createElement(\"span\");\n span.className = \"ori-atom\";\n span.contentEditable = \"false\";\n span.dataset.atom = \"true\";\n span.dataset.off = String(item.start);\n span.dataset.len = \"1\";\n el.appendChild(span);\n const renderer = this.opts.renderAtom(item.atom.type);\n if (renderer) {\n const r = createRoot(span);\n r.render(renderer({ editor: this.editor, atom: item.atom }) as ReactNode);\n this.roots.set(span, r);\n }\n } else {\n el.appendChild(buildRun(item));\n }\n }\n }\n\n private unmountRootsIn(el: HTMLElement) {\n for (const [node, root] of this.roots) {\n if (el === node || el.contains(node)) {\n root.unmount();\n this.roots.delete(node);\n }\n }\n }\n\n // --- selection ---------------------------------------------------------\n\n private readSelection() {\n const s = window.getSelection();\n if (!s || s.rangeCount === 0 || !this.root.contains(s.anchorNode)) return null;\n const a = domToModel(this.root, s.anchorNode, s.anchorOffset);\n const f = domToModel(this.root, s.focusNode, s.focusOffset);\n if (!a || !f) return null;\n return { anchor: { blockId: a.blockId, offset: a.offset }, focus: { blockId: f.blockId, offset: f.offset } };\n }\n\n /** Push the controller's selection back into the DOM (after a model op). */\n private writeSelection() {\n const sel = this.editor.getSelection();\n if (!sel) return;\n const a = modelToDom(this.root, sel.anchor.blockId, sel.anchor.offset);\n const f = modelToDom(this.root, sel.focus.blockId, sel.focus.offset);\n if (!a || !f) return;\n const r = document.createRange();\n const s = window.getSelection();\n if (!s) return;\n this.applyingModel = true;\n try {\n r.setStart(a.node, a.offset);\n s.removeAllRanges();\n s.addRange(r);\n s.extend(f.node, f.offset);\n } catch {\n /* node detached mid-reconcile */\n } finally {\n this.applyingModel = false;\n }\n }\n\n /** The block text as the model sees it (atoms collapse to one placeholder). */\n private domBlockText(el: HTMLElement): string {\n let out = \"\";\n for (const child of Array.from(el.childNodes)) {\n if (child instanceof HTMLElement && child.dataset.atom != null) {\n out += PLACEHOLDER;\n } else {\n out += child.textContent ?? \"\";\n }\n }\n return out;\n }\n\n // --- input -------------------------------------------------------------\n\n /** Formatting + history shortcuts (the browser fires these as keydown). */\n private onKeyDown(e: KeyboardEvent) {\n if (this.opts.readOnly) return;\n const mod = e.metaKey || e.ctrlKey;\n if (!mod || e.altKey) return;\n const k = e.key.toLowerCase();\n const mark = ({ b: \"bold\", i: \"italic\", u: \"underline\", e: \"code\" } as const)[k];\n if (mark) {\n e.preventDefault();\n const sel = this.readSelection();\n if (sel) this.editor.setSelection(sel);\n this.editor.toggleMark(mark);\n this.commit();\n } else if (k === \"z\") {\n e.preventDefault();\n if (e.shiftKey) this.editor.redo();\n else this.editor.undo();\n this.commit();\n } else if (k === \"y\") {\n e.preventDefault();\n this.editor.redo();\n this.commit();\n }\n }\n\n private onBeforeInput(e: InputEvent) {\n if (this.opts.readOnly) {\n e.preventDefault();\n return;\n }\n const sel = this.readSelection();\n if (!sel) return;\n this.editor.setSelection(sel);\n const collapsed = isCollapsed(sel);\n const startOffset = this.editor.orderedSelection()?.start.offset ?? sel.focus.offset;\n const t = e.inputType;\n\n // Native fast path: collapsed in-block typing / deletion. The browser mutates\n // a single text node; onInput reads it back. Keeps autocorrect/IME native.\n if (collapsed && (t === \"insertText\" || t === \"insertCompositionText\" || t === \"insertReplacementText\")) return;\n if (collapsed && t === \"deleteContentForward\") return;\n if (collapsed && t === \"deleteContentBackward\" && startOffset > 0) return;\n\n // Everything else (structural + cross-block) is handled through the controller.\n const ed = this.editor;\n if (t === \"insertParagraph\") {\n e.preventDefault();\n ed.insertParagraphBreak();\n } else if (t.startsWith(\"delete\")) {\n e.preventDefault();\n if (t === \"deleteContentForward\") ed.deleteForward();\n else ed.deleteBackward();\n } else if (t === \"insertText\" || t === \"insertReplacementText\" || t === \"insertFromPaste\") {\n e.preventDefault();\n const text = e.data ?? e.dataTransfer?.getData(\"text/plain\") ?? \"\";\n if (text) ed.insertText(text);\n } else if (t === \"insertLineBreak\") {\n e.preventDefault();\n ed.insertText(\"\\n\");\n } else {\n return; // let the browser handle anything we don't model\n }\n this.commit();\n }\n\n private onInput() {\n if (this.composing || this.opts.readOnly) return;\n const blockEl = blockElOf(window.getSelection()?.anchorNode ?? null, this.root);\n if (!blockEl) {\n // structure changed under us (browser merged blocks) → full resync\n this.renderBlocks();\n this.lastRevision = this.rev();\n return;\n }\n const id = blockEl.dataset.blockId as string;\n const next = this.domBlockText(blockEl);\n const cur = this.editor.getBlockText(id);\n if (next === cur) return;\n\n // diff → splice through the controller (which infers marks at the caret)\n const max = Math.min(cur.length, next.length);\n let p = 0;\n while (p < max && cur[p] === next[p]) p++;\n let s = 0;\n while (s < max - p && cur[cur.length - 1 - s] === next[next.length - 1 - s]) s++;\n const from = p;\n const to = cur.length - s;\n const insert = next.slice(p, next.length - s);\n this.editor.setSelection({ anchor: { blockId: id, offset: from }, focus: { blockId: id, offset: to } });\n if (to > from) this.editor.deleteBackward();\n if (insert) this.editor.insertText(insert);\n // The browser already painted the text; just realign the run offsets.\n this.reindex(blockEl);\n this.lastRevision = this.rev();\n }\n\n /** Re-derive data-off / data-len after a native edit (no node replacement). */\n private reindex(el: HTMLElement) {\n let off = 0;\n for (const child of Array.from(el.children) as HTMLElement[]) {\n if (child.dataset.off == null) continue;\n child.dataset.off = String(off);\n const len = child.dataset.atom != null ? 1 : (child.textContent ?? \"\").length;\n child.dataset.len = String(len);\n off += len;\n }\n }\n}\n","import type { EditorController } from \"@wingleeio/ori-core\";\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type PointerEvent as ReactPointerEvent,\n} from \"react\";\nimport { EditorView } from \"./ce/view\";\nimport { useEditorSnapshot } from \"./hooks\";\nimport type { AtomRenderer, BlockRenderer } from \"./renderers\";\n\nexport interface NoteEditorProps {\n editor: EditorController;\n className?: string;\n style?: CSSProperties;\n /** Max width of the centered content column, in px. */\n maxWidth?: number;\n placeholder?: string;\n autoFocus?: boolean;\n readOnly?: boolean;\n /** Renderers for custom (atomic) block node types. */\n blockRenderers?: Record<string, BlockRenderer>;\n /** Renderers for custom inline atom types. */\n atomRenderers?: Record<string, AtomRenderer>;\n}\n\n/** A viewport-space rectangle (client coordinates). */\nexport interface ViewportRect {\n top: number;\n left: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n}\n\n/** Imperative handle for building floating UI (slash / selection menus). */\nexport interface NoteEditorHandle {\n focus(): void;\n /** Caret position in viewport coordinates, or null if unavailable. */\n getCaretRect(): { x: number; y: number; height: number } | null;\n /** Bounding box of the current selection in viewport coordinates, or null. */\n getSelectionRect(): ViewportRect | null;\n /** The scrolling element, for scroll-aware positioning. */\n getScrollElement(): HTMLElement | null;\n}\n\nfunction caretClientRect(): DOMRect | null {\n const s = window.getSelection();\n if (!s || s.rangeCount === 0) return null;\n const r = s.getRangeAt(0).cloneRange();\n r.collapse(s.focusNode === r.endContainer && s.focusOffset === r.endOffset ? false : true);\n const rects = r.getClientRects();\n if (rects.length) return rects[rects.length - 1];\n const b = r.getBoundingClientRect();\n if (b.height || b.width) return b;\n // Empty block (`<br>` only): a collapsed range there has no client rects, so\n // synthesize the caret from the block box + its line metrics. Without this the\n // custom caret would vanish on empty lines (the native caret is hidden).\n const node = r.startContainer;\n const el = (node.nodeType === Node.TEXT_NODE ? node.parentElement : (node as HTMLElement)) ?? null;\n if (!el) return null;\n const eb = el.getBoundingClientRect();\n const cs = getComputedStyle(el);\n const lh = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.4 || 18;\n const padL = parseFloat(cs.paddingLeft) || 0;\n const padT = parseFloat(cs.paddingTop) || 0;\n return new DOMRect(eb.left + padL, eb.top + padT, 0, lh);\n}\n\n/**\n * A contentEditable note editor: the browser owns caret, selection, trackpad,\n * native menus and IME on the live text, while edits are routed through the\n * {@link EditorController} (Y.Doc). A custom caret is drawn on top so it can be\n * branded/animated independently of the (hidden) native one.\n */\nexport const NoteEditor = forwardRef<NoteEditorHandle, NoteEditorProps>(function NoteEditor(\n { editor, className, style, maxWidth = 720, placeholder, autoFocus, readOnly, blockRenderers, atomRenderers },\n ref,\n) {\n const snapshot = useEditorSnapshot(editor);\n const scrollerRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n const viewRef = useRef<EditorView | null>(null);\n const [focused, setFocused] = useState(false);\n const [caret, setCaret] = useState<{ x: number; y: number; h: number } | null>(null);\n\n // Keep the latest renderers reachable without recreating the view.\n const renderersRef = useRef({ blockRenderers, atomRenderers });\n renderersRef.current = { blockRenderers, atomRenderers };\n\n useImperativeHandle(\n ref,\n (): NoteEditorHandle => ({\n focus: () => contentRef.current?.focus(),\n getCaretRect: () => {\n const r = caretClientRect();\n return r ? { x: r.left, y: r.top, height: r.height || 16 } : null;\n },\n getSelectionRect: () => {\n const s = window.getSelection();\n if (!s || s.rangeCount === 0 || s.isCollapsed) return null;\n const b = s.getRangeAt(0).getBoundingClientRect();\n if (!b.width && !b.height) return null;\n return { top: b.top, left: b.left, right: b.right, bottom: b.bottom, width: b.width, height: b.height };\n },\n getScrollElement: () => scrollerRef.current,\n }),\n [],\n );\n\n // Create the imperative contentEditable view once.\n useEffect(() => {\n const el = contentRef.current;\n if (!el) return;\n const view = new EditorView(el, editor, {\n readOnly,\n renderAtom: (t) => renderersRef.current.atomRenderers?.[t],\n renderBlock: (t) => renderersRef.current.blockRenderers?.[t],\n });\n viewRef.current = view;\n return () => {\n view.destroy();\n viewRef.current = null;\n };\n }, [editor, readOnly]);\n\n // Reconcile the view when the model changes externally (app commands, undo,\n // remote). The view ignores revisions it produced itself (native typing).\n useEffect(() => {\n viewRef.current?.sync();\n }, [snapshot.revision]);\n\n useEffect(() => {\n if (autoFocus) contentRef.current?.focus();\n }, [autoFocus]);\n\n // Position the custom caret from the live DOM selection.\n useEffect(() => {\n const update = () => {\n const content = contentRef.current;\n const s = window.getSelection();\n if (!content || !s || s.rangeCount === 0 || !s.isCollapsed || !content.contains(s.anchorNode)) {\n setCaret(null);\n return;\n }\n const r = caretClientRect();\n const box = content.getBoundingClientRect();\n if (r) setCaret({ x: r.left - box.left, y: r.top - box.top, h: r.height || 18 });\n };\n document.addEventListener(\"selectionchange\", update);\n const ro = new ResizeObserver(update);\n if (contentRef.current) ro.observe(contentRef.current);\n update();\n return () => {\n document.removeEventListener(\"selectionchange\", update);\n ro.disconnect();\n };\n }, []);\n\n // Drive virtualization: keep the controller's width + viewport in sync.\n useLayoutEffect(() => {\n const sc = scrollerRef.current;\n const content = contentRef.current;\n if (!sc || !content) return;\n const sync = () => {\n editor.setWidth(content.clientWidth);\n editor.setViewport(sc.scrollTop, sc.clientHeight);\n };\n sync();\n const ro = new ResizeObserver(sync);\n ro.observe(sc);\n ro.observe(content);\n return () => ro.disconnect();\n }, [editor]);\n\n const onScroll = () => {\n const sc = scrollerRef.current;\n if (sc) editor.setViewport(sc.scrollTop, sc.clientHeight);\n };\n\n // Clicking the empty region below the content should focus the editor and put\n // the caret at the document end (the usual \"click to keep writing\" affordance).\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>) => {\n if (readOnly) return;\n if ((e.target as HTMLElement).closest(\"[data-block-id]\")) return; // real block → browser\n const content = contentRef.current;\n const blocks = content?.querySelectorAll(\"[data-block-id]\");\n const last = blocks && (blocks[blocks.length - 1] as HTMLElement | undefined);\n if (!content || !last) return;\n if (e.clientY <= last.getBoundingClientRect().bottom) return; // beside text, not below\n e.preventDefault();\n content.focus();\n const sel = window.getSelection();\n if (!sel) return;\n const range = document.createRange();\n range.selectNodeContents(last);\n range.collapse(false);\n sel.removeAllRanges();\n sel.addRange(range);\n };\n\n const showCaret = focused && !!caret && !readOnly;\n\n return (\n <div className={`ori-root${className ? ` ${className}` : \"\"}`} style={style}>\n <div className=\"ori-scroller\" ref={scrollerRef} onScroll={onScroll} onPointerDown={onPointerDown}>\n <div className=\"ori-content\" style={{ maxWidth, marginInline: \"auto\", position: \"relative\" }}>\n <div\n className=\"ori-canvas ori-ce\"\n ref={contentRef}\n onFocus={() => setFocused(true)}\n onBlur={() => setFocused(false)}\n suppressContentEditableWarning\n />\n {showCaret && caret ? (\n <div\n className=\"ori-caret\"\n style={{ position: \"absolute\", left: caret.x, top: caret.y, height: caret.h, pointerEvents: \"none\" }}\n aria-hidden\n />\n ) : null}\n {snapshot.empty && placeholder ? (\n <div className=\"ori-placeholder\" aria-hidden>\n {placeholder}\n </div>\n ) : null}\n </div>\n </div>\n </div>\n );\n});\n","import type { BlockLayout, EditorController, InlineAtom, VisibleBlock } from \"@wingleeio/ori-core\";\nimport { createContext, useContext, type ReactNode } from \"react\";\n\n/** Props for a custom block renderer (atomic nodes: divider, image, …). */\nexport interface BlockRendererProps {\n editor: EditorController;\n block: VisibleBlock;\n /** The block's synthetic layout (atomic blocks: one line, no fragments). */\n layout: BlockLayout;\n}\nexport type BlockRenderer = (props: BlockRendererProps) => ReactNode;\n\n/** Props for a custom inline-atom renderer (mention chip, inline math, …). */\nexport interface AtomRendererProps {\n editor: EditorController;\n atom: InlineAtom;\n}\nexport type AtomRenderer = (props: AtomRendererProps) => ReactNode;\n\nexport interface Renderers {\n blocks: Record<string, BlockRenderer>;\n atoms: Record<string, AtomRenderer>;\n}\n\nconst EMPTY: Renderers = { blocks: {}, atoms: {} };\n\nconst RenderersContext = createContext<Renderers>(EMPTY);\nexport const RenderersProvider = RenderersContext.Provider;\nexport const useRenderers = (): Renderers => useContext(RenderersContext);\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/useEditor.ts","../src/hooks.ts","../src/ce/clipboard.ts","../src/ce/dom.ts","../src/ce/view.ts","../src/NoteEditor.tsx","../src/renderers.tsx"],"names":["esc","textNode","NoteEditor","useRef","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import {\n EditorController,\n createCanvasMeasurer,\n type EditorSchema,\n type Measurer,\n type Typography,\n} from \"@wingleeio/ori-core\";\nimport { useEffect, useRef } from \"react\";\nimport type * as Y from \"yjs\";\n\nexport interface UseEditorOptions {\n /** Existing note `Y.Doc`. When switching notes, remount via `key` instead. */\n doc?: Y.Doc;\n typography?: Typography;\n measurer?: Measurer;\n overscan?: number;\n blockSpacing?: number;\n /** Custom block/atom nodes, merged over the built-ins. */\n schema?: Partial<EditorSchema>;\n}\n\n/**\n * Create (once) and own an {@link EditorController} for the lifetime of the\n * component. To switch documents, give the hosting component a `key` so it\n * remounts with a fresh controller.\n *\n * The controller is reconnected on mount and disconnected on unmount rather than\n * destroyed, so React StrictMode's dev mount → unmount → remount cycle reuses the\n * same controller (with all its state) instead of leaving a torn-down one behind.\n */\nexport function useEditor(options: UseEditorOptions = {}): EditorController {\n const ref = useRef<EditorController | null>(null);\n if (ref.current === null) {\n ref.current = new EditorController({\n doc: options.doc,\n measurer: options.measurer ?? createCanvasMeasurer(),\n typography: options.typography,\n overscan: options.overscan,\n blockSpacing: options.blockSpacing,\n schema: options.schema,\n });\n }\n useEffect(() => {\n const editor = ref.current;\n editor?.connect();\n return () => editor?.disconnect();\n }, []);\n return ref.current;\n}\n","import type { EditorController, EditorSnapshot, Marks } from \"@wingleeio/ori-core\";\nimport { useSyncExternalStore } from \"react\";\n\n/** Subscribe a component to the controller's snapshot stream. */\nexport function useEditorSnapshot(editor: EditorController): EditorSnapshot {\n return useSyncExternalStore(editor.subscribe, editor.getSnapshot, editor.getSnapshot);\n}\n\n/**\n * The marks active at the current selection. Recomputed whenever the editor\n * notifies (selection move, edit, or pending-mark toggle), so toolbars stay in\n * sync without their own subscription.\n */\nexport function useActiveMarks(editor: EditorController): Marks {\n const snapshot = useEditorSnapshot(editor);\n // `revision` changes on every notify; reading it ties this to the store.\n void snapshot.revision;\n return editor.getActiveMarks();\n}\n","import type { InlineItem, Marks } from \"@wingleeio/ori-core\";\n\n/**\n * Clipboard (de)serialization for the contentEditable view. Copy writes three\n * payloads — `text/plain`, `text/html` (for other apps), and a private JSON MIME\n * that round-trips marks/atoms exactly — and paste prefers the private MIME, then\n * falls back to parsing external HTML, then plain text. Content is grouped one\n * array of inline runs per block so block boundaries survive a multi-block copy.\n */\nexport const ORI_MIME = \"application/x-ori-inline\";\n\nfunction atomPlain(it: InlineItem): string {\n const d = (it.atom?.data ?? {}) as Record<string, unknown>;\n const label = d.label ?? d.text ?? d.name;\n return label != null ? `@${String(label)}` : \"\";\n}\n\nfunction blockPlain(items: InlineItem[]): string {\n return items.map((it) => (it.atom ? atomPlain(it) : it.text)).join(\"\");\n}\n\nconst MARK_TAGS: Array<[keyof Marks, string]> = [\n [\"bold\", \"strong\"],\n [\"italic\", \"em\"],\n [\"underline\", \"u\"],\n [\"strike\", \"s\"],\n [\"code\", \"code\"],\n];\n\nfunction esc(s: string): string {\n return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n}\n\nfunction runHtml(it: InlineItem): string {\n if (it.atom) return `<span>${esc(atomPlain(it))}</span>`;\n let html = esc(it.text);\n const m = it.marks ?? {};\n for (const [k, tag] of MARK_TAGS) if (m[k]) html = `<${tag}>${html}</${tag}>`;\n if (m.link) html = `<a href=\"${esc(m.link)}\">${html}</a>`;\n return html;\n}\n\n/** Build the three clipboard payloads for a block-grouped selection. */\nexport function serializeSelection(blocks: InlineItem[][]): { text: string; html: string; json: string } {\n const text = blocks.map(blockPlain).join(\"\\n\");\n const html = blocks.map((items) => `<p>${items.map(runHtml).join(\"\") || \"<br>\"}</p>`).join(\"\");\n const json = JSON.stringify({\n v: 1,\n blocks: blocks.map((items) =>\n items.map((it) =>\n it.atom ? { embed: it.atom.data ?? { type: it.atom.type } } : { text: it.text, marks: it.marks },\n ),\n ),\n });\n return { text, html, json };\n}\n\ninterface SerItem {\n text?: string;\n marks?: Marks;\n embed?: Record<string, unknown>;\n}\n\n/** Parse our own clipboard JSON back into block-grouped inline items. */\nexport function deserializeOri(json: string): InlineItem[][] | null {\n try {\n const data = JSON.parse(json) as { v?: number; blocks?: SerItem[][] };\n if (!Array.isArray(data.blocks)) return null;\n return data.blocks.map((items) =>\n items.map((it) =>\n it.embed\n ? { text: \"\", start: 0, atom: { type: String(it.embed.type ?? \"\"), width: 0, data: it.embed } }\n : { text: it.text ?? \"\", start: 0, marks: it.marks },\n ),\n );\n } catch {\n return null;\n }\n}\n\n/** Plain text → one block per line. */\nexport function textToBlocks(text: string): InlineItem[][] {\n return text\n .replace(/\\r\\n?/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => (line ? [{ text: line, start: 0 } as InlineItem] : []));\n}\n\n/** Parse external HTML into block-grouped inline items (best-effort marks). */\nexport function htmlToBlocks(html: string): InlineItem[][] {\n if (typeof DOMParser === \"undefined\") return [];\n const doc = new DOMParser().parseFromString(html, \"text/html\");\n const blocks: InlineItem[][] = [];\n let cur: InlineItem[] = [];\n const flush = () => {\n blocks.push(cur);\n cur = [];\n };\n const push = (text: string, marks: Marks) => {\n if (!text) return;\n cur.push({ text, start: 0, marks: Object.keys(marks).length ? { ...marks } : undefined });\n };\n const BLOCK = new Set([\n \"P\", \"DIV\", \"H1\", \"H2\", \"H3\", \"H4\", \"H5\", \"H6\", \"LI\", \"BLOCKQUOTE\", \"PRE\", \"SECTION\", \"ARTICLE\", \"UL\", \"OL\",\n ]);\n const walk = (node: Node, marks: Marks) => {\n for (const child of Array.from(node.childNodes)) {\n if (child.nodeType === Node.TEXT_NODE) {\n push((child.textContent ?? \"\").replace(/\\s+/g, \" \"), marks);\n continue;\n }\n if (child.nodeType !== Node.ELEMENT_NODE) continue;\n const el = child as HTMLElement;\n const tag = el.tagName;\n if (tag === \"BR\") {\n if (cur.length) flush();\n continue;\n }\n const m: Marks = { ...marks };\n if (tag === \"STRONG\" || tag === \"B\") m.bold = true;\n if (tag === \"EM\" || tag === \"I\") m.italic = true;\n if (tag === \"U\" || tag === \"INS\") m.underline = true;\n if (tag === \"S\" || tag === \"STRIKE\" || tag === \"DEL\") m.strike = true;\n if (tag === \"CODE\" || tag === \"KBD\" || tag === \"TT\") m.code = true;\n const href = tag === \"A\" ? el.getAttribute(\"href\") : null;\n if (href) m.link = href;\n const isBlock = BLOCK.has(tag);\n if (isBlock && cur.length) flush();\n walk(el, m);\n if (isBlock) flush();\n }\n };\n walk(doc.body, {});\n if (cur.length) flush();\n // Trim leading/trailing empty blocks left by formatting whitespace.\n while (blocks.length && blocks[0].length === 0) blocks.shift();\n while (blocks.length && blocks[blocks.length - 1].length === 0) blocks.pop();\n return blocks;\n}\n","import type { InlineItem } from \"@wingleeio/ori-core\";\n\n/** CSS.escape with a fallback (jsdom lacks it). */\nexport function esc(s: string): string {\n return typeof CSS !== \"undefined\" && CSS.escape ? CSS.escape(s) : s.replace(/[\"\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Imperative DOM helpers for the contentEditable view. Each block is a\n * block-level element carrying `data-block-id`; its inline runs are spans\n * carrying `data-off` (their start offset in the block) so DOM positions map\n * back to {blockId, offset} and vice-versa.\n */\n\nexport const BLOCK_SEL = \"[data-block-id]\";\n\nexport function blockElOf(node: Node | null, root: HTMLElement): HTMLElement | null {\n let n: Node | null = node;\n while (n && n !== root) {\n if (n instanceof HTMLElement && n.dataset.blockId) return n;\n n = n.parentNode;\n }\n return null;\n}\n\nfunction spanOf(node: Node | null): HTMLElement | null {\n let n: Node | null = node;\n while (n) {\n if (n instanceof HTMLElement && n.dataset.off != null) return n;\n n = n.parentNode;\n }\n return null;\n}\n\n/** Map a DOM (node, offset) to a {blockId, offset} model position. */\nexport function domToModel(\n root: HTMLElement,\n node: Node | null,\n offset: number,\n): { blockId: string; offset: number } | null {\n const blockEl = blockElOf(node, root);\n if (!blockEl) return null;\n const blockId = blockEl.dataset.blockId as string;\n\n if (node && node.nodeType === Node.TEXT_NODE) {\n const span = spanOf(node);\n const base = span ? Number(span.dataset.off) : 0;\n return { blockId, offset: base + offset };\n }\n\n // node is an element; `offset` is a child index. Resolve via the child spans.\n const el = node as HTMLElement;\n if (el.dataset?.off != null) {\n // selection landed on a span boundary\n return { blockId, offset: Number(el.dataset.off) + (offset > 0 ? spanLen(el) : 0) };\n }\n const kids = Array.from(el.childNodes);\n for (let i = offset; i < kids.length; i++) {\n const k = kids[i];\n if (k instanceof HTMLElement && k.dataset.off != null) return { blockId, offset: Number(k.dataset.off) };\n }\n // past the last span → block end\n let end = 0;\n for (const k of kids) if (k instanceof HTMLElement && k.dataset.off != null) end = Math.max(end, Number(k.dataset.off) + spanLen(k));\n return { blockId, offset: end };\n}\n\nfunction spanLen(span: HTMLElement): number {\n return span.dataset.len != null ? Number(span.dataset.len) : (span.textContent ?? \"\").length;\n}\n\n/** Find the DOM (node, offset) for a {blockId, offset} model position. */\nexport function modelToDom(\n root: HTMLElement,\n blockId: string,\n offset: number,\n): { node: Node; offset: number } | null {\n const blockEl = root.querySelector(`[data-block-id=\"${esc(blockId)}\"]`) as HTMLElement | null;\n if (!blockEl) return null;\n const spans = Array.from(blockEl.querySelectorAll(\"[data-off]\")) as HTMLElement[];\n if (spans.length === 0) {\n return { node: blockEl, offset: 0 }; // empty block\n }\n for (const span of spans) {\n const start = Number(span.dataset.off);\n const len = spanLen(span);\n if (offset <= start + len) {\n if (span.dataset.atom != null) {\n // atom: place before or after it (offset is start or start+1)\n const idx = Array.prototype.indexOf.call(blockEl.childNodes, span);\n return { node: blockEl, offset: offset <= start ? idx : idx + 1 };\n }\n const textNode = span.firstChild ?? span;\n return { node: textNode, offset: Math.max(0, Math.min(offset - start, (textNode.textContent ?? \"\").length)) };\n }\n }\n // past everything → after the last span\n const last = spans[spans.length - 1];\n const textNode = last.firstChild ?? last;\n return { node: textNode, offset: (textNode.textContent ?? \"\").length };\n}\n\nfunction markClass(marks: InlineItem[\"marks\"]): string {\n const m = marks ?? {};\n const cls = [\"ori-frag\"];\n if (m.bold) cls.push(\"ori-m-bold\");\n if (m.italic) cls.push(\"ori-m-italic\");\n if (m.underline) cls.push(\"ori-m-underline\");\n if (m.strike) cls.push(\"ori-m-strike\");\n if (m.code) cls.push(\"ori-frag-code\");\n if (m.link) cls.push(\"ori-frag-link\");\n return cls.join(\" \");\n}\n\n/** Build the inline run DOM for a block (text spans only; atoms handled by the view). */\nexport function buildRun(item: InlineItem): HTMLElement {\n const span = document.createElement(\"span\");\n span.className = markClass(item.marks);\n span.dataset.off = String(item.start);\n span.dataset.len = String(item.text.length);\n span.textContent = item.text;\n return span;\n}\n","import type { EditorController, InlineItem } from \"@wingleeio/ori-core\";\nimport { isCollapsed } from \"@wingleeio/ori-core\";\nimport type { ReactNode } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport type { AtomRenderer, BlockRenderer } from \"../renderers\";\nimport { ORI_MIME, deserializeOri, htmlToBlocks, serializeSelection, textToBlocks } from \"./clipboard\";\nimport { blockElOf, buildRun, domToModel, esc, modelToDom } from \"./dom\";\n\nconst PLACEHOLDER = \"\";\n\nexport interface ViewOptions {\n readOnly?: boolean;\n renderAtom: (type: string) => AtomRenderer | undefined;\n renderBlock: (type: string) => BlockRenderer | undefined;\n}\n\n/**\n * Imperative contentEditable view over an {@link EditorController}. The browser\n * owns caret / selection / trackpad / menus / IME on the live text; we intercept\n * structural + cross-block edits (beforeinput) and route them through the\n * controller, let smooth in-block typing flow natively and read it back, and\n * keep the DOM selection and the controller selection in lock-step.\n */\nexport class EditorView {\n private roots = new Map<HTMLElement, Root>();\n private composing = false;\n private applyingModel = false;\n private detachers: Array<() => void> = [];\n /** The model revision the DOM currently reflects (so external changes — remote\n * edits, app commands — re-render, but our own edits don't clobber the caret). */\n private lastRevision = -1;\n\n constructor(\n private root: HTMLElement,\n private editor: EditorController,\n private opts: ViewOptions,\n ) {\n root.setAttribute(\"contenteditable\", opts.readOnly ? \"false\" : \"true\");\n root.setAttribute(\"spellcheck\", opts.readOnly ? \"false\" : \"true\");\n root.setAttribute(\"role\", \"textbox\");\n root.setAttribute(\"aria-multiline\", \"true\");\n this.renderBlocks();\n this.lastRevision = this.rev();\n\n const on = <K extends keyof HTMLElementEventMap>(\n t: K,\n h: (e: HTMLElementEventMap[K]) => void,\n o?: AddEventListenerOptions,\n ) => {\n root.addEventListener(t, h as EventListener, o);\n this.detachers.push(() => root.removeEventListener(t, h as EventListener, o));\n };\n on(\"beforeinput\", (e) => this.onBeforeInput(e as InputEvent));\n on(\"input\", () => this.onInput());\n on(\"keydown\", (e) => this.onKeyDown(e as KeyboardEvent));\n on(\"blur\", () => {\n // Clicking outside the editor drops the selection (so a selection toolbar\n // hides). Defer so we can ignore a window/tab blur and focus-preserving\n // clicks (e.g. toolbar buttons that re-focus the editor).\n setTimeout(() => {\n if (document.activeElement === this.root || !document.hasFocus()) return;\n const sel = this.editor.getSelection();\n if (sel && !isCollapsed(sel)) {\n this.editor.collapse(sel.focus);\n this.lastRevision = this.rev();\n }\n }, 0);\n });\n on(\"compositionstart\", () => (this.composing = true));\n on(\"compositionend\", () => {\n this.composing = false;\n this.onInput();\n });\n on(\"copy\", (e) => this.onClipboard(e as ClipboardEvent, false));\n on(\"cut\", (e) => this.onClipboard(e as ClipboardEvent, true));\n on(\"paste\", (e) => this.onPaste(e as ClipboardEvent));\n\n const onSelChange = () => {\n if (this.applyingModel || this.composing) return;\n const sel = this.readSelection();\n if (!sel) return;\n this.editor.setSelection(sel);\n // DOM is already the source of truth here — record the revision so the\n // resulting React sync() doesn't write the selection back and collapse it.\n this.lastRevision = this.rev();\n };\n document.addEventListener(\"selectionchange\", onSelChange);\n this.detachers.push(() => document.removeEventListener(\"selectionchange\", onSelChange));\n }\n\n destroy() {\n this.detachers.forEach((d) => d());\n this.roots.forEach((r) => r.unmount());\n this.roots.clear();\n }\n\n focus() {\n this.root.focus();\n }\n\n // --- rendering ---------------------------------------------------------\n\n private rev(): number {\n return this.editor.getSnapshot().revision;\n }\n\n /**\n * Called by React on every model change. Only re-renders when the model moved\n * ahead of what we last drew (an *external* change — app command, undo, remote);\n * our own edits already updated the DOM and must not be clobbered.\n */\n sync() {\n const rev = this.rev();\n if (rev === this.lastRevision) return;\n // Only restore the DOM selection when the *content* changed (app command,\n // undo, remote). A selection-only change is already correct in the DOM, and\n // writing it back would fight (and collapse) the user's native selection.\n const changed = this.renderBlocks();\n if (changed) this.writeSelection();\n this.lastRevision = rev;\n }\n\n /** After a controlled (preventDefault'd) edit: re-render + restore the caret. */\n private commit() {\n this.renderBlocks();\n this.writeSelection();\n this.lastRevision = this.rev();\n }\n\n /** A content signature for a block, so unchanged blocks aren't re-rendered. */\n private sig(id: string): string {\n return this.editor.getBlockType(id) + \"|\" + JSON.stringify(this.editor.getInline(id));\n }\n\n /**\n * Reconcile the DOM to the *visible window* of blocks (virtualization): a top\n * spacer, the windowed blocks, then a bottom spacer — heights from the\n * controller's offscreen measurement. On-screen blocks are reused by id so a\n * caret inside one survives a scroll. Returns true if the DOM was mutated.\n */\n private renderBlocks(): boolean {\n let changed = false;\n const snap = this.editor.getSnapshot();\n const vis = snap.visible;\n const topH = vis.length ? vis[0].top : 0;\n const botH = vis.length\n ? Math.max(0, snap.totalHeight - (vis[vis.length - 1].top + vis[vis.length - 1].height))\n : Math.max(0, snap.totalHeight);\n\n const TOP = \"\u0000top\";\n const BOTTOM = \"\u0000bottom\";\n const want = [TOP, ...vis.map((v) => v.id), BOTTOM];\n const keyOf = (el: Element) => {\n const e = el as HTMLElement;\n return e.dataset.spacer ? \"\u0000\" + e.dataset.spacer : (e.dataset.blockId ?? \"\");\n };\n const have = new Map<string, HTMLElement>();\n for (const c of Array.from(this.root.children)) have.set(keyOf(c), c as HTMLElement);\n\n let prev: HTMLElement | null = null;\n for (const k of want) {\n let el: HTMLElement | undefined = have.get(k);\n if (el) {\n have.delete(k);\n } else {\n el = k === TOP || k === BOTTOM ? this.makeSpacer(k.slice(1)) : this.makeBlock(k);\n changed = true;\n }\n const anchor: ChildNode | null = prev ? prev.nextSibling : this.root.firstChild;\n if (anchor !== el) {\n this.root.insertBefore(el, anchor);\n changed = true;\n }\n prev = el;\n }\n for (const el of have.values()) {\n if (el.dataset.blockId) this.unmountRootsIn(el);\n el.remove();\n changed = true;\n }\n\n const top = this.root.firstElementChild as HTMLElement | null;\n if (top && top.style.height !== `${topH}px`) top.style.height = `${topH}px`;\n const bot = this.root.lastElementChild as HTMLElement | null;\n if (bot && bot.style.height !== `${botH}px`) bot.style.height = `${botH}px`;\n\n for (const vb of vis) {\n const el = this.root.querySelector(`[data-block-id=\"${esc(vb.id)}\"]`) as HTMLElement | null;\n if (!el) continue;\n const sig = this.sig(vb.id);\n if (el.dataset.sig !== sig) {\n el.dataset.sig = sig;\n this.renderBlockInner(el, vb.id);\n changed = true;\n }\n }\n return changed;\n }\n\n private makeBlock(id: string): HTMLElement {\n const el = document.createElement(\"div\");\n el.dataset.blockId = id;\n return el;\n }\n\n private makeSpacer(which: string): HTMLElement {\n const el = document.createElement(\"div\");\n el.dataset.spacer = which;\n el.setAttribute(\"contenteditable\", \"false\");\n el.setAttribute(\"aria-hidden\", \"true\");\n el.style.userSelect = \"none\";\n el.style.pointerEvents = \"none\";\n return el;\n }\n\n private renderBlockInner(el: HTMLElement, id: string) {\n this.unmountRootsIn(el);\n const type = this.editor.getBlockType(id);\n el.className = `ori-block ori-block-${type}`;\n\n const blockRenderer = this.opts.renderBlock(type);\n if (blockRenderer) {\n el.contentEditable = \"false\";\n el.textContent = \"\";\n const root = createRoot(el);\n root.render(blockRenderer({ editor: this.editor, block: { id, type, index: 0, top: 0, height: 0 }, layout: this.editor.getLayout(id)! }) as ReactNode);\n this.roots.set(el, root);\n return;\n }\n el.contentEditable = \"inherit\";\n el.textContent = \"\";\n const items = this.editor.getInline(id);\n if (items.length === 0) {\n el.appendChild(document.createElement(\"br\")); // keep an empty block selectable\n return;\n }\n for (const item of items) {\n if (item.atom) {\n const span = document.createElement(\"span\");\n span.className = \"ori-atom\";\n span.contentEditable = \"false\";\n span.dataset.atom = \"true\";\n span.dataset.off = String(item.start);\n span.dataset.len = \"1\";\n el.appendChild(span);\n const renderer = this.opts.renderAtom(item.atom.type);\n if (renderer) {\n const r = createRoot(span);\n r.render(renderer({ editor: this.editor, atom: item.atom }) as ReactNode);\n this.roots.set(span, r);\n }\n } else {\n el.appendChild(buildRun(item));\n }\n }\n }\n\n private unmountRootsIn(el: HTMLElement) {\n for (const [node, root] of this.roots) {\n if (el === node || el.contains(node)) {\n root.unmount();\n this.roots.delete(node);\n }\n }\n }\n\n // --- selection ---------------------------------------------------------\n\n private readSelection() {\n const s = window.getSelection();\n if (!s || s.rangeCount === 0 || !this.root.contains(s.anchorNode)) return null;\n const a = domToModel(this.root, s.anchorNode, s.anchorOffset);\n const f = domToModel(this.root, s.focusNode, s.focusOffset);\n if (!a || !f) return null;\n return { anchor: { blockId: a.blockId, offset: a.offset }, focus: { blockId: f.blockId, offset: f.offset } };\n }\n\n /** Push the controller's selection back into the DOM (after a model op). */\n private writeSelection() {\n const sel = this.editor.getSelection();\n if (!sel) return;\n const a = modelToDom(this.root, sel.anchor.blockId, sel.anchor.offset);\n const f = modelToDom(this.root, sel.focus.blockId, sel.focus.offset);\n if (!a || !f) return;\n const r = document.createRange();\n const s = window.getSelection();\n if (!s) return;\n this.applyingModel = true;\n try {\n r.setStart(a.node, a.offset);\n s.removeAllRanges();\n s.addRange(r);\n s.extend(f.node, f.offset);\n } catch {\n /* node detached mid-reconcile */\n } finally {\n this.applyingModel = false;\n }\n }\n\n /** The block text as the model sees it (atoms collapse to one placeholder). */\n private domBlockText(el: HTMLElement): string {\n let out = \"\";\n for (const child of Array.from(el.childNodes)) {\n if (child instanceof HTMLElement && child.dataset.atom != null) {\n out += PLACEHOLDER;\n } else {\n out += child.textContent ?? \"\";\n }\n }\n return out;\n }\n\n // --- input -------------------------------------------------------------\n\n /** Formatting + history shortcuts (the browser fires these as keydown). */\n private onKeyDown(e: KeyboardEvent) {\n if (this.opts.readOnly) return;\n const mod = e.metaKey || e.ctrlKey;\n if (!mod || e.altKey) return;\n const k = e.key.toLowerCase();\n const mark = ({ b: \"bold\", i: \"italic\", u: \"underline\", e: \"code\" } as const)[k];\n if (mark) {\n e.preventDefault();\n const sel = this.readSelection();\n if (sel) this.editor.setSelection(sel);\n this.editor.toggleMark(mark);\n this.commit();\n } else if (k === \"z\") {\n e.preventDefault();\n if (e.shiftKey) this.editor.redo();\n else this.editor.undo();\n this.commit();\n } else if (k === \"y\") {\n e.preventDefault();\n this.editor.redo();\n this.commit();\n }\n }\n\n private onBeforeInput(e: InputEvent) {\n if (this.opts.readOnly) {\n e.preventDefault();\n return;\n }\n const sel = this.readSelection();\n if (!sel) return;\n this.editor.setSelection(sel);\n const collapsed = isCollapsed(sel);\n const startOffset = this.editor.orderedSelection()?.start.offset ?? sel.focus.offset;\n const t = e.inputType;\n\n // Native fast path: collapsed in-block typing / deletion. The browser mutates\n // a single text node; onInput reads it back. Keeps autocorrect/IME native.\n if (collapsed && (t === \"insertText\" || t === \"insertCompositionText\" || t === \"insertReplacementText\")) return;\n if (collapsed && t === \"deleteContentForward\") return;\n if (collapsed && t === \"deleteContentBackward\" && startOffset > 0) return;\n\n // Everything else (structural + cross-block) is handled through the controller.\n const ed = this.editor;\n if (t === \"insertParagraph\") {\n e.preventDefault();\n ed.insertParagraphBreak();\n } else if (t.startsWith(\"delete\")) {\n e.preventDefault();\n if (t === \"deleteContentForward\") ed.deleteForward();\n else ed.deleteBackward();\n } else if (t === \"insertText\" || t === \"insertReplacementText\") {\n // Non-collapsed (e.g. autocorrect replacement, or typing over a selection):\n // replace the range. Paste has its own handler (onPaste).\n e.preventDefault();\n if (!collapsed) ed.deleteBackward();\n const text = e.data ?? \"\";\n if (text) ed.insertText(text);\n } else if (t === \"insertLineBreak\") {\n e.preventDefault();\n ed.insertText(\"\\n\");\n } else {\n return; // let the browser handle anything we don't model\n }\n this.commit();\n }\n\n private onInput() {\n if (this.composing || this.opts.readOnly) return;\n const blockEl = blockElOf(window.getSelection()?.anchorNode ?? null, this.root);\n if (!blockEl) {\n // structure changed under us (browser merged blocks) → full resync\n this.renderBlocks();\n this.lastRevision = this.rev();\n return;\n }\n const id = blockEl.dataset.blockId as string;\n const next = this.domBlockText(blockEl);\n const cur = this.editor.getBlockText(id);\n if (next === cur) return;\n\n // diff → splice through the controller (which infers marks at the caret)\n const max = Math.min(cur.length, next.length);\n let p = 0;\n while (p < max && cur[p] === next[p]) p++;\n let s = 0;\n while (s < max - p && cur[cur.length - 1 - s] === next[next.length - 1 - s]) s++;\n const from = p;\n const to = cur.length - s;\n const insert = next.slice(p, next.length - s);\n this.editor.setSelection({ anchor: { blockId: id, offset: from }, focus: { blockId: id, offset: to } });\n if (to > from) this.editor.deleteBackward();\n if (insert) this.editor.insertText(insert);\n // The browser already painted the text; just realign the run offsets.\n this.reindex(blockEl);\n this.lastRevision = this.rev();\n }\n\n /** Re-derive data-off / data-len after a native edit (no node replacement). */\n private reindex(el: HTMLElement) {\n let off = 0;\n for (const child of Array.from(el.children) as HTMLElement[]) {\n if (child.dataset.off == null) continue;\n child.dataset.off = String(off);\n const len = child.dataset.atom != null ? 1 : (child.textContent ?? \"\").length;\n child.dataset.len = String(len);\n off += len;\n }\n }\n\n // --- clipboard ---------------------------------------------------------\n\n /** Copy/cut: put plain, HTML and a private (mark-preserving) payload on the clipboard. */\n private onClipboard(e: ClipboardEvent, isCut: boolean) {\n const blocks = this.editor.getSelectionInline();\n if (!blocks.length || !e.clipboardData) return;\n e.preventDefault();\n const { text, html, json } = serializeSelection(blocks);\n e.clipboardData.setData(\"text/plain\", text);\n e.clipboardData.setData(\"text/html\", html);\n e.clipboardData.setData(ORI_MIME, json);\n if (isCut && !this.opts.readOnly) {\n this.editor.deleteBackward();\n this.commit();\n }\n }\n\n /** Paste: restore marks from our payload, else parse external HTML, else plain text. */\n private onPaste(e: ClipboardEvent) {\n if (this.opts.readOnly || !e.clipboardData) return;\n e.preventDefault();\n const sel = this.readSelection();\n if (sel) {\n this.editor.setSelection(sel);\n if (!isCollapsed(sel)) this.editor.deleteBackward();\n }\n const cd = e.clipboardData;\n const ori = cd.getData(ORI_MIME);\n const html = cd.getData(\"text/html\");\n let blocks = ori ? deserializeOri(ori) : null;\n if (!blocks?.length && html) blocks = htmlToBlocks(html);\n if (!blocks?.length) blocks = textToBlocks(cd.getData(\"text/plain\"));\n this.pasteBlocks(blocks);\n this.commit();\n }\n\n private pasteBlocks(blocks: InlineItem[][]) {\n blocks.forEach((items, i) => {\n if (i > 0) this.editor.insertParagraphBreak();\n if (items.length) this.editor.insertInline(items);\n });\n }\n}\n","import type { EditorController } from \"@wingleeio/ori-core\";\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type PointerEvent as ReactPointerEvent,\n} from \"react\";\nimport { EditorView } from \"./ce/view\";\nimport { useEditorSnapshot } from \"./hooks\";\nimport type { AtomRenderer, BlockRenderer } from \"./renderers\";\n\nexport interface NoteEditorProps {\n editor: EditorController;\n className?: string;\n style?: CSSProperties;\n /** Max width of the centered content column, in px. */\n maxWidth?: number;\n placeholder?: string;\n autoFocus?: boolean;\n readOnly?: boolean;\n /** Renderers for custom (atomic) block node types. */\n blockRenderers?: Record<string, BlockRenderer>;\n /** Renderers for custom inline atom types. */\n atomRenderers?: Record<string, AtomRenderer>;\n}\n\n/** A viewport-space rectangle (client coordinates). */\nexport interface ViewportRect {\n top: number;\n left: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n}\n\n/** Imperative handle for building floating UI (slash / selection menus). */\nexport interface NoteEditorHandle {\n focus(): void;\n /** Caret position in viewport coordinates, or null if unavailable. */\n getCaretRect(): { x: number; y: number; height: number } | null;\n /** Bounding box of the current selection in viewport coordinates, or null. */\n getSelectionRect(): ViewportRect | null;\n /** The scrolling element, for scroll-aware positioning. */\n getScrollElement(): HTMLElement | null;\n /**\n * The content overlay element (a positioned layer that scrolls *with* the\n * text). Render floating UI into this with `position: absolute` and\n * content-relative coordinates so it rides the scroll natively instead of\n * trailing it (which causes a fixed-position toolbar to shake on scroll).\n */\n getOverlayElement(): HTMLElement | null;\n}\n\nfunction caretClientRect(): DOMRect | null {\n const s = window.getSelection();\n if (!s || s.rangeCount === 0) return null;\n const r = s.getRangeAt(0).cloneRange();\n r.collapse(s.focusNode === r.endContainer && s.focusOffset === r.endOffset ? false : true);\n const rects = r.getClientRects();\n if (rects.length) return rects[rects.length - 1];\n const b = r.getBoundingClientRect();\n if (b.height || b.width) return b;\n // Empty block (`<br>` only): a collapsed range there has no client rects, so\n // synthesize the caret from the block box + its line metrics. Without this the\n // custom caret would vanish on empty lines (the native caret is hidden).\n const node = r.startContainer;\n const el = (node.nodeType === Node.TEXT_NODE ? node.parentElement : (node as HTMLElement)) ?? null;\n if (!el) return null;\n const eb = el.getBoundingClientRect();\n const cs = getComputedStyle(el);\n const lh = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.4 || 18;\n const padL = parseFloat(cs.paddingLeft) || 0;\n const padT = parseFloat(cs.paddingTop) || 0;\n return new DOMRect(eb.left + padL, eb.top + padT, 0, lh);\n}\n\n/**\n * A contentEditable note editor: the browser owns caret, selection, trackpad,\n * native menus and IME on the live text, while edits are routed through the\n * {@link EditorController} (Y.Doc). A custom caret is drawn on top so it can be\n * branded/animated independently of the (hidden) native one.\n */\nexport const NoteEditor = forwardRef<NoteEditorHandle, NoteEditorProps>(function NoteEditor(\n { editor, className, style, maxWidth = 720, placeholder, autoFocus, readOnly, blockRenderers, atomRenderers },\n ref,\n) {\n const snapshot = useEditorSnapshot(editor);\n const scrollerRef = useRef<HTMLDivElement>(null);\n const overlayRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n const viewRef = useRef<EditorView | null>(null);\n const [focused, setFocused] = useState(false);\n const [caret, setCaret] = useState<{ x: number; y: number; h: number } | null>(null);\n\n // Keep the latest renderers reachable without recreating the view.\n const renderersRef = useRef({ blockRenderers, atomRenderers });\n renderersRef.current = { blockRenderers, atomRenderers };\n\n useImperativeHandle(\n ref,\n (): NoteEditorHandle => ({\n focus: () => contentRef.current?.focus(),\n getCaretRect: () => {\n const r = caretClientRect();\n return r ? { x: r.left, y: r.top, height: r.height || 16 } : null;\n },\n getSelectionRect: () => {\n const s = window.getSelection();\n if (!s || s.rangeCount === 0 || s.isCollapsed) return null;\n const b = s.getRangeAt(0).getBoundingClientRect();\n if (!b.width && !b.height) return null;\n return { top: b.top, left: b.left, right: b.right, bottom: b.bottom, width: b.width, height: b.height };\n },\n getScrollElement: () => scrollerRef.current,\n getOverlayElement: () => overlayRef.current,\n }),\n [],\n );\n\n // Create the imperative contentEditable view once.\n useEffect(() => {\n const el = contentRef.current;\n if (!el) return;\n const view = new EditorView(el, editor, {\n readOnly,\n renderAtom: (t) => renderersRef.current.atomRenderers?.[t],\n renderBlock: (t) => renderersRef.current.blockRenderers?.[t],\n });\n viewRef.current = view;\n return () => {\n view.destroy();\n viewRef.current = null;\n };\n }, [editor, readOnly]);\n\n // Reconcile the view when the model changes externally (app commands, undo,\n // remote). The view ignores revisions it produced itself (native typing).\n useEffect(() => {\n viewRef.current?.sync();\n }, [snapshot.revision]);\n\n useEffect(() => {\n if (autoFocus) contentRef.current?.focus();\n }, [autoFocus]);\n\n // Position the custom caret from the live DOM selection.\n useEffect(() => {\n const update = () => {\n const content = contentRef.current;\n const s = window.getSelection();\n if (!content || !s || s.rangeCount === 0 || !s.isCollapsed || !content.contains(s.anchorNode)) {\n setCaret(null);\n return;\n }\n const r = caretClientRect();\n const box = content.getBoundingClientRect();\n if (r) setCaret({ x: r.left - box.left, y: r.top - box.top, h: r.height || 18 });\n };\n document.addEventListener(\"selectionchange\", update);\n const ro = new ResizeObserver(update);\n if (contentRef.current) ro.observe(contentRef.current);\n update();\n return () => {\n document.removeEventListener(\"selectionchange\", update);\n ro.disconnect();\n };\n }, []);\n\n // Drive virtualization: keep the controller's width + viewport in sync.\n useLayoutEffect(() => {\n const sc = scrollerRef.current;\n const content = contentRef.current;\n if (!sc || !content) return;\n const sync = () => {\n editor.setWidth(content.clientWidth);\n editor.setViewport(sc.scrollTop, sc.clientHeight);\n };\n sync();\n const ro = new ResizeObserver(sync);\n ro.observe(sc);\n ro.observe(content);\n return () => ro.disconnect();\n }, [editor]);\n\n const onScroll = () => {\n const sc = scrollerRef.current;\n if (sc) editor.setViewport(sc.scrollTop, sc.clientHeight);\n };\n\n // Clicking the empty region below the content should focus the editor and put\n // the caret at the document end (the usual \"click to keep writing\" affordance).\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>) => {\n if (readOnly) return;\n // Only act on the editor's own empty surface — not on blocks (the browser\n // places the caret) and not on floating UI (menus) layered into the overlay.\n const t = e.target as HTMLElement;\n const onSurface =\n t === scrollerRef.current ||\n t === overlayRef.current ||\n t.classList.contains(\"ori-ce\") ||\n t.dataset.spacer != null;\n if (!onSurface) return;\n const content = contentRef.current;\n const blocks = content?.querySelectorAll(\"[data-block-id]\");\n const last = blocks && (blocks[blocks.length - 1] as HTMLElement | undefined);\n if (!content || !last) return;\n if (e.clientY <= last.getBoundingClientRect().bottom) return; // beside text, not below\n e.preventDefault();\n content.focus();\n const sel = window.getSelection();\n if (!sel) return;\n const range = document.createRange();\n range.selectNodeContents(last);\n range.collapse(false);\n sel.removeAllRanges();\n sel.addRange(range);\n };\n\n const showCaret = focused && !!caret && !readOnly;\n\n return (\n <div className={`ori-root${className ? ` ${className}` : \"\"}`} style={style}>\n <div className=\"ori-scroller\" ref={scrollerRef} onScroll={onScroll} onPointerDown={onPointerDown}>\n <div className=\"ori-content\" ref={overlayRef} style={{ maxWidth, marginInline: \"auto\", position: \"relative\" }}>\n <div\n className=\"ori-canvas ori-ce\"\n ref={contentRef}\n onFocus={() => setFocused(true)}\n onBlur={() => setFocused(false)}\n suppressContentEditableWarning\n />\n {showCaret && caret ? (\n <div\n className=\"ori-caret\"\n style={{ position: \"absolute\", left: caret.x, top: caret.y, height: caret.h, pointerEvents: \"none\" }}\n aria-hidden\n />\n ) : null}\n {snapshot.empty && placeholder ? (\n <div className=\"ori-placeholder\" aria-hidden>\n {placeholder}\n </div>\n ) : null}\n </div>\n </div>\n </div>\n );\n});\n","import type { BlockLayout, EditorController, InlineAtom, VisibleBlock } from \"@wingleeio/ori-core\";\nimport { createContext, useContext, type ReactNode } from \"react\";\n\n/** Props for a custom block renderer (atomic nodes: divider, image, …). */\nexport interface BlockRendererProps {\n editor: EditorController;\n block: VisibleBlock;\n /** The block's synthetic layout (atomic blocks: one line, no fragments). */\n layout: BlockLayout;\n}\nexport type BlockRenderer = (props: BlockRendererProps) => ReactNode;\n\n/** Props for a custom inline-atom renderer (mention chip, inline math, …). */\nexport interface AtomRendererProps {\n editor: EditorController;\n atom: InlineAtom;\n}\nexport type AtomRenderer = (props: AtomRendererProps) => ReactNode;\n\nexport interface Renderers {\n blocks: Record<string, BlockRenderer>;\n atoms: Record<string, AtomRenderer>;\n}\n\nconst EMPTY: Renderers = { blocks: {}, atoms: {} };\n\nconst RenderersContext = createContext<Renderers>(EMPTY);\nexport const RenderersProvider = RenderersContext.Provider;\nexport const useRenderers = (): Renderers => useContext(RenderersContext);\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wingleeio/ori-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "React bindings for the Ori virtualized, local-first note editor.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"styles.css"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@wingleeio/ori-
|
|
39
|
-
"@wingleeio/ori-
|
|
38
|
+
"@wingleeio/ori-core": "0.2.0",
|
|
39
|
+
"@wingleeio/ori-pretext": "0.0.1"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"react": "^18 || ^19",
|
package/styles.css
CHANGED
|
@@ -131,15 +131,13 @@
|
|
|
131
131
|
color: var(--ori-link, #2563eb);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
/* Native selection highlight, branded via --ori-selection (the browser draws
|
|
135
|
+
* the selection now that the editor is contentEditable). */
|
|
136
|
+
.ori-ce ::selection {
|
|
137
|
+
background: var(--ori-selection, rgba(56, 132, 255, 0.22));
|
|
138
138
|
}
|
|
139
|
-
|
|
140
|
-
.ori-selection-rect {
|
|
139
|
+
.ori-ce ::-moz-selection {
|
|
141
140
|
background: var(--ori-selection, rgba(56, 132, 255, 0.22));
|
|
142
|
-
border-radius: 2px;
|
|
143
141
|
}
|
|
144
142
|
|
|
145
143
|
.ori-caret {
|