@weasel-js/text-dom 0.0.0-stage → 1.9.4
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/LICENSE +21 -0
- package/README.md +26 -2
- package/dist/index.d.ts +345 -0
- package/dist/index.js +1089 -0
- package/dist/index.js.map +1 -0
- package/package.json +50 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/domOffsets.ts","../src/domRuns.ts","../src/overlayDirection.ts","../src/useTextEdit.ts"],"names":["opts","nodeStyle","sel","range","numericWeight","cssFontFamily","smallCapsScaleFor"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Character offsets in the edit overlay's DOM, counted the way `domToRuns`\n * reads its text: every text node's characters, plus one newline for each\n * break element a browser or a paste can leave behind.\n */\n\n/** One stretch of the overlay's text, in document order. */\nexport type OverlayPiece =\n | { text: Text }\n /** A newline with no text node of its own: a `<br>`, or the boundary a block opens. */\n | { br: Element }\n | { block: Element };\n\n/** Elements whose boundary reads as a newline. */\nexport const BLOCK_TAGS: ReadonlySet<string> = new Set(['DIV', 'P']);\n\n/**\n * `parent`'s text as pieces. A block (`<div>`, `<p>`) reads as a newline\n * before its contents unless it opens the text, which is how a browser renders\n * the boundary. Both offset walkers below read through here, and `domToRuns`\n * applies the same rule from `BLOCK_TAGS` in its own styled walk.\n */\nexport function overlayPieces(parent: Element): OverlayPiece[] {\n const out: OverlayPiece[] = [];\n const visit = (node: Node): void => {\n if (node.nodeType === Node.TEXT_NODE) {\n if ((node as Text).data.length > 0) out.push({ text: node as Text });\n return;\n }\n if (!(node instanceof Element)) return;\n if (node.tagName === 'BR') { out.push({ br: node }); return; }\n if (BLOCK_TAGS.has(node.tagName) && out.length > 0) out.push({ block: node });\n for (const child of node.childNodes) visit(child);\n };\n for (const child of parent.childNodes) visit(child);\n return out;\n}\n\nconst indexIn = (el: Element): number => Array.prototype.indexOf.call(el.parentNode!.childNodes, el);\n\n/** The DOM position just past a break piece, where the next character goes. */\nfunction afterBreak(piece: { br: Element } | { block: Element }): { node: Node; offset: number } {\n return 'br' in piece\n ? { node: piece.br.parentNode!, offset: indexIn(piece.br) + 1 }\n : { node: piece.block, offset: 0 };\n}\n\n/**\n * The DOM position of plain-text character position `offset`: a text node\n * and an offset into it wherever one holds the position, otherwise an element\n * and a child index (just past a `<br>` that ends the text). Offsets beyond\n * the text clamp to its end. Returns `{ node: parent, offset: 0 }` for an\n * overlay with no text.\n */\nexport function charOffsetToDomPosition(\n parent: HTMLElement,\n offset: number,\n): { node: Node; offset: number } | null {\n let remaining = offset;\n let end: { node: Node; offset: number } = { node: parent, offset: 0 };\n /** Set while the position sits just past a break, with no text met since. */\n let pending: { node: Node; offset: number } | null = null;\n for (const piece of overlayPieces(parent)) {\n if ('text' in piece) {\n const len = piece.text.data.length;\n if (remaining <= len) return { node: piece.text, offset: remaining };\n remaining -= len;\n end = { node: piece.text, offset: len };\n pending = null;\n continue;\n }\n if (remaining === 0) {\n return pending ?? ('br' in piece\n ? { node: piece.br.parentNode!, offset: indexIn(piece.br) }\n : afterBreak(piece));\n }\n remaining -= 1;\n end = afterBreak(piece);\n pending = remaining === 0 ? end : null;\n }\n return end;\n}\n\n/**\n * Inverse of `charOffsetToDomPosition`: the characters that precede the DOM\n * position `(node, offset)`.\n *\n * When `node` is an element the DOM offset indexes *child nodes*, not\n * characters — `(overlay, 0)` is the start of the text and `(overlay,\n * childNodes.length)` its end. That shape is not exotic: `Range.\n * selectNodeContents`, which `useTextEdit` uses for its select-all caret,\n * produces exactly it. So an element position is resolved by counting the\n * pieces that end at or before the boundary point.\n */\nexport function domPositionToCharOffset(\n parent: HTMLElement,\n node: Node,\n offset: number,\n): number {\n const pieces = overlayPieces(parent);\n let total = 0;\n if (node.nodeType === Node.TEXT_NODE) {\n for (const piece of pieces) {\n if (!('text' in piece)) { total += 1; continue; }\n if (piece.text === node) return total + offset;\n total += piece.text.data.length;\n }\n return total;\n }\n const point = document.createRange();\n point.setStart(node, Math.max(0, Math.min(offset, node.childNodes.length)));\n point.collapse(true);\n for (const piece of pieces) {\n if ('text' in piece) {\n // A text node cannot contain the point, so it is wholly before or after.\n if (point.comparePoint(piece.text, 0) < 0) total += piece.text.data.length;\n } else {\n const past = afterBreak(piece);\n if (point.comparePoint(past.node, past.offset) <= 0) total += 1;\n }\n }\n return total;\n}\n","/**\n * Pure DOM ↔ `StyledRun[]` serializers for the contenteditable overlay\n * used by `useTextEdit`. The overlay's children are a flat sequence of\n * `<span data-run>` elements, each carrying one run's text and inline\n * styles. Newlines inside a run are literal `\\n` characters; the overlay\n * has `white-space: pre-wrap` so they render as line breaks. The browser\n * breaks at no other UAX #14 hard break, so each of those is written as a\n * `<span data-break>` holding a `\\n` in its place — one character for one,\n * which keeps DOM offsets equal to source offsets.\n *\n * A small-caps run is the one exception to one text node per span: its\n * lowercase letters sit in `<span data-small-caps>` pieces, uppercased and\n * sized at the scale the canvas draws them with, since a browser's own\n * synthesis uses a fixed factor of its own. The pieces are presentation\n * only — `domToRuns` reads straight through them.\n */\n\nimport type { FillStyle } from '@weasel-js/paint';\nimport {\n DEFAULT_TEXT_STYLE, isHardLineBreak, numericWeight, smallCapsScaleFor, smallCapsText, transformRunTexts,\n SMALL_CAPS_SCALE,\n type FontVariantCaps, type ResolvedTextStyle, type StyledRun, type TextTransform,\n} from '@weasel-js/text';\nimport { cssFontFamily } from '@weasel-js/font';\nimport { BLOCK_TAGS } from './domOffsets';\n\nexport { charOffsetToDomPosition, domPositionToCharOffset } from './domOffsets';\n\nfunction solidColor(p: FillStyle | null | undefined): string | null {\n if (!p) return null;\n if ('color' in p) return p.color;\n return null;\n}\n\n/** Holds, as JSON, a run fill its span's CSS color cannot say: a gradient, a\n * pattern, or `null` for no fill. */\nconst FILL_ATTR = 'data-fill';\n\ninterface StyleState {\n bold: boolean;\n italic: boolean;\n underline: boolean;\n strikethrough: boolean;\n overline: boolean;\n fontWeight?: number;\n fontSize?: number;\n fontFamily?: string;\n color?: string;\n /** `FILL_ATTR`'s value, which wins over `color`. */\n fillJson?: string;\n letterSpacing?: number;\n script?: 'super' | 'sub';\n baselineShift?: number;\n fontScale?: number;\n textTransform?: TextTransform;\n fontVariantCaps?: FontVariantCaps;\n}\n\nconst TRANSFORMS: ReadonlySet<string> = new Set(['none', 'uppercase', 'lowercase', 'capitalize']);\n\nconst EMPTY_STYLE: StyleState = {\n bold: false,\n italic: false,\n underline: false,\n strikethrough: false,\n overline: false,\n};\n\n/**\n * Parse a CSS `letter-spacing` value into world units. `runsToDom` only ever\n * writes `px`, but paste is a live path into the contenteditable and CSSOM\n * keeps whatever unit the pasted markup used. Any other unit is still\n * numerically coerced — `parseFloat` reads the leading digits — but flagged,\n * since e.g. `0.1em` silently becomes `0.1` world units, off by a factor of\n * the font size. Mirrors `parseLetterSpacing` in the SVG reader.\n */\nfunction parseLetterSpacing(raw: string): number | undefined {\n const n = parseFloat(raw);\n if (!Number.isFinite(n)) return undefined;\n const unit = /^-?[\\d.]+([a-z%]+)$/i.exec(raw.trim())?.[1]?.toLowerCase();\n if (unit && unit !== 'px') {\n console.warn(\n `weasel domRuns: letter-spacing \"${raw}\" uses unit \"${unit}\", which is not converted; treated as ${n} world units`,\n );\n }\n return n;\n}\n\n/** A small-caps piece is presentation `runsToDom` split a run into, not styling. */\nconst isSmallCapsPiece = (el: Element): boolean => el.hasAttribute('data-small-caps');\n\n/** The element's own `font-variant`, from the shorthand or the caps longhand\n * pasted markup may carry alone. */\nfunction cssFontVariant(el: HTMLElement): FontVariantCaps | undefined {\n const v = el.style.fontVariant || el.style.getPropertyValue('font-variant-caps');\n return v === 'small-caps' || v === 'normal' ? v : undefined;\n}\n\nfunction styleStateFromElement(el: Element, parent: StyleState): StyleState {\n if (isSmallCapsPiece(el)) return parent;\n const next: StyleState = { ...parent };\n const tag = el.tagName;\n if (tag === 'B' || tag === 'STRONG') {\n next.bold = true;\n next.fontWeight = undefined;\n }\n if (tag === 'I' || tag === 'EM') next.italic = true;\n // `runsToDom` never emits these, but a browser contenteditable can (Cmd+U\n // runs the native `underline` command, which produces `<u>` in Chrome), so\n // read them for the same reason `<b>`/`<i>` are read.\n if (tag === 'U') next.underline = true;\n if (tag === 'S' || tag === 'STRIKE' || tag === 'DEL') next.strikethrough = true;\n if (tag === 'SUP') next.script = 'super';\n if (tag === 'SUB') next.script = 'sub';\n if (el instanceof HTMLElement) {\n // 700 and 400 are the bold flag on and off, which is what pasted markup\n // means by them. A run's own weight is written with an attribute beside\n // the CSS, so a stored 400 or 700 comes back as the weight it was.\n const fw = el.style.fontWeight;\n const ownWeight = Number(el.getAttribute('data-font-weight') ?? fw);\n if (el.hasAttribute('data-font-weight') || !['', '700', 'bold', '400', 'normal'].includes(fw)) {\n if (Number.isFinite(ownWeight) && ownWeight > 0) {\n next.fontWeight = ownWeight;\n next.bold = false;\n }\n } else if (fw !== '') {\n next.bold = fw === '700' || fw === 'bold';\n next.fontWeight = undefined;\n }\n const fs = el.style.fontStyle;\n if (fs === 'italic') next.italic = true;\n if (fs === 'normal') next.italic = false;\n // Decoration accumulates down the tree — unlike `font-weight`/`font-style`\n // above, `text-decoration` does not inherit, it *propagates*, and a\n // descendant cannot cancel what an ancestor drew. So OR the flags in\n // rather than overwriting: `<u><span style=\"text-decoration: line-through\">`\n // renders both lines, and that is a reachable shape here, since `runsToDom`\n // emits the span and an unintercepted Cmd+U supplies the `<u>`. An explicit\n // `none` contributes no tokens and cancels nothing.\n //\n // A declaration block carrying only the longhand serializes the shorthand\n // as `''` (the shorthand needs the full set), and browsers and pasted HTML\n // both produce that, so fall back to `text-decoration-line`.\n const td = el.style.textDecoration || el.style.textDecorationLine;\n if (td && !td.includes('none')) {\n next.underline ||= td.includes('underline');\n next.strikethrough ||= td.includes('line-through');\n next.overline ||= td.includes('overline');\n }\n // A percentage is `fontScale`'s own spelling — CSS resolves it against the\n // parent, which is exactly what the field means. Any other unit is an\n // absolute size.\n if (el.style.fontSize) {\n const size = parseFloat(el.style.fontSize);\n if (Number.isFinite(size)) {\n if (el.style.fontSize.trim().endsWith('%')) next.fontScale = size / 100;\n else next.fontSize = size;\n }\n }\n const va = el.style.verticalAlign;\n if (va === 'super' || va === 'sub') next.script = va === 'super' ? 'super' : 'sub';\n if (va === 'baseline') next.script = undefined;\n const rawShift = el.getAttribute('data-baseline-shift');\n if (rawShift != null) {\n const shift = parseFloat(rawShift);\n if (Number.isFinite(shift)) next.baselineShift = shift;\n }\n const tt = el.style.textTransform;\n if (TRANSFORMS.has(tt)) next.textTransform = tt as TextTransform;\n const fv = cssFontVariant(el);\n if (fv) next.fontVariantCaps = fv;\n // The attribute holds the run's family; the CSS holds the face it maps to.\n const family = el.getAttribute('data-font-family') ?? el.style.fontFamily;\n if (family) next.fontFamily = family;\n const fillJson = el.getAttribute(FILL_ATTR);\n if (fillJson != null) {\n next.fillJson = fillJson;\n next.color = undefined;\n } else if (el.style.color) {\n next.color = el.style.color;\n next.fillJson = undefined;\n }\n const ls = el.style.letterSpacing;\n if (ls === 'normal') {\n next.letterSpacing = undefined;\n } else if (ls) {\n const px = parseLetterSpacing(ls);\n if (px != null) next.letterSpacing = px;\n }\n }\n return next;\n}\n\nfunction styleEquals(a: StyleState, b: StyleState): boolean {\n return (\n a.bold === b.bold &&\n a.italic === b.italic &&\n a.underline === b.underline &&\n a.strikethrough === b.strikethrough &&\n a.overline === b.overline &&\n a.fontWeight === b.fontWeight &&\n a.fontSize === b.fontSize &&\n a.fontFamily === b.fontFamily &&\n a.color === b.color &&\n a.fillJson === b.fillJson &&\n a.letterSpacing === b.letterSpacing &&\n a.script === b.script &&\n a.baselineShift === b.baselineShift &&\n a.fontScale === b.fontScale &&\n a.textTransform === b.textTransform &&\n a.fontVariantCaps === b.fontVariantCaps\n );\n}\n\nfunction toRun(text: string, style: StyleState): StyledRun {\n const run: StyledRun = { text };\n if (style.bold) run.bold = true;\n if (style.italic) run.italic = true;\n if (style.fontWeight != null) run.fontWeight = style.fontWeight;\n if (style.fontSize != null) run.fontSize = style.fontSize;\n if (style.fontFamily != null) run.fontFamily = style.fontFamily;\n if (style.fillJson !== undefined) run.fill = JSON.parse(style.fillJson) as FillStyle | null;\n else if (style.color != null) run.fill = { fill: 'solid', color: style.color };\n // `letterSpacing: 0` is a meaningful override (it cancels node-level\n // tracking for this run), so test for presence, not truthiness.\n if (style.letterSpacing != null) run.letterSpacing = style.letterSpacing;\n // Run-level flags are additive over the node style — a run cannot un-set\n // one — so an undecorated run gets an absent key, never `false`.\n if (style.underline) run.underline = true;\n if (style.strikethrough) run.strikethrough = true;\n if (style.overline) run.overline = true;\n if (style.script != null) run.script = style.script;\n // Both are meaningful at values that test falsy — a 0 shift cancels an\n // inherited script's rise — so test for presence, as `letterSpacing` does.\n if (style.baselineShift != null) run.baselineShift = style.baselineShift;\n if (style.fontScale != null) run.fontScale = style.fontScale;\n if (style.textTransform != null) run.textTransform = style.textTransform;\n if (style.fontVariantCaps != null) run.fontVariantCaps = style.fontVariantCaps;\n return run;\n}\n\nconst BREAK_ATTR = 'data-break';\n\n/** A break stand-in's source text: its hard break, and anything typed into it after. */\nfunction restoreBreak(el: Element): string {\n const text = el.textContent ?? '';\n const code = parseInt(el.getAttribute(BREAK_ATTR) ?? '', 16);\n return text.startsWith('\\n') && Number.isFinite(code) ? String.fromCharCode(code) + text.slice(1) : text;\n}\n\n/**\n * Append `text` to `parent` as the overlay sets it: a hard break the browser\n * would not break at becomes a `<span data-break>` holding a `\\n`, carrying\n * the original's code as hex for `domToRuns` to restore. A CR that opens a\n * CRLF is left as it is — the LF breaks, and the CR draws nothing.\n */\nexport function appendOverlayText(parent: Node, text: string): void {\n let from = 0;\n for (let i = 0; i < text.length; i++) {\n const c = text.charCodeAt(i);\n if (c === 10 || !isHardLineBreak(c) || (c === 13 && text.charCodeAt(i + 1) === 10)) continue;\n if (i > from) parent.appendChild(document.createTextNode(text.slice(from, i)));\n const span = document.createElement('span');\n span.setAttribute(BREAK_ATTR, c.toString(16));\n span.textContent = '\\n';\n parent.appendChild(span);\n from = i + 1;\n }\n if (from < text.length) parent.appendChild(document.createTextNode(text.slice(from)));\n}\n\n/** Walk an overlay tree and emit a coalesced `StyledRun[]`. */\nexport function domToRuns(parent: HTMLElement): StyledRun[] {\n const fragments: Array<{ text: string; style: StyleState }> = [];\n\n function visit(node: Node, style: StyleState): void {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = (node as Text).data;\n if (text.length > 0) fragments.push({ text, style });\n return;\n }\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n const el = node as Element;\n if (el.tagName === 'BR') {\n fragments.push({ text: '\\n', style });\n return;\n }\n if (el.hasAttribute(BREAK_ATTR)) {\n const restored = restoreBreak(el);\n if (restored.length > 0) fragments.push({ text: restored, style });\n return;\n }\n if (BLOCK_TAGS.has(el.tagName) && fragments.length > 0) {\n fragments.push({ text: '\\n', style });\n }\n const nextStyle = styleStateFromElement(el, style);\n for (const child of Array.from(el.childNodes)) {\n visit(child, nextStyle);\n }\n }\n\n for (const child of Array.from(parent.childNodes)) {\n visit(child, EMPTY_STYLE);\n }\n\n // Coalesce adjacent fragments with identical style.\n const runs: StyledRun[] = [];\n let i = 0;\n while (i < fragments.length) {\n let j = i + 1;\n while (j < fragments.length && styleEquals(fragments[i].style, fragments[j].style)) {\n j++;\n }\n const merged = fragments.slice(i, j).map((f) => f.text).join('');\n runs.push(toRun(merged, fragments[i].style));\n i = j;\n }\n return runs;\n}\n\n/** What a run inherits from its node, for the overlay's small caps: which\n * runs have it, and the face and transform that decide their pieces. */\nexport type OverlayRunBase = Pick<\n ResolvedTextStyle, 'fontFamily' | 'fontWeight' | 'fontStyle' | 'textTransform' | 'fontVariantCaps'\n>;\n\n/** The custom property carrying a small-caps run's scale down to its pieces. */\nexport const SMALL_CAPS_SCALE_PROPERTY = '--weasel-small-caps';\n\n/** A run's source text cut where small caps changes size, per `smallCapsText`\n * over the text as `transform` draws it. */\nfunction smallCapsPieces(text: string, transform: TextTransform): Array<{ text: string; small: boolean }> {\n const [shown] = transformRunTexts([text], [transform]);\n const caps = smallCapsText(shown.text, shown.srcMap);\n const small = new Array<boolean>(text.length).fill(false);\n caps.small?.forEach((s, i) => {\n if (s) small[caps.srcMap ? caps.srcMap.starts[i] : i] = true;\n });\n const out: Array<{ text: string; small: boolean }> = [];\n let at = 0;\n for (const ch of text) {\n const last = out[out.length - 1];\n if (last && last.small === small[at]) last.text += ch;\n else out.push({ text: ch, small: small[at] });\n at += ch.length;\n }\n return out;\n}\n\n/** Replace `span`'s children with `text`, its small-caps letters in pieces. */\nfunction writeSmallCaps(span: HTMLElement, text: string, transform: TextTransform): void {\n span.replaceChildren();\n for (const p of smallCapsPieces(text, transform)) {\n if (!p.small) { appendOverlayText(span, p.text); continue; }\n const piece = document.createElement('span');\n piece.setAttribute('data-small-caps', '');\n piece.style.fontSize = `calc(var(${SMALL_CAPS_SCALE_PROPERTY}, ${SMALL_CAPS_SCALE}) * 1em)`;\n piece.style.textTransform = 'uppercase';\n piece.textContent = p.text;\n span.appendChild(piece);\n }\n}\n\n/**\n * Build a flat sequence of `<span data-run>` children from `runs`, replacing\n * any existing children of `parent`. `base` is the node's style, which a run\n * inheriting small caps needs to be split by; without it the kit defaults\n * stand in.\n */\nexport function runsToDom(\n runs: readonly StyledRun[],\n parent: HTMLElement,\n base: OverlayRunBase = DEFAULT_TEXT_STYLE,\n): void {\n parent.replaceChildren();\n for (const run of runs) {\n const span = document.createElement('span');\n span.setAttribute('data-run', '');\n if ((run.fontVariantCaps ?? base.fontVariantCaps) === 'small-caps') {\n const scale = smallCapsScaleFor(\n run.fontFamily ?? base.fontFamily,\n run.fontWeight ?? (run.bold ? 700 : numericWeight(base.fontWeight)),\n run.italic ? 'italic' : base.fontStyle,\n );\n span.style.setProperty(SMALL_CAPS_SCALE_PROPERTY, String(scale));\n writeSmallCaps(span, run.text, run.textTransform ?? base.textTransform);\n } else {\n appendOverlayText(span, run.text);\n }\n // CSS as well as the pieces: it is what pasted markup says, and it gives a\n // letter typed outside a piece a small cap until the next normalize.\n if (run.fontVariantCaps != null) span.style.fontVariant = run.fontVariantCaps;\n if (run.fontWeight != null) {\n span.style.fontWeight = String(run.fontWeight);\n span.setAttribute('data-font-weight', String(run.fontWeight));\n } else if (run.bold) span.style.fontWeight = '700';\n if (run.italic) span.style.fontStyle = 'italic';\n // An absolute size wins over a relative one, as it does in `resolveRuns`.\n if (run.fontSize != null) span.style.fontSize = `${run.fontSize}px`;\n else if (run.fontScale != null) span.style.fontSize = `${run.fontScale * 100}%`;\n if (run.fontFamily != null) {\n span.style.fontFamily = cssFontFamily(run.fontFamily, {\n weight: run.fontWeight ?? (run.bold ? 700 : undefined),\n style: run.italic ? 'italic' : undefined,\n });\n span.setAttribute('data-font-family', run.fontFamily);\n }\n const color = solidColor(run.fill);\n if (color != null) span.style.color = color;\n else if (run.fill !== undefined) span.setAttribute(FILL_ATTR, JSON.stringify(run.fill));\n // Black, as an unfilled node edits in: no CSS color leaves it legible.\n if (run.fill === null) span.style.color = '#000';\n // Decoration goes on the span as an inline style rather than `<u>`/`<s>`\n // wrappers: one representation for `domToRuns` to unwrap, and one element\n // per run so the caret-offset walkers stay flat.\n const decorations: string[] = [];\n if (run.underline) decorations.push('underline');\n if (run.strikethrough) decorations.push('line-through');\n if (run.overline) decorations.push('overline');\n if (decorations.length > 0) span.style.textDecoration = decorations.join(' ');\n if (run.script != null) span.style.verticalAlign = run.script;\n // The one run field with no CSS spelling: `vertical-align` takes a length\n // or a percentage of the *line height*, and this is a fraction of the\n // parent's font size. An attribute keeps the round-trip exact; the canvas\n // underneath is what actually draws the run at its offset.\n if (run.baselineShift != null) {\n span.setAttribute('data-baseline-shift', String(run.baselineShift));\n }\n // World units — the overlay's own node-level tracking is screen-scaled,\n // but a run override is stored as-is so the round-trip is lossless. CSS\n // `letter-spacing` is inherited and a child declaration *replaces* the\n // inherited value, so this composes with the overlay's rather than adding.\n if (run.letterSpacing != null) span.style.letterSpacing = `${run.letterSpacing}px`;\n // CSS draws the transform, so the span's text stays the source and the\n // caret-offset walkers below need no map.\n if (run.textTransform != null) span.style.textTransform = run.textTransform;\n parent.appendChild(span);\n }\n}\n\n/** `el`'s text as `domToRuns` reads it: each break stand-in restored. */\nfunction sourceText(el: Element): string {\n let out = '';\n for (const n of el.childNodes) {\n if (n.nodeType === Node.TEXT_NODE) out += (n as Text).data;\n else if (n instanceof Element) out += n.hasAttribute(BREAK_ATTR) ? restoreBreak(n) : sourceText(n);\n }\n return out;\n}\n\n/** Whether `span`'s children are the pieces `writeSmallCaps` would write. */\nfunction piecesMatch(span: HTMLElement, transform: TextTransform): boolean {\n const want = smallCapsPieces(sourceText(span), transform);\n const have: Array<{ text: string; small: boolean }> = [];\n for (const n of span.childNodes) {\n let small: boolean;\n let text: string;\n if (n.nodeType === Node.TEXT_NODE) { small = false; text = (n as Text).data; }\n else if (n instanceof HTMLElement && n.hasAttribute(BREAK_ATTR)) { small = false; text = restoreBreak(n); }\n else if (n instanceof HTMLElement && isSmallCapsPiece(n) && n.children.length === 0) { small = true; text = n.textContent ?? ''; }\n else return false;\n if (text.length === 0) continue;\n const last = have[have.length - 1];\n if (last && last.small === small) last.text += text;\n else have.push({ text, small });\n }\n return want.length === have.length\n && want.every((p, i) => p.text === have[i].text && p.small === have[i].small);\n}\n\n/**\n * Put every run span's small-caps pieces back where its text now needs them —\n * typing lands a letter in whichever piece holds the caret, not the one its\n * case belongs in. Returns whether anything was rewritten, which moves the\n * DOM selection: the caller restores it by character offset.\n */\nexport function normalizeSmallCaps(parent: HTMLElement): boolean {\n let changed = false;\n const visit = (el: HTMLElement, variant: FontVariantCaps, transform: TextTransform): void => {\n const v = cssFontVariant(el) ?? variant;\n const tt = el.style.textTransform;\n const t = TRANSFORMS.has(tt) ? (tt as TextTransform) : transform;\n if (el.hasAttribute('data-run')) {\n if (v === 'small-caps') {\n if (!piecesMatch(el, t)) { writeSmallCaps(el, sourceText(el), t); changed = true; }\n } else if (el.querySelector('[data-small-caps]')) {\n const text = sourceText(el);\n el.replaceChildren();\n appendOverlayText(el, text);\n changed = true;\n }\n return;\n }\n for (const child of el.children) if (child instanceof HTMLElement) visit(child, v, t);\n };\n visit(parent, 'normal', 'none');\n return changed;\n}\n","/**\n * The edit overlay's reading direction, alignment, and tab stops, set so the\n * browser resolves them the way `layoutRuns` does for the canvas.\n */\nimport { paragraphDirection, resolveAlign, type ResolvedTextStyle } from '@weasel-js/text';\n\n/**\n * A stated direction goes on the overlay as CSS `direction`. `auto` becomes\n * `unicode-bidi: plaintext`, CSS's spelling of \"each paragraph reads the way\n * its first strong character does\", under which `start` and `end` follow each\n * paragraph too, so those are left for the browser to resolve.\n */\nexport function applyOverlayDirection(el: HTMLElement, style: ResolvedTextStyle): void {\n const auto = style.direction === 'auto';\n el.style.direction = auto ? '' : style.direction;\n el.style.setProperty('unicode-bidi', auto ? 'plaintext' : '');\n el.style.setProperty('tab-size', String(style.tabSize));\n const justify = style.align === 'justify';\n const edge = style.direction === 'auto'\n ? (justify ? 'start' : style.align)\n : resolveAlign(style.align, style.direction);\n el.style.textAlign = justify ? 'justify' : edge;\n // Pinned, so a justified paragraph's last line sits where the canvas puts it.\n el.style.setProperty('text-align-last', justify ? edge : '');\n}\n\n/** The absolute edge the overlay's text is set from, by its first paragraph. */\nexport function overlayAlignEdge(el: HTMLElement, style: ResolvedTextStyle): 'left' | 'center' | 'right' {\n return resolveAlign(style.align, paragraphDirection(el.textContent ?? '', style.direction));\n}\n","/**\n * In-place text editing via a contenteditable overlay positioned over the\n * text node's screen-space pose. Enter / blur commit; Shift+Enter inserts a\n * newline; Escape cancels. The hook owns the DOM lifecycle of the overlay\n * element — caller just provides a container, the lookup hooks, and a\n * `setText` callback (which is responsible for op-batching/undo).\n *\n * The text layer should hide the node it's currently editing\n * (`isHidden: (n) => n.id === editingId`) so the overlay isn't drawn twice.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useLatest, useVisibleRaf } from '@weasel-js/react';\nimport type { ResolvedTextStyle, TextStyle } from '@weasel-js/text';\nimport {\n fontString, numericWeight, resolveTextStyle, scriptMetricsFor, smallCapsScaleFor,\n} from '@weasel-js/text';\nimport { cssFontFamily, cssFontFamilyLoading, isCanvasFont } from '@weasel-js/font';\nimport type { TextPaint, TextVerticalAlign } from '@weasel-js/text';\nimport { layoutTextPose, verticalAlignOffset } from '@weasel-js/text';\nimport type { StyledRun } from '@weasel-js/text';\nimport { runsToPlainText } from '@weasel-js/text';\nimport {\n runsToDom, domToRuns, appendOverlayText, charOffsetToDomPosition, domPositionToCharOffset, normalizeSmallCaps,\n SMALL_CAPS_SCALE_PROPERTY, type OverlayRunBase,\n} from './domRuns';\nimport {\n applyStyleToRange, nodeHasFlag, patchRangeStyle, rangeWeight, runsCarryStyling, setFlagOverRange,\n styleAtRange, supersededKey, unboldPatch, type FlagKey, type RangeStyle, type RunStylePatch,\n} from '@weasel-js/text';\nimport { applyOverlayDirection, overlayAlignEdge } from './overlayDirection';\n\n/**\n * A styling a shortcut or a control toggles. The additive booleans, plus the\n * two `script` values — which are exclusive rather than additive, so they\n * toggle against one enum rather than each owning a boolean.\n */\nexport type StyleToggle = FlagKey | 'super' | 'sub';\n\n/**\n * The shortcut each styling answers to. Strikethrough takes Cmd+Shift+X\n * (Docs' binding) and MUST require shift: bare Cmd+X is cut, and swallowing\n * it here would break cutting text mid-edit. Superscript takes Word's\n * Cmd+Shift+=; subscript takes Cmd+Shift+- rather than Word's Cmd+-, because\n * the unshifted pair is browser zoom, which a page cannot cancel.\n * `overline` has no shortcut — no editor has established one — and is\n * reachable only from a control.\n *\n * Matching is on the *unshifted* character (`shiftedKey`): a US layout\n * reports Cmd+Shift+= as `'+'` and Cmd+Shift+- as `'_'`, so keying the table\n * on what the legend says needs that mapping to survive the shift.\n *\n * Underline has to be intercepted, not merely supported. Left alone, the\n * browser runs its own `formatUnderline` and `domToRuns`' `<u>` flattening\n * makes that *look* like it worked while bypassing `patchForToggle`\n * entirely — no toggle-off, no mixed-range \"turn the whole selection on\"\n * rule, no pending style for a collapsed caret. The flattening stays\n * regardless, since it is what lets pasted decoration survive, but it is\n * defense in depth and was never the mechanism.\n */\nconst STYLE_SHORTCUTS: ReadonlyArray<{ key: string; shift: boolean; toggle: StyleToggle }> = [\n { key: 'b', shift: false, toggle: 'bold' },\n { key: 'i', shift: false, toggle: 'italic' },\n { key: 'u', shift: false, toggle: 'underline' },\n { key: 'x', shift: true, toggle: 'strikethrough' },\n { key: '=', shift: true, toggle: 'super' },\n { key: '-', shift: true, toggle: 'sub' },\n];\n\n/** The characters shift produces from the keys the table names. */\nconst UNSHIFT: Readonly<Record<string, string>> = { '+': '=', _: '-' };\n\n/** The styling `e` toggles, or null when it isn't a styling shortcut. */\nfunction toggleForKey(e: KeyboardEvent): StyleToggle | null {\n if (!e.metaKey && !e.ctrlKey) return null;\n const raw = e.key.toLowerCase();\n const key = UNSHIFT[raw] ?? raw;\n return STYLE_SHORTCUTS.find((s) => s.key === key && s.shift === e.shiftKey)?.toggle ?? null;\n}\n\n/**\n * The patch that toggles `toggle` against the styling in `current`: if it is\n * already carried, clear it; otherwise set it — so a mixed range turns fully\n * on, as in every other text editor. `script` clears to `undefined` rather\n * than to `false`, since the off state of an enum is its absence.\n *\n * `nodeStyle` is read as well as `current`, and has to be: a node flag\n * renders on every run whether or not the runs carry it, so a toggle that\n * consulted the runs alone would read Cmd+B inside a `fontWeight: 700` node\n * as \"not bold\" and *add* bold rather than clearing it. `script` has no node\n * level to consult — by design; see `StyledRun.script`.\n */\nfunction patchForToggle(\n current: RangeStyle,\n toggle: StyleToggle,\n nodeStyle: TextStyle,\n): RunStylePatch {\n if (toggle === 'super' || toggle === 'sub') {\n return { script: current.script === toggle ? undefined : toggle };\n }\n const on = toggle === 'bold'\n ? rangeWeight(current, nodeStyle).bold === true\n : current[toggle] === true || nodeHasFlag(nodeStyle, toggle);\n return { [toggle]: !on };\n}\n\n/**\n * The styling at a collapsed caret: the run to its left, or — at the very\n * start of the text — the run to its right. This is what the next typed\n * character inherits, so it is what a character bar should be showing.\n */\nfunction styleAtCaret(runs: readonly StyledRun[], at: number): RangeStyle {\n return at > 0 ? styleAtRange(runs, at - 1, at) : styleAtRange(runs, 0, 1);\n}\n\n/**\n * Splice `run` into `runs` at character offset `at`, splitting whichever run\n * spans it. The result is normalized (empty runs dropped, identical\n * neighbours merged) by the same algebra every other write goes through.\n */\nfunction spliceRunAt(runs: readonly StyledRun[], at: number, run: StyledRun): StyledRun[] {\n const out: StyledRun[] = [];\n let pos = 0;\n let placed = false;\n for (const r of runs) {\n const end = pos + r.text.length;\n if (!placed && at <= end) {\n const k = at - pos;\n if (k > 0) out.push({ ...r, text: r.text.slice(0, k) });\n out.push(run);\n if (k < r.text.length) out.push({ ...r, text: r.text.slice(k) });\n placed = true;\n } else {\n out.push({ ...r });\n }\n pos = end;\n }\n if (!placed) out.push(run);\n // An empty patch over an empty range: this is the array-wide normalization\n // pass, not a styling.\n return applyStyleToRange(out, 0, 0, {});\n}\n\n/**\n * Return focus to the overlay after a styling arrived from editor chrome.\n *\n * A control that took focus in order to be clicked still holds it when the\n * patch lands, so the next keystroke goes to that button — and in an app that\n * binds bare letters to tools, \"click Superscript, then type the 2\" activates\n * the Text tool and pans the canvas instead of typing a 2. Restoring the\n * caret is what makes a styling control usable mid-edit at all.\n *\n * Two things are left holding focus deliberately: a text entry in the chrome\n * (the user is still typing a font size — stealing that is worse than the\n * problem) and anything inside an open dialog, which is where a color\n * picker's live `onChange` fires from.\n */\nfunction restoreOverlayFocus(overlay: HTMLElement, range: TextEditSelection): void {\n const active = document.activeElement;\n if (active === overlay || overlay.contains(active)) return;\n if (\n active instanceof HTMLInputElement\n || active instanceof HTMLTextAreaElement\n || (active instanceof HTMLElement && active.isContentEditable)\n || (active instanceof Element && active.closest('[role=\"dialog\"]') !== null)\n ) return;\n overlay.focus();\n const a = charOffsetToDomPosition(overlay, range.start);\n const b = charOffsetToDomPosition(overlay, range.end);\n const sel = window.getSelection();\n if (!a || !b || !sel) return;\n const r = document.createRange();\n r.setStart(a.node, a.offset);\n r.setEnd(b.node, b.offset);\n sel.removeAllRanges();\n sel.addRange(r);\n}\n\n/**\n * Put the caret *between* two run spans when `offset` falls on the boundary\n * of one, rather than at the same offset inside the left span's text node.\n *\n * The two positions are the same character offset and browsers report them\n * identically, but they type differently: a caret inside a span has the next\n * character absorbed by that run, and one between spans starts a fresh one.\n * That distinction is the whole point after a pending style has just been\n * committed to its own run — otherwise the character after a superscript is\n * superscript too. Leaves the selection alone when the offset falls mid-run,\n * where there is no boundary to prefer.\n */\nfunction placeCaretBetweenRuns(\n overlay: HTMLElement,\n runs: readonly StyledRun[],\n offset: number,\n): void {\n let acc = 0;\n let index = -1;\n for (let i = 0; i < runs.length; i++) {\n acc += runs[i].text.length;\n if (acc === offset) { index = i; break; }\n if (acc > offset) return;\n }\n const span = index >= 0 ? overlay.children[index] : null;\n const sel = window.getSelection();\n if (!span || !sel) return;\n const range = document.createRange();\n range.setStartAfter(span);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/** No pending style. One frozen object so re-publishing an already-empty\n * pending style doesn't re-render every consumer. */\nconst NO_PENDING: RunStylePatch = Object.freeze({});\n\n/**\n * Merge `patch` into a pending style. A key set to `false` or `undefined` is\n * deleted rather than stored — the same canonical form `patchRun` keeps, so\n * the pending style and a stored run agree on what \"off\" looks like, and\n * bold and a weight supersede each other here as they do there.\n */\nfunction mergePending(prev: RunStylePatch, patch: RunStylePatch): RunStylePatch {\n const next: Record<string, unknown> = { ...prev };\n const superseded = supersededKey(patch);\n if (superseded !== undefined) delete next[superseded];\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined || value === false) delete next[key];\n else next[key] = value;\n }\n return next as RunStylePatch;\n}\n\n/**\n * The caret's character range within the text being edited. Half-open\n * `[start, end)` over the concatenated run text, normalized so `start <= end`\n * regardless of which way the user dragged. `start === end` is a collapsed\n * caret — a real position, not the absence of one, which is why the hook\n * reports `null` rather than a zero-width range when there is no caret.\n */\nexport interface TextEditSelection {\n start: number;\n end: number;\n}\n\n/**\n * Character offsets of the current DOM selection within `overlay`, or `null`\n * when there is no selection or it lies outside the overlay. The one\n * DOM→offset conversion in the hook; everything that needs offsets goes\n * through here.\n */\nfunction readSelectionOffsets(overlay: HTMLElement): TextEditSelection | null {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n const range = sel.getRangeAt(0);\n if (!overlay.contains(range.startContainer) || !overlay.contains(range.endContainer)) {\n return null;\n }\n // `Range` boundary points are already in document order, so this is the\n // normalization for a backwards drag — anchor/focus are not consulted.\n const start = domPositionToCharOffset(overlay, range.startContainer, range.startOffset);\n const end = domPositionToCharOffset(overlay, range.endContainer, range.endOffset);\n return start <= end ? { start, end } : { start: end, end: start };\n}\n\n/**\n * Replace the overlay's contents with `runs` and put the caret back on\n * `[start, end)`. Rewriting the DOM destroys the selection, and losing it\n * after every styling change would mean re-selecting the word to apply a\n * second style — so this is the only way styling writes back.\n *\n * The caret is **not** restored while focus sits in a text-entry control.\n * Browsers route editing commands by selection rather than by focus, so a\n * document selection put back inside the contenteditable while a bar's\n * number field has focus means the very Enter that committed that field also\n * runs its `insertParagraph` default over the restored range — replacing the\n * text that was just styled with a line break. (Observed in Chrome.)\n *\n * Focus on a *button* is the opposite case and must still restore: toggling\n * bold, then italic, then underline is one flow over one selection, and\n * clicking a toolbar button does take focus. Buttons turn keystrokes into\n * clicks, not into editing commands, so the range is safe there.\n *\n * The hook remembers the range as character offsets either way, so a skipped\n * restore costs the highlight, never the target.\n */\nfunction writeRunsPreservingSelection(\n overlay: HTMLElement,\n runs: readonly StyledRun[],\n start: number,\n end: number,\n base: OverlayRunBase,\n): void {\n const active = document.activeElement;\n const inTextEntry =\n active !== overlay &&\n !overlay.contains(active) &&\n (active instanceof HTMLInputElement ||\n active instanceof HTMLTextAreaElement ||\n (active instanceof HTMLElement && active.isContentEditable));\n runsToDom(runs, overlay, base);\n if (inTextEntry) return;\n const a = charOffsetToDomPosition(overlay, start);\n const b = charOffsetToDomPosition(overlay, end);\n const sel = window.getSelection();\n if (!a || !b || !sel) return;\n const range = document.createRange();\n range.setStart(a.node, a.offset);\n range.setEnd(b.node, b.offset);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * Drop the one trailing newline a contenteditable keeps so the caret has\n * somewhere to sit on the last line. `domToRuns` maps the `<br>` to a\n * literal `'\\n'`, which the edit never typed. Exactly one, so a newline\n * the user actually typed survives — the holder is never doubled.\n *\n * An empty run left behind is dropped: it carries no text and would otherwise\n * defeat `runsCarryStyling`'s \"did this edit produce styling\" question by\n * existing.\n */\nfunction trimCaretHolder(runs: StyledRun[]): StyledRun[] {\n const last = runs[runs.length - 1];\n if (last === undefined || !last.text.endsWith('\\n')) return runs;\n const trimmed = { ...last, text: last.text.slice(0, -1) };\n const head = runs.slice(0, -1);\n return trimmed.text === '' ? head : [...head, trimmed];\n}\n\nfunction sameSelection(a: TextEditSelection | null, b: TextEditSelection | null): boolean {\n if (a === null || b === null) return a === b;\n return a.start === b.start && a.end === b.end;\n}\n\n/** Screen-space pose passed to `useTextEdit` so the overlay can be placed and sized in CSS pixels. */\nexport interface TextEditScreenPose {\n /** Top-left in CSS pixels relative to `container`. Always screen pixels,\n * including when `zoom` is set — the scale is anchored at this point, not\n * translated by it. */\n x: number;\n y: number;\n /** Pre-scale — CSS pixels, or world units when `zoom` is set. */\n width: number;\n height: number;\n /** Pre-scale font size: `style.fontSize * zoom` when `zoom` is omitted, the\n * world-unit `style.fontSize` when it is set. */\n fontSize: number;\n /** Effective on-screen line height multiplier (defaults to style.lineHeight). */\n lineHeight?: number;\n /**\n * Where the text sits within `height`, as the canvas places it. `'center'`\n * and `'bottom'` size the overlay to its own content and offset it by the\n * slack, re-measured as typing changes the line count. Default `'top'`.\n */\n verticalAlign?: TextVerticalAlign;\n /**\n * CSS scale applied to the overlay (`transform: scale(zoom)`, anchored at\n * its top-left). Every other size on this pose, and every typographic\n * metric the hook writes, is then **pre-scale** — pass world units and the\n * transform does the world→screen conversion.\n *\n * This is the only way run-level typography can be correct at a zoom other\n * than 1. `runsToDom` emits run `fontSize` / `letterSpacing` in world units\n * and `domToRuns` reads them straight back; threading a scale through the\n * writer and its inverse through the reader would go lossy on fractional\n * zooms. Scaling the whole overlay instead leaves that serializer pure and\n * scales node-level and run-level values by the same factor for free.\n *\n * Omit it (the default, `1`) and the pose is plain screen pixels — the hook\n * then infers the world→screen factor from `fontSize / style.fontSize` to\n * scale node-level `letterSpacing`, and run-level overrides are left\n * unscaled. Correct only at zoom 1.\n */\n zoom?: number;\n}\n\n/** A box in CSS pixels relative to `useTextEdit`'s `container`. */\nexport interface TextEditClipRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** What one edit session changed, as `UseTextEditOptions.commit` receives it. */\nexport interface TextEditCommit {\n text: string;\n runs?: StyledRun[];\n style?: TextStyle;\n}\n\n/** Options for `useTextEdit`. */\nexport interface UseTextEditOptions {\n /** Element the overlay is appended to. Must be `position: relative`/absolute. */\n container: HTMLElement | null;\n /** Read the current text for `id`. */\n getText: (id: string) => string;\n /** Read style for `id` (used for font setup on the overlay). */\n getStyle: (id: string) => TextStyle | undefined;\n /**\n * Read the node's paint for `id` — its `data.fill` / `data.stroke`. The\n * overlay paints its text and caret from the fill, so omitting this\n * renders every node's editor in the default black however the node\n * itself is painted.\n */\n getPaint?: (id: string) => TextPaint | undefined;\n /**\n * Write style back for `id`. Optional; needed only to turn a flag **off**\n * inside a node whose own `TextStyle` sets it. Run flags are additive, so\n * that edit is expressed by lowering the node flag and raising it on the\n * runs outside the selection — which needs somewhere to put the new node\n * style. Without this or `commit`, such a toggle is declined and nothing\n * changes. See `flagRange` in `@weasel-js/text`.\n *\n * Called when the edit commits, never during it: the session holds the\n * rewritten style until then (see `UseTextEditReturn.nodeStyle`), so a\n * canceled edit writes nothing.\n */\n setStyle?: (id: string, style: TextStyle) => void;\n /** Read screen-space pose for `id`. Called per frame while editing. */\n getScreenPose: (id: string) => TextEditScreenPose | null;\n /**\n * The box, in CSS pixels relative to `container`, the overlay is visible\n * within — where the canvas clips the glyphs the overlay stands in for.\n * Re-read every frame. Omit it, or return `null`, to clip nothing.\n *\n * The clip cannot scroll, so a caret moving past its edge leaves the page\n * where it is; a scrollable container would drag the canvas after the caret.\n */\n getClipRect?: () => TextEditClipRect | null;\n /** Commit text. Caller wraps in op/undo. Required unless `commit` is given. */\n setText?: (id: string, text: string) => void;\n /**\n * Take the whole edit in one call, so the caller can make it one write and\n * one undo step. When given, it replaces `setText`, `setRuns`, and\n * `setStyle`, none of which is called. `runs` is present when runs are in\n * play (see `setRuns`), `style` when the edit rewrote the node's own style\n * (see `setStyle`).\n */\n commit?: (id: string, edit: TextEditCommit) => void;\n /**\n * Optional: read the current rich-text runs for `id`. When provided AND\n * returns a non-empty array, the overlay renders the runs as styled\n * `<span data-run>` elements; otherwise the overlay is seeded with plain\n * text via `getText`.\n */\n getRuns?: (id: string) => readonly StyledRun[] | undefined;\n /**\n * Optional: commit rich-text runs back to the node. When omitted, only\n * `setText` is called with the plain-text form on commit. When provided,\n * commit calls both `setText` (with `runsToPlainText(runs)`) and\n * `setRuns(id, runs)` — but only when runs are actually in play: the node\n * already had some, or the edit produced styling. A plain-text edit of a\n * plain-text node still calls `setText` alone, so a node that has never\n * been styled doesn't grow a single-run `runs` array just for being edited.\n */\n setRuns?: (id: string, runs: StyledRun[]) => void;\n /**\n * Is `el` part of the editor's own chrome — a character-options bar, a\n * color popover, anything whose whole purpose is to style the text being\n * edited? Focus moving into one does not end the edit.\n *\n * Without this, the controls the feature exists for are exactly what\n * destroys it: clicking a size field blurs the overlay, blur commits, and\n * the caret the control was about to act on is gone. Toggle buttons can\n * dodge it by `preventDefault()`-ing their own mousedown, but a field the\n * user has to type into cannot.\n *\n * Chrome focus does not disturb the reported `selection` either — see\n * `UseTextEditReturn.selection`.\n */\n isEditorChrome?: (el: Element) => boolean;\n /** What Escape does to the edit: `'cancel'` (the default) drops it,\n * `'commit'` keeps the text as Enter would. */\n escape?: 'cancel' | 'commit';\n /**\n * How long, in ms, an edit opening waits for the overlay's face before\n * showing the text in the fallback. Defaults to {@link TEXT_EDIT_FONT_HOLD}.\n *\n * The overlay stands in for canvas text the host has hidden, so the wait\n * shows nothing at all; past it, the fallback shows and reflows to the real\n * face when that lands. A face already loaded — the usual case, since\n * `@weasel-js/font` builds it as soon as its bytes arrive — shows at once.\n * `0` never waits.\n */\n fontHold?: number;\n}\n\n/**\n * The default {@link UseTextEditOptions.fontHold}: at 100ms a blank edit\n * still reads as an instant response, and it is the block period CSS gives\n * `font-display: fallback` for the same trade.\n */\nexport const TEXT_EDIT_FONT_HOLD = 100;\n\n/** Options for `useTextEdit().startEdit`. */\nexport interface StartEditOptions {\n /**\n * Where to place the caret on edit start. Number = caret offset (0..text.length);\n * `'all'` selects the whole text (default — preserves the prior behavior).\n */\n caret?: number | 'all';\n}\n\n/** Return shape of `useTextEdit`. */\nexport interface UseTextEditReturn {\n editingId: string | null;\n startEdit: (id: string, opts?: StartEditOptions) => void;\n cancelEdit: () => void;\n /** End the edit and write it. An edit that leaves the text, the runs, and\n * the node's style as it found them writes nothing. */\n commit: () => void;\n isEditing: (id: string) => boolean;\n /**\n * The node-wide style this edit has rewritten and not yet written back, or\n * `null` when it has rewritten none (the node's own style stands) or\n * nothing is being edited. Lowering a flag the node sets rewrites it; the\n * write waits for the commit. A control showing the node's style during an\n * edit reads this first.\n */\n nodeStyle: TextStyle | null;\n /**\n * The caret's character range, or `null` when nothing is being edited. A\n * collapsed caret reports `{ start: n, end: n }`, so `null` and \"caret at\n * n\" stay distinguishable — a styling written at a collapsed caret arms\n * {@link UseTextEditReturn.pendingStyle} instead of restyling a range.\n *\n * Follows the DOM selection, which browsers (and jsdom) report from a task\n * rather than synchronously; anything this hook writes itself updates it\n * synchronously. A DOM selection that leaves the overlay does **not** clear\n * it: that is what happens when the user clicks a styling control, and\n * reporting `null` there would read as \"collapsed caret\" and send the\n * control's patch to the node instead of to the range. It is cleared on\n * `startEdit` and when the edit ends.\n */\n selection: TextEditSelection | null;\n /**\n * The styling shared by every run in `selection` — a concrete value where\n * the range agrees, `MIXED` where it doesn't. `null` exactly when\n * `selection` is `null`. A collapsed caret reports the styling *at* the\n * caret (the run to its left, or the run to its right at offset 0), which\n * is what the next typed character inherits.\n *\n * This does not include {@link UseTextEditReturn.pendingStyle}. A control\n * showing what the next character will look like wants both, merged in\n * that order; one showing what is already written wants only this.\n */\n rangeStyle: RangeStyle | null;\n /**\n * Styling armed at a collapsed caret, applied to the next character typed\n * and then dropped. `{}` when nothing is armed — which is always the case\n * while `selection` covers a real range, since a range is styled directly.\n *\n * Moving the caret abandons it, as in any other editor.\n */\n pendingStyle: RunStylePatch;\n /**\n * Write `patch` over `selection`. A no-op with no active edit or an empty\n * patch. Over a real range this restyles the runs under it; at a collapsed\n * caret it merges into `pendingStyle` instead, so the styling lands on\n * what gets typed next rather than on text the user didn't select.\n *\n * Lowering a flag the *node* sets is neither of those — a run cannot say\n * \"not italic\" — so it rewrites instead: the node flag is cleared and raised\n * on every run outside the range. Bold is spared that: a run's own\n * `fontWeight` can say \"regular\", so it is written over the range.\n *\n * The caret survives, so a second style can be applied without\n * re-selecting, and `rangeStyle` reflects the write before this returns.\n */\n applyStyleToSelection: (patch: RunStylePatch) => void;\n /**\n * Toggle one styling over `selection` — set it if the range doesn't\n * uniformly carry it, clear it if it does. The shape a B / I / x² control\n * or a keyboard shortcut wants, and what this hook's own shortcuts call.\n */\n toggleStyle: (toggle: StyleToggle) => void;\n}\n\n/** In-place text editing via a contenteditable overlay positioned over the text node's screen-space pose. */\nexport function useTextEdit(\n opts: UseTextEditOptions,\n): UseTextEditReturn {\n const optsRef = useLatest(opts);\n\n const [editingId, setEditingId] = useState<string | null>(null);\n // `applyStyleToSelection` needs the node being edited to reach its\n // `TextStyle`, and is called from event handlers rather than from render.\n const editingIdRef = useLatest(editingId);\n const overlayRef = useRef<HTMLDivElement | null>(null);\n /** The editing node's resolved style, which run spans inheriting small caps\n * are split by whenever the runs are rewritten. */\n const baseRef = useRef<OverlayRunBase>(resolveTextStyle(undefined));\n const [nodeStyle, setNodeStyle] = useState<TextStyle | null>(null);\n /** `nodeStyle`, read synchronously by the handlers that rewrite and commit it. */\n const nodeStyleRef = useRef<TextStyle | null>(null);\n const holdNodeStyle = useCallback((style: TextStyle | null) => {\n nodeStyleRef.current = style;\n setNodeStyle(style);\n }, []);\n const styleOf = useCallback(\n (id: string): TextStyle | undefined => nodeStyleRef.current ?? optsRef.current.getStyle(id),\n [optsRef],\n );\n // The overlay-follow loop is built inside the editing effect; the gate's\n // frame callback reaches it through this ref.\n const tickRef = useRef<() => void>(() => {});\n const frameLoop = useVisibleRaf(() => { tickRef.current(); });\n const initialCaretRef = useRef<number | 'all'>('all');\n /** What the overlay read back as when the edit opened, before any input. */\n const openedRef = useRef<string | null>(null);\n const [selection, setSelection] = useState<TextEditSelection | null>(null);\n const [rangeStyle, setRangeStyle] = useState<RangeStyle | null>(null);\n const [pendingStyle, setPendingStyle] = useState<RunStylePatch>(NO_PENDING);\n /** The pending style, read synchronously by `beforeinput` — which fires\n * well before React has re-rendered with the state above. */\n const pendingRef = useRef<RunStylePatch>(NO_PENDING);\n /** The caret offset the pending style was armed at, or `null` when nothing\n * is armed. Publishing any other range abandons it. */\n const pendingAtRef = useRef<number | null>(null);\n\n const armPending = useCallback((next: RunStylePatch, at: number) => {\n const empty = Object.keys(next).length === 0;\n pendingRef.current = empty ? NO_PENDING : next;\n pendingAtRef.current = empty ? null : at;\n setPendingStyle(pendingRef.current);\n }, []);\n\n const dropPending = useCallback(() => {\n if (pendingAtRef.current === null) return;\n pendingRef.current = NO_PENDING;\n pendingAtRef.current = null;\n setPendingStyle(NO_PENDING);\n }, []);\n\n /**\n * The published range, mirrored in a ref. `applyStyleToSelection` reads it\n * synchronously, and it is the fallback when the DOM selection has moved\n * into editing chrome. Cleared with the state, never separately.\n */\n const selectionRef = useRef<TextEditSelection | null>(null);\n\n /**\n * Recompute the published caret range and its styling from the overlay.\n * Called from the `selectionchange` listener and directly after anything\n * the hook writes, so a control reading `rangeStyle` right after a patch\n * sees the new value rather than flickering back to the old one.\n *\n * A selection that is not inside the overlay leaves the published range\n * alone rather than clearing it. That state means focus moved into a\n * control — which is precisely when the range matters most, and reporting\n * `null` would read to a consumer as \"collapsed caret\" and send its patch\n * to the wrong target. The range is cleared where it is actually over: on\n * `startEdit` and on teardown.\n */\n /** Publish `range` and the styling the overlay currently carries across it. */\n const publishRange = useCallback((overlay: HTMLElement, range: TextEditSelection) => {\n const collapsed = range.start === range.end;\n // A pending style belongs to the caret position it was armed at. Any\n // other range means the caret moved, which abandons it.\n if (pendingAtRef.current !== null\n && !(collapsed && range.start === pendingAtRef.current)) {\n dropPending();\n }\n selectionRef.current = range;\n setSelection((prev) => (sameSelection(prev, range) ? prev : range));\n const runs = domToRuns(overlay);\n setRangeStyle(collapsed\n ? styleAtCaret(runs, range.start)\n : styleAtRange(runs, range.start, range.end));\n }, [dropPending]);\n\n const syncSelection = useCallback(() => {\n const overlay = overlayRef.current;\n if (!overlay) return;\n const next = readSelectionOffsets(overlay);\n if (next === null) return;\n publishRange(overlay, next);\n }, [publishRange]);\n\n /** Drop the published range — the edit session it described is over. */\n const clearSelection = useCallback(() => {\n selectionRef.current = null;\n setSelection(null);\n setRangeStyle(null);\n dropPending();\n }, [dropPending]);\n\n const cancelEdit = useCallback(() => {\n setEditingId(null);\n }, []);\n\n const commit = useCallback(() => {\n const id = editingId;\n const overlay = overlayRef.current;\n if (id == null || !overlay) {\n setEditingId(null);\n return;\n }\n // What decides this is whether *runs* are in play at the end of the\n // edit — not whether the overlay was seeded from them. Mirroring the\n // init-time guard (`getRuns` returned something non-empty) was the old\n // rule, and it silently dropped every styling a freshly created text\n // node acquired: no prior runs, so commit took the plain-text branch and\n // `domToRuns`' output went in the bin. So two ways in:\n //\n // - the node already had runs — they have to be rewritten even when the\n // edit ended up unstyled, or stale styling survives a Cmd-B that\n // turned it off; or\n // - the edit produced styling, whatever the node started as.\n //\n // A plain-text edit of a plain-text node satisfies neither and commits\n // text alone, so a node that has no `runs` doesn't grow a single-run\n // array just for being edited.\n const { getRuns, setRuns, setText, setStyle, commit: commitAll } = optsRef.current;\n const priorRuns = getRuns?.(id);\n const read = domToRuns(overlay);\n const style = nodeStyleRef.current;\n // Compared untrimmed: a seeded trailing newline reads back the same at\n // both ends, where the trimmed form would differ from the node's text.\n if (!style && JSON.stringify(read) === openedRef.current) {\n setEditingId(null);\n return;\n }\n const runs = trimCaretHolder(read);\n const hadRuns = priorRuns != null && priorRuns.length > 0;\n const runsInPlay = hadRuns || runsCarryStyling(runs);\n // Read from the DOM, not `innerText`: a browser applies `text-transform`\n // to what that reports, and a break stand-in reads back as its `\\n`.\n const text = runsToPlainText(runs);\n holdNodeStyle(null);\n if (commitAll) {\n commitAll(id, { text, ...(runsInPlay ? { runs } : {}), ...(style ? { style } : {}) });\n } else {\n if (style) setStyle?.(id, style);\n setText?.(id, text);\n if (setRuns && runsInPlay) setRuns(id, runs);\n }\n setEditingId(null);\n }, [editingId, optsRef, holdNodeStyle]);\n\n const startEdit = useCallback((id: string, opts?: StartEditOptions) => {\n initialCaretRef.current = opts?.caret ?? 'all';\n setEditingId(id);\n }, []);\n\n const isEditing = useCallback((id: string) => editingId === id, [editingId]);\n\n const applyStyleToSelection = useCallback((patch: RunStylePatch) => {\n const overlay = overlayRef.current;\n if (!overlay) return;\n // An empty patch would still round-trip the runs through\n // `applyStyleToRange`, whose normalization applies to the whole array and\n // not just the patched span. Nothing asked for that, so don't do it.\n if (Object.keys(patch).length === 0) return;\n // Fall back to the last range that WAS in the overlay: the caller may be\n // a control that took focus (and with it the DOM selection) to be\n // clicked. `writeRunsPreservingSelection` puts the range back afterwards,\n // so a second styling can follow without re-selecting either way.\n const range = readSelectionOffsets(overlay) ?? selectionRef.current;\n if (!range) return;\n\n // Lowering a flag the node itself sets is not expressible additively —\n // the run algebra can only add — so it takes the rewrite in\n // `setFlagOverRange`: clear the node flag, raise it outside the range.\n // This is the one styling that reaches existing text from a collapsed\n // caret, and has to: \"stop being bold from here on\" is otherwise\n // unsayable in a bold node.\n const id = editingIdRef.current;\n const canWriteStyle = optsRef.current.setStyle !== undefined || optsRef.current.commit !== undefined;\n const runs = domToRuns(overlay);\n if (patch.bold === false && !('fontWeight' in patch) && id !== null) {\n patch = { ...patch, ...unboldPatch(styleOf(id) ?? {}) };\n }\n const unsetFlag = id !== null && canWriteStyle\n ? (Object.keys(patch) as FlagKey[]).find((key) =>\n key !== 'bold'\n && patch[key] === false\n && nodeHasFlag(styleOf(id) ?? {}, key))\n : undefined;\n if (unsetFlag !== undefined && id !== null) {\n const r = setFlagOverRange(runs, styleOf(id) ?? {}, range.start, range.end, unsetFlag, false);\n holdNodeStyle(r.style);\n // The root's own decoration and slant reach every run by inheritance,\n // the range just cleared included.\n const resolved = resolveTextStyle(r.style, optsRef.current.getPaint?.(id));\n baseRef.current = resolved;\n applyOverlayStyle(overlay, resolved);\n writeRunsPreservingSelection(overlay, r.runs, range.start, range.end, resolved);\n publishRange(overlay, range);\n // The rewrite raised the flag on every existing run, so a caret sitting\n // at the end of one is now *inside* a flagged span and the next\n // character would be absorbed by it. Arming the `false` keeps it out:\n // it is not a storable run value, but it is enough to make\n // `beforeinput` open a fresh span, which `runsToDom` then emits bare.\n if (range.start === range.end) {\n armPending({ ...pendingRef.current, [unsetFlag]: false }, range.start);\n }\n restoreOverlayFocus(overlay, range);\n // Whatever else the patch carried still applies on its own terms.\n const rest = { ...patch };\n delete rest[unsetFlag];\n if (Object.keys(rest).length > 0) applyStyleToSelection(rest);\n return;\n }\n\n // A collapsed caret has no run to restyle, so the styling is armed for\n // the next character instead of silently doing nothing.\n if (range.start === range.end) {\n armPending(mergePending(pendingRef.current, patch), range.start);\n restoreOverlayFocus(overlay, range);\n return;\n }\n\n const next = applyStyleToRange(runs, range.start, range.end, patch);\n writeRunsPreservingSelection(overlay, next, range.start, range.end, baseRef.current);\n restoreOverlayFocus(overlay, range);\n // Republish from the range we just styled, not from the DOM selection:\n // when the patch came from chrome the selection is in that control, and\n // re-reading it would leave a consumer showing the pre-patch styling.\n publishRange(overlay, range);\n }, [publishRange, armPending, editingIdRef, optsRef, styleOf, holdNodeStyle]);\n\n const toggleStyle = useCallback((toggle: StyleToggle) => {\n const overlay = overlayRef.current;\n if (!overlay) return;\n const range = readSelectionOffsets(overlay) ?? selectionRef.current;\n if (!range) return;\n const runs = domToRuns(overlay);\n const id = editingIdRef.current;\n const nodeStyle = (id !== null ? styleOf(id) : undefined) ?? {};\n // At a collapsed caret the styling in play is what the caret sits in plus\n // whatever is already armed, so pressing Cmd+B twice disarms rather than\n // arming a second time.\n const current = range.start === range.end\n ? patchRangeStyle(styleAtCaret(runs, range.start), pendingRef.current)\n : styleAtRange(runs, range.start, range.end);\n applyStyleToSelection(patchForToggle(current, toggle, nodeStyle));\n }, [applyStyleToSelection, editingIdRef, styleOf]);\n\n useEffect(() => {\n if (editingId == null) return;\n const { container, getText, getStyle, getPaint } = optsRef.current;\n if (!container) return;\n holdNodeStyle(null);\n\n const style = resolveTextStyle(getStyle(editingId), getPaint?.(editingId));\n const overlay = document.createElement('div');\n const overlayClass = `weasel-text-edit-${++OVERLAY_SEQ}`;\n overlay.classList.add(overlayClass);\n overlay.setAttribute('contenteditable', 'true');\n overlay.spellcheck = false;\n baseRef.current = style;\n const initialRuns = optsRef.current.getRuns?.(editingId);\n if (initialRuns && initialRuns.length > 0) {\n runsToDom(initialRuns, overlay, style);\n } else if (style.fontVariantCaps === 'small-caps') {\n // Small caps needs its lowercase in pieces, which only a run span holds.\n runsToDom([{ text: getText(editingId) }], overlay, style);\n } else {\n // Not `innerText`, which turns each newline into a `<br>` the caret\n // walkers cannot count and U+2028 into a space.\n appendOverlayText(overlay, getText(editingId));\n }\n openedRef.current = JSON.stringify(domToRuns(overlay));\n applyOverlayStyle(overlay, style);\n const hold = holdForFaces(style, initialRuns ?? []);\n if (hold) overlay.style.opacity = '0';\n const styleEl = installSelectionStyle(overlayClass, style);\n const clipBox = createClipBox();\n clipBox.appendChild(overlay);\n container.appendChild(clipBox);\n overlayRef.current = overlay;\n\n const place = () => {\n const clip = optsRef.current.getClipRect?.() ?? null;\n placeOverlay(overlay, clipBox, optsRef.current.getScreenPose(editingId), clip, style);\n };\n place();\n // Measured again on release: the first `place` ran in the fallback face.\n let held = hold !== null;\n const release = () => {\n if (!held) return;\n held = false;\n clearTimeout(holdTimer);\n place();\n overlay.style.opacity = '';\n };\n const holdTimer = held ? setTimeout(release, optsRef.current.fontHold ?? TEXT_EDIT_FONT_HOLD) : undefined;\n void hold?.then(release);\n\n const range = document.createRange();\n const initial = initialCaretRef.current;\n if (initial === 'all') {\n range.selectNodeContents(overlay);\n } else {\n placeCaretAt(overlay, range, initial);\n }\n // Focus first, then place the caret: focusing an editable host is itself\n // a selection-moving act (jsdom collapses to the start; browsers vary),\n // so a range set beforehand is not reliably the one the user ends up with.\n overlay.focus();\n const sel = window.getSelection();\n sel?.removeAllRanges();\n sel?.addRange(range);\n // The caret exists now, so publish it rather than waiting for the\n // `selectionchange` task — a control mounted alongside the editor would\n // otherwise render one frame with no selection.\n syncSelection();\n\n const onKeyDown = (e: KeyboardEvent) => {\n // The key belongs to the IME: Enter confirms a candidate, Escape dismisses\n // them. Safari reports it after `compositionend`, as keyCode 229.\n if (e.isComposing || e.keyCode === 229) return;\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n commit();\n return;\n }\n if (e.key === 'Escape') {\n e.preventDefault();\n if (optsRef.current.escape === 'commit') commit();\n else cancelEdit();\n return;\n }\n const toggle = toggleForKey(e);\n if (toggle) {\n e.preventDefault();\n toggleStyle(toggle);\n }\n };\n const onBlur = (e: FocusEvent) => {\n const next = e.relatedTarget;\n const isChrome = optsRef.current.isEditorChrome;\n if (isChrome && next instanceof Element && isChrome(next)) return;\n commit();\n };\n\n const onBeforeInput = (ie: InputEvent) => {\n if (ie.inputType !== 'insertText' || !ie.data) return;\n const pending = pendingRef.current;\n if (Object.keys(pending).length > 0) {\n // Rebuild from the runs rather than splicing a span into the DOM.\n // `insertNode` at a caret sitting inside a run span nests the new\n // span *within* it, and `domToRuns` reads styling down the ancestor\n // chain — so a pending style that has to escape the surrounding run\n // (the `false` armed after a node-flag rewrite) would inherit exactly\n // the flag it exists to shed. Going through the algebra also gets\n // every run field for free, with no CSS written here.\n const at = readSelectionOffsets(overlay) ?? selectionRef.current;\n if (!at || at.start !== at.end) return;\n ie.preventDefault();\n const next = spliceRunAt(domToRuns(overlay), at.start, {\n ...pending, text: ie.data,\n } as StyledRun);\n const after = at.start + ie.data.length;\n writeRunsPreservingSelection(overlay, next, after, after, baseRef.current);\n placeCaretBetweenRuns(overlay, next, after);\n dropPending();\n publishRange(overlay, { start: after, end: after });\n return;\n }\n ie.preventDefault();\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n range.deleteContents();\n {\n // No pending style — insert the character as a plain text node at the\n // caret position so the surrounding run's span absorbs it.\n const textNode = document.createTextNode(ie.data);\n range.insertNode(textNode);\n const after = document.createRange();\n after.setStartAfter(textNode);\n after.collapse(true);\n sel.removeAllRanges();\n sel.addRange(after);\n }\n resplitSmallCaps();\n };\n\n /** Put small-caps letters back in the pieces their case belongs in after\n * an edit, keeping the caret. Never mid-composition: rewriting the DOM\n * under an IME ends the composition. */\n const resplitSmallCaps = (e?: Event) => {\n if (e instanceof InputEvent && e.isComposing) return;\n const at = readSelectionOffsets(overlay);\n if (!normalizeSmallCaps(overlay) || !at) return;\n const a = charOffsetToDomPosition(overlay, at.start);\n const b = charOffsetToDomPosition(overlay, at.end);\n const sel = window.getSelection();\n if (!a || !b || !sel) return;\n const r = document.createRange();\n r.setStart(a.node, a.offset);\n r.setEnd(b.node, b.offset);\n sel.removeAllRanges();\n sel.addRange(r);\n };\n const onInput = (e: Event) => {\n resplitSmallCaps(e);\n place();\n };\n\n // Blur can't be the only way out. Once focus has moved into editing\n // chrome the overlay is no longer focused, so nothing blurs when the user\n // clicks away and the edit would never end. A pointerdown that lands\n // outside both the overlay and the chrome is that click. Capture phase so\n // it runs ahead of whatever the click was aimed at (a canvas gesture, a\n // different tool) rather than after it.\n const onPointerDownOutside = (e: Event) => {\n const target = e.target;\n if (!(target instanceof Node) || overlay.contains(target)) return;\n const isChrome = optsRef.current.isEditorChrome;\n if (isChrome && target instanceof Element && isChrome(target)) return;\n commit();\n };\n\n overlay.addEventListener('keydown', onKeyDown);\n overlay.addEventListener('blur', onBlur);\n // Typing can change the line count; re-placing here rather than on the\n // next frame keeps a center/bottom-aligned overlay from jumping a frame late.\n overlay.addEventListener('input', onInput);\n overlay.addEventListener('beforeinput', onBeforeInput);\n document.addEventListener('pointerdown', onPointerDownOutside, true);\n // `selectionchange` only exists on the document — there is no per-element\n // event for it — so this listens globally and `readSelectionOffsets`\n // filters to selections inside the overlay.\n document.addEventListener('selectionchange', syncSelection);\n\n // Follows the node's screen pose every frame — behind the visibility gate,\n // so an overlay left open in a background tab costs nothing.\n tickRef.current = () => {\n place();\n frameLoop.request();\n };\n frameLoop.request();\n\n return () => {\n held = false;\n clearTimeout(holdTimer);\n frameLoop.cancel();\n tickRef.current = () => {};\n overlay.removeEventListener('keydown', onKeyDown);\n overlay.removeEventListener('blur', onBlur);\n overlay.removeEventListener('input', onInput);\n overlay.removeEventListener('beforeinput', onBeforeInput);\n document.removeEventListener('pointerdown', onPointerDownOutside, true);\n document.removeEventListener('selectionchange', syncSelection);\n clipBox.remove();\n styleEl?.remove();\n overlayRef.current = null;\n holdNodeStyle(null);\n clearSelection();\n };\n }, [editingId, opts.container, optsRef, commit, cancelEdit, syncSelection, clearSelection,\n frameLoop, toggleStyle, dropPending, publishRange, holdNodeStyle]);\n\n return {\n editingId, startEdit, cancelEdit, commit, isEditing, nodeStyle,\n selection, rangeStyle, pendingStyle, applyStyleToSelection, toggleStyle,\n };\n}\n\nlet OVERLAY_SEQ = 0;\n\n/**\n * The loads the overlay's faces are still waiting on — the node's and each\n * run's that names its own family — or `null` when every one is in hand.\n */\nfunction holdForFaces(style: ResolvedTextStyle, runs: readonly StyledRun[]): Promise<unknown> | null {\n const pending = [\n cssFontFamilyLoading(style.fontFamily, {\n weight: numericWeight(style.fontWeight), style: style.fontStyle,\n }),\n ...runs.filter((r) => r.fontFamily != null).map((r) => cssFontFamilyLoading(r.fontFamily!, {\n weight: r.fontWeight ?? (r.bold ? 700 : undefined),\n style: r.italic ? 'italic' : undefined,\n })),\n ].filter((p) => p !== null);\n return pending.length === 0 ? null : Promise.all(pending);\n}\n\n/**\n * Place a collapsed caret `offset` characters into the overlay's text,\n * walking its text nodes. Out-of-range offsets clamp to the end.\n */\nfunction placeCaretAt(root: HTMLElement, range: Range, offset: number): void {\n let remaining = offset;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);\n let node: Text | null = walker.nextNode() as Text | null;\n while (node) {\n const len = node.data.length;\n if (remaining <= len) {\n range.setStart(node, remaining);\n range.setEnd(node, remaining);\n return;\n }\n remaining -= len;\n node = walker.nextNode() as Text | null;\n }\n // Fallback: collapse at end of the root.\n range.selectNodeContents(root);\n range.collapse(false);\n}\n\n/** The overlay's positioning parent. Passes pointer input through everywhere\n * but the overlay itself, which spans no more than the canvas it covers. */\nfunction createClipBox(): HTMLDivElement {\n const el = document.createElement('div');\n el.style.position = 'absolute';\n el.style.margin = '0';\n el.style.padding = '0';\n el.style.border = '0';\n el.style.pointerEvents = 'none';\n return el;\n}\n\nfunction applyOverlayStyle(el: HTMLDivElement, style: ResolvedTextStyle): void {\n el.style.position = 'absolute';\n el.style.pointerEvents = 'auto';\n el.style.boxSizing = 'border-box';\n el.style.margin = '0';\n el.style.padding = '0';\n el.style.border = '0';\n el.style.outline = 'none';\n el.style.background = 'transparent';\n // Unfilled text still edits in black: the overlay has to be legible, and\n // there is no CSS spelling of \"no fill\" that leaves the glyphs visible.\n el.style.color = style.fill !== null && 'color' in style.fill ? style.fill.color : '#000';\n el.style.caretColor = style.caretColor;\n // The canvas's face, not the browser's reading of the family name.\n const fontFamily = cssFontFamily(style.fontFamily, {\n weight: numericWeight(style.fontWeight), style: style.fontStyle,\n });\n el.style.font = fontString({ ...style, fontFamily });\n // Linux Chromium otherwise rounds every advance to a whole pixel at DPR 1, while\n // the canvas lays out a face's own fractional ones: 'Small Caps' at 24px ran 3px\n // long. A canvas font is measured by the browser's default rendering, so keeps it.\n el.style.textRendering = isCanvasFont(style.fontFamily) ? '' : 'geometricPrecision';\n el.style.lineHeight = String(style.lineHeight);\n applyOverlayDirection(el, style);\n // Node-level decoration, so the overlay looks like the canvas the moment\n // editing starts. Runs are additive over the node style (a run can't un-set\n // a flag), which is exactly how CSS decoration propagates to descendants —\n // a run span adds its own decoration but can't remove this one.\n const decorations: string[] = [];\n if (style.underline) decorations.push('underline');\n if (style.strikethrough) decorations.push('line-through');\n if (style.overline) decorations.push('overline');\n el.style.textDecoration = decorations.length > 0 ? decorations.join(' ') : 'none';\n el.style.textTransform = style.textTransform;\n // The CSS spelling for what a browser reads; the scale for the pieces\n // `runsToDom` splits inheriting runs into, so they match the canvas.\n el.style.fontVariant = style.fontVariantCaps;\n el.style.setProperty(\n SMALL_CAPS_SCALE_PROPERTY,\n style.fontVariantCaps === 'small-caps'\n ? String(smallCapsScaleFor(style.fontFamily, numericWeight(style.fontWeight), style.fontStyle))\n : '',\n );\n // Line breaks follow the node's declared `wrap`, as the canvas's do. Layout\n // breaks only between words, never inside one.\n el.style.whiteSpace = style.wrap ? 'pre-wrap' : 'pre';\n el.style.overflowWrap = 'normal';\n el.style.wordBreak = 'normal';\n}\n\n/**\n * Inject a `<style>` element scoped to `overlayClass` so the edit overlay's\n * `::selection` matches the configured colors. Returns the style element so\n * the effect cleanup can remove it. Returns `null` when no selection\n * theming was requested.\n */\nfunction installSelectionStyle(\n overlayClass: string,\n style: ResolvedTextStyle,\n): HTMLStyleElement | null {\n if (style.selectionBackground == null && style.selectionColor == null) return null;\n const el = document.createElement('style');\n const decls: string[] = [];\n if (style.selectionBackground != null) {\n decls.push(`background: ${style.selectionBackground};`);\n }\n if (style.selectionColor != null) {\n decls.push(`color: ${style.selectionColor};`);\n }\n el.textContent = `.${overlayClass}::selection { ${decls.join(' ')} }`;\n document.head.appendChild(el);\n return el;\n}\n\nconst ALIGN_ANCHOR = { left: 0, center: 0.5, right: 1 } as const;\n\n/**\n * The overlay's `top`, in container pixels, for content `contentHeight` tall\n * (pre-scale, like the rest of `pose`): the pose's top, shifted by the same\n * `verticalAlign` slack the canvas applies, plus `drop` — how far below the\n * CSS line's baseline the canvas puts its own, from {@link baselineDrop}.\n * @internal\n */\nexport function overlayTop(pose: TextEditScreenPose, contentHeight: number, drop = 0): number {\n const slack = verticalAlignOffset(pose.verticalAlign, pose.height, contentHeight);\n return pose.y + (slack + drop) * (pose.zoom ?? 1);\n}\n\n/**\n * The canvas and CSS both hang a line's baseline half the leading plus one\n * ascent below the line top, from the same ascent rule, but each engine\n * rounds the font's metrics and that leading its own way, and a face that\n * states no ascent and descent hangs from its ascent alone. So the difference\n * is read from both sides rather than predicted: the canvas's from its own layout, the\n * overlay's from a zero-height inline box on a hidden line set exactly as the\n * overlay is. Pre-scale; `0` when either side has nothing to measure.\n * @internal\n */\nexport function baselineDrop(el: HTMLElement, style: ResolvedTextStyle, pose: TextEditScreenPose, lineHeight: number): number {\n const canvas = layoutTextPose({\n x: 0, y: 0, width: pose.width, height: pose.height, text: ' ',\n style: {\n fontFamily: style.fontFamily, fontWeight: style.fontWeight, fontStyle: style.fontStyle,\n fontSize: pose.fontSize, lineHeight, script: style.script,\n },\n }).laid.lines[0]?.baselineY ?? 0;\n const css = cssBaseline(el);\n return canvas > 0 && css > 0 ? canvas - css : 0;\n}\n\nconst CSS_BASELINES = new Map<string, number>();\n\nfunction cssBaseline(el: HTMLElement): number {\n const parent = el.parentElement;\n if (!parent) return 0;\n const { fontFamily, fontWeight, fontStyle, fontSize, lineHeight, textRendering } = el.style;\n const key = [fontFamily, fontWeight, fontStyle, fontSize, lineHeight, textRendering].join('|');\n const cached = CSS_BASELINES.get(key);\n if (cached !== undefined) return cached;\n const line = document.createElement('div');\n Object.assign(line.style, {\n position: 'absolute', left: '0', top: '0', width: '100px', margin: '0', padding: '0', border: '0',\n visibility: 'hidden', whiteSpace: 'pre', fontFamily, fontWeight, fontStyle, fontSize, lineHeight, textRendering,\n });\n const mark = document.createElement('span');\n Object.assign(mark.style, { display: 'inline-block', width: '0', height: '0', verticalAlign: 'baseline' });\n line.appendChild(mark);\n parent.appendChild(line);\n const box = line.getBoundingClientRect();\n // Rect over layout width undoes any transform on an ancestor.\n const scale = box.width / 100;\n const baseline = scale > 0 ? (mark.getBoundingClientRect().top - box.top) / scale : 0;\n line.remove();\n // A web font still loading is measured as its fallback; ask again later.\n if (baseline > 0 && document.fonts?.status !== 'loading') {\n if (CSS_BASELINES.size >= 64) CSS_BASELINES.clear();\n CSS_BASELINES.set(key, baseline);\n }\n return baseline;\n}\n\nfunction placeOverlay(\n el: HTMLDivElement,\n clipBox: HTMLDivElement,\n pose: TextEditScreenPose | null,\n clip: TextEditClipRect | null,\n style: ResolvedTextStyle,\n): void {\n if (!pose) {\n el.style.display = 'none';\n return;\n }\n // `clip` rather than `hidden`: a `hidden` box is still scrollable, and the\n // browser scrolls it to keep the caret in view.\n clipBox.style.overflow = clip ? 'clip' : 'visible';\n clipBox.style.left = `${clip?.x ?? 0}px`;\n clipBox.style.top = `${clip?.y ?? 0}px`;\n clipBox.style.width = `${clip?.width ?? 0}px`;\n clipBox.style.height = `${clip?.height ?? 0}px`;\n el.style.display = '';\n // An unwrapped line can be wider than its box, and the canvas aligns it\n // about the box's left edge, center or right edge regardless. The overlay\n // sizes to its text and grows from that same anchor: `left` puts the anchor\n // there and a trailing translate pulls the box back by that fraction of its\n // own width.\n const anchor = style.wrap ? 0 : ALIGN_ANCHOR[overlayAlignEdge(el, style)];\n el.style.left = `${pose.x + pose.width * (pose.zoom ?? 1) * anchor - (clip?.x ?? 0)}px`;\n el.style.width = style.wrap ? `${pose.width}px` : 'max-content';\n el.style.minWidth = style.wrap ? '' : `${pose.width}px`;\n // A node-level script draws the glyphs smaller and raised on the line the\n // plain text would hold, so the line height is pinned in pixels of the\n // unscripted size rather than left to scale with the font. The rise is\n // added to `top` with the baseline correction.\n const script = style.script\n ? scriptMetricsFor(style.fontFamily, numericWeight(style.fontWeight), style.fontStyle)[style.script]\n : undefined;\n const lineHeight = pose.lineHeight ?? style.lineHeight;\n el.style.fontSize = `${pose.fontSize * (script?.size ?? 1)}px`;\n el.style.lineHeight = script ? `${pose.fontSize * lineHeight}px` : String(lineHeight);\n // A top-aligned overlay fills its box, so a click anywhere in it lands in\n // the editor. Any other alignment needs the content's own height, which a\n // min-height would mask; `offsetHeight` is pre-transform, in pose units.\n const aligned = pose.verticalAlign !== undefined && pose.verticalAlign !== 'top';\n el.style.minHeight = aligned ? '' : `${pose.height}px`;\n const drop = baselineDrop(el, style, pose, lineHeight) - (script?.shift ?? 0) * pose.fontSize;\n el.style.top = `${overlayTop(pose, aligned ? el.offsetHeight : pose.height, drop) - (clip?.y ?? 0)}px`;\n // A declared `zoom` means every size on the pose is pre-scale and the\n // overlay carries the view scale as a transform. Anchored at the top-left so\n // `left`/`top` stay screen pixels. Written unconditionally (`none` at zoom\n // 1) because the overlay element outlives an edit session and would\n // otherwise keep a stale scale.\n el.style.transformOrigin = '0 0';\n const transforms: string[] = [];\n if (pose.zoom !== undefined && pose.zoom !== 1) transforms.push(`scale(${pose.zoom})`);\n if (anchor !== 0) transforms.push(`translateX(${-anchor * 100}%)`);\n el.style.transform = transforms.length > 0 ? transforms.join(' ') : 'none';\n // `letter-spacing` is not part of the CSS `font` shorthand, so\n // `applyOverlayStyle`'s `el.style.font` never carries it — it needs its own\n // assignment. It also lives here rather than there because without a\n // transform it is the one world-unit typography value that has to be\n // re-scaled as the view zooms.\n //\n // Under a transform there is nothing to re-scale: the world value is the\n // value, and run-level overrides — which `runsToDom` writes in world units\n // — scale by the same factor. Without one, `pose.fontSize` is documented as\n // `style.fontSize * zoom`, so their ratio is the world→screen factor; run\n // overrides then stay unscaled, which is why that path is only correct at\n // zoom 1. (CSS inheritance makes a run span's own declaration *replace* this\n // value rather than add to it, in both paths.)\n const scale =\n pose.zoom !== undefined ? 1 : style.fontSize > 0 ? pose.fontSize / style.fontSize : 1;\n el.style.letterSpacing = `${style.letterSpacing * scale}px`;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weasel-js/text-dom",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.9.4",
|
|
4
|
+
"description": "In-place text editing over a canvas: a contenteditable overlay that reads and writes styled runs, with range styling, caret mapping and font-load handling. A React hook; no scene graph.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
},
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"react": ">=18"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@weasel-js/font": "1.9.4",
|
|
23
|
+
"@weasel-js/paint": "1.9.4",
|
|
24
|
+
"@weasel-js/react": "1.9.4",
|
|
25
|
+
"@weasel-js/text": "1.9.4"
|
|
26
|
+
},
|
|
27
|
+
"author": "orochi235",
|
|
28
|
+
"homepage": "https://orochi235.github.io/weasel/",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/orochi235/weasel.git",
|
|
32
|
+
"directory": "packages/text-dom"
|
|
33
|
+
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/orochi235/weasel/issues"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=22"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"README.md",
|
|
43
|
+
"LICENSE"
|
|
44
|
+
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsup"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public",
|
|
50
|
+
"provenance": true
|
|
51
|
+
}
|
|
52
|
+
}
|