@inkbar/core 0.5.0 → 0.6.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/README.md +73 -1
- package/dist/dom.d.mts +477 -41
- package/dist/dom.d.mts.map +1 -1
- package/dist/dom.mjs +1338 -259
- package/dist/dom.mjs.map +1 -1
- package/dist/index.d.mts +16 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +181 -25
- package/dist/index.mjs.map +1 -1
- package/dist/{signatures-BwaXi7C8.d.mts → signatures-By4B40DP.d.mts} +86 -4
- package/dist/signatures-By4B40DP.d.mts.map +1 -0
- package/dist/{signatures-CMapTKrC.mjs → signatures-D68fuLlt.mjs} +268 -50
- package/dist/signatures-D68fuLlt.mjs.map +1 -0
- package/package.json +3 -3
- package/dist/signatures-BwaXi7C8.d.mts.map +0 -1
- package/dist/signatures-CMapTKrC.mjs.map +0 -1
package/dist/dom.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dom.mjs","names":["isCancellation","SVG","CORNERS","fmt","SVG","createToolController","SVG_NS","MIN_CSS","MIN_CSS","SVG_NS","createWith","ITEMS","TABBABLE","button","button","SVG_NS"],"sources":["../src/dom/transform.ts","../src/dom/layout.ts","../src/dom/viewport.ts","../src/dom/viewport-keys.ts","../src/dom/dpr-watch.ts","../src/dom/page-renderer.ts","../src/pdfjs/text-layer.ts","../src/dom/text-layer.ts","../src/dom/selection.ts","../src/dom/ink-stroke.ts","../src/dom/overlay-render.ts","../src/dom/freetext-editor.ts","../src/pdfjs/render-region.ts","../src/dom/loupe-layer.ts","../src/dom/mask-layer.ts","../src/dom/overlay.ts","../src/dom/page-mount.ts","../src/dom/tools/options.ts","../src/dom/tools/selection-edit.ts","../src/dom/tools/controller.ts","../src/dom/tools/freehand.ts","../src/dom/tools/draw.ts","../src/dom/tools/freetext.ts","../src/dom/tools/highlight.ts","../src/dom/tools/note.ts","../src/dom/tools/redact-area.ts","../src/dom/tools/select.ts","../src/dom/tools/select-text.ts","../src/dom/tools/shape.ts","../src/dom/tools/signature.ts","../src/dom/tools/sketch.ts","../src/dom/tools/index.ts","../src/dom/palette.ts","../src/dom/ui.ts","../src/dom/menu-keys.ts","../src/dom/annotation-element.ts","../src/dom/popover-focus.ts","../src/dom/viewer/dom.ts","../src/dom/viewer/popover.ts","../src/dom/viewer-engine.ts","../src/dom/viewer/thread-popover.ts","../src/dom/viewer/create-viewer.ts","../src/dom/viewer/controls.ts","../src/dom/viewer/menu.ts","../src/dom/viewer/style-menu.ts","../src/dom/viewer/color-menu.ts","../src/dom/viewer/text-style-menu.ts","../src/dom/shape-icons.ts","../src/dom/viewer/shape-menu.ts","../src/dom/markup-icons.ts","../src/dom/viewer/highlight-menu.ts","../src/dom/signature-pad.ts","../src/dom/signature-draft.ts","../src/dom/viewer/signature-dialog.ts","../src/dom/viewer/signature-menu.ts"],"sourcesContent":["import {\n applyMatrix,\n invertMatrix,\n type Matrix,\n type Point,\n type Quad,\n type Rect,\n} from '../model/geometry'\n\nimport type { PageInfo } from '../model/pages'\n\nexport type ViewRotation = 0 | 90 | 180 | 270\n\n/** CSS box: `left`,`top` from the rendered page's top-left corner, in CSS pixels. */\nexport interface CssRect {\n left: number\n top: number\n width: number\n height: number\n}\n\nexport interface PageTransform {\n readonly page: PageInfo\n /** The viewer zoom the transform was built for. 1 is one CSS pixel per user-space unit at /UserUnit 1. */\n readonly zoom: number\n /**\n * CSS pixels per user-space unit: `zoom × page.userUnit`. This is PDF.js `PageViewport.scale`\n * and the value its text and annotation layers read from `--total-scale-factor`.\n */\n readonly scale: number\n /** Rotation the viewer applied on top of the page's own /Rotate. */\n readonly rotation: ViewRotation\n /** The page's /Rotate plus the viewer rotation. */\n readonly totalRotation: ViewRotation\n /** Rendered page width in CSS pixels at this zoom and total rotation. */\n readonly cssWidth: number\n /** Rendered page height in CSS pixels at this zoom and total rotation. */\n readonly cssHeight: number\n /** User space to CSS pixels. Same matrix PDF.js builds for `getViewport`. */\n readonly matrix: Matrix\n toCss(p: Point): Point\n toCssRect(r: Rect): CssRect\n toCssQuad(q: Quad): Quad\n /** Converts a length in user-space units (stroke width, font size) to CSS pixels: zoom times `/UserUnit`. */\n toCssLength(points: number): number\n fromCss(p: Point): Point\n fromCssRect(r: CssRect): Rect\n /** Converts a length in CSS pixels to user-space units. */\n fromCssLength(px: number): number\n}\n\n/** Folds any integer multiple of 90 onto 0, 90, 180 or 270. Throws `RangeError` otherwise. */\nexport function normalizeRotation(deg: number): ViewRotation {\n if (!Number.isFinite(deg) || deg % 90 !== 0) {\n throw new RangeError(`rotation must be a multiple of 90, got ${deg}`)\n }\n return (((deg % 360) + 360) % 360) as ViewRotation\n}\n\n/**\n * Port of PDF.js `PageViewport` (display/page_viewport.js) with offsetX = offsetY = 0 and\n * dontFlip = false. Using the same maths keeps the canvas, text layer and overlay aligned.\n */\nexport function createPageTransform(\n page: PageInfo,\n zoom: number,\n viewRotation: ViewRotation = 0\n): PageTransform {\n const rotation = normalizeRotation(viewRotation)\n const totalRotation = normalizeRotation(page.rotate + rotation)\n // PDF.js PageViewport does `scale *= userUnit`; zoom 1 is one user-space unit, so 1 point only when userUnit is 1.\n const scale = zoom * page.userUnit\n const x0 = page.box.x\n const y0 = page.box.y\n const x1 = page.box.x + page.box.width\n const y1 = page.box.y + page.box.height\n const centerX = (x1 + x0) / 2\n const centerY = (y1 + y0) / 2\n let rotateA: number\n let rotateB: number\n let rotateC: number\n let rotateD: number\n switch (totalRotation) {\n case 180:\n rotateA = -1\n rotateB = 0\n rotateC = 0\n rotateD = 1\n break\n case 90:\n rotateA = 0\n rotateB = 1\n rotateC = 1\n rotateD = 0\n break\n case 270:\n rotateA = 0\n rotateB = -1\n rotateC = -1\n rotateD = 0\n break\n default:\n rotateA = 1\n rotateB = 0\n rotateC = 0\n rotateD = -1\n }\n let offsetCanvasX: number\n let offsetCanvasY: number\n let cssWidth: number\n let cssHeight: number\n if (rotateA === 0) {\n offsetCanvasX = Math.abs(centerY - y0) * scale\n offsetCanvasY = Math.abs(centerX - x0) * scale\n cssWidth = Math.abs(y1 - y0) * scale\n cssHeight = Math.abs(x1 - x0) * scale\n } else {\n offsetCanvasX = Math.abs(centerX - x0) * scale\n offsetCanvasY = Math.abs(centerY - y0) * scale\n cssWidth = Math.abs(x1 - x0) * scale\n cssHeight = Math.abs(y1 - y0) * scale\n }\n const matrix: Matrix = [\n rotateA * scale,\n rotateB * scale,\n rotateC * scale,\n rotateD * scale,\n offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,\n offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY,\n ]\n const inverse = invertMatrix(matrix)\n const toCss = (p: Point): Point => applyMatrix(matrix, p)\n const fromCss = (p: Point): Point => applyMatrix(inverse, p)\n\n const bounds = (\n points: Point[]\n ): { x: number; y: number; width: number; height: number } => {\n const xs = points.map((p) => p.x)\n const ys = points.map((p) => p.y)\n const x = Math.min(...xs)\n const y = Math.min(...ys)\n return { x, y, width: Math.max(...xs) - x, height: Math.max(...ys) - y }\n }\n\n return {\n page,\n zoom,\n scale,\n rotation,\n totalRotation,\n cssWidth,\n cssHeight,\n matrix,\n toCss,\n fromCss,\n toCssRect(r) {\n const b = bounds([\n toCss({ x: r.x, y: r.y }),\n toCss({ x: r.x + r.width, y: r.y }),\n toCss({ x: r.x, y: r.y + r.height }),\n toCss({ x: r.x + r.width, y: r.y + r.height }),\n ])\n return { left: b.x, top: b.y, width: b.width, height: b.height }\n },\n toCssQuad(q) {\n return { p1: toCss(q.p1), p2: toCss(q.p2), p3: toCss(q.p3), p4: toCss(q.p4) }\n },\n toCssLength: (points) => points * scale,\n fromCssRect(r) {\n return bounds([\n fromCss({ x: r.left, y: r.top }),\n fromCss({ x: r.left + r.width, y: r.top }),\n fromCss({ x: r.left, y: r.top + r.height }),\n fromCss({ x: r.left + r.width, y: r.top + r.height }),\n ])\n },\n fromCssLength: (px) => px / scale,\n }\n}\n","import { createPageTransform, type ViewRotation } from './transform'\n\nimport type { PageInfo } from '../model/pages'\n\nexport type LayoutMode = 'single' | 'continuous'\n\n/** Where one page sits inside the pages element, in CSS pixels. */\nexport interface CssPageBox {\n index: number\n left: number\n top: number\n width: number\n height: number\n}\n\n/** Every laid-out page plus the size of the pages element, in CSS pixels. */\nexport interface CssLayout {\n boxes: CssPageBox[]\n width: number\n height: number\n}\n\nexport interface CssLayoutInput {\n pages: readonly PageInfo[]\n zoom: number\n rotation: ViewRotation\n /** Gap above, between and below pages, CSS px. */\n gap: number\n mode: LayoutMode\n /** The page shown in `single` mode. */\n current: number\n /** The container's content width (client width less padding), CSS px. Narrower pages are centred. */\n containerWidth: number\n}\n\nfunction cssSize(page: PageInfo, zoom: number, rotation: ViewRotation) {\n const t = createPageTransform(page, zoom, rotation)\n return { width: t.cssWidth, height: t.cssHeight }\n}\n\n/** Stacks pages vertically, centred horizontally, with `gap` around each. */\nexport function computeCssLayout(input: CssLayoutInput): CssLayout {\n const pages =\n input.mode === 'single'\n ? input.pages.filter((p) => p.index === input.current)\n : input.pages\n const sizes = pages.map((p) => cssSize(p, input.zoom, input.rotation))\n // A reduce, not Math.max(...spread): spreading hundreds of thousands of pages overflows the stack.\n const width = sizes.reduce((max, s) => Math.max(max, s.width), input.containerWidth)\n let top = input.gap\n const boxes = pages.map((p, i): CssPageBox => {\n const s = sizes[i]!\n const box = {\n index: p.index,\n left: (width - s.width) / 2,\n top,\n width: s.width,\n height: s.height,\n }\n top += s.height + input.gap\n return box\n })\n return { boxes, width, height: top }\n}\n\n/** The zoom at which `page` fits a container of the given CSS size, less `padding` on each side. */\nexport function fitZoomCss(\n page: PageInfo,\n rotation: ViewRotation,\n container: { width: number; height: number },\n mode: 'fit-width' | 'fit-page',\n padding: number\n): number {\n const size = cssSize(page, 1, rotation)\n const byWidth = (container.width - padding * 2) / size.width\n if (mode === 'fit-width') return Math.max(0.05, byWidth)\n const byHeight = (container.height - padding * 2) / size.height\n return Math.max(0.05, Math.min(byWidth, byHeight))\n}\n\n/**\n * Indexes of pages intersecting [scrollTop, scrollTop + viewportHeight], extended by\n * `buffer` pages each side. Past the end it returns the last page plus its buffer.\n */\nexport function visibleRangeCss(\n layout: CssLayout,\n scrollTop: number,\n viewportHeight: number,\n buffer: number\n): number[] {\n const boxes = layout.boxes\n if (boxes.length === 0) return []\n const bottom = scrollTop + viewportHeight\n let first = boxes.findIndex((b) => b.top + b.height >= scrollTop)\n if (first === -1) first = boxes.length - 1\n let last = first\n while (last + 1 < boxes.length && boxes[last + 1]!.top <= bottom) last++\n const from = Math.max(0, first - buffer)\n const to = Math.min(boxes.length - 1, last + buffer)\n return boxes.slice(from, to + 1).map((b) => b.index)\n}\n\n/** The page with the most visible height in the viewport; the first page on a tie. */\nexport function mostVisiblePageCss(\n layout: CssLayout,\n scrollTop: number,\n viewportHeight: number\n): number {\n let best = layout.boxes[0]?.index ?? 0\n let bestArea = -1\n const bottom = scrollTop + viewportHeight\n for (const b of layout.boxes) {\n const visible = Math.max(\n 0,\n Math.min(b.top + b.height, bottom) - Math.max(b.top, scrollTop)\n )\n if (visible > bestArea) {\n bestArea = visible\n best = b.index\n }\n }\n return best\n}\n","/*\n * Inline styles. The headless DOM layer sets only what it cannot work without:\n * - container: `overflow: auto`, and `position: relative` when its computed position is static;\n * - pages element: `position: relative`, plus `width`/`height` from the layout;\n * - page hosts: `position: absolute` and `left`/`top`/`width`/`height` from the layout;\n * - page hosts: the `--scale-factor` (zoom) and `--total-scale-factor` (zoom × /UserUnit)\n * custom properties.\n * Nothing cosmetic (colours, borders, backgrounds, fonts) is ever set inline; that belongs to\n * the stylesheet. `destroy()` restores the container's overflow and position.\n */\nimport { readonly, writable, type Readable } from '../model/readable'\n\nimport {\n computeCssLayout,\n fitZoomCss,\n mostVisiblePageCss,\n visibleRangeCss,\n type CssLayout,\n type CssPageBox,\n type LayoutMode,\n} from './layout'\nimport { createPageTransform, type PageTransform, type ViewRotation } from './transform'\n\nimport type { InkDocument } from '../model/document'\nimport type { Point, Rect } from '../model/geometry'\n\nexport type ZoomValue = number | 'fit-width' | 'fit-page'\n\nexport interface ViewportOptions {\n container: HTMLElement\n document: InkDocument\n /** Default `'fit-width'`. */\n zoom?: ZoomValue\n /** Default `'continuous'`. */\n mode?: LayoutMode\n /** Default 0. */\n rotation?: ViewRotation\n /** Gap between pages, and the page padding used by fit modes, CSS px. Default 16. */\n gap?: number\n /** Pages to keep mounted either side of the visible range. Default 2. */\n buffer?: number\n /** Default 0.1. */\n minZoom?: number\n /** Default 8. */\n maxZoom?: number\n onMount(page: number, host: HTMLElement, transform: PageTransform): void\n onUpdate(page: number, host: HTMLElement, transform: PageTransform): void\n onUnmount(page: number, host: HTMLElement): void\n}\n\n/** The mounted page under a client point. The tools layer adds `user` and `css` (`PageHit`). */\nexport interface ViewportHit {\n page: number\n host: HTMLElement\n transform: PageTransform\n}\n\nexport interface Viewport {\n readonly zoom: Readable<ZoomValue>\n /** Effective numeric zoom, with fit modes resolved. */\n readonly scale: Readable<number>\n readonly currentPage: Readable<number>\n readonly mounted: Readable<readonly number[]>\n readonly layout: Readable<CssLayout>\n readonly rotation: Readable<ViewRotation>\n readonly mode: Readable<LayoutMode>\n /** `anchorCss` is relative to the container's top-left inside its border, CSS px; defaults to its centre. */\n setZoom(zoom: ZoomValue, anchorCss?: Point): void\n zoomBy(factor: number, anchorCss?: Point): void\n setMode(mode: LayoutMode): void\n setRotation(rotation: ViewRotation): void\n scrollToPage(index: number, opts?: { behavior?: ScrollBehavior }): void\n /** Scrolls so `rect` (user space on `page`) is visible, centring it when it was not. */\n scrollToRect(page: number, rect: Rect): void\n transformFor(page: number): PageTransform\n hostFor(page: number): HTMLElement | undefined\n /** The mounted page under a viewport (client) point, if any. */\n pageAtCss(clientX: number, clientY: number): ViewportHit | undefined\n destroy(): void\n}\n\nfunction sameList(a: readonly number[], b: readonly number[]): boolean {\n return a.length === b.length && a.every((v, i) => v === b[i])\n}\n\nexport function createViewport(opts: ViewportOptions): Viewport {\n const { container, document: doc } = opts\n const gap = opts.gap ?? 16\n const buffer = opts.buffer ?? 2\n const minZoom = opts.minZoom ?? 0.1\n const maxZoom = opts.maxZoom ?? 8\n const clamp = (z: number): number => Math.min(maxZoom, Math.max(minZoom, z))\n\n const zoom = writable<ZoomValue>(\n typeof opts.zoom === 'number' ? clamp(opts.zoom) : (opts.zoom ?? 'fit-width')\n )\n const scale = writable(1)\n const rotation = writable<ViewRotation>(opts.rotation ?? 0)\n const mode = writable<LayoutMode>(opts.mode ?? 'continuous')\n const currentPage = writable(0)\n const mounted = writable<readonly number[]>([])\n const layout = writable<CssLayout>({ boxes: [], width: 0, height: 0 })\n\n const previousStyle = {\n overflow: container.style.overflow,\n position: container.style.position,\n }\n container.dataset.inkViewport = ''\n container.style.overflow = 'auto'\n if (getComputedStyle(container).position === 'static')\n container.style.position = 'relative'\n\n const pagesEl = container.ownerDocument.createElement('div')\n pagesEl.className = 'ink-pages'\n pagesEl.dataset.inkPages = ''\n pagesEl.style.position = 'relative'\n container.append(pagesEl)\n\n const hosts = new Map<number, HTMLElement>()\n const transforms = new Map<number, PageTransform>()\n let lastSize = { width: -1, height: -1 }\n let destroyed = false\n\n function boxFor(page: number, l = layout.get()): CssPageBox | undefined {\n return l.boxes.find((b) => b.index === page)\n }\n\n /** Where the pages element starts inside the container's scrollable content (its padding). */\n function origin(): Point {\n return { x: pagesEl.offsetLeft, y: pagesEl.offsetTop }\n }\n\n /** The container's content box, CSS px: client size less padding. The pages element sits inside it. */\n function innerSize(): { width: number; height: number } {\n const cs = getComputedStyle(container)\n const px = (v: string): number => Number.parseFloat(v) || 0\n return {\n width: container.clientWidth - px(cs.paddingLeft) - px(cs.paddingRight),\n height: container.clientHeight - px(cs.paddingTop) - px(cs.paddingBottom),\n }\n }\n\n function resolveScale(): number {\n const z = zoom.get()\n if (typeof z === 'number') return clamp(z)\n const page = doc.pages[currentPage.get()] ?? doc.pages[0]\n if (!page) return 1\n return clamp(fitZoomCss(page, rotation.get(), innerSize(), z, gap))\n }\n\n function transformFor(page: number): PageTransform {\n let t = transforms.get(page)\n if (!t) {\n const info = doc.pages[page]\n if (!info) throw new RangeError(`page ${page} out of range`)\n t = createPageTransform(info, scale.get(), rotation.get())\n transforms.set(page, t)\n }\n return t\n }\n\n function layoutOnce(): void {\n scale.set(resolveScale())\n transforms.clear()\n const l = computeCssLayout({\n pages: doc.pages,\n zoom: scale.get(),\n rotation: rotation.get(),\n gap,\n mode: mode.get(),\n current: currentPage.get(),\n containerWidth: innerSize().width,\n })\n pagesEl.style.width = `${l.width}px`\n pagesEl.style.height = `${l.height}px`\n layout.set(l)\n }\n\n /**\n * Recomputes the layout. Sizing the pages element can add or remove a scrollbar, which\n * changes the client width the layout (and a fit zoom) was based on, so it runs again\n * once when that happens.\n */\n function relayout(): void {\n const width = container.clientWidth\n layoutOnce()\n if (container.clientWidth !== width) layoutOnce()\n lastSize = { width: container.clientWidth, height: container.clientHeight }\n const l = layout.get()\n for (const [page, host] of hosts) {\n if (!boxFor(page, l)) continue\n place(page, host, l)\n opts.onUpdate(page, host, transformFor(page))\n }\n sync()\n }\n\n function place(page: number, host: HTMLElement, l: CssLayout): void {\n const box = boxFor(page, l)\n if (!box) return\n const t = transformFor(page)\n host.style.left = `${box.left}px`\n host.style.top = `${box.top}px`\n host.style.width = `${t.cssWidth}px`\n host.style.height = `${t.cssHeight}px`\n // As in PDF.js's viewer: --scale-factor is the zoom, --total-scale-factor also folds in\n // /UserUnit (pdf_viewer.css: calc(var(--scale-factor) * var(--user-unit))).\n host.style.setProperty('--scale-factor', String(t.zoom))\n host.style.setProperty('--total-scale-factor', String(t.scale))\n host.dataset.rotation = String(t.totalRotation)\n }\n\n /** Mounts and unmounts hosts for the scroll position, and updates the current page. */\n function sync(): void {\n if (destroyed) return\n const l = layout.get()\n const top = container.scrollTop - origin().y\n const wanted = visibleRangeCss(l, top, container.clientHeight, buffer)\n const wantedSet = new Set(wanted)\n for (const [page, host] of [...hosts]) {\n if (wantedSet.has(page)) continue\n hosts.delete(page)\n opts.onUnmount(page, host)\n host.remove()\n }\n for (const page of wanted) {\n if (hosts.has(page)) continue\n const host = container.ownerDocument.createElement('div')\n host.className = 'ink-page'\n host.dataset.page = String(page)\n host.style.position = 'absolute'\n place(page, host, l)\n hosts.set(page, host)\n pagesEl.append(host)\n opts.onMount(page, host, transformFor(page))\n }\n if (!sameList(mounted.get(), wanted)) mounted.set(wanted)\n if (mode.get() === 'continuous') {\n currentPage.set(mostVisiblePageCss(l, top, container.clientHeight))\n }\n }\n\n let scrollFrame = 0\n const onScroll = (): void => {\n if (scrollFrame) return\n scrollFrame = requestAnimationFrame(() => {\n scrollFrame = 0\n sync()\n })\n }\n container.addEventListener('scroll', onScroll, { passive: true })\n\n const ro = new ResizeObserver(() => {\n if (destroyed) return\n if (\n container.clientWidth === lastSize.width &&\n container.clientHeight === lastSize.height\n ) {\n return\n }\n withAnchor(undefined, () => undefined)\n })\n ro.observe(container)\n\n function pageAtCss(clientX: number, clientY: number): ViewportHit | undefined {\n for (const [page, host] of hosts) {\n const r = host.getBoundingClientRect()\n if (\n clientX >= r.left &&\n clientX <= r.right &&\n clientY >= r.top &&\n clientY <= r.bottom\n ) {\n return { page, host, transform: transformFor(page) }\n }\n }\n return undefined\n }\n\n /**\n * The page box an anchor at layout-space `y` belongs to: the one whose vertical span\n * contains it, otherwise the nearest one (an anchor in a gap or past either end).\n */\n function anchorBox(l: CssLayout, y: number): CssPageBox | undefined {\n let best: CssPageBox | undefined\n let bestDistance = Infinity\n for (const b of l.boxes) {\n const distance =\n y < b.top ? b.top - y : y > b.top + b.height ? y - b.top - b.height : 0\n if (distance < bestDistance) {\n best = b\n bestDistance = distance\n }\n }\n return best\n }\n\n /**\n * Keeps the user-space point under `anchorCss` still while `change` alters the layout.\n * The anchor is taken in layout space, so it holds in the margins and gaps too: there it\n * is extrapolated from the nearest page's transform, which is affine, so the point maps\n * back exactly. The browser may still clamp the scroll at the content edges.\n */\n function withAnchor(anchorCss: Point | undefined, change: () => void): void {\n const anchor = anchorCss ?? {\n x: container.clientWidth / 2,\n y: container.clientHeight / 2,\n }\n // Read everything from the old layout before relayout() clears the cached transforms.\n const o = origin()\n const x = container.scrollLeft + anchor.x - o.x\n const y = container.scrollTop + anchor.y - o.y\n const old = anchorBox(layout.get(), y)\n const user = old\n ? transformFor(old.index).fromCss({ x: x - old.left, y: y - old.top })\n : undefined\n change()\n relayout()\n if (!old || !user) return\n const box = boxFor(old.index)\n if (!box) return\n const after = transformFor(old.index).toCss(user)\n const o2 = origin()\n container.scrollLeft = o2.x + box.left + after.x - anchor.x\n container.scrollTop = o2.y + box.top + after.y - anchor.y\n sync()\n }\n\n const viewport: Viewport = {\n zoom: readonly(zoom),\n scale: readonly(scale),\n currentPage: readonly(currentPage),\n mounted: readonly(mounted),\n layout: readonly(layout),\n rotation: readonly(rotation),\n mode: readonly(mode),\n setZoom(z, anchorCss) {\n withAnchor(anchorCss, () => zoom.set(typeof z === 'number' ? clamp(z) : z))\n },\n zoomBy(factor, anchorCss) {\n viewport.setZoom(clamp(scale.get() * factor), anchorCss)\n },\n setMode(m) {\n if (m === mode.get()) return\n // Catch up with a scroll whose frame has not run yet, then keep that page: relayout()\n // re-derives the current page from the scroll position, which the new mode changes.\n if (mode.get() === 'continuous') sync()\n const page = currentPage.get()\n mode.set(m)\n relayout()\n viewport.scrollToPage(page)\n },\n setRotation(r) {\n withAnchor(undefined, () => rotation.set(r))\n },\n scrollToPage(index, o) {\n const page = Math.max(0, Math.min(doc.pages.length - 1, index))\n const behavior = o?.behavior ?? 'auto'\n if (mode.get() === 'single') {\n // Also relayout when the layout shows another page, even if currentPage already matches.\n if (page !== currentPage.get() || layout.get().boxes[0]?.index !== page) {\n currentPage.set(page)\n relayout()\n }\n container.scrollTo({ top: 0, behavior })\n sync()\n return\n }\n const box = boxFor(page)\n if (!box) return\n container.scrollTo({ top: Math.max(0, origin().y + box.top - gap), behavior })\n sync()\n },\n scrollToRect(page, rect) {\n if (mode.get() === 'single' && currentPage.get() !== page) {\n currentPage.set(page)\n relayout()\n }\n const box = boxFor(page)\n if (!box) return\n const css = transformFor(page).toCssRect(rect)\n const o = origin()\n const top = o.y + box.top + css.top\n if (\n top < container.scrollTop ||\n top + css.height > container.scrollTop + container.clientHeight\n ) {\n container.scrollTop = Math.max(0, top - (container.clientHeight - css.height) / 2)\n }\n const left = o.x + box.left + css.left\n if (\n left < container.scrollLeft ||\n left + css.width > container.scrollLeft + container.clientWidth\n ) {\n container.scrollLeft = Math.max(0, left - (container.clientWidth - css.width) / 2)\n }\n sync()\n },\n transformFor,\n hostFor: (page) => hosts.get(page),\n pageAtCss,\n destroy() {\n if (destroyed) return\n destroyed = true\n ro.disconnect()\n container.removeEventListener('scroll', onScroll)\n if (scrollFrame) cancelAnimationFrame(scrollFrame)\n for (const [page, host] of hosts) {\n opts.onUnmount(page, host)\n host.remove()\n }\n hosts.clear()\n transforms.clear()\n pagesEl.remove()\n delete container.dataset.inkViewport\n container.style.overflow = previousStyle.overflow\n container.style.position = previousStyle.position\n },\n }\n\n relayout()\n return viewport\n}\n","import type { Viewport } from './viewport'\n\nexport interface ViewportKeysOptions {\n viewport: Viewport\n /** Read on every key, so it follows the open document. */\n pageCount: () => number\n}\n\n/** Factor `+`/`=` zoom in by; `-` zooms out by its inverse. */\nconst ZOOM_STEP = 1.25\n\n/** Keys typed here belong to the element, not the viewport. */\nconst IGNORE =\n 'input, textarea, select, [contenteditable]:not([contenteditable=\"false\"]), [data-annotation]'\n\n/**\n * Keyboard shortcuts for a focused viewport container: `+` or `=` and `-` zoom, `Home` and\n * `End` go to the first and last page, `PageDown` and `PageUp` to the next and previous.\n * Events from inputs, editable content and annotation elements, chords with Ctrl, Meta or\n * Alt (browser zoom stays the browser's), and events already handled are left alone. Only\n * handled keys are prevented. Returns a function that removes the listener.\n */\nexport function attachViewportKeys(\n el: HTMLElement,\n opts: ViewportKeysOptions\n): () => void {\n const { viewport } = opts\n const onKeydown = (e: KeyboardEvent): void => {\n if (e.defaultPrevented || e.ctrlKey || e.metaKey || e.altKey) return\n if (e.target instanceof Element && e.target.closest(IGNORE)) return\n switch (e.key) {\n case '+':\n case '=':\n viewport.zoomBy(ZOOM_STEP)\n break\n case '-':\n viewport.zoomBy(1 / ZOOM_STEP)\n break\n case 'Home':\n viewport.scrollToPage(0)\n break\n case 'End':\n viewport.scrollToPage(opts.pageCount() - 1)\n break\n case 'PageDown':\n viewport.scrollToPage(viewport.currentPage.get() + 1)\n break\n case 'PageUp':\n viewport.scrollToPage(viewport.currentPage.get() - 1)\n break\n default:\n return\n }\n e.preventDefault()\n }\n el.addEventListener('keydown', onKeydown)\n return () => el.removeEventListener('keydown', onKeydown)\n}\n","// Watches the device pixel ratio for the layers that render at it: the page canvas and the\n// loupes. The media query matches only the ratio it was built for, so it is rebuilt after\n// every change. During a browser-zoom or screen transition the query can fire while\n// devicePixelRatio still reports the old value, so each change also schedules follow-up checks.\n\nconst RECHECK_MS = [100, 500]\n\nexport interface DprWatch {\n /** Watches for a change away from `dpr`, the ratio just rendered at. */\n watch(dpr: number): void\n destroy(): void\n}\n\n/**\n * Calls `onChange` when `view`'s device pixel ratio moves away from the one last passed to\n * `watch`. `current` reads the ratio now. Does nothing where `matchMedia` is missing.\n */\nexport function watchDevicePixelRatio(\n view: Window | null | undefined,\n current: () => number,\n onChange: () => void\n): DprWatch {\n let query: MediaQueryList | undefined\n let watched: number | undefined\n let rechecks: ReturnType<typeof setTimeout>[] = []\n let destroyed = false\n\n const clearRechecks = (): void => {\n rechecks.forEach(clearTimeout)\n rechecks = []\n }\n const fire = (): void => {\n if (destroyed) return\n arm(current(), true)\n onChange()\n clearRechecks()\n rechecks = RECHECK_MS.map((ms) =>\n setTimeout(() => {\n if (!destroyed && current() !== watched) fire()\n }, ms)\n )\n }\n function arm(dpr: number, force = false): void {\n if (destroyed || !view?.matchMedia) return\n if (dpr === watched && !force) return\n watched = dpr\n query?.removeEventListener('change', fire)\n query = view.matchMedia(`(resolution: ${dpr}dppx)`)\n query.addEventListener('change', fire)\n }\n\n return {\n watch: (dpr) => arm(dpr),\n destroy() {\n destroyed = true\n query?.removeEventListener('change', fire)\n query = undefined\n clearRechecks()\n },\n }\n}\n","// Inline styles here are structural only: the wrapper fills the page host and clips\n// (`position:absolute; inset:0; overflow:hidden`), and each canvas is pinned to the top-left\n// with its CSS size set from the transform (`position:absolute; left:0; top:0; width; height`).\n// Everything cosmetic (background, shadow, border) belongs to the theme.\nimport { watchDevicePixelRatio } from './dpr-watch'\n\nimport type { PageTransform } from './transform'\nimport type { InkDocument } from '../model/document'\nimport type { PdfjsRenderTask } from '../pdfjs/types'\n\nexport interface PageRendererOptions {\n document: InkDocument\n /** Zero-based page index. */\n page: number\n /** The page host (`div.ink-page`); the renderer appends its canvas layer to it. */\n host: HTMLElement\n transform: PageTransform\n /**\n * Fixed device pixel ratio. When omitted, `window.devicePixelRatio` is read at every render\n * and the page re-renders when it changes (browser zoom, moving to another screen).\n */\n devicePixelRatio?: number\n onRendered?(): void\n /** Called for any render failure other than a superseded render's cancellation. */\n onError?(error: unknown): void\n}\n\nexport interface PageRenderer {\n readonly element: HTMLElement\n /**\n * Resolves once the most recent `update` has painted, failed (see `onError`) or the\n * renderer was destroyed. Never rejects. A promise read before a later `update` resolves\n * together with that later render, so every promise handed out settles.\n */\n readonly rendered: Promise<void>\n update(transform: PageTransform): void\n destroy(): void\n}\n\nconst isCancellation = (error: unknown): boolean =>\n (error as { name?: unknown } | null)?.name === 'RenderingCancelledException'\n\nexport function createPageRenderer(opts: PageRendererOptions): PageRenderer {\n const { document: doc, page, host } = opts\n const view = host.ownerDocument.defaultView\n const currentDpr = (): number =>\n opts.devicePixelRatio ??\n (view && view.devicePixelRatio > 0 ? view.devicePixelRatio : 1)\n const wrapper = host.ownerDocument.createElement('div')\n wrapper.className = 'ink-canvas-layer'\n wrapper.dataset.inkCanvasLayer = ''\n wrapper.style.cssText = 'position:absolute;inset:0;overflow:hidden;'\n host.append(wrapper)\n\n let current: HTMLCanvasElement | undefined\n let latest = opts.transform\n let task: PdfjsRenderTask | undefined\n let destroyed = false\n let generation = 0\n\n // One deferred per busy period: renders that supersede each other share it, and it\n // resolves when the newest one settles.\n let resolvePending: (() => void) | undefined\n let rendered: Promise<void> = Promise.resolve()\n\n function settle() {\n resolvePending?.()\n resolvePending = undefined\n }\n\n /**\n * Drops a canvas for good. Zeroing it frees its bitmap now rather than at garbage\n * collection; Safari caps the total canvas memory, which a long scroll would otherwise hit.\n */\n function release(canvas: HTMLCanvasElement): void {\n canvas.width = 0\n canvas.height = 0\n canvas.remove()\n }\n\n function sizeCanvas(canvas: HTMLCanvasElement, transform: PageTransform) {\n canvas.style.width = `${transform.cssWidth}px`\n canvas.style.height = `${transform.cssHeight}px`\n }\n\n async function render(transform: PageTransform): Promise<void> {\n const gen = ++generation\n latest = transform\n const dpr = currentDpr()\n dprWatch?.watch(dpr)\n task?.cancel()\n task = undefined\n if (!resolvePending) {\n rendered = new Promise<void>((resolve) => (resolvePending = resolve))\n }\n // The previous bitmap stays visible, stretched to the new size, until the new one lands.\n if (current) sizeCanvas(current, transform)\n let canvas: HTMLCanvasElement | undefined\n try {\n const pdfPage = await doc._pdfjs.getPage(page)\n if (destroyed || gen !== generation) return\n const { AnnotationMode } = doc._pdfjs.module\n const viewport = pdfPage.getViewport({\n scale: transform.zoom,\n rotation: transform.totalRotation,\n })\n canvas = host.ownerDocument.createElement('canvas')\n canvas.dataset.inkCanvas = ''\n canvas.setAttribute('aria-hidden', 'true')\n canvas.width = Math.round(transform.cssWidth * dpr)\n canvas.height = Math.round(transform.cssHeight * dpr)\n canvas.style.cssText = 'position:absolute;left:0;top:0;'\n sizeCanvas(canvas, transform)\n const ownTask = pdfPage.render({\n canvas,\n viewport,\n // Pages are paper: an opaque white canvas, whatever the theme puts behind it.\n background: '#ffffff',\n annotationMode: AnnotationMode.ENABLE,\n ...(dpr === 1 ? {} : { transform: [dpr, 0, 0, dpr, 0, 0] }),\n })\n task = ownTask\n await ownTask.promise\n if (task === ownTask) task = undefined\n if (destroyed || gen !== generation) {\n release(canvas)\n return\n }\n if (current) release(current)\n current = canvas\n wrapper.append(canvas)\n opts.onRendered?.()\n } catch (error) {\n if (canvas && canvas !== current) release(canvas)\n const superseded = destroyed || gen !== generation\n if (!(superseded && isCancellation(error)) && !destroyed) opts.onError?.(error)\n } finally {\n if (gen === generation) settle()\n }\n }\n\n // Re-render when the device pixel ratio changes, unless the caller fixed it.\n const dprWatch =\n opts.devicePixelRatio === undefined\n ? watchDevicePixelRatio(view, currentDpr, () => void render(latest))\n : undefined\n\n void render(opts.transform)\n\n return {\n element: wrapper,\n get rendered() {\n return rendered\n },\n update(transform) {\n if (destroyed) return\n void render(transform)\n },\n destroy() {\n if (destroyed) return\n destroyed = true\n dprWatch?.destroy()\n task?.cancel()\n task = undefined\n if (current) release(current)\n current = undefined\n wrapper.remove()\n settle()\n },\n }\n}\n","// The only file that touches PDF.js's `TextLayer`. It takes the already-loaded PDF.js module\n// instead of importing `#pdfjs`, so `@inkbar/core/dom` can re-export the text layer without\n// evaluating PDF.js at import time.\nimport type { PdfjsModule, PdfjsPage, PdfjsViewport } from './types'\n\nexport interface MountedTextLayer {\n update(viewport: PdfjsViewport): void\n cancel(): void\n}\n\nexport interface MountPdfjsTextLayerOptions {\n /** The loaded PDF.js module, i.e. `InkDocument._pdfjs.module`. */\n module: PdfjsModule\n pdfPage: PdfjsPage\n container: HTMLElement\n viewport: PdfjsViewport\n /** Aborting cancels the render (and any later use of the layer). */\n signal?: AbortSignal\n}\n\n/**\n * Renders the page's text into `container` as positioned spans. The constructor sizes the\n * container from `--total-scale-factor` and sets `data-main-rotation`; CSS (the theme) turns\n * those into the final layout. Rejects with PDF.js's `AbortException` if `signal` aborts first.\n * On any rejection the layer is cancelled and detached from `signal`.\n */\nexport async function mountPdfjsTextLayer(\n opts: MountPdfjsTextLayerOptions\n): Promise<MountedTextLayer> {\n const layer = new opts.module.TextLayer({\n textContentSource: opts.pdfPage.streamTextContent({\n includeMarkedContent: false,\n disableNormalization: true,\n }),\n container: opts.container,\n viewport: opts.viewport,\n })\n const mounted: MountedTextLayer = {\n update(viewport) {\n layer.update({ viewport })\n },\n cancel() {\n layer.cancel()\n },\n }\n const onAbort = (): void => layer.cancel()\n opts.signal?.addEventListener('abort', onAbort, { once: true })\n if (opts.signal?.aborted) layer.cancel()\n try {\n await layer.render()\n } catch (error) {\n // A failed layer is dropped here: cancelled, and no longer held by the caller's signal, so\n // a retry on the same signal does not keep every failed attempt alive.\n opts.signal?.removeEventListener('abort', onAbort)\n layer.cancel()\n throw error\n }\n return mounted\n}\n","// Inline styles here are structural only: the layer covers the page host\n// (`position:absolute; inset:0`) and its text must stay selectable whatever the page around it\n// sets (`user-select:text`). PDF.js sets the layer's width/height from `--total-scale-factor`.\n// Span styling (transparent colour, absolute positioning, font sizing, rotation transforms)\n// is the theme's job.\nimport { mountPdfjsTextLayer, type MountedTextLayer } from '../pdfjs/text-layer'\n\nimport type { PageTransform } from './transform'\nimport type { InkDocument } from '../model/document'\n\nexport interface TextLayerOptions {\n document: InkDocument\n /** Zero-based page index. */\n page: number\n /** The page host (`div.ink-page`), which must carry `--total-scale-factor`. */\n host: HTMLElement\n transform: PageTransform\n /**\n * Mount or update failures. Cancellation by `destroy` is not reported. If it throws, the\n * exception is rethrown asynchronously; `ready` still resolves.\n */\n onError?(error: unknown): void\n /** The layer mounted, or applied an `update`, without error. */\n onRendered?(): void\n}\n\nexport interface TextLayerHandle {\n readonly element: HTMLElement\n /** Resolves once the latest mount or `update` has applied. Never rejects. */\n readonly ready: Promise<void>\n update(transform: PageTransform): void\n destroy(): void\n}\n\nexport function createTextLayer(opts: TextLayerOptions): TextLayerHandle {\n const { document: doc, page } = opts\n const el = opts.host.ownerDocument.createElement('div')\n el.className = 'ink-text-layer'\n el.dataset.inkTextLayer = ''\n el.style.cssText = 'position:absolute;inset:0;user-select:text;'\n opts.host.append(el)\n\n const abort = new AbortController()\n let mounted: MountedTextLayer | undefined\n\n const viewportFor = async (transform: PageTransform) => {\n const pdfPage = await doc._pdfjs.getPage(page)\n return {\n pdfPage,\n viewport: pdfPage.getViewport({\n scale: transform.zoom,\n rotation: transform.totalRotation,\n }),\n }\n }\n\n // A throwing `onError` must not reject `ready`: its exception is rethrown from a microtask,\n // so it still surfaces as an uncaught error.\n const report = (error: unknown) => {\n if (abort.signal.aborted || !opts.onError) return\n try {\n opts.onError(error)\n } catch (thrown) {\n queueMicrotask(() => {\n throw thrown\n })\n }\n }\n\n const mount = async (transform: PageTransform): Promise<void> => {\n const { pdfPage, viewport } = await viewportFor(transform)\n if (abort.signal.aborted) return\n mounted = await mountPdfjsTextLayer({\n module: doc._pdfjs.module,\n pdfPage,\n container: el,\n viewport,\n signal: abort.signal,\n })\n if (!abort.signal.aborted) opts.onRendered?.()\n }\n\n let ready: Promise<void> = mount(opts.transform).catch(report)\n\n return {\n element: el,\n get ready() {\n return ready\n },\n update(transform) {\n if (abort.signal.aborted) return\n ready = ready\n .then(async () => {\n if (abort.signal.aborted) return\n // A mount that failed is tried again, so the layer can recover with the page.\n if (!mounted) {\n el.replaceChildren()\n await mount(transform)\n return\n }\n const { viewport } = await viewportFor(transform)\n if (abort.signal.aborted) return\n mounted.update(viewport)\n opts.onRendered?.()\n })\n .catch(report)\n },\n destroy() {\n if (abort.signal.aborted) return\n abort.abort()\n el.remove()\n },\n }\n}\n","import { mergeLineRects } from '../model/selection'\n\nimport type { PageTransform } from './transform'\nimport type { Quad, Rect } from '../model/geometry'\n\nexport interface SelectionQuads {\n /** Zero-based page index. */\n page: number\n /** One user-space quad per selected line, top to bottom. */\n quads: Quad[]\n text: string\n}\n\n/**\n * Converts viewport-relative CSS-pixel rects (from `getClientRects()`) to user-space rects on\n * the page rendered in `host`. Empty rects are skipped.\n */\nexport function cssRectsToUserRects(\n rects: Iterable<DOMRect>,\n host: HTMLElement,\n transform: PageTransform\n): Rect[] {\n const h = host.getBoundingClientRect()\n const out: Rect[] = []\n for (const r of rects) {\n if (r.width === 0 || r.height === 0) continue\n out.push(\n transform.fromCssRect({\n left: r.left - h.left,\n top: r.top - h.top,\n width: r.width,\n height: r.height,\n })\n )\n }\n return out\n}\n\n/**\n * Reads the live DOM selection and returns one entry per page it touches, with line-merged\n * user-space quads. Only text inside `[data-ink-text-layer]` under a `[data-page]` host counts;\n * `pageFor` maps a host to its page index and current transform.\n */\nexport function getSelectionQuads(\n root: HTMLElement,\n pageFor: (host: HTMLElement) => { page: number; transform: PageTransform } | undefined\n): SelectionQuads[] {\n const sel = root.ownerDocument.defaultView?.getSelection()\n if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return []\n const results = new Map<number, { rects: Rect[]; text: string[] }>()\n const layers = [...root.querySelectorAll<HTMLElement>('[data-ink-text-layer]')]\n if (root.matches('[data-ink-text-layer]')) layers.unshift(root)\n for (let i = 0; i < sel.rangeCount; i++) {\n const range = sel.getRangeAt(i)\n for (const layer of layers) {\n if (!range.intersectsNode(layer)) continue\n const host = layer.closest<HTMLElement>('[data-page]')\n if (!host) continue\n const info = pageFor(host)\n if (!info) continue\n const sub = range.cloneRange()\n if (!layer.contains(range.startContainer)) sub.setStart(layer, 0)\n if (!layer.contains(range.endContainer)) sub.setEnd(layer, layer.childNodes.length)\n const entry = results.get(info.page) ?? { rects: [], text: [] }\n entry.rects.push(...cssRectsToUserRects(sub.getClientRects(), host, info.transform))\n entry.text.push(rangeText(sub))\n results.set(info.page, entry)\n }\n }\n return [...results.entries()]\n .sort(([a], [b]) => a - b)\n .map(([page, { rects, text }]) => ({\n page,\n quads: mergeLineRects(rects),\n text: normaliseText(text.join('\\n')),\n }))\n .filter((r) => r.quads.length > 0)\n}\n\n/**\n * The range's text with each PDF.js `<br>` (an end of line) kept as a newline.\n * `Range.toString()` would run the lines together.\n */\nfunction rangeText(range: Range): string {\n const fragment = range.cloneContents()\n for (const br of fragment.querySelectorAll('br')) br.replaceWith('\\n')\n return fragment.textContent ?? ''\n}\n\n/**\n * Collapses runs of horizontal whitespace to one space and drops the spaces around a line\n * break. Breaks themselves are all kept, so a blank line (two breaks) survives.\n */\nfunction normaliseText(text: string): string {\n return text\n .replace(/[^\\S\\n]+/g, ' ')\n .replace(/ ?\\n ?/g, '\\n')\n .trim()\n}\n","// Turns the sampled points of an ink stroke into a smoothed, filled outline. Overlay rendering\n// and the draw tool's live preview share it, so a stroke looks the same while drawn and after.\nimport { getStroke } from 'perfect-freehand'\n\nimport type { Point } from '../model/geometry'\n\n/** Strokes started within this long of the last one join its annotation. */\nexport const JOIN_GAP_MS = 1000\n\n/**\n * The polygon around a stroke. `width` is the stroke width, in the points' own unit; without\n * `pressure` the line keeps an even width.\n */\nexport function strokeOutline(\n points: readonly Point[],\n pressure: readonly number[] | undefined,\n width: number\n): Point[] {\n const withPressure = pressure !== undefined\n const input = points.map(\n (p, i) => [p.x, p.y, pressure?.[i] ?? 0.5] as [number, number, number]\n )\n return getStroke(input, {\n size: width,\n thinning: withPressure ? 0.5 : 0,\n smoothing: 0.5,\n streamline: 0.5,\n simulatePressure: false,\n }).map(([x, y]) => ({ x, y }))\n}\n\n/** A closed SVG path `d` through `outline`; empty for an empty outline. */\nexport function outlinePath(outline: readonly Point[]): string {\n if (outline.length === 0) return ''\n const r = (n: number): string => String(Math.round(n * 100) / 100)\n return `M${outline.map((p) => `${r(p.x)},${r(p.y)}`).join('L')}Z`\n}\n","import { ICON_ATTRIBUTES, MessageSquareText } from '@inkbar/icons'\n\nimport {\n calloutStroke,\n freeTextBox,\n isStandardCallout,\n} from '../model/annotations/callout'\nimport { isBubble, isTextMarkup, WEDGE_HALF } from '../model/annotations/edit'\nimport { isKnown, LINE_ENDINGS } from '../model/annotations/pdf-names'\n\nimport { outlinePath, strokeOutline } from './ink-stroke'\nimport { normalizeRotation, type CssRect, type PageTransform } from './transform'\n\nimport type {\n Annotation,\n FreeTextAnnotation,\n LineEnding,\n StampAnnotation,\n TextMarkupAnnotation,\n} from '../model/annotations/types'\nimport type { Point, Quad } from '../model/geometry'\n\nconst SVG = 'http://www.w3.org/2000/svg'\n\n/** Side of an edit handle, CSS px. */\nconst HANDLE_PX = 8\nconst CORNERS = ['nw', 'ne', 'sw', 'se'] as const\n/** Width in CSS px of the band along a mask's edge that takes presses. */\nconst MASK_EDGE = 6\n/** Width in CSS px of the band straddling a text box's edge, which drags the box. */\nconst TEXT_EDGE = 6\n\n/**\n * Which edit handles an element shows: none, the four CSS corners of a box (`nw`, `ne`, `sw`,\n * `se`), or a line's two ends (`start`, `end`), all element-local CSS px.\n */\nexport type HandleSpec =\n | { kind: 'none' }\n | {\n kind: 'corners'\n /** The box's top-left corner; 0,0 (the element's own) when absent. */\n left?: number\n top?: number\n width: number\n height: number\n /** A callout's tip: one more handle, `callout`. */\n tail?: Point\n }\n | { kind: 'ends'; start: Point; end: Point }\n\n/**\n * Syncs an element's edit handles (`.ink-handle[data-handle]`) with `spec`. Each is an 8px\n * `position:absolute; pointer-events:auto` box centred on its point; its look is the theme's.\n */\nexport function syncHandles(node: HTMLElement, spec: HandleSpec): void {\n const existing = [...node.querySelectorAll<HTMLElement>(':scope > [data-handle]')]\n const names: readonly string[] =\n spec.kind === 'none'\n ? []\n : spec.kind === 'ends'\n ? ['start', 'end']\n : spec.tail\n ? [...CORNERS, 'callout']\n : CORNERS\n if (\n existing.length !== names.length ||\n existing.some((h, i) => h.dataset.handle !== names[i])\n ) {\n existing.forEach((h) => h.remove())\n existing.length = 0\n for (const name of names) {\n const h = node.ownerDocument.createElement('div')\n h.className = 'ink-handle'\n h.dataset.handle = name\n h.setAttribute('aria-hidden', 'true')\n h.style.cssText = `position:absolute;width:${HANDLE_PX}px;height:${HANDLE_PX}px;pointer-events:auto;`\n node.append(h)\n existing.push(h)\n }\n }\n for (const h of existing) {\n const name = h.dataset.handle!\n const at =\n spec.kind === 'ends'\n ? name === 'start'\n ? spec.start\n : spec.end\n : spec.kind === 'corners'\n ? name === 'callout' && spec.tail\n ? spec.tail\n : {\n x: (spec.left ?? 0) + (name[1] === 'w' ? 0 : spec.width),\n y: (spec.top ?? 0) + (name[0] === 'n' ? 0 : spec.height),\n }\n : { x: 0, y: 0 }\n h.style.left = `${at.x - HANDLE_PX / 2}px`\n h.style.top = `${at.y - HANDLE_PX / 2}px`\n }\n}\n\n/** Width in CSS px a thin stroke's invisible hit twin is widened to. */\nconst HIT_STROKE = 8\n\n/**\n * True when `a` is drawn as a stroke alone (a line, polyline, ink, or an unfilled square,\n * circle or polygon with a border), so a press beside the stroke would miss it. These get an\n * invisible, wider hit twin of their geometry.\n */\nfunction hasHitTwin(a: Annotation): boolean {\n switch (a.type) {\n case 'line':\n case 'polyline':\n case 'ink':\n return true\n case 'polygon':\n case 'square':\n case 'circle':\n return a.interiorColor === undefined && a.width > 0\n default:\n return false\n }\n}\n\n/** The width in CSS px of `a`'s hit twin: 8px, or the drawn stroke if that is wider. */\nfunction hitWidth(a: Annotation, t: PageTransform): number {\n return Math.max(HIT_STROKE, 'width' in a ? t.toCssLength(a.width) : 0)\n}\n\n/**\n * The CSS box an annotation's default visual occupies. Usually `toCssRect(a.rect)`. Stroked\n * paths (lines, polylines, polygons, ink) use the bounds of their own points instead of\n * `rect` (which may already carry stroke padding, as a derived ink rect does), padded once by\n * half their stroke width on every side, at least 1px in all, so a horizontal or vertical\n * line still has a box to draw and hit-test in. A shape with a hit twin (see `hasHitTwin`)\n * is padded by at least 4px more, so its wider hit area is not clipped. Custom elements do\n * not use this: they sit on `toCssRect(a.rect)`.\n */\nexport function annotationBox(a: Annotation, t: PageTransform): CssRect {\n const drawn = handleBox(a, t)\n if (!hasHitTwin(a)) return drawn\n const pad = hitPad(a, t)\n return {\n left: drawn.left - pad,\n top: drawn.top - pad,\n width: drawn.width + pad * 2,\n height: drawn.height + pad * 2,\n }\n}\n\n/**\n * How far past `handleBox` a shape with a hit twin extends its element: the twin's overhang\n * beyond the drawn stroke, and at least 4px.\n */\nfunction hitPad(a: Annotation, t: PageTransform): number {\n const overhang = Math.max(0, hitWidth(a, t) - t.toCssLength('width' in a ? a.width : 0))\n return Math.max(HIT_STROKE / 2, overhang / 2)\n}\n\n/**\n * The CSS box an annotation's edit handles and resizing work on: `annotationBox` without the\n * padding its hit twin needs. `toCssRect(a.rect)` for a rect-shaped annotation; the padded\n * bounds of its points for a stroked path.\n */\nexport function handleBox(a: Annotation, t: PageTransform): CssRect {\n const points =\n a.type === 'line'\n ? [a.start, a.end]\n : a.type === 'polyline' || a.type === 'polygon'\n ? a.vertices\n : a.type === 'ink'\n ? a.inklist.flat()\n : undefined\n if (!points || points.length === 0 || !('width' in a)) return t.toCssRect(a.rect)\n const box = t.toCssRect(pointBounds(points))\n const stroke = Math.max(t.toCssLength(a.width), 1)\n // Endings reach up to ENDING_SCALE strokes either side of their end.\n const pad = hasEndings(a) ? ENDING_SCALE * stroke : stroke / 2\n return {\n left: box.left - pad,\n top: box.top - pad,\n width: box.width + pad * 2,\n height: box.height + pad * 2,\n }\n}\n\n/** An ending's length, and its full width, as a multiple of the stroke width. */\nconst ENDING_SCALE = 3\n\n/** A name Inkbar does not draw is drawn as no ending; the annotation keeps it. */\nfunction drawable(kind: LineEnding | undefined): LineEnding {\n return kind !== undefined && isKnown(LINE_ENDINGS, kind) ? kind : 'None'\n}\n\nfunction endingKinds(a: Annotation): { head: LineEnding; tail: LineEnding } | undefined {\n return a.type === 'line' || a.type === 'polyline'\n ? { head: drawable(a.head), tail: drawable(a.tail) }\n : undefined\n}\n\nfunction hasEndings(a: Annotation): boolean {\n const e = endingKinds(a)\n return e !== undefined && (e.head !== 'None' || e.tail !== 'None')\n}\n\nconst fmt = (n: number): string => String(Math.round(n * 1000) / 1000 + 0)\n\n/**\n * SVG path data for a line ending at `at`, in the caller's coordinates (CSS px). `from` is the\n * other end of the segment the ending sits on, so the ending points from `from` towards `at`.\n * Sized from the stroke `width` (at least 1): arrows are 3 strokes long, the rest 3 across.\n * Returns an empty string for `none` or a zero-length segment.\n */\nexport function lineEndingPath(\n kind: LineEnding,\n at: Point,\n from: Point,\n width: number\n): string {\n const len = Math.hypot(at.x - from.x, at.y - from.y)\n if (!isKnown(LINE_ENDINGS, kind) || kind === 'None' || len === 0) return ''\n const size = ENDING_SCALE * Math.max(width, 1)\n const half = size / 2\n const dx = (at.x - from.x) / len\n const dy = (at.y - from.y) / len\n // Unit normal, 90 degrees clockwise on screen.\n const nx = -dy\n const ny = dx\n const pt = (along: number, across: number, o: Point = at): string =>\n `${fmt(o.x + dx * along + nx * across)} ${fmt(o.y + dy * along + ny * across)}`\n switch (kind) {\n case 'OpenArrow':\n return `M${pt(-size, -half)}L${pt(0, 0)}L${pt(-size, half)}`\n case 'ClosedArrow':\n return `M${pt(-size, -half)}L${pt(0, 0)}L${pt(-size, half)}Z`\n case 'ROpenArrow':\n return `M${pt(0, -half)}L${pt(-size, 0)}L${pt(0, half)}`\n case 'RClosedArrow':\n return `M${pt(0, -half)}L${pt(-size, 0)}L${pt(0, half)}Z`\n case 'Square':\n return `M${pt(-half, -half)}L${pt(half, -half)}L${pt(half, half)}L${pt(-half, half)}Z`\n case 'Diamond':\n return `M${pt(-half, 0)}L${pt(0, -half)}L${pt(half, 0)}L${pt(0, half)}Z`\n case 'Circle':\n return `M${pt(half, 0)}A${fmt(half)} ${fmt(half)} 0 1 0 ${pt(-half, 0)}A${fmt(half)} ${fmt(half)} 0 1 0 ${pt(half, 0)}Z`\n case 'Butt':\n return `M${pt(0, -half)}L${pt(0, half)}`\n case 'Slash': {\n // Tilted 30 degrees from the butt, as PDF draws it.\n const s = Math.sin(Math.PI / 6) * half\n const c = Math.cos(Math.PI / 6) * half\n return `M${pt(-s, -c)}L${pt(s, c)}`\n }\n default:\n return ''\n }\n}\n\n/** Endings that are solid shapes: filled with the stroke colour. */\nconst FILLED_ENDINGS: ReadonlySet<LineEnding> = new Set([\n 'ClosedArrow',\n 'RClosedArrow',\n 'Square',\n 'Circle',\n 'Diamond',\n])\n\nfunction pointBounds(points: readonly Point[]): {\n x: number\n y: number\n width: number\n height: number\n} {\n const xs = points.map((p) => p.x)\n const ys = points.map((p) => p.y)\n const x = Math.min(...xs)\n const y = Math.min(...ys)\n return { x, y, width: Math.max(...xs) - x, height: Math.max(...ys) - y }\n}\n\n/**\n * Draws the default visual for an annotation inside its positioned element. Coordinates are\n * relative to the element. Colour, opacity and stroke are SVG attributes, never inline style,\n * so a theme can override them with CSS.\n */\nexport function renderAnnotationContent(\n el: HTMLElement,\n a: Annotation,\n t: PageTransform\n): void {\n const doc = el.ownerDocument\n el.replaceChildren()\n const box = annotationBox(a, t)\n /** A user-space point in element-local CSS px. */\n const at = (p: Point): Point => {\n const c = t.toCss(p)\n return { x: c.x - box.left, y: c.y - box.top }\n }\n const local = (p: Point): string => {\n const c = at(p)\n return `${c.x},${c.y}`\n }\n const node = (name: string, attrs: Record<string, string | number>): SVGElement => {\n const n = doc.createElementNS(SVG, name)\n for (const [k, v] of Object.entries(attrs)) n.setAttribute(k, String(v))\n return n\n }\n\n if (a.type === 'text') {\n // The note's box is its shape: a transparent rect takes the hits, the icon is theme art.\n const svg = boxSvg(doc, box.width, box.height)\n const hit = node('rect', {\n x: 0,\n y: 0,\n width: box.width,\n height: box.height,\n fill: 'transparent',\n stroke: 'none',\n 'pointer-events': 'all',\n })\n hit.classList.add('ink-note-box')\n svg.append(hit)\n const icon = doc.createElement('span')\n icon.className = 'ink-note-icon'\n icon.dataset.icon = a.icon\n el.append(svg, icon)\n return\n }\n if (a.type === 'freetext') {\n if (isBubble(a)) {\n // One path draws the box and its tail; the text box sits above it with no look of its own.\n const svg = boxSvg(doc, box.width, box.height)\n svg.classList.add('ink-annotation-shape')\n svg.setAttribute('opacity', String(a.opacity))\n const path = node('path', {\n d: bubblePath(a, t),\n fill: a.color ?? 'none',\n stroke: a.width > 0 ? (a.borderColor ?? a.defaultStyle.color) : 'none',\n 'stroke-width': t.toCssLength(a.width),\n 'stroke-linejoin': 'round',\n 'pointer-events': 'visiblePainted',\n })\n path.classList.add('ink-bubble')\n dash(path, a.dashes, t)\n svg.append(path)\n el.append(svg)\n } else if (isStandardCallout(a)) {\n // The leader line runs from the tip to the box, with its ending at the tip.\n const svg = boxSvg(doc, box.width, box.height)\n svg.classList.add('ink-annotation-shape')\n svg.setAttribute('opacity', String(a.opacity))\n const stroke = calloutStroke(a)\n const sw = t.toCssLength(stroke.width)\n const line = node('polyline', {\n points: a.callout.map(local).join(' '),\n fill: 'none',\n stroke: stroke.color,\n 'stroke-width': sw,\n 'stroke-linejoin': 'round',\n 'stroke-linecap': 'butt',\n 'pointer-events': 'visiblePainted',\n })\n line.classList.add('ink-callout-line')\n // The leader line is dashed as the box's border is.\n dash(line, a.dashes, t)\n svg.append(line)\n const kind = drawable(a.head)\n const d = lineEndingPath(kind, at(a.callout[0]!), at(a.callout[1]!), sw)\n if (d) {\n const ending = node('path', {\n d,\n fill: FILLED_ENDINGS.has(kind) ? stroke.color : 'none',\n stroke: stroke.color,\n 'stroke-width': sw,\n 'stroke-linejoin': 'round',\n 'stroke-linecap': kind === 'Butt' || kind === 'Slash' ? 'butt' : 'round',\n 'pointer-events': 'visiblePainted',\n })\n ending.setAttribute('data-ending', 'head')\n svg.append(ending)\n }\n el.append(svg)\n }\n // HTML rather than SVG <text>: a text box must wrap, and SVG text does not.\n const text = doc.createElement('div')\n text.className = 'ink-free-text'\n text.textContent = a.contents\n styleFreeText(text, a, t)\n if (a.fringe) {\n // Inset from the element, which covers the whole rect.\n const inner = freeTextLocalBox(a, t)\n text.style.position = 'absolute'\n text.style.left = `${inner.left}px`\n text.style.top = `${inner.top}px`\n text.style.width = `${inner.width}px`\n text.style.height = `${inner.height}px`\n }\n // Structural: the element itself ignores the pointer, the text box takes it.\n text.style.pointerEvents = 'auto'\n el.append(text, edgeBand(doc, box, freeTextLocalBox(a, t)))\n appendSelectionFrame(el, a, t)\n return\n }\n\n if (a.type === 'stamp') {\n el.append(stampImage(doc, a, t, box))\n return\n }\n\n const svg = boxSvg(doc, box.width, box.height)\n svg.classList.add('ink-annotation-shape')\n /** Invisible wider copies of stroke-only geometry, added once the drawn shapes are. */\n const twins: SVGElement[] = []\n\n switch (a.type) {\n case 'highlight':\n for (const q of a.quads) {\n svg.append(\n node('polygon', {\n points: quadPoints(q).map(local).join(' '),\n fill: a.color,\n 'fill-opacity': a.opacity,\n })\n )\n }\n break\n case 'underline':\n case 'strikeout':\n case 'squiggly':\n svg.setAttribute('opacity', String(a.opacity))\n for (const q of a.quads) {\n const pts = markupLine(a.type, q)\n svg.append(\n node('polyline', {\n points: pts.map(local).join(' '),\n fill: 'none',\n stroke: a.color,\n 'stroke-width': t.toCssLength(markupStroke(q)),\n })\n )\n }\n break\n case 'redact': {\n const shapes = a.quads\n ? a.quads.map((q) =>\n node('polygon', { points: quadPoints(q).map(local).join(' ') })\n )\n : [node('rect', { x: 0, y: 0, width: box.width, height: box.height })]\n for (const s of shapes) {\n s.setAttribute('fill', a.interiorColor)\n s.setAttribute('fill-opacity', '0.15')\n s.setAttribute('stroke', a.color)\n s.setAttribute('stroke-width', String(t.toCssLength(1)))\n svg.append(s)\n }\n svg.setAttribute('opacity', String(a.opacity))\n break\n }\n case 'square':\n case 'circle': {\n const sw = t.toCssLength(a.width)\n // The element is the rect plus its hit twin's padding, if it has a twin.\n const pad = hasHitTwin(a) ? hitPad(a, t) : 0\n const w = box.width - pad * 2\n const h = box.height - pad * 2\n const geometry =\n a.type === 'square'\n ? {\n name: 'rect',\n attrs: {\n x: pad + sw / 2,\n y: pad + sw / 2,\n width: Math.max(0, w - sw),\n height: Math.max(0, h - sw),\n ...(a.cornerRadius ? { rx: t.toCssLength(a.cornerRadius) } : {}),\n },\n }\n : {\n name: 'ellipse',\n attrs: {\n cx: box.width / 2,\n cy: box.height / 2,\n rx: Math.max(0, w / 2 - sw / 2),\n ry: Math.max(0, h / 2 - sw / 2),\n },\n }\n const shape = node(geometry.name, geometry.attrs)\n shape.setAttribute('fill', a.interiorColor ?? 'none')\n shape.setAttribute('stroke', a.color)\n shape.setAttribute('stroke-width', String(sw))\n dash(shape, a.dashes, t)\n svg.append(shape)\n if (hasHitTwin(a))\n twins.push(hitTwin(node, geometry.name, geometry.attrs, hitWidth(a, t)))\n svg.setAttribute('opacity', String(a.opacity))\n break\n }\n case 'loupe': {\n // The rim, over the magnified canvas the overlay's loupe layer puts first in the\n // element. Its transparent fill takes presses anywhere on the lens.\n const sw = t.toCssLength(a.width)\n const rim = node('circle', {\n cx: box.width / 2,\n cy: box.height / 2,\n r: Math.max(0, Math.min(box.width, box.height) / 2 - sw / 2),\n fill: 'transparent',\n stroke: sw > 0 ? a.color : 'none',\n 'stroke-width': sw,\n })\n rim.classList.add('ink-loupe-rim')\n svg.append(rim)\n svg.setAttribute('opacity', String(a.opacity))\n break\n }\n case 'mask': {\n // The shape's outline as an invisible band just inside the edge: it takes presses on\n // the edge only, so the spotlight stays readable, selectable and annotatable, and the\n // dimmed area outside belongs to the page. The dimming is the mask layer's.\n const inset = MASK_EDGE / 2\n const shape =\n a.shape === 'ellipse'\n ? node('ellipse', {\n cx: box.width / 2,\n cy: box.height / 2,\n rx: Math.max(0, box.width / 2 - inset),\n ry: Math.max(0, box.height / 2 - inset),\n })\n : node('rect', {\n x: inset,\n y: inset,\n width: Math.max(0, box.width - MASK_EDGE),\n height: Math.max(0, box.height - MASK_EDGE),\n })\n shape.setAttribute('fill', 'none')\n shape.setAttribute('stroke', 'transparent')\n shape.setAttribute('stroke-width', String(MASK_EDGE))\n shape.classList.add('ink-mask-shape')\n svg.append(shape)\n break\n }\n case 'line':\n case 'polyline':\n case 'polygon': {\n const pts = a.type === 'line' ? [a.start, a.end] : a.vertices\n const stroked = node(a.type === 'polygon' ? 'polygon' : 'polyline', {\n points: pts.map(local).join(' '),\n fill: a.type === 'polygon' ? (a.interiorColor ?? 'none') : 'none',\n stroke: a.color,\n 'stroke-width': t.toCssLength(a.width),\n 'stroke-linejoin': 'round',\n })\n dash(stroked, a.dashes, t)\n svg.append(stroked)\n if (hasHitTwin(a)) {\n twins.push(\n hitTwin(\n node,\n stroked.tagName,\n { points: stroked.getAttribute('points')!, 'stroke-linejoin': 'round' },\n hitWidth(a, t)\n )\n )\n }\n const ends = endingKinds(a)\n if (ends && pts.length >= 2) {\n for (const [name, kind, tip, other] of [\n ['head', ends.head, pts[0]!, pts[1]!],\n ['tail', ends.tail, pts[pts.length - 1]!, pts[pts.length - 2]!],\n ] as const) {\n const d = lineEndingPath(kind, at(tip), at(other), t.toCssLength(a.width))\n if (!d) continue\n const ending = node('path', {\n d,\n fill: FILLED_ENDINGS.has(kind) ? a.color : 'none',\n stroke: a.color,\n 'stroke-width': t.toCssLength(a.width),\n 'stroke-linejoin': 'round',\n // A butt or slash ending is a cut across the line: a round cap would blunt it.\n 'stroke-linecap': kind === 'Butt' || kind === 'Slash' ? 'butt' : 'round',\n })\n ending.setAttribute('data-ending', name)\n svg.append(ending)\n twins.push(\n hitTwin(\n node,\n 'path',\n { d, 'stroke-linejoin': 'round', 'stroke-linecap': 'round' },\n hitWidth(a, t)\n )\n )\n }\n }\n svg.setAttribute('opacity', String(a.opacity))\n break\n }\n case 'ink':\n // Every stroke is a smoothed filled outline, thinned by pressure when there is some.\n // Dashes do not apply to a filled outline.\n a.inklist.forEach((path, i) => {\n const outline = strokeOutline(\n path.map(at),\n a.pressure?.[i],\n t.toCssLength(a.width)\n )\n svg.append(\n node('path', { class: 'ink-stroke', d: outlinePath(outline), fill: a.color })\n )\n twins.push(\n hitTwin(\n node,\n 'polyline',\n {\n points: path.map(local).join(' '),\n 'stroke-linejoin': 'round',\n 'stroke-linecap': 'round',\n },\n hitWidth(a, t)\n )\n )\n })\n svg.setAttribute('opacity', String(a.opacity))\n break\n }\n // Hits follow the painted shape, so a press beside it reaches the text layer underneath.\n for (const shape of svg.children) shape.setAttribute('pointer-events', 'visiblePainted')\n svg.append(...twins)\n el.append(svg)\n appendCommentMarker(el, a, t)\n}\n\n/**\n * An invisible copy of a stroke-only shape's geometry, `width` CSS px wide, that takes\n * presses on the stroke alone (`[data-ink-hit-stroke]`), so a thin line is easy to hit.\n */\nfunction hitTwin(\n node: (name: string, attrs: Record<string, string | number>) => SVGElement,\n name: string,\n attrs: Record<string, string | number>,\n width: number\n): SVGElement {\n const twin = node(name, attrs)\n twin.setAttribute('data-ink-hit-stroke', '')\n twin.setAttribute('fill', 'none')\n twin.setAttribute('stroke', 'transparent')\n twin.setAttribute('stroke-width', String(width))\n twin.setAttribute('pointer-events', 'stroke')\n return twin\n}\n\n/**\n * The band a press on a free text's edge lands on: an invisible `rect[data-ink-edge]` stroke\n * `TEXT_EDGE` px wide along the text box's edge, half inside it and half out, in its own SVG\n * over the element. A press inside the box edits it; one on the band selects and drags it.\n * It is there whether or not the box draws a border. Geometry only.\n */\nfunction edgeBand(doc: Document, el: CssRect, box: CssRect): SVGSVGElement {\n // A later sibling of the text box, so it paints above it once the theme positions it.\n const svg = boxSvg(doc, el.width, el.height)\n const band = doc.createElementNS(SVG, 'rect')\n band.setAttribute('x', String(box.left))\n band.setAttribute('y', String(box.top))\n band.setAttribute('width', String(box.width))\n band.setAttribute('height', String(box.height))\n band.setAttribute('fill', 'none')\n band.setAttribute('stroke', 'transparent')\n band.setAttribute('stroke-width', String(TEXT_EDGE))\n band.setAttribute('pointer-events', 'stroke')\n band.setAttribute('data-ink-edge', '')\n svg.append(band)\n return svg\n}\n\n/**\n * A stamp's `img.ink-stamp`, filling the element's box. The image is upright in user space\n * turned by the stamp's `rotation` (anticlockwise), and the page turns it again on screen\n * (clockwise), so it is drawn turned by the difference: a signature placed against the page's\n * turn reads upright. Size, position and turn are geometry, set inline; the opacity travels as\n * `--ink-opacity` for the theme.\n */\nfunction stampImage(\n doc: Document,\n a: StampAnnotation,\n t: PageTransform,\n box: CssRect\n): HTMLImageElement {\n const img = doc.createElement('img')\n img.className = 'ink-stamp'\n img.alt = ''\n img.draggable = false\n img.decoding = 'async'\n img.src = a.imagedata\n const turn = normalizeRotation(t.totalRotation - (a.rotation ?? 0))\n const sideways = turn === 90 || turn === 270\n const width = sideways ? box.height : box.width\n const height = sideways ? box.width : box.height\n img.style.position = 'absolute'\n img.style.left = `${(box.width - width) / 2}px`\n img.style.top = `${(box.height - height) / 2}px`\n img.style.width = `${width}px`\n img.style.height = `${height}px`\n if (turn !== 0) img.style.transform = `rotate(${turn}deg)`\n // Structural: the element itself ignores the pointer, the image takes it.\n img.style.pointerEvents = 'auto'\n img.style.setProperty('--ink-opacity', String(a.opacity))\n return img\n}\n\n/**\n * Styles a free-text box (`.ink-free-text`) from its annotation, as the theme reads it: the text\n * style, fill, border colour and width, corner radius and opacity travel as custom properties\n * (`--ink-font-size`, `--ink-font-family`, `--ink-font-weight`, `--ink-font-style`,\n * `--ink-text-decoration`, `--ink-text-color`, `--ink-fill`, `--ink-box-border`,\n * `--ink-border-width`, `--ink-corner-radius`, `--ink-opacity`); alignment as `data-align`,\n * and a border as `data-border` (`solid` or `dashed`, absent at width 0). Lengths are scaled to\n * CSS px. Shared by the overlay and the in-place editor, so both look the same.\n */\nexport function styleFreeText(\n node: HTMLElement,\n a: FreeTextAnnotation,\n t: PageTransform\n): void {\n const s = a.defaultStyle\n const set = (name: string, value: string | undefined): void => {\n if (value === undefined) node.style.removeProperty(name)\n else node.style.setProperty(name, value)\n }\n set('--ink-font-size', `${t.toCssLength(s.fontSize)}px`)\n set('--ink-font-family', cssString(s.fontFamily))\n set('--ink-font-weight', s.fontWeight)\n set('--ink-font-style', s.fontStyle)\n set('--ink-text-decoration', s.textDecoration)\n set('--ink-text-color', s.color)\n // A speech bubble's outline and fill are drawn by its path, not by the text box.\n const bubble = isBubble(a)\n set('--ink-fill', bubble ? undefined : a.color)\n // Not `--ink-border`, the interface's border token: a box with no border colour of its own\n // takes its text colour, as a bubble's outline does.\n set('--ink-box-border', bubble ? undefined : (a.borderColor ?? s.color))\n set(\n '--ink-border-width',\n !bubble && a.width > 0 ? `${t.toCssLength(a.width)}px` : undefined\n )\n set(\n '--ink-corner-radius',\n !bubble && a.cornerRadius ? `${t.toCssLength(a.cornerRadius)}px` : undefined\n )\n set('--ink-opacity', String(a.opacity))\n node.dataset.align = s.textAlign\n if (bubble) node.dataset.bubble = ''\n else delete node.dataset.bubble\n if (!bubble && a.width > 0) node.dataset.border = a.dashes?.length ? 'dashed' : 'solid'\n else delete node.dataset.border\n}\n\n/**\n * A free text's text box (`freeTextBox`) in CSS px, relative to the top-left of its rect on\n * screen, where its overlay element sits.\n */\nexport function freeTextLocalBox(a: FreeTextAnnotation, t: PageTransform): CssRect {\n const origin = t.toCssRect(a.rect)\n const box = t.toCssRect(freeTextBox(a))\n return {\n left: box.left - origin.left,\n top: box.top - origin.top,\n width: box.width,\n height: box.height,\n }\n}\n\n/**\n * The outline of a speech bubble as SVG path data in CSS px relative to `origin` (by default\n * the top-left of its rect on screen, where its overlay element sits): the rounded text box\n * (`freeTextBox`) with a wedge to the tip, `callout[0]`. The wedge leaves the box edge nearest\n * `callout`'s last point, at that point's position along it, kept clear of the corners.\n */\nexport function bubblePath(\n a: FreeTextAnnotation & { callout: readonly Point[] },\n t: PageTransform,\n origin: { left: number; top: number } = t.toCssRect(a.rect)\n): string {\n const css = t.toCssRect(freeTextBox(a))\n // Box-relative CSS px: the box's top-left is 0,0.\n const inBox = (p: Point): Point => {\n const c = t.toCss(p)\n return { x: c.x - css.left, y: c.y - css.top }\n }\n const tip = inBox(a.callout[0]!)\n const edge = inBox(a.callout[a.callout.length - 1]!)\n const w = css.width\n const h = css.height\n const r = Math.min(t.toCssLength(a.cornerRadius ?? 0), w / 2, h / 2)\n // The edge nearest the last point, as `nearestEdge` (model/annotations/edit.ts) picks it,\n // ties included (left, right, bottom, top on an unturned page); change both together.\n const gaps = {\n left: Math.abs(edge.x),\n right: Math.abs(edge.x - w),\n bottom: Math.abs(edge.y - h),\n top: Math.abs(edge.y),\n }\n const side = (Object.keys(gaps) as (keyof typeof gaps)[]).reduce((best, s) =>\n gaps[s] < gaps[best] ? s : best\n )\n const along = side === 'top' || side === 'bottom' ? w : h\n const half = Math.min(t.toCssLength(WEDGE_HALF), along / 4)\n const lo = Math.min(r + half, along / 2)\n const at = Math.min(\n Math.max(side === 'top' || side === 'bottom' ? edge.x : edge.y, lo),\n along - lo\n )\n const dx = css.left - origin.left\n const dy = css.top - origin.top\n const P = (x: number, y: number): string => `${fmt(x + dx)} ${fmt(y + dy)}`\n const arc = (x: number, y: number): string =>\n r > 0 ? `A${fmt(r)} ${fmt(r)} 0 0 1 ${P(x, y)}` : ''\n const spike = (x: number, y: number): string => `L${P(x, y)}L${P(tip.x, tip.y)}`\n return [\n `M${P(r, 0)}`,\n side === 'top' ? `${spike(at - half, 0)}L${P(at + half, 0)}` : '',\n `L${P(w - r, 0)}${arc(w, r)}`,\n side === 'right' ? `${spike(w, at - half)}L${P(w, at + half)}` : '',\n `L${P(w, h - r)}${arc(w - r, h)}`,\n side === 'bottom' ? `${spike(at + half, h)}L${P(at - half, h)}` : '',\n `L${P(r, h)}${arc(0, h - r)}`,\n side === 'left' ? `${spike(0, at + half)}L${P(0, at - half)}` : '',\n `L${P(0, r)}${arc(r, 0)}Z`,\n ].join('')\n}\n\n/**\n * Redraws an open bubble's outline as `a`, a draft of it (the editor's, as its box grows with\n * its text), in an element whose top-left is `origin` on screen. No-op on any other element.\n */\nexport function refitBubble(\n el: HTMLElement,\n a: FreeTextAnnotation,\n t: PageTransform,\n origin: { left: number; top: number }\n): void {\n const path = el.querySelector(':scope > svg > .ink-bubble')\n if (!path || !isBubble(a)) return\n path.setAttribute('d', bubblePath(a, t, origin))\n}\n\n/** Sets `stroke-dasharray` from a dash pattern in points, scaled to CSS px. */\nfunction dash(\n shape: Element,\n dashes: readonly number[] | undefined,\n t: PageTransform\n): void {\n if (!dashes || dashes.length === 0) return\n shape.setAttribute('stroke-dasharray', dashes.map((d) => t.toCssLength(d)).join(' '))\n}\n\n/**\n * An invisible hit area for an annotation the overlay does not draw (embedded ones, which\n * PDF.js paints on the canvas): polygons over its quads, or its rect. Selection chrome only.\n */\nexport function renderHitArea(el: HTMLElement, a: Annotation, t: PageTransform): void {\n drawHitArea(el, a, t)\n if (a.type === 'freetext') appendSelectionFrame(el, a, t)\n appendCommentMarker(el, a, t)\n}\n\n/**\n * For a free text inset by a fringe: a `div.ink-selection-frame` over its text box, where its\n * corner handles sit, and `data-framed` on the element, so the theme draws the selection\n * outline on the box rather than round the whole rect. Geometry only, `pointer-events:none`.\n */\nfunction appendSelectionFrame(\n el: HTMLElement,\n a: FreeTextAnnotation,\n t: PageTransform\n): void {\n el.toggleAttribute('data-framed', a.fringe !== undefined)\n if (!a.fringe) return\n const box = freeTextLocalBox(a, t)\n const frame = el.ownerDocument.createElement('div')\n frame.className = 'ink-selection-frame'\n frame.setAttribute('aria-hidden', 'true')\n frame.style.cssText =\n `position:absolute;pointer-events:none;left:${box.left}px;top:${box.top}px;` +\n `width:${box.width}px;height:${box.height}px;`\n el.append(frame)\n}\n\n/** True for text markup whose `contents` holds a comment. */\nexport function hasComment(a: Annotation): a is TextMarkupAnnotation {\n return isTextMarkup(a) && !!a.contents?.trim()\n}\n\n/**\n * Marks commented text markup with `span.ink-comment-marker`, holding a comment glyph, at the\n * last quad's top-right corner (its end in reading order), relative to the element. The theme\n * sizes and colours it.\n */\nfunction appendCommentMarker(el: HTMLElement, a: Annotation, t: PageTransform): void {\n if (!hasComment(a)) return\n const last = a.quads[a.quads.length - 1]\n if (!last) return\n const box = annotationBox(a, t)\n const at = t.toCss(last.p2)\n const marker = el.ownerDocument.createElement('span')\n marker.className = 'ink-comment-marker'\n marker.dataset.inkCommentMarker = ''\n marker.setAttribute('aria-hidden', 'true')\n marker.style.left = `${at.x - box.left}px`\n marker.style.top = `${at.y - box.top}px`\n const icon = el.ownerDocument.createElementNS(SVG, 'svg')\n for (const [k, v] of Object.entries(ICON_ATTRIBUTES)) icon.setAttribute(k, v)\n for (const [tag, attrs] of MessageSquareText) {\n const child = el.ownerDocument.createElementNS(SVG, tag)\n for (const [k, v] of Object.entries(attrs)) child.setAttribute(k, v)\n icon.append(child)\n }\n marker.append(icon)\n el.append(marker)\n}\n\nfunction drawHitArea(el: HTMLElement, a: Annotation, t: PageTransform): void {\n const doc = el.ownerDocument\n el.replaceChildren()\n const box = annotationBox(a, t)\n const svg = boxSvg(doc, box.width, box.height)\n svg.dataset.inkHit = ''\n const quads = 'quads' in a && a.quads ? a.quads : undefined\n const shapes = quads\n ? quads.map((q) => {\n const poly = doc.createElementNS(SVG, 'polygon')\n poly.setAttribute(\n 'points',\n quadPoints(q)\n .map((p) => {\n const c = t.toCss(p)\n return `${c.x - box.left},${c.y - box.top}`\n })\n .join(' ')\n )\n return poly\n })\n : [doc.createElementNS(SVG, 'rect')]\n for (const shape of shapes) {\n if (shape.tagName === 'rect') {\n shape.setAttribute('width', String(box.width))\n shape.setAttribute('height', String(box.height))\n }\n shape.setAttribute('fill', 'transparent')\n shape.setAttribute('stroke', 'none')\n shape.setAttribute('pointer-events', 'all')\n svg.append(shape)\n }\n el.append(svg)\n}\n\nfunction boxSvg(doc: Document, width: number, height: number): SVGSVGElement {\n const svg = doc.createElementNS(SVG, 'svg')\n svg.setAttribute('width', String(width))\n svg.setAttribute('height', String(height))\n svg.setAttribute('viewBox', `0 0 ${width} ${height}`)\n svg.setAttribute('overflow', 'visible')\n // Block, not inline: an inline SVG sits on the text baseline and drifts below a short box.\n // The theme positions it absolutely as well.\n svg.setAttribute('display', 'block')\n svg.setAttribute('aria-hidden', 'true')\n return svg\n}\n\n/** Quad corners in drawing order: p1 top-left, p2 top-right, p4 bottom-right, p3 bottom-left. */\nfunction quadPoints(q: Quad): Point[] {\n return [q.p1, q.p2, q.p4, q.p3]\n}\n\nconst lerp = (a: Point, b: Point, f: number): Point => ({\n x: a.x + (b.x - a.x) * f,\n y: a.y + (b.y - a.y) * f,\n})\nconst dist = (a: Point, b: Point): number => Math.hypot(b.x - a.x, b.y - a.y)\n\n/** Line thickness in points for a text markup: a fraction of the quad's height. */\nfunction markupStroke(q: Quad): number {\n return Math.max(0.5, dist(q.p1, q.p3) / 14)\n}\n\n/** The stroke for an underline, strikeout or squiggly, in user space. */\nfunction markupLine(type: 'underline' | 'strikeout' | 'squiggly', q: Quad): Point[] {\n if (type === 'strikeout') return [lerp(q.p1, q.p3, 0.5), lerp(q.p2, q.p4, 0.5)]\n const height = dist(q.p1, q.p3)\n // The baseline sits a little above the quad's bottom edge.\n const start = lerp(q.p3, q.p1, 0.1)\n const end = lerp(q.p4, q.p2, 0.1)\n if (type === 'underline') return [start, end]\n const length = dist(start, end)\n const amp = Math.max(0.5, height / 16)\n const step = amp * 2\n const steps = Math.max(1, Math.round(length / step))\n // Unit normal pointing from the bottom edge towards the top edge.\n const up = {\n x: (q.p1.x - q.p3.x) / (height || 1),\n y: (q.p1.y - q.p3.y) / (height || 1),\n }\n const pts: Point[] = []\n for (let i = 0; i <= steps; i++) {\n const p = lerp(start, end, i / steps)\n const s = i % 2 === 0 ? -amp : amp\n pts.push({ x: p.x + up.x * s, y: p.y + up.y * s })\n }\n return pts\n}\n\n/** A CSS string literal, so any PDF font name is a single family name. */\nfunction cssString(value: string): string {\n return `\"${value.replace(/[\"\\\\]/g, '\\\\$&').replace(/\\n/g, '\\\\a ')}\"`\n}\n","// In-place editing for a free-text box. The editor is a plain-text `contenteditable` laid over\n// the box inside its overlay element, styled from the annotation exactly as the box is\n// (`styleFreeText`), with the box itself hidden underneath. It grows downwards on screen as the\n// text needs more lines, and nothing reaches the store until it closes: a commit hands back the\n// text and the grown rect together, so the edit is one change and one undo step. A callout's\n// `rect` and `fringe` are refit around the grown box and its callout (`grownFreeText`).\n//\n// Inline styles here are structural or geometric only: the editor's position and minimum\n// height, the box's `visibility` while it is covered, and the element's grown height.\nimport { freeTextBox } from '../model/annotations/callout'\nimport { hasCallout, isBubble, resizedBox, withBox } from '../model/annotations/edit'\n\nimport { freeTextLocalBox, refitBubble, styleFreeText } from './overlay-render'\n\nimport type { PageTransform } from './transform'\nimport type { AnnotationStore } from '../model/annotations/store'\nimport type { Annotation, FreeTextAnnotation } from '../model/annotations/types'\nimport type { Point, Rect } from '../model/geometry'\n\nexport interface FreeTextEditor {\n /** Closes the editor, handing its text to `commit` (true) or calling `cancel` (false). */\n close(commit: boolean): void\n}\n\n/**\n * What closed an editor: Escape, a press outside it, focus leaving it, or a call to `close`\n * (a redraw, the page unmounting, the box being removed, a tool switch).\n */\nexport type EditorCloseReason = 'escape' | 'press' | 'focus' | 'api'\n\nexport interface FreeTextEditorOptions {\n transform: PageTransform\n /**\n * The edited text and the box's rect, grown to fit it (`grownFreeText`), in user space.\n * `grown` is the growth alone, in CSS px (0 when the box kept its height), for a caller whose\n * box may have moved or been resized while the editor was open. `how` says what closed it.\n */\n commit(contents: string, rect: Rect, grown: number, how: EditorCloseReason): void\n cancel(): void\n /** Where to put the caret, a client point (a click on the box); at the end when absent. */\n caret?: { clientX: number; clientY: number } | undefined\n}\n\n/** The open editor on each overlay element. */\nconst editors = new WeakMap<HTMLElement, FreeTextEditor>()\n/** Presses that closed an editor, so a tool can leave them alone. */\nconst closingPresses = new WeakSet<Event>()\n\n/** The editor open on an overlay element, if any. */\nexport function editorFor(el: HTMLElement): FreeTextEditor | undefined {\n return editors.get(el)\n}\n\n/** True when `e` is a press outside an editor that closed it. */\nexport function closedEditor(e: Event): boolean {\n return closingPresses.has(e)\n}\n\n/** Point within which a grown height counts as unchanged, CSS px. */\nconst SAME_PX = 0.5\n/** The editor's narrowest width, in ems of the box's font size, for a box inset to nothing. */\nconst MIN_WIDTH_EM = 2\n\n/**\n * Opens an editor on `el`, the overlay element showing `a` (or a stand-in for a box not in the\n * store yet), with the caret at `opts.caret` or after the text. `Escape` commits; a press\n * outside the editor, or focus leaving it, commits too.\n * Closing while the editor has focus hands focus to `el`. Keys typed in the\n * editor stop there, so no viewport or tool shortcut sees them. Opening a second editor on the\n * same element commits the first.\n */\nexport function editFreeText(\n el: HTMLElement,\n a: FreeTextAnnotation,\n opts: FreeTextEditorOptions\n): FreeTextEditor {\n editors.get(el)?.close(true)\n const doc = el.ownerDocument\n const view = doc.defaultView\n // The element covers the rect; the text box sits inside it, inset by any fringe.\n const base = opts.transform.toCssRect(a.rect)\n const inner = freeTextLocalBox(a, opts.transform)\n const box = el.querySelector<HTMLElement>(':scope > .ink-free-text')\n\n const field = doc.createElement('div')\n field.className = 'ink-free-text'\n field.dataset.inkEditor = ''\n field.setAttribute('role', 'textbox')\n field.setAttribute('aria-multiline', 'true')\n field.setAttribute('aria-label', 'Text box')\n styleFreeText(field, a, opts.transform)\n field.style.position = 'absolute'\n field.style.left = `${inner.left}px`\n field.style.top = `${inner.top}px`\n // A fringe can leave a box too narrow to type in: never narrower than a couple of letters.\n const floor = opts.transform.toCssLength(a.defaultStyle.fontSize * MIN_WIDTH_EM)\n field.style.width = a.fringe ? `${Math.max(inner.width, floor)}px` : '100%'\n field.style.height = 'auto'\n field.style.minHeight = `${inner.height}px`\n field.style.pointerEvents = 'auto'\n makeEditable(field)\n field.textContent = a.contents\n if (box) box.style.visibility = 'hidden'\n el.append(field)\n\n /** The box's CSS height for the text now in it: never less than it started at. */\n const height = (): number =>\n Math.max(inner.height, field.getBoundingClientRect().height)\n /** `a` with its box grown by `grown` CSS px. */\n const grownTo = (grown: number): FreeTextAnnotation =>\n grown === 0 ? a : { ...a, ...grownFreeText(a, grown, opts.transform) }\n const grow = (): void => {\n const h = height()\n el.style.height = `${base.height + h - inner.height}px`\n // A bubble's outline grows with its text.\n refitBubble(el, grownTo(h - inner.height), opts.transform, base)\n }\n const Observer = view?.ResizeObserver\n const observer = Observer ? new Observer(grow) : undefined\n observer?.observe(field)\n\n const read = (): string => {\n const text = field.innerText.replace(/\\r\\n?/g, '\\n')\n // A trailing line break is held open by a placeholder <br>, which reads as one more.\n return field.lastChild?.nodeName === 'BR' ? text.replace(/\\n$/, '') : text\n }\n /** How far the box grew, CSS px; 0 within `SAME_PX`. */\n const growth = (): number => {\n const grown = height() - inner.height\n return Math.abs(grown) < SAME_PX ? 0 : grown\n }\n\n let closed = false\n const finish = (commit: boolean, how: EditorCloseReason): void => {\n if (closed) return\n closed = true\n const contents = read()\n const grown = growth()\n const next = grownTo(grown).rect\n observer?.disconnect()\n view?.removeEventListener('pointerdown', onOutside, true)\n editors.delete(el)\n // While the editor has focus, it moves to the box before the editor goes, so it never\n // falls back to <body>. Focus that already left (a click on a control) stays where it is.\n if (field.contains(doc.activeElement)) el.focus({ preventScroll: true })\n field.remove()\n box?.style.removeProperty('visibility')\n el.style.height = `${base.height}px`\n refitBubble(el, a, opts.transform, base)\n if (commit) opts.commit(contents, next, grown, how)\n else opts.cancel()\n }\n\n const onOutside = (e: Event): void => {\n if (e.target instanceof Node && field.contains(e.target)) return\n closingPresses.add(e)\n finish(true, 'press')\n }\n view?.addEventListener('pointerdown', onOutside, true)\n field.addEventListener('keydown', (e) => {\n e.stopPropagation()\n if (e.key === 'Escape' && !e.isComposing) {\n e.preventDefault()\n finish(true, 'escape')\n }\n })\n field.addEventListener('focusout', (e) => {\n // A window losing focus (another tab, devtools) leaves the edit open.\n if (!doc.hasFocus()) return\n const to = e.relatedTarget\n if (to instanceof Node && field.contains(to)) return\n finish(true, 'focus')\n })\n // Plain text only, whatever the clipboard holds and whichever editing mode the browser has.\n field.addEventListener('paste', (e) => {\n e.preventDefault()\n insertText(field, e.clipboardData?.getData('text/plain') ?? '')\n })\n field.addEventListener('beforeinput', (e) => {\n if (e.inputType.startsWith('format')) e.preventDefault()\n })\n\n field.focus({ preventScroll: true })\n const selection = doc.getSelection()\n if (selection) {\n let range = opts.caret && caretIn(field, opts.caret)\n if (!range) {\n range = doc.createRange()\n range.selectNodeContents(field)\n range.collapse(false)\n }\n selection.removeAllRanges()\n selection.addRange(range)\n }\n grow()\n\n const editor: FreeTextEditor = { close: (commit) => finish(commit, 'api') }\n editors.set(el, editor)\n return editor\n}\n\n/**\n * True when `a` can be edited in place on its overlay element `el`: an unlocked free-text box\n * the overlay draws itself. Embedded boxes (painted on the canvas, with only a hit area here)\n * and host-rendered (`data-custom`) elements are not. Every edit path asks this.\n */\nexport function canEditFreeText(\n a: Annotation | undefined,\n el: Element | null | undefined\n): a is FreeTextAnnotation {\n return (\n a !== undefined &&\n a.type === 'freetext' &&\n !a.locked &&\n a.source !== 'pdf' &&\n !!el &&\n !el.hasAttribute('data-custom')\n )\n}\n\n/**\n * Opens an editor on the overlay element `el` for the free-text box `id`, wired to the store: a\n * commit is one `update` with the text and the grown rect (none when neither changed), and an\n * empty box is removed, as an abandoned note is. A speech bubble is the exception: its outline\n * shows without text, so it is kept. `onClose` runs after the store change, with what closed\n * the editor; `caret` is a client point to put the caret at (`editFreeText`). Returns\n * undefined when the box cannot be edited (`canEditFreeText`).\n */\nexport function editFreeTextIn(\n store: AnnotationStore,\n el: HTMLElement,\n id: string,\n transform: PageTransform,\n opts: {\n onClose?(how: EditorCloseReason): void\n caret?: { clientX: number; clientY: number }\n } = {}\n): FreeTextEditor | undefined {\n const a = store._getProposed(id) ?? store.get(id)\n if (!canEditFreeText(a, el)) return undefined\n const current = (): FreeTextAnnotation | undefined => {\n const now = store._getProposed(id) ?? store.get(id)\n return now?.type === 'freetext' ? now : undefined\n }\n const write = (contents: string, grown: number): void => {\n const now = current()\n if (!now) return\n if (contents.trim() === '' && !isBubble(now)) {\n store.remove(id)\n return\n }\n // The growth applies to the box as it is now: it may have moved while the editor was open.\n if (grown === 0) {\n if (contents !== now.contents) store.update(id, { contents })\n return\n }\n store.update(id, { contents, ...grownFreeText(now, grown, transform) })\n }\n return editFreeText(el, a, {\n transform,\n caret: opts.caret,\n commit(contents, _rect, grown, how) {\n write(contents, grown)\n opts.onClose?.(how)\n },\n cancel() {\n const now = current()\n if (now && now.contents.trim() === '' && !isBubble(now)) store.remove(id)\n opts.onClose?.('api')\n },\n })\n}\n\n/**\n * The patch that grows a free text's text box down the screen by `grown` CSS px, its top edge\n * fixed, with `rect` and `fringe` refit. A callout's last point moves with the box edge it sits\n * on. A bubble's tip below the box comes down with it; a standard callout's tip and bend stay on\n * what they point at.\n */\nexport function grownFreeText(\n a: FreeTextAnnotation,\n grown: number,\n t: PageTransform\n): Partial<FreeTextAnnotation> {\n const css = t.toCssRect(freeTextBox(a))\n const box = t.fromCssRect({ ...css, height: css.height + grown })\n if (!hasCallout(a)) return withBox(a, box)\n const resized = resizedBox(a, box)\n if (!isBubble(a) || t.toCss(a.callout[0]).y <= css.top + css.height) return resized\n const last = a.callout.length - 1\n const down = (p: Point): Point => {\n const c = t.toCss(p)\n return t.fromCss({ x: c.x, y: c.y + grown })\n }\n return withBox(\n a,\n box,\n resized.callout!.map((p, i) => (i === last ? p : down(p)))\n )\n}\n\n/**\n * A collapsed range at the text position under a client point, if that position is in `field`.\n * The editor lies over the box with the same look, so a point on the box lands on the same\n * character in the editor.\n */\nfunction caretIn(\n field: HTMLElement,\n at: { clientX: number; clientY: number }\n): Range | undefined {\n const doc = field.ownerDocument\n let node: Node | undefined\n let offset = 0\n if (typeof doc.caretPositionFromPoint === 'function') {\n const p = doc.caretPositionFromPoint(at.clientX, at.clientY)\n if (p) ({ offsetNode: node, offset } = p)\n } else if (typeof doc.caretRangeFromPoint === 'function') {\n const r = doc.caretRangeFromPoint(at.clientX, at.clientY)\n if (r) ({ startContainer: node, startOffset: offset } = r)\n }\n if (!node || !field.contains(node)) return undefined\n const range = doc.createRange()\n range.setStart(node, offset)\n range.collapse(true)\n return range\n}\n\n/** `plaintext-only` where the browser has it, else `true` (paste and formatting are then guarded). */\nfunction makeEditable(field: HTMLElement): void {\n try {\n field.contentEditable = 'plaintext-only'\n } catch {\n // Older engines throw on the value.\n }\n if (field.contentEditable !== 'plaintext-only') field.contentEditable = 'true'\n}\n\n/** Inserts `text` at the caret, replacing any selected text, and leaves the caret after it. */\nfunction insertText(field: HTMLElement, text: string): void {\n const doc = field.ownerDocument\n const selection = doc.getSelection()\n const node = doc.createTextNode(text)\n if (!selection || selection.rangeCount === 0) {\n field.append(node)\n return\n }\n const range = selection.getRangeAt(0)\n if (!field.contains(range.commonAncestorContainer)) {\n field.append(node)\n return\n }\n range.deleteContents()\n range.insertNode(node)\n range.setStartAfter(node)\n range.collapse(true)\n selection.removeAllRanges()\n selection.addRange(range)\n}\n","// Renders one region of a page, in PDF user space, into a canvas of its own: the loupe's\n// magnified view. The viewport is the page's own at `scale`, shifted so the region's top-left\n// corner lands on the canvas origin, so the region fills the canvas exactly.\nimport type { InkDocument } from '../model/document'\nimport type { Rect } from '../model/geometry'\n\nconst isCancellation = (error: unknown): boolean =>\n (error as { name?: unknown } | null)?.name === 'RenderingCancelledException'\n\n/**\n * Draws `userRect` of `page` (0-based) into `canvas` at `scale` device pixels per user-space\n * unit (times `/UserUnit`, as PDF.js applies it), turned by `rotation`: the page's /Rotate plus\n * any view rotation, the page's own /Rotate when omitted. The canvas is resized to the region,\n * so a 50 pt square at scale 4 gives a 200 × 200 canvas. Like the page canvas, the background\n * is white and embedded annotation appearances are drawn.\n *\n * Rejects with `signal.reason` once `signal` aborts; an abort mid-render cancels it, leaving\n * the canvas partly drawn.\n *\n * @internal\n */\nexport async function renderRegion(\n doc: InkDocument,\n page: number,\n userRect: Rect,\n scale: number,\n canvas: HTMLCanvasElement,\n signal?: AbortSignal,\n rotation?: number\n): Promise<void> {\n signal?.throwIfAborted()\n const pdfPage = await doc._pdfjs.getPage(page)\n signal?.throwIfAborted()\n const turn = rotation ?? pdfPage.rotate\n const full = pdfPage.getViewport({ scale, rotation: turn })\n // The region's corners on the unshifted canvas, in device pixels.\n const [x1, y1] = full.convertToViewportPoint(userRect.x, userRect.y) as [number, number]\n const [x2, y2] = full.convertToViewportPoint(\n userRect.x + userRect.width,\n userRect.y + userRect.height\n ) as [number, number]\n const viewport = pdfPage.getViewport({\n scale,\n rotation: turn,\n offsetX: -Math.min(x1, x2),\n offsetY: -Math.min(y1, y2),\n })\n canvas.width = Math.max(1, Math.round(Math.abs(x2 - x1)))\n canvas.height = Math.max(1, Math.round(Math.abs(y2 - y1)))\n const task = pdfPage.render({\n canvas,\n viewport,\n background: '#ffffff',\n annotationMode: doc._pdfjs.module.AnnotationMode.ENABLE,\n })\n const cancel = (): void => task.cancel()\n signal?.addEventListener('abort', cancel, { once: true })\n try {\n await task.promise\n } catch (error) {\n if (signal?.aborted && isCancellation(error)) throw signal.reason\n throw error\n } finally {\n signal?.removeEventListener('abort', cancel)\n }\n // Finished just as the signal aborted: the caller has moved on.\n signal?.throwIfAborted()\n}\n","// The loupe's magnified view: one canvas per loupe, first in the loupe's own annotation\n// element, under the rim the overlay draws. It holds the page region under the loupe's centre,\n// `magnification` times smaller than the loupe, rendered at the zoom times the device pixel\n// ratio times the magnification, so it fills the element at full sharpness. Page content only:\n// session annotations under the loupe are not magnified.\n//\n// Inline styles are structural: the canvas fills the element (`position:absolute; left:0;\n// top:0; width:100%; height:100%`), is clipped to the inscribed circle (`clip-path`) and leaves\n// the pointer to the rim (`pointer-events:none`).\nimport { renderRegion } from '../pdfjs/render-region'\n\nimport { watchDevicePixelRatio, type DprWatch } from './dpr-watch'\n\nimport type { PageTransform } from './transform'\nimport type { LoupeAnnotation } from '../model/annotations/types'\nimport type { InkDocument } from '../model/document'\nimport type { Rect } from '../model/geometry'\n\n/** Pause after a move, resize or zoom before a loupe re-renders, in ms. */\nexport const LOUPE_RENDER_DELAY = 100\n\nexport interface LoupeLayerOptions {\n document: InkDocument\n /**\n * Fixed device pixel ratio. When omitted, `window.devicePixelRatio` is read at every render\n * and the loupes re-render when it changes (browser zoom, moving to another screen).\n */\n devicePixelRatio?: number\n}\n\nexport interface LoupeLayer {\n /**\n * Puts the loupe's canvas first in `el`, its annotation element, and brings it up to date\n * with `a` at `t`. The first render starts at once; later ones wait for a pause of\n * `LOUPE_RENDER_DELAY` ms in the changes, and a change aborts a render in flight. The last\n * bitmap stays, stretched with the element, until the next one lands.\n */\n attach(el: HTMLElement, a: LoupeAnnotation, t: PageTransform): void\n /** Forgets a loupe that is gone, cancelling its render. */\n drop(id: string): void\n destroy(): void\n}\n\n/** The page region a loupe shows: its rect shrunk by the magnification about its centre. */\nexport function loupeRegion(a: Pick<LoupeAnnotation, 'rect' | 'magnification'>): Rect {\n const { rect, magnification } = a\n const width = rect.width / magnification\n const height = rect.height / magnification\n return {\n x: rect.x + (rect.width - width) / 2,\n y: rect.y + (rect.height - height) / 2,\n width,\n height,\n }\n}\n\ninterface Lens {\n canvas: HTMLCanvasElement\n /** What the canvas shows or is about to: the last scheduled render's inputs. */\n key: string | undefined\n timer: ReturnType<typeof setTimeout> | undefined\n controller: AbortController | undefined\n /** The last `attach`, replayed when the device pixel ratio changes. */\n last: { el: HTMLElement; a: LoupeAnnotation; t: PageTransform } | undefined\n}\n\n/** Frees a canvas's bitmap now rather than at garbage collection (Safari caps the total). */\nfunction release(canvas: HTMLCanvasElement): void {\n canvas.width = 0\n canvas.height = 0\n canvas.remove()\n}\n\nexport function createLoupeLayer(opts: LoupeLayerOptions): LoupeLayer {\n const lenses = new Map<string, Lens>()\n let destroyed = false\n let dprWatch: DprWatch | undefined\n\n const dprOf = (el: HTMLElement): number => {\n if (opts.devicePixelRatio !== undefined) return opts.devicePixelRatio\n const ratio = el.ownerDocument.defaultView?.devicePixelRatio ?? 1\n return ratio > 0 ? ratio : 1\n }\n\n const stop = (lens: Lens): void => {\n clearTimeout(lens.timer)\n lens.timer = undefined\n lens.controller?.abort()\n lens.controller = undefined\n }\n\n async function render(\n lens: Lens,\n page: number,\n region: Rect,\n scale: number,\n rotation: number\n ): Promise<void> {\n const controller = new AbortController()\n lens.controller = controller\n const doc = lens.canvas.ownerDocument\n const next = doc.createElement('canvas')\n try {\n await renderRegion(\n opts.document,\n page,\n region,\n scale,\n next,\n controller.signal,\n rotation\n )\n if (controller.signal.aborted || destroyed) return\n lens.canvas.width = next.width\n lens.canvas.height = next.height\n lens.canvas.getContext('2d')?.drawImage(next, 0, 0)\n } catch {\n // Aborted for a newer render, or failed: the last bitmap stays. A failure has nowhere\n // useful to go; the page canvas reports the document's render failures.\n } finally {\n release(next)\n if (lens.controller === controller) lens.controller = undefined\n }\n }\n\n function lensFor(el: HTMLElement, id: string): Lens {\n const known = lenses.get(id)\n if (known) return known\n const canvas = el.ownerDocument.createElement('canvas')\n canvas.className = 'ink-loupe-lens'\n canvas.dataset.inkLoupe = ''\n canvas.setAttribute('aria-hidden', 'true')\n canvas.style.cssText =\n 'position:absolute;left:0;top:0;width:100%;height:100%;' +\n 'clip-path:circle(50%);pointer-events:none;'\n // Blank until the first render lands.\n canvas.width = 0\n canvas.height = 0\n const lens: Lens = {\n canvas,\n key: undefined,\n timer: undefined,\n controller: undefined,\n last: undefined,\n }\n lenses.set(id, lens)\n return lens\n }\n\n function attach(el: HTMLElement, a: LoupeAnnotation, t: PageTransform): void {\n if (destroyed) return\n const lens = lensFor(el, a.id)\n lens.last = { el, a, t }\n if (el.firstChild !== lens.canvas) el.prepend(lens.canvas)\n const region = loupeRegion(a)\n const dpr = dprOf(el)\n if (opts.devicePixelRatio === undefined) {\n dprWatch ??= watchDevicePixelRatio(\n el.ownerDocument.defaultView,\n () => dprOf(el),\n () => {\n for (const { last } of [...lenses.values()])\n if (last) attach(last.el, last.a, last.t)\n }\n )\n dprWatch.watch(dpr)\n }\n const scale = t.zoom * dpr * a.magnification\n const rotation = t.totalRotation\n const key = JSON.stringify([a.page, region, scale, rotation])\n if (key === lens.key) return\n const first = lens.key === undefined\n lens.key = key\n stop(lens)\n if (first) {\n void render(lens, a.page, region, scale, rotation)\n return\n }\n lens.timer = setTimeout(() => {\n lens.timer = undefined\n void render(lens, a.page, region, scale, rotation)\n }, LOUPE_RENDER_DELAY)\n }\n\n return {\n attach,\n drop(id) {\n const lens = lenses.get(id)\n if (!lens) return\n stop(lens)\n release(lens.canvas)\n lenses.delete(id)\n },\n destroy() {\n if (destroyed) return\n destroyed = true\n dprWatch?.destroy()\n for (const lens of lenses.values()) {\n stop(lens)\n release(lens.canvas)\n }\n lenses.clear()\n },\n }\n}\n","// The mask's dimming: one SVG per page, between the page content (canvas, text layer) and the\n// annotation overlay, holding one even-odd path: the whole page, minus the mask's shape. The\n// mask annotation's own element (drawn by the overlay) is the shape's outline and takes the\n// hits; this layer never does.\n//\n// Inline styles and attributes are structural: the SVG is `position:absolute; left:0; top:0;\n// pointer-events:none` at the page's CSS size, and the path's fill is the mask's colour at its\n// `dim`.\nimport type { PageTransform } from './transform'\nimport type { MaskAnnotation } from '../model/annotations/types'\n\nconst SVG = 'http://www.w3.org/2000/svg'\n\nconst fmt = (n: number): string => String(Math.round(n * 1000) / 1000)\n\n/**\n * The path data of a mask's dimming at `t`, in CSS pixels from the page's top-left corner: the\n * page rectangle, then the shape (the rectangle, or the ellipse inscribed in it) as a second\n * subpath that the even-odd rule cuts out. `t.toCssRect` turns the shape's box with the page,\n * so this holds at any /Rotate and view rotation.\n */\nexport function maskPath(\n a: Pick<MaskAnnotation, 'rect' | 'shape'>,\n t: Pick<PageTransform, 'toCssRect' | 'cssWidth' | 'cssHeight'>\n): string {\n const w = t.cssWidth\n const h = t.cssHeight\n const page = `M0 0L${fmt(w)} 0L${fmt(w)} ${fmt(h)}L0 ${fmt(h)}Z`\n const { left, top, width, height } = t.toCssRect(a.rect)\n if (a.shape === 'ellipse') {\n const rx = width / 2\n const ry = height / 2\n const cy = top + ry\n const arc = `A${fmt(rx)} ${fmt(ry)} 0 1 0`\n return `${page}M${fmt(left)} ${fmt(cy)}${arc} ${fmt(left + width)} ${fmt(cy)}${arc} ${fmt(left)} ${fmt(cy)}Z`\n }\n const right = left + width\n const bottom = top + height\n return `${page}M${fmt(left)} ${fmt(top)}L${fmt(right)} ${fmt(top)}L${fmt(right)} ${fmt(bottom)}L${fmt(left)} ${fmt(bottom)}Z`\n}\n\nexport interface MaskLayer {\n /** Draws `mask` at `t`, or removes the layer when there is none. */\n update(mask: MaskAnnotation | undefined, t: PageTransform): void\n destroy(): void\n}\n\n/** The page's mask layer: its SVG goes into `host` just before `before`, the annotation overlay. */\nexport function createMaskLayer(host: HTMLElement, before: Node): MaskLayer {\n let svg: SVGSVGElement | undefined\n let path: SVGPathElement | undefined\n\n return {\n update(mask, t) {\n if (!mask) {\n svg?.remove()\n svg = undefined\n path = undefined\n return\n }\n if (!svg || !path) {\n const doc = host.ownerDocument\n svg = doc.createElementNS(SVG, 'svg')\n svg.classList.add('ink-mask-layer')\n svg.dataset.inkMaskLayer = ''\n svg.setAttribute('aria-hidden', 'true')\n svg.style.cssText = 'position:absolute;left:0;top:0;pointer-events:none;'\n path = doc.createElementNS(SVG, 'path')\n path.setAttribute('fill-rule', 'evenodd')\n path.setAttribute('clip-rule', 'evenodd')\n path.setAttribute('stroke', 'none')\n svg.append(path)\n }\n if (svg.parentNode !== host || svg.nextSibling !== before)\n host.insertBefore(svg, before)\n svg.setAttribute('width', String(t.cssWidth))\n svg.setAttribute('height', String(t.cssHeight))\n svg.setAttribute('viewBox', `0 0 ${t.cssWidth} ${t.cssHeight}`)\n path.setAttribute('d', maskPath(mask, t))\n path.setAttribute('fill', mask.color)\n path.setAttribute('fill-opacity', String(mask.dim))\n },\n destroy() {\n svg?.remove()\n svg = undefined\n path = undefined\n },\n }\n}\n","// Inline styles here are structural or geometric only: the container is\n// `position:absolute; inset:0; pointer-events:none` so it covers the page without eating\n// events, and each annotation element is `position:absolute` with `left/top/width/height`\n// from `annotationBox` (stroked paths padded once by their stroke, and thin ones by their wider\n// hit twin), or from\n// `PageTransform.toCssRect(a.rect)` for custom elements. Hit-testing\n// follows the drawn shape, not the box: elements are `pointer-events:none` and their shapes\n// opt back in (overlay-render.ts), so a press beside a shape still reaches the text layer.\n// Edit handles (`.ink-handle[data-handle]`) are 8px `position:absolute;\n// pointer-events:auto` boxes on the element's corners or a line's ends, placed with\n// left/top; their look is the theme's.\n// Custom elements are the exception and stay `pointer-events:auto`: the host draws them and\n// only it knows their shape. Every visual (colour, opacity, stroke, fill) is an SVG\n// attribute or a theme hook.\nimport { freeTextBox } from '../model/annotations/callout'\nimport {\n hasCallout,\n hasCornerHandles,\n hasRectGeometry,\n isTextMarkup,\n keepsAspect,\n resizedBox,\n resizedRect,\n translated,\n} from '../model/annotations/edit'\nimport { withoutReplies } from '../model/annotations/threads'\nimport { isProduction } from '../model/env'\n\nimport { canEditFreeText, editFreeTextIn, editorFor } from './freetext-editor'\nimport { createLoupeLayer } from './loupe-layer'\nimport { createMaskLayer } from './mask-layer'\nimport {\n annotationBox,\n handleBox,\n freeTextLocalBox,\n hasComment,\n renderAnnotationContent,\n renderHitArea,\n syncHandles,\n type HandleSpec,\n} from './overlay-render'\n\nimport type { PageTransform } from './transform'\nimport type { AnnotationStore } from '../model/annotations/store'\nimport type { Annotation, MaskAnnotation } from '../model/annotations/types'\nimport type { InkDocument } from '../model/document'\nimport type { Point } from '../model/geometry'\n\nexport interface OverlayOptions {\n host: HTMLElement\n /** 0-based page index this overlay shows. */\n page: number\n store: AnnotationStore\n transform: PageTransform\n /** Called when an annotation is clicked, or activated with Enter or Space. */\n onActivate?(id: string): void\n /** Return true to render only the positioned shell; the host (e.g. a Vue slot) fills it. */\n isCustom?(annotation: Annotation): boolean\n /**\n * The document the page belongs to. Loupes magnify its page content; without it they show\n * only their rim.\n */\n document?: InkDocument\n /** Fixed device pixel ratio for loupes; `window.devicePixelRatio` when omitted. */\n devicePixelRatio?: number\n /**\n * The app's own data attributes, classes and description for an annotation's element, read\n * whenever the annotations change and on `redecorate`. Core's own attributes and `ink-`\n * classes win over them.\n */\n decorate?: DecorateAnnotation\n}\n\n/**\n * Data attributes, classes and a description an app adds to an annotation's element, to style\n * or find its own marks. Each `data` key is written as `data-<key>`.\n */\nexport interface AnnotationDecoration {\n /** Written as data-<key>; keys are lower-case kebab (/^[a-z][a-z0-9-]*$/). */\n data?: Readonly<Record<string, string>>\n classes?: readonly string[]\n /**\n * Extra words screen readers announce after the element's label, such as \"Needs review\".\n * Written as `aria-description`.\n */\n description?: string\n}\n\n/** Returns the decoration for an annotation's element, or undefined for none. */\nexport type DecorateAnnotation = (\n annotation: Annotation\n) => AnnotationDecoration | undefined\n\nexport interface Overlay {\n readonly element: HTMLElement\n /** Repositions every element and redraws content for a new zoom or rotation. */\n update(transform: PageTransform): void\n elementFor(id: string): HTMLElement | undefined\n /** Runs `decorate` again for every element, for when its output changed but no annotation did. */\n redecorate(): void\n destroy(): void\n}\n\ntype State = 'idle' | 'hover' | 'selected'\n\n/** A text position: a node and an offset in it. */\ninterface Caret {\n node: Node\n offset: number\n}\n\n/** Pointer travel, CSS px, within which a press on text markup is still a click. */\nconst CLICK_SLOP = 3\n/** Longest press, ms, that still counts as a click on text markup. */\nconst CLICK_MS = 500\n\n/** Arrow keys as user-space unit steps (y grows upwards). */\nconst ARROW_STEPS: Record<string, { x: number; y: number }> = {\n ArrowRight: { x: 1, y: 0 },\n ArrowLeft: { x: -1, y: 0 },\n ArrowUp: { x: 0, y: 1 },\n ArrowDown: { x: 0, y: -1 },\n}\n\nconst LABELS: Record<Annotation['type'], string> = {\n highlight: 'Highlight',\n underline: 'Underline',\n strikeout: 'Strikethrough',\n squiggly: 'Squiggly underline',\n text: 'Note',\n freetext: 'Text box',\n square: 'Rectangle',\n circle: 'Ellipse',\n line: 'Line',\n polyline: 'Polyline',\n polygon: 'Polygon',\n ink: 'Drawing',\n stamp: 'Stamp',\n loupe: 'Loupe',\n mask: 'Mask',\n redact: 'Redaction',\n}\n\nfunction ariaLabel(a: Annotation): string {\n const base =\n a.subject === 'Signature' && (a.type === 'ink' || a.type === 'stamp')\n ? 'Signature'\n : LABELS[a.type]\n const named = hasComment(a) ? `${base} with comment` : base\n return a.author ? `${named} by ${a.author}` : named\n}\n\n/** Reading order in user space: top edge first (y grows upwards), then left edge. */\nfunction readingOrder(a: Annotation, b: Annotation): number {\n return b.rect.y + b.rect.height - (a.rect.y + a.rect.height) || a.rect.x - b.rect.x\n}\n\n/** A decoration's data key: lower-case kebab, as written after `data-`. */\nconst DECORATION_KEY = /^[a-z][a-z0-9-]*$/\n\n/**\n * `data-*` keys core writes on an annotation element or inside it; a decoration cannot set\n * them. `data-ink-*` is core's too.\n */\nconst RESERVED_DATA = new Set([\n 'annotation',\n 'type',\n 'source',\n 'locked',\n 'state',\n 'custom',\n 'handle',\n 'framed',\n 'align',\n 'bubble',\n 'border',\n 'icon',\n 'ending',\n])\n\n/** Skipped decoration keys and classes already warned about. */\nconst warnedDecorations = new Set<string>()\n\nfunction warnDecoration(what: string, why: string): void {\n if (isProduction() || warnedDecorations.has(what)) return\n warnedDecorations.add(what)\n console.warn(`[inkbar] annotation decoration: skipped ${what}: ${why}`)\n}\n\n/** What a decoration applied to an element last time, to take off what the next drops. */\ninterface Applied {\n data: Set<string>\n classes: Set<string>\n description: boolean\n}\n\nfunction usableData(key: string): boolean {\n if (!DECORATION_KEY.test(key)) {\n warnDecoration(`data key \"${key}\"`, 'keys are lower-case kebab')\n return false\n }\n if (RESERVED_DATA.has(key) || key === 'ink' || key.startsWith('ink-')) {\n warnDecoration(`data key \"${key}\"`, 'core sets it')\n return false\n }\n return true\n}\n\nfunction usableClass(name: string): boolean {\n if (name.startsWith('ink-')) {\n warnDecoration(`class \"${name}\"`, \"`ink-` classes are core's\")\n return false\n }\n // classList rejects empty and whitespace tokens.\n if (name === '' || /\\s/.test(name)) {\n warnDecoration(`class \"${name}\"`, 'not a single class name')\n return false\n }\n return true\n}\n\nfunction setFlag(node: HTMLElement, key: string, on: boolean): void {\n if (on) node.dataset[key] = ''\n else delete node.dataset[key]\n}\n\nexport function createOverlay(opts: OverlayOptions): Overlay {\n const { store, page } = opts\n const doc = opts.host.ownerDocument\n let transform = opts.transform\n const root = doc.createElement('div')\n root.className = 'ink-overlay'\n root.dataset.inkOverlay = ''\n root.style.cssText = 'position:absolute;inset:0;pointer-events:none;'\n opts.host.append(root)\n\n const elements = new Map<string, HTMLElement>()\n const masks = createMaskLayer(opts.host, root)\n const loupes = opts.document\n ? createLoupeLayer({\n document: opts.document,\n ...(opts.devicePixelRatio === undefined\n ? {}\n : { devicePixelRatio: opts.devicePixelRatio }),\n })\n : undefined\n /** What each element's content was last drawn from; absent when it has none of ours. */\n const drawn = new Map<string, { a: Annotation; t: PageTransform }>()\n const hovered = new Set<string>()\n /** The decoration each element last got, so a later one can drop what it no longer has. */\n const decorated = new WeakMap<HTMLElement, Applied>()\n let order: string[] = []\n let destroyed = false\n\n function stateOf(id: string, selected: ReadonlySet<string>): State {\n if (selected.has(id)) return 'selected'\n return hovered.has(id) ? 'hover' : 'idle'\n }\n\n function applyState(node: HTMLElement, id: string): void {\n const selected = new Set(store.selection.get())\n const anyHere = order.some((x) => selected.has(x))\n const state = stateOf(id, selected)\n node.dataset.state = state\n node.setAttribute('aria-pressed', String(state === 'selected'))\n node.tabIndex = !anyHere || state === 'selected' ? 0 : -1\n const a = store.get(id)\n syncHandles(\n node,\n a && !a.locked && state === 'selected' && editsSelection()\n ? handleSpec(node, a)\n : { kind: 'none' }\n )\n }\n\n /** `handleBox` relative to an element at `left`,`top`. */\n function handleLocalBox(a: Annotation, left: number, top: number) {\n const box = handleBox(a, transform)\n return {\n left: box.left - left,\n top: box.top - top,\n width: box.width,\n height: box.height,\n }\n }\n\n /**\n * Line ends for a line, corners for what a corner drag resizes (a free text's on its text\n * box), plus the tip for a callout, else none.\n */\n function handleSpec(node: HTMLElement, a: Annotation): HandleSpec {\n const left = parseFloat(node.style.left) || 0\n const top = parseFloat(node.style.top) || 0\n if (a.type === 'line') {\n const local = (p: Point): Point => {\n const c = transform.toCss(p)\n return { x: c.x - left, y: c.y - top }\n }\n return { kind: 'ends', start: local(a.start), end: local(a.end) }\n }\n if (!hasCornerHandles(a)) return { kind: 'none' }\n const corners =\n a.type === 'freetext'\n ? { kind: 'corners' as const, ...freeTextLocalBox(a, transform) }\n : {\n kind: 'corners' as const,\n // On the drawn shape, inside the padding its hit area may add.\n ...handleLocalBox(a, left, top),\n }\n if (!hasCallout(a)) return corners\n const tip = transform.toCss(a.callout[0])\n return { ...corners, tail: { x: tip.x - left, y: tip.y - top } }\n }\n\n /**\n * True while the tool controller marks the tool root (an ancestor) with a select tool,\n * `data-ink-tool=\"select\"` or `\"select-text\"`, or with `data-ink-made`: what a creation tool\n * just made can be moved and resized too.\n */\n function editsSelection(): boolean {\n const root = opts.host.closest('[data-ink-tool]')\n const tool = root?.getAttribute('data-ink-tool')\n return (\n tool === 'select' ||\n tool === 'select-text' ||\n root?.hasAttribute('data-ink-made') === true\n )\n }\n // Re-sync handles on a tool switch. The controller's root is normally the viewport\n // container; pages can mount before the controller marks it, so fall back to that.\n const toolRoot =\n opts.host.closest('[data-ink-tool]') ?? opts.host.closest('[data-ink-viewport]')\n const Observer = doc.defaultView?.MutationObserver\n let toolObserver: MutationObserver | undefined\n if (toolRoot && Observer) {\n toolObserver = new Observer(() => {\n if (destroyed) return\n for (const [id, node] of elements) applyState(node, id)\n })\n toolObserver.observe(toolRoot, {\n attributes: true,\n attributeFilter: ['data-ink-tool', 'data-ink-made'],\n })\n }\n\n function applyAttributes(node: HTMLElement, a: Annotation): void {\n node.dataset.type = a.type\n node.dataset.source = a.source\n setFlag(node, 'locked', a.locked === true)\n node.setAttribute('aria-label', ariaLabel(a))\n applyDecoration(node, a)\n }\n\n /** The app's data attributes, classes and description, from `decorate`; a throw adds none. */\n function applyDecoration(node: HTMLElement, a: Annotation): void {\n let decoration: AnnotationDecoration | undefined\n try {\n decoration = opts.decorate?.(a)\n } catch (error) {\n console.error(error)\n }\n const prev = decorated.get(node)\n if (!decoration && !prev) return\n const next: Applied = { data: new Set(), classes: new Set(), description: false }\n for (const [key, value] of Object.entries(decoration?.data ?? {})) {\n if (!usableData(key)) continue\n node.setAttribute(`data-${key}`, value)\n next.data.add(key)\n }\n for (const name of decoration?.classes ?? []) {\n if (!usableClass(name)) continue\n node.classList.add(name)\n next.classes.add(name)\n }\n if (decoration?.description) {\n node.setAttribute('aria-description', decoration.description)\n next.description = true\n } else if (prev?.description) node.removeAttribute('aria-description')\n for (const key of prev?.data ?? [])\n if (!next.data.has(key)) node.removeAttribute(`data-${key}`)\n for (const name of prev?.classes ?? [])\n if (!next.classes.has(name)) node.classList.remove(name)\n decorated.set(node, next)\n }\n\n function applyGeometry(node: HTMLElement, a: Annotation): void {\n // Custom elements hold host content laid out against the annotation's own rect.\n const box =\n opts.isCustom?.(a) === true\n ? transform.toCssRect(a.rect)\n : annotationBox(a, transform)\n node.style.left = `${box.left}px`\n node.style.top = `${box.top}px`\n node.style.width = `${box.width}px`\n node.style.height = `${box.height}px`\n }\n\n function applyContent(node: HTMLElement, a: Annotation): void {\n const custom = opts.isCustom?.(a) === true\n setFlag(node, 'custom', custom)\n node.style.pointerEvents = custom ? 'auto' : 'none'\n // Custom elements are the host's to fill: draw nothing.\n if (custom) {\n loupes?.drop(a.id)\n if (drawn.delete(a.id)) node.replaceChildren()\n return\n }\n const last = drawn.get(a.id)\n if (last?.a === a && last.t === transform) return\n // Embedded annotations are already painted on the canvas by PDF.js, so they get only an\n // invisible hit area.\n if (a.source === 'pdf') renderHitArea(node, a, transform)\n else renderAnnotationContent(node, a, transform)\n if (a.type === 'loupe') loupes?.attach(node, a, transform)\n drawn.set(a.id, { a, t: transform })\n }\n\n /**\n * Opens the in-place editor on a free-text box this overlay draws. False when it cannot be\n * edited: not free text, locked, embedded or host-rendered.\n */\n function edit(id: string): boolean {\n const a = store.get(id)\n const node = elements.get(id)\n if (!node || !canEditFreeText(a, node) || opts.isCustom?.(a) === true) return false\n if (editorFor(node)) return true\n return editFreeTextIn(store, node, id, transform) !== undefined\n }\n\n /** Commits every open editor: before a redraw that would lose it, or teardown. */\n function closeEditors(): void {\n for (const node of elements.values()) editorFor(node)?.close(true)\n }\n\n function activate(id: string): void {\n store.select([id])\n opts.onActivate?.(id)\n }\n\n /** The live press on text markup, until its release or cancel. */\n let markupPress: (() => void) | undefined\n\n /**\n * A press on text markup does nothing yet. A release within `CLICK_SLOP` px and `CLICK_MS`\n * of it selects and activates the markup (with `Shift`, toggles it in the selection); a\n * longer drag selects the text under it instead, from the press point to the pointer, as a\n * drag on the bare text would. Rectangle select claims markup presses before they get here.\n */\n function pressMarkup(e: PointerEvent, id: string): void {\n // The browser's own selection would start inside the overlay, not the text: drive it here.\n e.preventDefault()\n markupPress?.()\n const view = doc.defaultView\n if (!view) return\n const { clientX: x0, clientY: y0, pointerId, timeStamp: t0 } = e\n let anchor: Caret | undefined\n let dragging = false\n const mine = (ev: PointerEvent): boolean => ev.pointerId === pointerId\n const onMove = (ev: PointerEvent): void => {\n if (!mine(ev)) return\n if (ev.buttons === 0) return end()\n if (!dragging && Math.hypot(ev.clientX - x0, ev.clientY - y0) <= CLICK_SLOP) return\n dragging = true\n anchor ??= caretAt(x0, y0)\n const focus = caretAt(ev.clientX, ev.clientY)\n if (anchor && focus)\n doc\n .getSelection()\n ?.setBaseAndExtent(anchor.node, anchor.offset, focus.node, focus.offset)\n }\n const onUp = (ev: PointerEvent): void => {\n if (!mine(ev) || ev.button !== 0) return\n end()\n if (\n !dragging &&\n !destroyed &&\n Math.hypot(ev.clientX - x0, ev.clientY - y0) <= CLICK_SLOP &&\n ev.timeStamp - t0 <= CLICK_MS &&\n store.get(id)\n ) {\n if (!(e.shiftKey || ev.shiftKey)) return activate(id)\n // Shift-click adds the markup to the selection, or takes it out.\n const selected = store.selection.get()\n store.select(\n selected.includes(id) ? selected.filter((s) => s !== id) : [...selected, id]\n )\n }\n }\n const onCancel = (ev: PointerEvent): void => {\n if (mine(ev)) end()\n }\n const end = (): void => {\n view.removeEventListener('pointermove', onMove, true)\n view.removeEventListener('pointerup', onUp, true)\n view.removeEventListener('pointercancel', onCancel, true)\n if (markupPress === end) markupPress = undefined\n }\n // Capture on the window: the release still arrives when a tool captured the pointer or a\n // handler on the way stops it.\n view.addEventListener('pointermove', onMove, true)\n view.addEventListener('pointerup', onUp, true)\n view.addEventListener('pointercancel', onCancel, true)\n markupPress = end\n }\n\n /**\n * The text position under a client point on this page's text layer, looked up with the\n * overlay hidden so the markup on top does not answer instead.\n */\n function caretAt(x: number, y: number): Caret | undefined {\n const visibility = root.style.visibility\n root.style.visibility = 'hidden'\n let caret: Caret | undefined\n try {\n if (typeof doc.caretPositionFromPoint === 'function') {\n const p = doc.caretPositionFromPoint(x, y)\n if (p) caret = { node: p.offsetNode, offset: p.offset }\n } else if (typeof doc.caretRangeFromPoint === 'function') {\n const r = doc.caretRangeFromPoint(x, y)\n if (r) caret = { node: r.startContainer, offset: r.startOffset }\n }\n } finally {\n root.style.visibility = visibility\n }\n const layer = opts.host.querySelector('[data-ink-text-layer]')\n return caret && layer?.contains(caret.node) ? caret : undefined\n }\n\n function focusAt(index: number): void {\n const id = order[Math.max(0, Math.min(order.length - 1, index))]\n if (id !== undefined) elements.get(id)?.focus()\n }\n\n /**\n * `Shift+Arrow` moves the annotation 1 pt in user space (`Shift+Alt+Arrow` 10 pt; up is +y).\n * `Ctrl+Shift+Arrow` or `Meta+Shift+Arrow` resizes a rect-shaped one by 1 pt: Right and Down\n * grow it, Left and Up shrink it, keeping its top-left corner. A free text resizes its text\n * box, as its corner handles do. Locked items ignore both.\n * Returns true when the key was one of these chords.\n */\n function onEditKey(e: KeyboardEvent, id: string): boolean {\n const step = ARROW_STEPS[e.key]\n if (!step || !e.shiftKey) return false\n e.preventDefault()\n const a = store.get(id)\n if (!a || a.locked) return true\n if (e.ctrlKey || e.metaKey) {\n if (a.type === 'freetext')\n store.update(id, resizedBox(a, resizedRect(freeTextBox(a), step.x, -step.y)))\n else if (hasRectGeometry(a))\n store.update(id, { rect: resizedRect(a.rect, step.x, -step.y, keepsAspect(a)) })\n return true\n }\n const by = e.altKey ? 10 : 1\n store.update(id, translated(a, step.x * by, step.y * by))\n return true\n }\n\n function onKey(e: KeyboardEvent, id: string): void {\n if (onEditKey(e, id)) return\n switch (e.key) {\n case 'Enter':\n case ' ':\n e.preventDefault()\n // Enter on a free-text box edits it in place.\n if (e.key === 'Enter' && edit(id)) store.select([id])\n else activate(id)\n break\n case 'Delete':\n case 'Backspace': {\n // The overlay owns deletion from a focused annotation: it removes that one only, never\n // the rest of the selection. `preventDefault` tells the select tool to stand down.\n e.preventDefault()\n const a = store.get(id)\n if (a && !a.locked) store.remove(id)\n break\n }\n case 'Escape':\n e.preventDefault()\n store.select([])\n break\n case 'ArrowDown':\n case 'ArrowUp':\n e.preventDefault()\n focusAt(order.indexOf(id) + (e.key === 'ArrowDown' ? 1 : -1))\n break\n default:\n }\n }\n\n function create(id: string): HTMLElement {\n const node = doc.createElement('div')\n node.className = 'ink-annotation'\n node.dataset.annotation = id\n node.setAttribute('role', 'button')\n node.style.position = 'absolute'\n node.addEventListener('pointerenter', () => {\n hovered.add(id)\n applyState(node, id)\n })\n node.addEventListener('pointerleave', () => {\n hovered.delete(id)\n applyState(node, id)\n })\n node.addEventListener('pointerdown', (e) => {\n if (e.button !== 0) return\n // Presses in a free-text editor place the caret: they are the editor's.\n if (e.target instanceof Element && e.target.closest('[data-ink-editor]')) return\n // A press on a custom element's own content (a host's button, say) is that content's:\n // no selection, and it bubbles on to the host's delegated handlers.\n if (\n e.target !== node &&\n node.hasAttribute('data-custom') &&\n !(e.target instanceof Element && e.target.closest('[data-handle]'))\n )\n return\n // Text markup waits for the release: a drag across it is a text selection.\n const a = store.get(id)\n if (a && isTextMarkup(a)) {\n pressMarkup(e, id)\n return\n }\n // A tool listening on the page root must not start a drag from this press.\n e.stopPropagation()\n activate(id)\n })\n node.addEventListener('dblclick', (e) => {\n if (e.target instanceof Element && e.target.closest('[data-ink-editor]')) return\n if (edit(id)) e.preventDefault()\n })\n node.addEventListener('keydown', (e) => {\n // Keys typed in descendants (a custom element's buttons and inputs) are theirs.\n if (e.target !== node) return\n onKey(e, id)\n })\n return node\n }\n\n function render(): void {\n if (destroyed) return\n // Replies show in the thread popover only: no element, hit area or tab stop here.\n const current = withoutReplies(store.list.get())\n .filter((a) => a.page === page)\n .sort(readingOrder)\n const ids = new Set(current.map((a) => a.id))\n const active = doc.activeElement\n let focusId = [...elements].find(([, n]) => n === active)?.[0]\n /** The focused element is going away with nothing on this page to take over. */\n let focusRoot = false\n\n if (focusId !== undefined && !ids.has(focusId)) {\n // The focused element is going away: hand focus to the next survivor, else the previous.\n const i = order.indexOf(focusId)\n focusId =\n order.slice(i + 1).find((x) => ids.has(x)) ??\n order\n .slice(0, i)\n .reverse()\n .find((x) => ids.has(x))\n focusRoot = focusId === undefined\n }\n for (const [id, node] of elements) {\n if (ids.has(id)) continue\n // The box is gone (removed elsewhere, or undone): its edit goes with it.\n editorFor(node)?.close(false)\n node.remove()\n loupes?.drop(id)\n elements.delete(id)\n drawn.delete(id)\n hovered.delete(id)\n }\n\n masks.update(\n current.find((a): a is MaskAnnotation => a.type === 'mask'),\n transform\n )\n\n order = current.map((a) => a.id)\n for (const a of current) {\n let node = elements.get(a.id)\n if (!node) {\n node = create(a.id)\n elements.set(a.id, node)\n }\n applyAttributes(node, a)\n // An open editor owns the element's content and height until it closes; the element\n // still follows the page.\n if (editorFor(node)) {\n const height = node.style.height\n applyGeometry(node, a)\n node.style.height = height\n } else {\n applyGeometry(node, a)\n applyContent(node, a)\n }\n applyState(node, a.id)\n }\n\n // DOM order is tab order: keep it in reading order. Moving nodes blurs them, so only\n // re-append when the order actually changed.\n const inDom = [...root.children]\n if (\n inDom.length !== order.length ||\n order.some((id, i) => inDom[i] !== elements.get(id))\n ) {\n for (const id of order) root.append(elements.get(id)!)\n }\n if (focusId !== undefined) {\n const target = elements.get(focusId)\n if (target && doc.activeElement !== target) target.focus({ preventScroll: true })\n } else if (focusRoot) {\n // Last one on the page: back to the scroll element (as the popovers do), not <body>.\n const scroll = opts.host.closest<HTMLElement>('[data-ink-viewport]')\n if (scroll) {\n // A container the host did not make focusable still takes focus from script.\n if (!scroll.hasAttribute('tabindex')) scroll.tabIndex = -1\n scroll.focus({ preventScroll: true })\n }\n }\n }\n\n const offList = store.list.subscribe(render)\n const offSelection = store.selection.subscribe(() => {\n for (const [id, node] of elements) applyState(node, id)\n })\n render()\n\n return {\n element: root,\n update(next) {\n // An editor is laid out for one zoom and rotation: a change to either commits it first\n // (focus moves to its box). Any other relayout leaves it open.\n if (next.zoom !== transform.zoom || next.rotation !== transform.rotation)\n closeEditors()\n transform = next\n render()\n },\n elementFor: (id) => elements.get(id),\n redecorate() {\n if (destroyed) return\n for (const [id, node] of elements) {\n const a = store.get(id)\n if (a) applyDecoration(node, a)\n }\n },\n destroy() {\n if (destroyed) return\n closeEditors()\n destroyed = true\n markupPress?.()\n offList()\n offSelection()\n toolObserver?.disconnect()\n loupes?.destroy()\n masks.destroy()\n root.remove()\n elements.clear()\n drawn.clear()\n hovered.clear()\n order = []\n },\n }\n}\n","import { createOverlay, type DecorateAnnotation, type Overlay } from './overlay'\nimport { createPageRenderer, type PageRenderer } from './page-renderer'\nimport { createTextLayer, type TextLayerHandle } from './text-layer'\n\nimport type { PageTransform } from './transform'\nimport type { AnnotationStore } from '../model/annotations/store'\nimport type { Annotation } from '../model/annotations/types'\nimport type { InkDocument } from '../model/document'\n\nexport interface PageMountOptions {\n document: InkDocument\n /** Zero-based page index. */\n page: number\n /** The page host (`div.ink-page`) from the viewport's `onMount`. */\n host: HTMLElement\n transform: PageTransform\n store: AnnotationStore\n onActivate?(id: string): void\n isCustom?(a: Annotation): boolean\n /** The app's data attributes and classes for each annotation element (see `OverlayOptions`). */\n decorate?: DecorateAnnotation\n /** Defaults to `window.devicePixelRatio`. */\n devicePixelRatio?: number\n /**\n * Canvas and text layer failures, with the layer that failed (cancellations are not\n * reported).\n */\n onError?(error: unknown, layer: PageLayer): void\n /**\n * A layer finished without error: the canvas painted, or the text layer mounted or applied\n * an update. Pair it with `onError` to tell when a failed layer has recovered.\n */\n onRendered?(layer: PageLayer): void\n}\n\n/** The page layers that can fail and recover: the canvas and the text layer. */\nexport type PageLayer = 'canvas' | 'text'\n\nexport interface PageMount {\n readonly renderer: PageRenderer\n readonly textLayer: TextLayerHandle\n readonly overlay: Overlay\n update(transform: PageTransform): void\n destroy(): void\n}\n\n/** Canvas, text layer and annotation overlay for one page, stacked in that order. */\nexport function createPageMount(opts: PageMountOptions): PageMount {\n const { document, page, host, transform } = opts\n const callbacks = (layer: PageLayer) => ({\n ...(opts.onError\n ? { onError: (error: unknown) => opts.onError?.(error, layer) }\n : {}),\n ...(opts.onRendered ? { onRendered: () => opts.onRendered?.(layer) } : {}),\n })\n const renderer = createPageRenderer({\n document,\n page,\n host,\n transform,\n ...(opts.devicePixelRatio === undefined\n ? {}\n : { devicePixelRatio: opts.devicePixelRatio }),\n ...callbacks('canvas'),\n })\n const textLayer = createTextLayer({\n document,\n page,\n host,\n transform,\n ...callbacks('text'),\n })\n const overlay = createOverlay({\n host,\n page,\n store: opts.store,\n transform,\n document,\n ...(opts.devicePixelRatio === undefined\n ? {}\n : { devicePixelRatio: opts.devicePixelRatio }),\n ...(opts.onActivate ? { onActivate: (id: string) => opts.onActivate?.(id) } : {}),\n ...(opts.isCustom\n ? { isCustom: (a: Annotation) => opts.isCustom?.(a) === true }\n : {}),\n ...(opts.decorate ? { decorate: opts.decorate } : {}),\n })\n return {\n renderer,\n textLayer,\n overlay,\n update(next) {\n renderer.update(next)\n textLayer.update(next)\n overlay.update(next)\n },\n destroy() {\n overlay.destroy()\n textLayer.destroy()\n renderer.destroy()\n },\n }\n}\n","// Per-tool options (the shape kind, the highlight kind, the chosen signature…). They persist\n// per tool for the viewer's life: the engine keeps one registry across rebuilds, so reopening a\n// tool, or rebuilding the viewport, keeps its last options.\nimport { readonly, writable, type Readable, type Writable } from '../../model/readable'\n\nimport type { Tool, ToolId } from './controller'\n\nexport interface ToolOptions {\n /** The tool's current options. Throws a `RangeError` for an id no tool registered. */\n readable(id: ToolId): Readable<object>\n get(id: ToolId): object\n /** Merges `patch` into the tool's options. */\n merge(id: ToolId, patch: object): void\n /** Registers tools not seen yet, seeded from their `defaultOptions`; known ids keep theirs. */\n register(tools: readonly Tool[]): void\n}\n\nexport function createToolOptions(tools: readonly Tool[] = []): ToolOptions {\n const byId = new Map<ToolId, Writable<object>>()\n const views = new Map<ToolId, Readable<object>>()\n\n const entry = (id: ToolId): Writable<object> => {\n const w = byId.get(id)\n if (!w) throw new RangeError(`Unknown tool ${id}`)\n return w\n }\n\n function register(list: readonly Tool[]): void {\n for (const t of list) {\n if (byId.has(t.id)) continue\n const w = writable<object>({ ...(t.defaultOptions ?? {}) })\n byId.set(t.id, w)\n views.set(t.id, readonly(w))\n }\n }\n register(tools)\n\n return {\n readable(id) {\n entry(id)\n return views.get(id) as Readable<object>\n },\n get: (id) => entry(id).get(),\n merge(id, patch) {\n const w = entry(id)\n w.set({ ...w.get(), ...patch })\n },\n register,\n }\n}\n","// Move, resize and marquee for the two select tools.\n//\n// The marquee is `position:absolute; pointer-events:none` with left/top/width/height from the\n// drag. Moving annotations are shown with a temporary `transform: translate(...)` on their\n// overlay elements; a resizing one with `translate(...) scale(...)` from a `0 0` origin. A line\n// whose end is being dragged is hidden (`visibility`) and drawn into a temporary\n// `pointer-events:none` preview element beside it. All of these are geometry; their look comes\n// from the theme.\n//\n// Resize: a press on one of the overlay's corner handles (`[data-handle=nw|ne|sw|se]`, drawn\n// on a selected, unlocked annotation) drags that CSS corner while the opposite one stays put.\n// The new box is converted back to user space once, on release, and the annotation's rect and\n// points are scaled onto it in one `store.update`. Neither side goes below 1 pt. `Shift`, or\n// a type that always keeps its aspect (`keepsAspect`), keeps the box's aspect ratio. A free\n// text's corners are its text box's: the box takes the new size and `rect` and `fringe` are\n// refit around it (`resizedBox`). One with a fringe or a callout is shown resizing in a\n// preview element, as a line end is, since scaling its element would stretch the callout too.\n//\n// Line ends: a press on `[data-handle=start|end]` drags that end; the other stays put. A\n// callout's tip (`[data-handle=callout]`) drags the same way and moves `callout[0]` only, the\n// text box staying where it is (`movedTip`).\n//\n// Move: dragging a pressed annotation moves it, or, when it belongs to the selection, every\n// selected unlocked annotation, in one history step.\n//\n// Text boxes: a press inside one that can be edited (`canEditFreeText`) selects it and, on the\n// release, opens its editor with the caret where the press landed; it never moves the box. The\n// box moves by the band along its edge (`[data-ink-edge]`), or a speech bubble by its outline\n// and tail, as any annotation does. A locked or embedded box only selects.\n//\n// Under select-text, text markup is left to the overlay: a drag across it selects text, a\n// click selects it, and a press on empty space clears the annotation selection and starts a\n// text selection (Shift keeps it). Rectangle select (`marquee`) handles markup like any other\n// annotation and draws a marquee on empty space.\nimport { freeTextBox } from '../../model/annotations/callout'\nimport {\n MIN_SIZE,\n hasCallout,\n hasCornerHandles,\n hasRectGeometry,\n isTextMarkup,\n keepsAspect,\n movedEndpoint,\n movedTip,\n resizedBox,\n scaled,\n translated,\n} from '../../model/annotations/edit'\nimport { withoutReplies } from '../../model/annotations/threads'\nimport { rectFromPoints, rectsIntersect } from '../../model/geometry'\nimport { canEditFreeText, editFreeTextIn, editorFor } from '../freetext-editor'\nimport { annotationBox, handleBox, renderAnnotationContent } from '../overlay-render'\n\nimport { cssIn, type PageHit, type ToolContext } from './controller'\n\nimport type { Annotation } from '../../model/annotations/types'\nimport type { Point, Rect } from '../../model/geometry'\nimport type { CssRect, PageTransform } from '../transform'\n\ntype Corner = 'nw' | 'ne' | 'sw' | 'se'\ntype End = 'start' | 'end' | 'callout'\nconst CORNERS: readonly string[] = ['nw', 'ne', 'sw', 'se']\nconst ENDS: readonly string[] = ['start', 'end']\nconst CALLOUT = 'callout'\n\n/** Pointer travel, CSS px, before a press on an annotation becomes a move. */\nconst DRAG_THRESHOLD = 3\n\ntype Mode =\n | { kind: 'idle' }\n | {\n kind: 'press'\n id: string\n start: PageHit\n /** Pressed a member of a multi-selection: a click narrows the selection to it. */\n narrow: boolean\n }\n | { kind: 'move'; ids: string[]; start: PageHit; els: HTMLElement[] }\n | {\n kind: 'edit'\n id: string\n start: PageHit\n /** Where the press landed, for the caret. */\n caret: { clientX: number; clientY: number }\n }\n | { kind: 'marquee'; start: PageHit; el: HTMLElement; additive: boolean }\n | {\n kind: 'resize'\n id: string\n start: PageHit\n corner: Corner\n /** The annotation's CSS box when the press began. */\n box: CssRect\n el: HTMLElement | undefined\n /** Keeps its aspect ratio whatever the modifier keys. */\n locked: boolean\n /** Where the resized annotation is drawn instead of scaling `el`, for a free text. */\n preview: HTMLElement | undefined\n }\n | {\n kind: 'endpoint'\n id: string\n start: PageHit\n which: End\n /** Where the dragged end was when the press began, CSS px. */\n from: Point\n el: HTMLElement | undefined\n preview: HTMLElement\n }\n\nexport interface SelectionEdit {\n onPointerDown(e: PointerEvent, hit: PageHit | undefined, id?: string): boolean | void\n onPointerMove(e: PointerEvent, hit: PageHit | undefined): void\n onPointerUp(e: PointerEvent, hit: PageHit | undefined): void\n onPointerCancel(): void\n /** `Escape` clears the selection; `Delete` and `Backspace` remove the unlocked selected. */\n onKeyDown(e: KeyboardEvent): void\n /** Drops any gesture in progress without writing. */\n reset(): void\n}\n\nexport interface SelectionEditOptions {\n /** A press on empty space draws a marquee (rectangle select). Otherwise it is left alone. */\n marquee?: boolean\n}\n\nexport function createSelectionEdit(\n ctx: ToolContext,\n opts: SelectionEditOptions = {}\n): SelectionEdit {\n let mode: Mode = { kind: 'idle' }\n const batch = (fn: () => void): void => (ctx.history ? ctx.history.batch(fn) : fn())\n\n const reset = (): void => {\n if (mode.kind === 'marquee') mode.el.remove()\n if (mode.kind === 'move') {\n for (const el of mode.els) el.style.transform = ''\n ctx.root.removeAttribute('data-ink-dragging')\n }\n if (mode.kind === 'resize' && mode.el) {\n mode.el.style.transform = ''\n mode.el.style.transformOrigin = ''\n mode.el.style.visibility = ''\n }\n if (mode.kind === 'resize') mode.preview?.remove()\n if (mode.kind === 'endpoint') {\n mode.preview.remove()\n if (mode.el) mode.el.style.visibility = ''\n }\n mode = { kind: 'idle' }\n }\n\n const elementIn = (root: ParentNode, id: string): HTMLElement | undefined =>\n root.querySelector<HTMLElement>(`[data-annotation=\"${CSS.escape(id)}\"]`) ?? undefined\n\n const previewFor = (host: HTMLElement, a: Annotation): HTMLElement => {\n const preview = host.ownerDocument.createElement('div')\n preview.className = 'ink-annotation ink-edit-preview'\n preview.dataset.inkPreview = ''\n preview.dataset.type = a.type\n preview.style.cssText = 'position:absolute;pointer-events:none;'\n return preview\n }\n\n /** Shows `draft` in `preview` beside `el`, which is hidden meanwhile. */\n const showPreview = (\n preview: HTMLElement,\n el: HTMLElement | undefined,\n draft: Annotation,\n start: PageHit\n ): void => {\n drawPreview(preview, draft, start)\n if (el) el.style.visibility = 'hidden'\n // Beside the annotation in the overlay, so it paints where the annotation does.\n if (!preview.isConnected) (el?.parentElement ?? start.host).append(preview)\n }\n\n function startHandle(\n e: PointerEvent,\n hit: PageHit,\n a: Annotation,\n handle: string\n ): boolean {\n const el = elementIn(hit.host, a.id)\n if (CORNERS.includes(handle) && hasCornerHandles(a)) {\n const text = a.type === 'freetext'\n mode = {\n kind: 'resize',\n id: a.id,\n start: hit,\n corner: handle as Corner,\n box: text ? hit.transform.toCssRect(freeTextBox(a)) : handleBox(a, hit.transform),\n el,\n locked: keepsAspect(a),\n preview:\n text && (a.fringe !== undefined || hasCallout(a))\n ? previewFor(hit.host, a)\n : undefined,\n }\n } else if (\n (ENDS.includes(handle) && a.type === 'line') ||\n (handle === CALLOUT && hasCallout(a))\n ) {\n const preview = previewFor(hit.host, a)\n mode = {\n kind: 'endpoint',\n id: a.id,\n start: hit,\n which: handle as End,\n from: hit.transform.toCss(endOf(a, handle as End)!),\n el,\n preview,\n }\n } else {\n return false\n }\n // The annotation is already selected (it has handles): keep the overlay from\n // re-activating it.\n e.stopPropagation()\n e.preventDefault()\n return true\n }\n\n return {\n reset,\n onPointerDown(e, hit, annotationId) {\n if (!hit) return\n reset()\n if (annotationId !== undefined) {\n const a = ctx.store.get(annotationId)\n if (!a) return\n // Under select-text, text markup lets a drag through to text selection and the overlay\n // selects it on a click. Rectangle select treats it as any other annotation: it selects\n // on the press and a drag moves it, so it claims the press from the overlay.\n const markup = isTextMarkup(a)\n if (markup && !opts.marquee) return\n const handle = handleOf(e.target)\n if (handle !== undefined && !a.locked && startHandle(e, hit, a, handle))\n return true\n const selected = ctx.store.selection.get()\n if (e.shiftKey) {\n // Toggle membership ourselves; the overlay would replace the selection.\n e.stopPropagation()\n ctx.store.select(\n selected.includes(annotationId)\n ? selected.filter((s) => s !== annotationId)\n : [...selected, annotationId]\n )\n return\n }\n if (inText(e.target) && canEditFreeText(a, elementIn(hit.host, annotationId))) {\n // Selected here, not by the overlay, which would also take the press for a move.\n e.stopPropagation()\n ctx.store.select([annotationId])\n ctx.onActivate?.(annotationId)\n mode = {\n kind: 'edit',\n id: annotationId,\n start: hit,\n caret: { clientX: e.clientX, clientY: e.clientY },\n }\n e.preventDefault()\n return true\n }\n const narrow = selected.length > 1 && selected.includes(annotationId)\n // A press on a member of the selection keeps the selection, so it can move as one.\n // Otherwise the overlay selects and activates it once this capture-phase handler\n // returns, except markup, which the overlay would hold until the release.\n if (narrow) e.stopPropagation()\n else if (markup) {\n e.stopPropagation()\n ctx.store.select([annotationId])\n ctx.onActivate?.(annotationId)\n }\n mode = { kind: 'press', id: annotationId, start: hit, narrow }\n e.preventDefault()\n return true\n }\n if (!opts.marquee) {\n // Select text: an empty press drops the annotation selection and is left alone, so a\n // text selection starts as usual. Shift keeps the selection.\n if (!e.shiftKey) ctx.store.select([])\n return\n }\n const el = hit.host.ownerDocument.createElement('div')\n el.className = 'ink-marquee'\n el.dataset.inkMarquee = ''\n el.style.cssText = `position:absolute;pointer-events:none;left:${hit.css.x}px;top:${hit.css.y}px;width:0;height:0;`\n hit.host.append(el)\n mode = { kind: 'marquee', start: hit, el, additive: e.shiftKey }\n if (!e.shiftKey) ctx.store.select([])\n e.preventDefault()\n return true\n },\n onPointerMove(e) {\n if (mode.kind === 'idle') return\n // No button down: the release was missed, so drop the gesture. So does a start host\n // that scrolling has unmounted.\n if (e.buttons === 0 || !mode.start.host.isConnected) {\n reset()\n return\n }\n const { start } = mode\n if (mode.kind === 'edit') return\n if (mode.kind === 'resize') {\n const { box, el, preview } = mode\n const next = resizeCss(box, mode.corner, cornerAt(mode, e), minCss(start), {\n aspect: mode.locked || e.shiftKey,\n page: start.transform,\n })\n if (preview) {\n const a = ctx.store.get(mode.id)\n if (a?.type !== 'freetext') return\n const draft = { ...a, ...resizedBox(a, userBox(start.transform, next)) }\n showPreview(preview, el, draft, start)\n } else if (el) {\n // The drawn box's corner within the element, which may be padded past it.\n const ox = box.left - (parseFloat(el.style.left) || 0)\n const oy = box.top - (parseFloat(el.style.top) || 0)\n el.style.transformOrigin = `${ox}px ${oy}px`\n el.style.transform =\n `translate(${next.left - box.left}px, ${next.top - box.top}px) ` +\n `scale(${next.width / box.width}, ${next.height / box.height})`\n }\n return\n }\n if (mode.kind === 'endpoint') {\n const a = ctx.store.get(mode.id)\n if (!a) return\n const patch = endPatch(a, mode.which, endAt(mode, e))\n if (!patch) return\n showPreview(mode.preview, mode.el, { ...a, ...patch } as Annotation, start)\n return\n }\n const css = cssIn(start.host, e)\n const dx = css.x - start.css.x\n const dy = css.y - start.css.y\n if (mode.kind === 'press') {\n if (Math.hypot(dx, dy) < DRAG_THRESHOLD) return\n const a = ctx.store.get(mode.id)\n if (!a || a.locked) {\n mode = { kind: 'idle' }\n return\n }\n const selected = ctx.store.selection.get()\n // Text markup is anchored to its text, and may carry a comment: it moves only when it\n // is what the drag pressed, never along with the rest of a selection.\n const pressed = mode.id\n const ids = selected.includes(pressed)\n ? selected.filter((id) => {\n const m = ctx.store.get(id)\n return m !== undefined && !m.locked && (id === pressed || !isTextMarkup(m))\n })\n : [pressed]\n const els = ids\n .map((id) => elementIn(ctx.root, id))\n .filter((el): el is HTMLElement => el !== undefined)\n mode = { kind: 'move', ids, start, els }\n // The theme shows the move cursor everywhere until the release.\n ctx.root.setAttribute('data-ink-dragging', '')\n }\n if (mode.kind === 'move') {\n for (const el of mode.els) el.style.transform = `translate(${dx}px, ${dy}px)`\n return\n }\n mode.el.style.left = `${Math.min(start.css.x, css.x)}px`\n mode.el.style.top = `${Math.min(start.css.y, css.y)}px`\n mode.el.style.width = `${Math.abs(dx)}px`\n mode.el.style.height = `${Math.abs(dy)}px`\n },\n onPointerCancel() {\n reset()\n },\n onPointerUp(e) {\n const current = mode\n reset()\n if (current.kind !== 'idle' && !current.start.host.isConnected) return\n switch (current.kind) {\n case 'press':\n // A click on a member of a multi-selection: just that one, as the overlay would.\n if (current.narrow) {\n ctx.store.select([current.id])\n ctx.onActivate?.(current.id)\n }\n return\n case 'edit': {\n // Opened on the release, so the press's own focus change has already happened.\n const el = elementIn(current.start.host, current.id)\n const a = ctx.store.get(current.id)\n if (!el || !canEditFreeText(a, el) || editorFor(el)) return\n editFreeTextIn(ctx.store, el, a.id, ctx.viewport.transformFor(a.page), {\n caret: current.caret,\n })\n return\n }\n case 'move': {\n const { start } = current\n const end = start.transform.fromCss(cssIn(start.host, e))\n const dx = end.x - start.user.x\n const dy = end.y - start.user.y\n batch(() => {\n for (const id of current.ids) {\n const a = ctx.store.get(id)\n if (a && !a.locked) ctx.store.update(id, translated(a, dx, dy))\n }\n })\n return\n }\n case 'resize': {\n const { start, box } = current\n const next = resizeCss(\n box,\n current.corner,\n cornerAt(current, e),\n minCss(start),\n {\n aspect: current.locked || e.shiftKey,\n page: start.transform,\n }\n )\n if (\n next.left === box.left &&\n next.top === box.top &&\n next.width === box.width &&\n next.height === box.height\n )\n return\n const a = ctx.store.get(current.id)\n if (!a || a.locked) return\n const to = userBox(start.transform, next)\n if (a.type === 'freetext') {\n ctx.store.update(a.id, resizedBox(a, to))\n return\n }\n // A rect-shaped annotation's box is its rect; a point-based one's is its drawn box.\n const from = hasRectGeometry(a) ? a.rect : start.transform.fromCssRect(box)\n ctx.store.update(a.id, scaled(a, from, to))\n return\n }\n case 'endpoint': {\n const a = ctx.store.get(current.id)\n if (!a || a.locked) return\n const css = cssIn(current.start.host, e)\n if (css.x === current.start.css.x && css.y === current.start.css.y) return\n const patch = endPatch(a, current.which, endAt(current, e))\n if (patch) ctx.store.update(a.id, patch)\n return\n }\n case 'marquee': {\n const { start } = current\n const box = rectFromPoints(\n start.user,\n start.transform.fromCss(cssIn(start.host, e))\n )\n if (box.width === 0 && box.height === 0) return\n // Replies have no element on the page, so a marquee never picks them.\n const ids = withoutReplies(ctx.store.list.get())\n .filter((a) => a.page === start.page && rectsIntersect(a.rect, box))\n .map((a) => a.id)\n ctx.store.select(\n current.additive ? [...new Set([...ctx.store.selection.get(), ...ids])] : ids\n )\n return\n }\n default:\n }\n },\n onKeyDown(e) {\n if (e.key === 'Escape') {\n reset()\n ctx.store.select([])\n return\n }\n if (e.key !== 'Delete' && e.key !== 'Backspace') return\n // A focused annotation's overlay element owns the key (it removes that one annotation\n // and prevents the default); deleting the selection too would double-handle it.\n if (e.defaultPrevented) return\n const target = e.target instanceof Element ? e.target : null\n if (\n target?.closest(\n '[data-annotation], input, textarea, [contenteditable]:not([contenteditable=\"false\"])'\n )\n )\n return\n for (const id of ctx.store.selection.get()) {\n if (ctx.store.get(id)?.locked !== true) ctx.store.remove(id)\n }\n },\n }\n}\n\n/** The handle (`nw`, `start`, ...) a press landed on, if it landed on one. */\nfunction handleOf(target: EventTarget | null): string | undefined {\n if (!(target instanceof Element)) return undefined\n return target.closest('[data-handle]')?.getAttribute('data-handle') ?? undefined\n}\n\n/** True when a press landed inside a free text's drawn text box. */\nfunction inText(target: EventTarget | null): boolean {\n return target instanceof Element && target.closest('.ink-free-text') !== null\n}\n\n/** The point a line's end or a callout's tip handle sits on. */\nfunction endOf(a: Annotation, which: End): Point | undefined {\n if (which === 'callout') return hasCallout(a) ? a.callout[0] : undefined\n return a.type === 'line' ? a[which] : undefined\n}\n\n/** The patch that moves a line's end, or a callout's tip, to `to`; undefined for neither. */\nfunction endPatch(a: Annotation, which: End, to: Point): Partial<Annotation> | undefined {\n if (which === 'callout') return hasCallout(a) ? movedTip(a, to) : undefined\n return a.type === 'line' ? movedEndpoint(a, which, to) : undefined\n}\n\n/** A resized CSS box in user space, at least `MIN_SIZE` a side. */\nfunction userBox(t: PageTransform, css: CssRect): Rect {\n const r = t.fromCssRect(css)\n return {\n ...r,\n width: Math.max(MIN_SIZE, r.width),\n height: Math.max(MIN_SIZE, r.height),\n }\n}\n\n/** Draws `a` into the preview element at its own box. */\nfunction drawPreview(el: HTMLElement, a: Annotation, start: PageHit): void {\n const box = annotationBox(a, start.transform)\n el.style.left = `${box.left}px`\n el.style.top = `${box.top}px`\n el.style.width = `${box.width}px`\n el.style.height = `${box.height}px`\n renderAnnotationContent(el, a, start.transform)\n}\n\n/** Keeps a CSS point on the page. */\nfunction onPage(start: PageHit, x: number, y: number): Point {\n const { cssWidth, cssHeight } = start.transform\n return {\n x: Math.min(Math.max(x, 0), cssWidth),\n y: Math.min(Math.max(y, 0), cssHeight),\n }\n}\n\n/**\n * Where the dragged line end is now, in user space: where it started plus the pointer's\n * travel, kept on the page.\n */\nfunction endAt(\n mode: { start: PageHit; from: Point },\n e: { clientX: number; clientY: number }\n): Point {\n const { start, from } = mode\n const css = cssIn(start.host, e)\n return start.transform.fromCss(\n onPage(start, from.x + css.x - start.css.x, from.y + css.y - start.css.y)\n )\n}\n\n/**\n * Where the dragged corner is now: where it started plus the pointer's travel since the\n * press, kept on the page. Keeping the press's offset from the corner means a click on a\n * handle, with no drag, leaves the box as it was.\n */\nfunction cornerAt(\n mode: { start: PageHit; box: CssRect; corner: Corner },\n e: { clientX: number; clientY: number }\n): Point {\n const { start, box, corner } = mode\n const css = cssIn(start.host, e)\n const x = (corner[1] === 'w' ? box.left : box.left + box.width) + css.x - start.css.x\n const y = (corner[0] === 'n' ? box.top : box.top + box.height) + css.y - start.css.y\n return onPage(start, x, y)\n}\n\n/** `MIN_SIZE` points as CSS px on the press's page. */\nfunction minCss(start: PageHit): number {\n return start.transform.toCssLength(MIN_SIZE)\n}\n\n/**\n * `box` with its `corner` dragged to `p` and the opposite corner fixed, at least `min` a side.\n * With `aspect`, the box keeps its proportions: it scales by the larger of the two axes'\n * changes, kept on the page.\n */\nfunction resizeCss(\n box: CssRect,\n corner: Corner,\n p: Point,\n min: number,\n opts: { aspect: boolean; page: { cssWidth: number; cssHeight: number } }\n): CssRect {\n const west = corner[1] === 'w'\n const north = corner[0] === 'n'\n /** The fixed corner. */\n const fx = west ? box.left + box.width : box.left\n const fy = north ? box.top + box.height : box.top\n let width = Math.max(west ? fx - p.x : p.x - fx, min)\n let height = Math.max(north ? fy - p.y : p.y - fy, min)\n if (opts.aspect && box.width > 0 && box.height > 0) {\n // Room from the fixed corner to the page edge the dragged corner moves towards.\n const roomX = west ? fx : opts.page.cssWidth - fx\n const roomY = north ? fy : opts.page.cssHeight - fy\n const lo = min / Math.min(box.width, box.height)\n const hi = Math.min(roomX / box.width, roomY / box.height)\n const s = Math.min(\n Math.max(width / box.width, height / box.height, lo),\n Math.max(hi, lo)\n )\n width = box.width * s\n height = box.height * s\n }\n return {\n left: west ? fx - width : fx,\n top: north ? fy - height : fy,\n width,\n height,\n }\n}\n","// The controller writes two things to the root: `data-ink-tool=\"<id>\"` (a marker for themes\n// and tests; `data-tool` belongs to toolbar buttons) and `style.cursor` from the active tool.\n// Both are structural, and both are removed on destroy.\n//\n// `pointerdown` is listened for in the capture phase. The overlay stops propagation of presses\n// on annotation shapes other than text markup (so a creation tool never starts a drag from\n// one), but a capture listener on the root runs before that, so the controller can pass the\n// pressed annotation's id to the tool. Move, up and key events bubble normally.\n//\n// When a tool starts a gesture (its `onPointerDown` returns true) the controller captures the\n// pointer on the root, so the release still arrives when it happens outside. `pointercancel`\n// and `lostpointercapture` reach the tool as `onPointerCancel`. `touch-action` is left to the\n// theme or host: touch gestures are theirs to arbitrate.\n//\n// The controller tracks the pressed pointer. Switching tools mid-press cancels the old tool's\n// gesture and swallows that pointer's release, so the new tool never sees half a gesture.\n// `lostpointercapture` after a completed release is not a cancel. Only primary-button presses\n// and releases reach tools. The root's own inline cursor is restored on destroy.\n//\n// A one-shot tool (`kind: 'one-shot'`) is used once, then hands back to `select-text`. It is\n// ready until it reports what it made (`ctx.made`), then made, with `data-ink-made` on the\n// root. A press on empty page (a page or a gap between pages, not a scroll bar) while made, or\n// Escape, ends it (`ctx.done`), and the tool never sees that press. A press on another annotation switches to `select-text` and goes to it, so\n// the same press can drag: in either state, bar text markup, which switches only when made. Whether a press finds the tool\n// made is read before anything the press itself does: on the window when it is created, or on\n// the document once a free-text editor (which listens on the window) has committed. So a note\n// dropped by the press that closes its popover still counts as made. Removing everything it\n// made (Delete, undo, a controlled host refusing the add) returns the tool to ready; the\n// selection moving to something else switches to `select-text`.\n//\n// While made, a press on a made item or on its handles goes to the controller's own selection\n// editor (selection-edit.ts) instead of the tool, as under `select-text`: a drag moves it, a\n// handle resizes it, a press inside a made text box reopens its editor, and the tool stays on\n// and made. Escape in an editor on a made text box (opened that way, or by Enter or a\n// double-click) commits and ends the tool, as in a new box. Delete and\n// Backspace go to the selection editor too, so the made item can be removed without switching.\nimport { isTextMarkup } from '../../model/annotations/edit'\nimport {\n createToolStyle,\n type StyleGroup,\n type ToolStyle,\n} from '../../model/annotations/tool-style'\nimport { readonly, writable, type Readable } from '../../model/readable'\nimport { canEditFreeText, editFreeTextIn, editorFor } from '../freetext-editor'\n\nimport { createToolOptions, type ToolOptions } from './options'\nimport { createSelectionEdit, type SelectionEdit } from './selection-edit'\n\nimport type { AnnotationStore } from '../../model/annotations/store'\nimport type { Point } from '../../model/geometry'\nimport type { SignatureLibrary } from '../../model/signatures'\nimport type { SelectionQuads } from '../selection'\nimport type { Viewport, ViewportHit } from '../viewport'\n\nexport type BuiltinToolId =\n | 'select-text'\n | 'select'\n | 'highlight'\n | 'redact-area'\n | 'note'\n | 'shape'\n | 'freetext'\n | 'draw'\n | 'sketch'\n | 'signature'\n/** A built-in tool's id, or any id a host registers its own tool under. */\nexport type ToolId = BuiltinToolId | (string & {})\n\n/**\n * A one-shot tool switches back to `select-text` once it has made something and the user moves\n * on; a sticky tool stays on. A tool without a kind is sticky.\n */\nexport type ToolKind = 'one-shot' | 'sticky'\n\nexport interface PageHit extends ViewportHit {\n /** Pointer position in user space. */\n user: Point\n /** Pointer position relative to the page host's top-left, CSS px. */\n css: Point\n}\n\nexport interface ToolContext {\n store: AnnotationStore\n viewport: Viewport\n /** The element pointer and key events are listened on (the viewport container). */\n root: HTMLElement\n /** The live text selection as user-space quads, one entry per page. */\n selectionQuads(): SelectionQuads[]\n clearSelection(): void\n onActivate?(id: string): void\n /** The style each group creates with, shared with the style controls. */\n toolStyle: ToolStyle\n /** The active tool's current options. */\n options<O extends object>(): O\n /**\n * Groups a gesture's changes into one undo step (a group move). Without it each change is\n * its own step.\n */\n history?: { batch(fn: () => void): void }\n /** The signature templates the `signature` tool places. Without it, it places nothing. */\n signatures?: SignatureLibrary | undefined\n /**\n * A one-shot tool reports what it just made, already added and selected. Does nothing under\n * a sticky tool or with an empty list.\n */\n made(ids: readonly string[]): void\n /** Clears the selection and switches to `select-text`. */\n done(): void\n}\n\nexport interface Tool<O extends object = object> {\n id: ToolId\n /** Default sticky. */\n kind?: ToolKind\n cursor: string\n /** Style group the tool creates into; select tools have none. */\n styleGroup?: StyleGroup\n /** Option defaults. Options persist per tool for the viewer's life. */\n defaultOptions?: O\n activate(ctx: ToolContext): void\n deactivate(): void\n /**\n * Runs in the capture phase, before the overlay sees the press. `annotationId` is set when\n * the press landed on an annotation; the overlay then selects and activates it (text markup\n * on a click, other types on the press), so tools other than the select tools should ignore\n * such presses. Calling `e.stopPropagation()` here keeps the overlay from handling it.\n * Return true when the press starts a gesture: the controller then captures the pointer\n * until it is released or cancelled.\n */\n onPointerDown?(\n e: PointerEvent,\n hit: PageHit | undefined,\n annotationId?: string\n ): boolean | void\n /**\n * A move with `e.buttons === 0` during a gesture means the release was missed (it happened\n * where no listener saw it): tools treat it as a cancel.\n */\n onPointerMove?(e: PointerEvent, hit: PageHit | undefined): void\n onPointerUp?(e: PointerEvent, hit: PageHit | undefined): void\n /** `pointercancel` or `lostpointercapture`: drop any gesture in progress without writing. */\n onPointerCancel?(e: PointerEvent): void\n onKeyDown?(e: KeyboardEvent): void\n}\n\nexport interface ToolController {\n readonly active: Readable<ToolId>\n /** Switches to the tool, first merging `options` into its options. */\n set(id: ToolId, options?: object): void\n /** Merges `patch` into a tool's options without switching to it. */\n setOptions(id: ToolId, patch: object): void\n options(id: ToolId): Readable<object>\n destroy(): void\n}\n\nexport interface ToolControllerOptions {\n /**\n * The controller adds `options`, `made` and `done`; `toolStyle` defaults to one of the\n * controller's own.\n */\n ctx: Omit<ToolContext, 'toolStyle' | 'options' | 'made' | 'done'> & {\n toolStyle?: ToolStyle\n }\n /** Default `'select-text'`. */\n initial?: ToolId\n tools: Tool[]\n /**\n * Where options live. Pass the same registry to each controller that replaces another (a\n * rebuild) so options persist; by default the controller keeps its own.\n */\n options?: ToolOptions\n}\n\n/** Host-relative CSS point for a client point. */\nexport function cssIn(host: HTMLElement, e: { clientX: number; clientY: number }): Point {\n const r = host.getBoundingClientRect()\n return { x: e.clientX - r.left, y: e.clientY - r.top }\n}\n\n/** Like `cssIn`, clamped to the host's box, so a drag past the page edge stops at the edge. */\nexport function clampedCssIn(\n host: HTMLElement,\n e: { clientX: number; clientY: number }\n): Point {\n const r = host.getBoundingClientRect()\n return {\n x: Math.min(Math.max(e.clientX - r.left, 0), r.width),\n y: Math.min(Math.max(e.clientY - r.top, 0), r.height),\n }\n}\n\n/** The mounted page under a client point, with the point in CSS px and user space. */\nexport function hitFor(\n ctx: ToolContext,\n e: { clientX: number; clientY: number }\n): PageHit | undefined {\n const hit = ctx.viewport.pageAtCss(e.clientX, e.clientY)\n if (!hit) return undefined\n const css = cssIn(hit.host, e)\n return { ...hit, css, user: hit.transform.fromCss(css) }\n}\n\nexport function createToolController(opts: ToolControllerOptions): ToolController {\n const byId = new Map(opts.tools.map((t) => [t.id, t]))\n const active = writable<ToolId>(opts.initial ?? 'select-text')\n let current: Tool | undefined\n const registry = opts.options ?? createToolOptions()\n registry.register(opts.tools)\n const ctx: ToolContext = {\n ...opts.ctx,\n // Read through, as a spread copies a getter's value once: the host's library may change.\n get signatures() {\n return opts.ctx.signatures\n },\n toolStyle:\n opts.ctx.toolStyle ??\n createToolStyle({\n store: opts.ctx.store,\n history: opts.ctx.history ?? { batch: (fn) => fn() },\n activeGroup: () => current?.styleGroup,\n active,\n }),\n // `current` is the activating tool already, so `activate` reads its own options.\n options: <O extends object>() => registry.get(current?.id ?? active.get()) as O,\n made(ids) {\n if (current?.kind !== 'one-shot' || ids.length === 0) return\n clearMade()\n made = [...ids]\n ctx.root.dataset.inkMade = ''\n stopMade = [\n ctx.store.list.subscribe(checkMade),\n ctx.store.selection.subscribe(checkMade),\n ]\n },\n done() {\n clearMade()\n ctx.store.select([])\n set('select-text')\n },\n }\n const originalCursor = ctx.root.style.cursor\n /** The pointer between a primary press and its release or cancel. */\n let pressed: number | undefined\n /** Pointers whose release belongs to a tool that is no longer active. */\n const swallow = new Set<number>()\n /** What the active one-shot tool made; undefined while it is ready. */\n let made: string[] | undefined\n let stopMade: (() => void)[] = []\n /** Whether the press now under way found the tool made (see the top of the file). */\n let pressFoundMade = false\n /** Moves and resizes what the active one-shot tool made. */\n let madeEdit: SelectionEdit | undefined\n /** The press now under way went to `madeEdit`, not the tool. */\n let editingMade = false\n\n function clearMade(): void {\n stopMade.forEach((stop) => stop())\n stopMade = []\n made = undefined\n delete ctx.root.dataset.inkMade\n }\n /** Leaves the made state when its items are gone, or switches when the selection moved on. */\n function checkMade(): void {\n if (!made) return\n const store = ctx.store\n if (!made.some((id) => (store.get(id) ?? store._getProposed(id)) !== undefined)) {\n clearMade()\n return\n }\n const selected = store.selection.get()\n if (!made.some((id) => selected.includes(id))) set('select-text')\n }\n\n /** True for events from a pointer other than the one whose press is live. */\n const foreign = (e: PointerEvent): boolean =>\n pressed !== undefined && pressed !== e.pointerId\n\n const readFirst = (): void => {\n pressFoundMade = made !== undefined\n }\n const readAfterEditor = (): void => {\n pressFoundMade ||= made !== undefined\n }\n const onDown = (e: PointerEvent): void => {\n if (!e.isPrimary || e.button !== 0 || inCustomContent(e.target)) return\n // One gesture at a time: a second pointer pressing mid-gesture is ignored.\n if (foreign(e)) return\n swallow.delete(e.pointerId)\n const target = e.target instanceof Element ? e.target : null\n const annotationId =\n target?.closest('[data-annotation]')?.getAttribute('data-annotation') ?? undefined\n if (current?.kind === 'one-shot') {\n // Empty page is a page or the gaps between pages, not the viewport's own scroll bars.\n if (pressFoundMade && annotationId === undefined && !onScrollBar(e, ctx.root)) {\n // No text selection starts. The press still bubbles, so a host's popover sees a\n // press outside it and closes.\n e.preventDefault()\n // The release belongs to no tool.\n swallow.add(e.pointerId)\n ctx.done()\n return\n }\n const a = annotationId === undefined ? undefined : ctx.store.get(annotationId)\n if (a && made?.includes(a.id) && madeEdit) {\n pressed = e.pointerId\n editingMade = true\n if (madeEdit.onPointerDown(e, hitFor(ctx, e), a.id) === true) capture(e.pointerId)\n return\n }\n // Text markup counts as another annotation once the tool has made something; while it\n // is ready the tool may claim the press (area redaction draws from it).\n if (a && (!isTextMarkup(a) || pressFoundMade)) set('select-text')\n }\n pressed = e.pointerId\n if (current?.onPointerDown?.(e, hitFor(ctx, e), annotationId) === true)\n capture(e.pointerId)\n }\n const onMove = (e: PointerEvent): void => {\n if (!e.isPrimary || foreign(e)) return\n // A buttonless move means the release was missed: the press is over (tools drop their\n // own gesture on the same signal), so another pointer may press again.\n const missed = pressed === e.pointerId && e.buttons === 0\n if (missed) pressed = undefined\n if (editingMade) {\n madeEdit?.onPointerMove(e, hitFor(ctx, e))\n if (missed) editingMade = false\n return\n }\n current?.onPointerMove?.(e, hitFor(ctx, e))\n }\n const onUp = (e: PointerEvent): void => {\n if (!e.isPrimary || e.button !== 0 || foreign(e)) return\n if (pressed === e.pointerId) pressed = undefined\n if (swallow.delete(e.pointerId)) {\n release(e.pointerId)\n return\n }\n if (editingMade) {\n editingMade = false\n madeEdit?.onPointerUp(e, hitFor(ctx, e))\n } else current?.onPointerUp?.(e, hitFor(ctx, e))\n release(e.pointerId)\n }\n const onCancel = (e: PointerEvent): void => {\n if (!e.isPrimary || foreign(e)) return\n // Capture is also lost when a completed release frees it: only a live press cancels.\n if (e.type === 'lostpointercapture' && pressed !== e.pointerId) return\n if (pressed === e.pointerId) pressed = undefined\n swallow.delete(e.pointerId)\n if (editingMade) {\n editingMade = false\n madeEdit?.onPointerCancel()\n } else current?.onPointerCancel?.(e)\n }\n const onKey = (e: KeyboardEvent): void => {\n if (inCustomContent(e.target)) return\n if (made && e.key === 'Escape' && !e.defaultPrevented) {\n e.preventDefault()\n ctx.done()\n return\n }\n if (made && (e.key === 'Delete' || e.key === 'Backspace')) {\n madeEdit?.onKeyDown(e)\n return\n }\n current?.onKeyDown?.(e)\n // Enter that no tool took edits the one selected text box, wherever focus is in the viewport.\n if (isViewportEnter(e, ctx.root)) editSelectedText(e)\n }\n /**\n * Escape in an editor on a made text box, however it was opened (a press inside, Enter, a\n * double-click): commits and ends the tool. Captured, as the editor keeps its keys to itself.\n */\n const onEditorEscape = (e: KeyboardEvent): void => {\n if (!made || e.key !== 'Escape' || e.isComposing || e.defaultPrevented) return\n const target = e.target instanceof Element ? e.target : null\n if (!target?.closest('[data-ink-editor]')) return\n const el = target.closest<HTMLElement>('[data-annotation]')\n const id = el?.getAttribute('data-annotation')\n if (!el || !id || !made.includes(id)) return\n e.preventDefault()\n e.stopPropagation()\n editorFor(el)?.close(true)\n ctx.done()\n }\n function editSelectedText(e: KeyboardEvent): void {\n const selected = ctx.store.selection.get()\n if (selected.length !== 1) return\n const id = selected[0]!\n const a = ctx.store.get(id)\n const el = ctx.root.querySelector<HTMLElement>(\n `[data-annotation=\"${CSS.escape(id)}\"]`\n )\n if (!canEditFreeText(a, el) || !el) return\n e.preventDefault()\n editFreeTextIn(ctx.store, el, id, ctx.viewport.transformFor(a.page))\n }\n\n // Capture is best effort: synthetic events may carry a pointer id the browser does not know.\n function capture(id: number): void {\n try {\n ctx.root.setPointerCapture?.(id)\n } catch {\n // Not an active pointer: the gesture still works while the pointer stays over the root.\n }\n }\n function release(id: number): void {\n try {\n if (ctx.root.hasPointerCapture?.(id)) ctx.root.releasePointerCapture(id)\n } catch {\n // Already released.\n }\n }\n const doc = ctx.root.ownerDocument\n doc.defaultView?.addEventListener('pointerdown', readFirst, { capture: true })\n doc.addEventListener('pointerdown', readAfterEditor, { capture: true })\n ctx.root.addEventListener('pointerdown', onDown, { capture: true })\n ctx.root.addEventListener('pointermove', onMove)\n ctx.root.addEventListener('pointerup', onUp)\n ctx.root.addEventListener('pointercancel', onCancel)\n ctx.root.addEventListener('lostpointercapture', onCancel)\n ctx.root.addEventListener('keydown', onKey)\n ctx.root.addEventListener('keydown', onEditorEscape, { capture: true })\n\n function set(id: ToolId, options?: object): void {\n const next = byId.get(id)\n if (!next) throw new RangeError(`Unknown tool ${id}`)\n if (options) registry.merge(id, options)\n if (pressed !== undefined) {\n // Mid-press: end the old tool's gesture here and keep its release from the new tool.\n if (editingMade) madeEdit?.onPointerCancel()\n else\n current?.onPointerCancel?.(\n new PointerEvent('pointercancel', { pointerId: pressed, isPrimary: true })\n )\n swallow.add(pressed)\n pressed = undefined\n }\n editingMade = false\n madeEdit?.reset()\n current?.deactivate()\n // After `deactivate`, which may commit an open edit and report it made.\n clearMade()\n current = next\n madeEdit = next.kind === 'one-shot' ? createSelectionEdit(ctx) : undefined\n next.activate(ctx)\n ctx.root.dataset.inkTool = id\n ctx.root.style.cursor = next.cursor\n active.set(id)\n }\n set(opts.initial ?? 'select-text')\n\n return {\n active: readonly(active),\n set,\n setOptions(id, patch) {\n if (!byId.has(id)) throw new RangeError(`Unknown tool ${id}`)\n registry.merge(id, patch)\n },\n options(id) {\n if (!byId.has(id)) throw new RangeError(`Unknown tool ${id}`)\n return registry.readable(id)\n },\n destroy() {\n madeEdit?.reset()\n madeEdit = undefined\n current?.deactivate()\n clearMade()\n current = undefined\n doc.defaultView?.removeEventListener('pointerdown', readFirst, { capture: true })\n doc.removeEventListener('pointerdown', readAfterEditor, { capture: true })\n ctx.root.removeEventListener('pointerdown', onDown, { capture: true })\n ctx.root.removeEventListener('pointermove', onMove)\n ctx.root.removeEventListener('pointerup', onUp)\n ctx.root.removeEventListener('pointercancel', onCancel)\n ctx.root.removeEventListener('lostpointercapture', onCancel)\n ctx.root.removeEventListener('keydown', onKey)\n ctx.root.removeEventListener('keydown', onEditorEscape, { capture: true })\n delete ctx.root.dataset.inkTool\n ctx.root.style.cursor = originalCursor\n },\n }\n}\n\n/**\n * True for an unmodified, unhandled Enter on the viewport's own elements: the scroll element\n * (`root`), a page host, or content of a page's text layer or canvas layer. Every other target\n * (annotations, custom slot content, any control a host puts in the page) keeps its Enter.\n * This is the keyboard trigger for the creation tools.\n */\nexport function isViewportEnter(e: KeyboardEvent, root: HTMLElement): boolean {\n if (e.key !== 'Enter' || e.defaultPrevented) return false\n if (e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || e.isComposing) return false\n const target = e.target\n if (target === root) return true\n if (!(target instanceof Element) || !root.contains(target)) return false\n if (target.matches('.ink-page[data-page]')) return true\n return target.closest('[data-ink-text-layer], [data-ink-canvas-layer]') !== null\n}\n\n/**\n * True for a press on `root` itself outside its client area: on a scroll bar (or its border).\n * Client coordinates only, so a synthetic press gives the same answer as a real one.\n */\nfunction onScrollBar(e: PointerEvent, root: HTMLElement): boolean {\n if (e.target !== root) return false\n const r = root.getBoundingClientRect()\n const x = e.clientX - r.left - root.clientLeft\n const y = e.clientY - r.top - root.clientTop\n return x < 0 || y < 0 || x >= root.clientWidth || y >= root.clientHeight\n}\n\n/**\n * True for a target inside a custom annotation element (`data-custom`) but not that element\n * itself: the host's buttons and inputs there own their presses and keys, as in the overlay.\n */\nfunction inCustomContent(target: EventTarget | null): boolean {\n if (!(target instanceof Element)) return false\n // A free-text editor's presses and keys are its own, too.\n if (target.closest('[data-ink-editor]')) return true\n const el = target.closest('[data-annotation]')\n return (\n el !== null &&\n el !== target &&\n el.hasAttribute('data-custom') &&\n // Resize handles are the overlay's, not the host's content.\n target.closest('[data-handle]') === null\n )\n}\n","// Freehand stroke capture, shared by `draw` and `sketch`. A press-drag-release is one stroke:\n// samples come from coalesced pointer events where the browser has them, with pen and touch\n// pressure, and a live preview paints the stroke as the ink it will become. The tool decides\n// what a finished stroke writes.\nimport { outlinePath, strokeOutline } from '../ink-stroke'\n\nimport {\n clampedCssIn,\n type PageHit,\n type Tool,\n type ToolContext,\n type ToolId,\n} from './controller'\n\nimport type { AnnotationInput } from '../../model/annotations/types'\nimport type { Point } from '../../model/geometry'\n\nconst SVG_NS = 'http://www.w3.org/2000/svg'\n\n/** A finished stroke, in user space. */\nexport interface FreehandStroke {\n page: number\n points: Point[]\n /**\n * One value per point, 0 to 1, from a pen or touch that reports real pressure; undefined for\n * a mouse, or a device that only ever reports 0 or 0.5.\n */\n pressure: number[] | undefined\n /** When the press happened (`Date.now()`). */\n startedAt: number\n}\n\nexport interface FreehandOptions {\n id: ToolId\n /** Writes a finished stroke. */\n commit(ctx: ToolContext, stroke: FreehandStroke): void\n /** Escape, or the tool deactivating. */\n end?(): void\n /** The tool deactivating (a tool switch, or the controller's destroy). */\n deactivate?(): void\n}\n\n/** A stroke being drawn: its page, and each sample in CSS px (host-relative) and user space. */\ninterface Stroke {\n from: PageHit\n css: Point[]\n user: Point[]\n /** One value per sample for pen and touch, else undefined. */\n pressure: number[] | undefined\n startedAt: number\n}\n\n/** Pressure from a device that reports it, else undefined. Shared with the signature pad. */\nexport function pressureOf(e: PointerEvent): number | undefined {\n if (e.pointerType !== 'pen' && e.pointerType !== 'touch') return undefined\n // Two decimals: the device's float32 noise has no place in the saved file.\n return Math.round(Math.min(Math.max(e.pressure, 0), 1) * 100) / 100\n}\n\n/** True when the samples carry real pressure: not all 0 or 0.5, the values of a device with none. */\nexport function reportsPressure(samples: readonly number[]): boolean {\n return samples.some((p) => p !== 0 && p !== 0.5)\n}\n\n/**\n * A tool in the `ink` style group that captures freehand strokes and previews them in\n * `.ink-draft[data-ink-draft=<id>]`.\n */\nexport function freehandTool(opts: FreehandOptions): Tool {\n let ctx: ToolContext | undefined\n let stroke: Stroke | undefined\n let draft: HTMLElement | undefined\n\n const clear = (): void => {\n draft?.remove()\n draft = undefined\n stroke = undefined\n }\n\n /** Adds a sample. A release reports 0 pressure, so it repeats the last sample's instead. */\n const sample = (s: Stroke, e: PointerEvent, release = false): void => {\n const css = clampedCssIn(s.from.host, e)\n s.css.push(css)\n s.user.push(s.from.transform.fromCss(css))\n const p = release ? s.pressure?.[s.pressure.length - 1] : pressureOf(e)\n if (p !== undefined) (s.pressure ??= []).push(p)\n }\n\n const paint = (c: ToolContext, s: Stroke): void => {\n const host = s.from.host\n const doc = host.ownerDocument\n if (!draft) {\n draft = doc.createElement('div')\n draft.className = 'ink-draft'\n draft.dataset.inkDraft = opts.id\n draft.style.position = 'absolute'\n draft.style.pointerEvents = 'none'\n draft.style.left = '0'\n draft.style.top = '0'\n host.append(draft)\n }\n draft.style.width = `${host.clientWidth}px`\n draft.style.height = `${host.clientHeight}px`\n const blank: AnnotationInput & { type: 'ink' } = {\n type: 'ink',\n page: s.from.page,\n inklist: [[]],\n }\n const style = c.toolStyle.resolve('ink', blank)\n const path = doc.createElementNS(SVG_NS, 'path')\n path.setAttribute(\n 'd',\n outlinePath(\n strokeOutline(s.css, s.pressure, s.from.transform.toCssLength(style.width ?? 2))\n )\n )\n path.setAttribute('fill', style.color ?? '#000000')\n if (style.opacity !== undefined) path.setAttribute('opacity', String(style.opacity))\n const svg = doc.createElementNS(SVG_NS, 'svg')\n svg.setAttribute('width', String(host.clientWidth))\n svg.setAttribute('height', String(host.clientHeight))\n svg.style.overflow = 'visible'\n svg.append(path)\n draft.replaceChildren(svg)\n }\n\n return {\n id: opts.id,\n kind: 'sticky',\n cursor: 'crosshair',\n styleGroup: 'ink',\n activate(c) {\n ctx = c\n },\n deactivate() {\n clear()\n opts.end?.()\n opts.deactivate?.()\n ctx = undefined\n },\n onPointerDown(e, hit) {\n if (!hit) return\n stroke = {\n from: hit,\n css: [],\n user: [],\n pressure: undefined,\n startedAt: Date.now(),\n }\n sample(stroke, e)\n // Drawing over an annotation draws; it neither selects it nor starts a text selection.\n e.stopPropagation()\n e.preventDefault()\n return true\n },\n onPointerMove(e) {\n if (!ctx || !stroke) return\n // No button down: the release was missed, so drop the stroke. A host scrolled out of the\n // mounted range is gone with it.\n if (e.buttons === 0 || !stroke.from.host.isConnected) {\n clear()\n return\n }\n const coalesced = e.getCoalescedEvents?.() ?? []\n for (const ev of coalesced.length > 0 ? coalesced : [e]) sample(stroke, ev)\n paint(ctx, stroke)\n },\n onPointerCancel() {\n clear()\n },\n onPointerUp(e) {\n if (!ctx || !stroke) return\n const s = stroke\n if (!s.from.host.isConnected) {\n clear()\n return\n }\n const last = s.css[s.css.length - 1]!\n const end = clampedCssIn(s.from.host, e)\n if (end.x !== last.x || end.y !== last.y) sample(s, e, true)\n clear()\n opts.commit(ctx, {\n page: s.from.page,\n points: s.user,\n pressure: s.pressure && reportsPressure(s.pressure) ? s.pressure : undefined,\n startedAt: s.startedAt,\n })\n },\n onKeyDown(e) {\n if (e.key !== 'Escape') return\n // Drops a stroke in progress too, so the release that follows commits nothing.\n clear()\n opts.end?.()\n },\n }\n}\n","// Freehand ink. A press-drag-release is one stroke; strokes that start within JOIN_GAP_MS of\n// the last one join its annotation, so a handwritten word stays one object. Each stroke is its\n// own undo step: the first is an `add`, the rest are `update`s that append to `inklist`.\n// Switching tools or pressing Escape ends the annotation. Pen and touch report pressure;\n// a mouse, or a device that always reports 0 or 0.5, leaves it out.\nimport { deriveRect } from '../../model/annotations/store'\nimport { JOIN_GAP_MS } from '../ink-stroke'\n\nimport { freehandTool } from './freehand'\n\nimport type { Tool, ToolContext } from './controller'\nimport type { InkAnnotation } from '../../model/annotations/types'\nimport type { Point } from '../../model/geometry'\n\n/** The annotation later strokes join, until the gap passes or something ends it. */\ninterface Session {\n id: string\n page: number\n endedAt: number\n}\n\nexport function drawTool(): Tool {\n let session: Session | undefined\n\n const join = (\n c: ToolContext,\n ink: InkAnnotation,\n points: Point[],\n pressure: number[] | undefined\n ): void => {\n const inklist = [...ink.inklist, points]\n // A stroke without pressure takes 0.5 throughout, which draws as no pressure does.\n const even = (p: Point[]): number[] => p.map(() => 0.5)\n const next =\n ink.pressure || pressure\n ? [...(ink.pressure ?? ink.inklist.map(even)), pressure ?? even(points)]\n : undefined\n c.store.update(ink.id, {\n inklist,\n pressure: next,\n rect: deriveRect({ type: 'ink', page: ink.page, inklist, width: ink.width }),\n })\n }\n\n return freehandTool({\n id: 'draw',\n end() {\n session = undefined\n },\n /** Appends the stroke to the live session's annotation, else starts a new one. */\n commit(c, s) {\n // The gap runs from the last stroke's release to this one's press. Under a host that\n // applies changes later, the last stroke may be proposed but not yet applied.\n const joined = session\n const current =\n joined && joined.page === s.page && s.startedAt - joined.endedAt <= JOIN_GAP_MS\n ? (c.store._getProposed(joined.id) ?? c.store.get(joined.id))\n : undefined\n if (current?.type === 'ink' && !current.locked) {\n join(c, current, s.points, s.pressure)\n session = { id: current.id, page: current.page, endedAt: Date.now() }\n return\n }\n const added = c.store.add(\n c.toolStyle.resolve('ink', {\n type: 'ink',\n page: s.page,\n inklist: [s.points],\n ...(s.pressure ? { pressure: [s.pressure] } : {}),\n })\n )\n session = { id: added.id, page: added.page, endedAt: Date.now() }\n },\n })\n}\n","// A click places a text box with its top-left corner at the press, a drag sizes one, and Enter\n// on the viewport places one at the centre of the current page. Each new box opens straight\n// into the in-place editor, and joins the store, selected, once it has text. The live draft is\n// `.ink-draft[data-ink-draft='freetext']`, `position:absolute; pointer-events:none`: geometry\n// only, the look is the theme's.\nimport { closedEditor, editFreeText, type FreeTextEditor } from '../freetext-editor'\nimport { renderAnnotationContent } from '../overlay-render'\n\nimport {\n clampedCssIn,\n isViewportEnter,\n type PageHit,\n type Tool,\n type ToolContext,\n} from './controller'\n\nimport type { AnnotationInput } from '../../model/annotations/types'\nimport type { CssRect } from '../transform'\n\ntype FreeTextInput = Extract<AnnotationInput, { type: 'freetext' }>\n\n/** Width of a box placed with a click or Enter, user-space points. */\nexport const DEFAULT_FREETEXT_WIDTH = 144\n\n/** Line height as a multiple of the font size, as the theme sets it. */\nconst LINE_HEIGHT = 1.2\n\n/** Font size a box gets when neither the text group nor the input sets one, points. */\nconst FONT_SIZE = 12\n\n/** Smallest drag, in CSS px on each axis, that sizes a box rather than counting as a click. */\nconst MIN_CSS = 3\n\nexport function freetextTool(): Tool {\n let ctx: ToolContext | undefined\n let start: PageHit | undefined\n let draft: HTMLElement | undefined\n\n const clear = (): void => {\n draft?.remove()\n draft = undefined\n start = undefined\n }\n\n /** The new box being typed into: it joins the store on its first non-empty commit. */\n let pending: FreeTextEditor | undefined\n\n /**\n * Opens an editor on a new box on `page` over `css` (the page host's CSS px), or, without a\n * box, one line high and `DEFAULT_FREETEXT_WIDTH` wide with its top-left at `at` (or centred\n * on it). The box is a stand-in element until the first commit with text, which adds and\n * selects it: creating and typing are one change and one undo step, and an empty box never\n * reaches the store.\n */\n const place = (\n c: ToolContext,\n page: number,\n css: CssRect | { at: { x: number; y: number }; centred: boolean }\n ): void => {\n const host = c.viewport.hostFor(page)\n if (!host) return\n pending?.close(true)\n const t = c.viewport.transformFor(page)\n const blank: FreeTextInput = { type: 'freetext', page, contents: '' }\n const input = c.toolStyle.resolve('text', blank)\n let box: CssRect\n if ('at' in css) {\n const size = input.defaultStyle?.fontSize ?? FONT_SIZE\n const border = input.width ?? 0\n const width = t.toCssLength(DEFAULT_FREETEXT_WIDTH)\n const height = t.toCssLength(size * LINE_HEIGHT + border * 2)\n box = css.centred\n ? { left: css.at.x - width / 2, top: css.at.y - height / 2, width, height }\n : { left: css.at.x, top: css.at.y, width, height }\n } else {\n box = css\n }\n const draftBox = c.store.completeInput({ ...input, rect: t.fromCssRect(box) })\n if (draftBox.type !== 'freetext') return\n const doc = host.ownerDocument\n // Laid out as the overlay lays out an annotation, stacked above the overlay (the theme\n // gives it z-index 1) so existing annotations under the new box neither cover its editor\n // nor take its presses.\n const el = doc.createElement('div')\n el.className = 'ink-annotation'\n el.dataset.inkPending = ''\n el.dataset.type = 'freetext'\n el.tabIndex = -1\n el.style.cssText = `position:absolute;left:${box.left}px;top:${box.top}px;width:${box.width}px;height:${box.height}px;pointer-events:none;z-index:2;`\n host.append(el)\n renderAnnotationContent(el, draftBox, t)\n\n // A new zoom or rotation commits the box as it stands, as does its page unmounting.\n const view = [\n ...[c.viewport.scale, c.viewport.rotation].map((r) =>\n r.subscribe(() => editor.close(true))\n ),\n c.viewport.mounted.subscribe((pages) => {\n if (!pages.includes(page)) editor.close(true)\n }),\n ]\n const done = (): void => {\n view.forEach((stop) => stop())\n el.remove()\n if (pending === editor) pending = undefined\n }\n /** After the stand-in goes: focus the new box, else the viewport, never <body>. */\n const refocus = (id?: string): void => {\n // Focus that already moved on (a click on a control) stays there.\n const active = doc.activeElement\n if (active && active !== doc.body && active !== el) return\n const drawn =\n id === undefined\n ? null\n : c.root.querySelector<HTMLElement>(`[data-annotation=\"${CSS.escape(id)}\"]`)\n if (drawn) drawn.focus({ preventScroll: true })\n else {\n if (!c.root.hasAttribute('tabindex')) c.root.tabIndex = -1\n c.root.focus({ preventScroll: true })\n }\n }\n const editor = editFreeText(el, draftBox, {\n transform: t,\n commit(contents, rect, _grown, how) {\n done()\n // An empty box makes nothing: the tool stays ready.\n if (contents.trim() === '') return refocus()\n const created = c.store.add({ ...input, id: draftBox.id, contents, rect })\n c.store.select([created.id])\n c.made([created.id])\n refocus(created.id)\n if (how === 'escape') c.done()\n },\n cancel() {\n done()\n refocus()\n },\n })\n pending = editor\n }\n\n const paint = (from: PageHit, e: PointerEvent): void => {\n const css = clampedCssIn(from.host, e)\n if (!draft) {\n draft = from.host.ownerDocument.createElement('div')\n draft.className = 'ink-draft'\n draft.dataset.inkDraft = 'freetext'\n draft.style.position = 'absolute'\n draft.style.pointerEvents = 'none'\n from.host.append(draft)\n }\n draft.style.left = `${Math.min(from.css.x, css.x)}px`\n draft.style.top = `${Math.min(from.css.y, css.y)}px`\n draft.style.width = `${Math.abs(css.x - from.css.x)}px`\n draft.style.height = `${Math.abs(css.y - from.css.y)}px`\n }\n\n return {\n id: 'freetext',\n kind: 'one-shot',\n cursor: 'text',\n styleGroup: 'text',\n defaultOptions: {},\n activate(c) {\n ctx = c\n },\n deactivate() {\n clear()\n pending?.close(true)\n ctx = undefined\n },\n onPointerDown(e, hit, annotationId) {\n // A press that ended an edit only ends it.\n if (!hit || annotationId !== undefined || closedEditor(e)) return\n start = hit\n // Keeps the press from starting a text selection or taking focus from the editor to be.\n e.preventDefault()\n return true\n },\n onPointerMove(e) {\n if (!start) return\n if (e.buttons === 0 || !start.host.isConnected) {\n clear()\n return\n }\n paint(start, e)\n },\n onPointerCancel() {\n clear()\n },\n onPointerUp(e) {\n const from = start\n clear()\n if (!ctx || !from || !from.host.isConnected) return\n const css = clampedCssIn(from.host, e)\n const dx = Math.abs(css.x - from.css.x)\n const dy = Math.abs(css.y - from.css.y)\n if (dx >= MIN_CSS && dy >= MIN_CSS) {\n place(ctx, from.page, {\n left: Math.min(from.css.x, css.x),\n top: Math.min(from.css.y, css.y),\n width: dx,\n height: dy,\n })\n } else {\n place(ctx, from.page, { at: from.css, centred: false })\n }\n },\n onKeyDown(e) {\n if (!ctx || !isViewportEnter(e, ctx.root)) return\n e.preventDefault()\n const page = ctx.viewport.currentPage.get()\n const t = ctx.viewport.transformFor(page)\n const { box } = t.page\n const middle = t.toCss({ x: box.x + box.width / 2, y: box.y + box.height / 2 })\n place(ctx, page, { at: middle, centred: true })\n },\n }\n}\n","import { isViewportEnter, type Tool, type ToolContext } from './controller'\n\nimport type { TextMarkupAnnotation } from '../../model/annotations/types'\n\nexport type MarkupKind = TextMarkupAnnotation['type']\n\n/** The text markup kinds, in menu order. */\nexport const MARKUP_KINDS: readonly MarkupKind[] = [\n 'highlight',\n 'underline',\n 'strikeout',\n 'squiggly',\n]\n\nexport interface HighlightOptions {\n /** Which text markup the tool makes. */\n kind: MarkupKind\n}\n\nexport const DEFAULT_HIGHLIGHT_OPTIONS: Readonly<HighlightOptions> = { kind: 'highlight' }\n\n/**\n * Turns the text selection into one markup of the chosen kind per page when the pointer is\n * released, or on Enter in the viewport (a keyboard selection), and selects what it made.\n * Without a selection both do nothing. The markup's `contents` is left for a comment: hosts\n * read the marked text with `doc.text(page)`.\n */\nexport function highlightTool(): Tool<HighlightOptions> {\n let ctx: ToolContext | undefined\n const convert = (): boolean => {\n if (!ctx) return false\n const selections = ctx.selectionQuads()\n if (selections.length === 0) return false\n const { kind } = { ...DEFAULT_HIGHLIGHT_OPTIONS, ...ctx.options<HighlightOptions>() }\n const ids: string[] = []\n for (const s of selections) {\n const a = ctx.store.add(\n ctx.toolStyle.resolve('markup', { type: kind, page: s.page, quads: s.quads })\n )\n ids.push(a.id)\n }\n ctx.clearSelection()\n ctx.store.select(ids)\n return true\n }\n return {\n id: 'highlight',\n kind: 'sticky',\n cursor: 'text',\n styleGroup: 'markup',\n defaultOptions: { ...DEFAULT_HIGHLIGHT_OPTIONS },\n activate(c) {\n ctx = c\n },\n deactivate() {\n ctx = undefined\n },\n onPointerUp() {\n convert()\n },\n onKeyDown(e) {\n if (!!ctx && isViewportEnter(e, ctx.root) && convert()) e.preventDefault()\n },\n }\n}\n","import { isViewportEnter, type PageHit, type Tool, type ToolContext } from './controller'\n\nimport type { Point } from '../../model/geometry'\n\n/** Side of a new note's icon box, user-space points. */\nconst SIZE = 20\n\n/** Frames to wait for a controlled host to apply a new note before giving up on focusing it. */\nconst FOCUS_FRAMES = 10\n\n/**\n * Click places a note centred on the press. Enter in the viewport places one at the centre of\n * the current page and focuses it. Either way the note is selected and activated.\n */\nexport function noteTool(): Tool {\n let ctx: ToolContext | undefined\n let down: PageHit | undefined\n\n const place = (c: ToolContext, page: number, at: Point): string => {\n const a = c.store.add({\n type: 'text',\n icon: 'Comment',\n page,\n rect: { x: at.x - SIZE / 2, y: at.y - SIZE / 2, width: SIZE, height: SIZE },\n })\n c.store.select([a.id])\n c.made([a.id])\n return a.id\n }\n\n return {\n id: 'note',\n kind: 'one-shot',\n cursor: 'copy',\n activate(c) {\n ctx = c\n },\n deactivate() {\n ctx = undefined\n down = undefined\n },\n onPointerDown(_e, hit, annotationId) {\n down = annotationId === undefined ? hit : undefined\n return down !== undefined\n },\n onPointerCancel() {\n down = undefined\n },\n onPointerUp(_e, hit) {\n const pressed = down\n down = undefined\n if (!ctx || !pressed || !hit || hit.page !== pressed.page) return\n const id = place(ctx, hit.page, hit.user)\n ctx.onActivate?.(id)\n },\n onKeyDown(e) {\n if (!ctx || !isViewportEnter(e, ctx.root)) return\n e.preventDefault()\n const c = ctx\n const page = c.viewport.currentPage.get()\n const { box } = c.viewport.transformFor(page).page\n const id = place(c, page, { x: box.x + box.width / 2, y: box.y + box.height / 2 })\n focusWhenDrawn(c, id)\n c.onActivate?.(id)\n },\n }\n}\n\n/**\n * Focuses the note's overlay element. An uncontrolled store draws it synchronously; a\n * controlled host applies the change later, so wait a few frames, and give up if focus has\n * meanwhile moved off the viewport (a popover took it).\n */\nfunction focusWhenDrawn(ctx: ToolContext, id: string): void {\n const doc = ctx.root.ownerDocument\n const find = (): HTMLElement | null =>\n ctx.root.querySelector<HTMLElement>(`[data-annotation=\"${CSS.escape(id)}\"]`)\n const now = find()\n if (now) {\n now.focus({ preventScroll: true })\n return\n }\n let frames = 0\n const view = doc.defaultView\n const tick = (): void => {\n if (doc.activeElement !== ctx.root) return\n const el = find()\n if (el) el.focus({ preventScroll: true })\n else if (++frames < FOCUS_FRAMES) view?.requestAnimationFrame(tick)\n }\n view?.requestAnimationFrame(tick)\n}\n","// The live draft is `position:absolute; pointer-events:none` with left/top/width/height from\n// the drag: geometry only. Its look comes from the theme (`.ink-draft[data-ink-draft]`).\nimport { isTextMarkup } from '../../model/annotations/edit'\n\nimport {\n clampedCssIn,\n isViewportEnter,\n type PageHit,\n type Tool,\n type ToolContext,\n} from './controller'\n\n/** Smallest drag, in CSS px on each axis, that draws a box rather than counting as a click. */\nconst MIN_CSS = 3\n\nexport function redactAreaTool(): Tool {\n let ctx: ToolContext | undefined\n let start: PageHit | undefined\n let draft: HTMLElement | undefined\n\n /** Selects what the tool just added, together, and reports it made. */\n const made = (c: ToolContext, ids: string[]): void => {\n c.store.select(ids)\n c.made(ids)\n }\n\n /** Text redactions from the live selection, one per page. False when nothing is selected. */\n const fromSelection = (): boolean => {\n if (!ctx) return false\n const selections = ctx.selectionQuads()\n if (selections.length === 0) return false\n const c = ctx\n const ids = selections.map(\n (s) =>\n c.store.add(\n c.toolStyle.resolve('redact', { type: 'redact', page: s.page, quads: s.quads })\n ).id\n )\n c.clearSelection()\n made(c, ids)\n return true\n }\n\n const clear = (): void => {\n draft?.remove()\n draft = undefined\n start = undefined\n }\n\n return {\n id: 'redact-area',\n kind: 'one-shot',\n cursor: 'crosshair',\n styleGroup: 'redact',\n activate(c) {\n ctx = c\n },\n deactivate() {\n clear()\n ctx = undefined\n },\n onPointerDown(e, hit, annotationId) {\n if (!hit) return\n if (annotationId !== undefined) {\n // Text markup would let a drag through to text selection, which the next click here\n // turns into a text redaction. Claim the press instead, as rectangle select does: a\n // drag from markup draws an area, and a click redacts the live selection.\n const a = ctx?.store.get(annotationId)\n if (!a || !isTextMarkup(a)) return\n e.stopPropagation()\n }\n start = hit\n // Keeps the press from starting a text selection; an existing one survives for the\n // text-derived mode on pointerup.\n e.preventDefault()\n return true\n },\n onPointerMove(e) {\n if (!start) return\n // No button down: the release was missed, so drop the draft. A host scrolled out of\n // the mounted range is gone with it.\n if (e.buttons === 0 || !start.host.isConnected) {\n clear()\n return\n }\n const css = clampedCssIn(start.host, e)\n if (!draft) {\n draft = start.host.ownerDocument.createElement('div')\n draft.className = 'ink-draft'\n draft.dataset.inkDraft = 'redact'\n draft.style.position = 'absolute'\n draft.style.pointerEvents = 'none'\n start.host.append(draft)\n }\n draft.style.left = `${Math.min(start.css.x, css.x)}px`\n draft.style.top = `${Math.min(start.css.y, css.y)}px`\n draft.style.width = `${Math.abs(css.x - start.css.x)}px`\n draft.style.height = `${Math.abs(css.y - start.css.y)}px`\n },\n onPointerCancel() {\n clear()\n },\n onPointerUp(e) {\n if (!ctx || !start) return\n if (!start.host.isConnected) {\n clear()\n return\n }\n const css = clampedCssIn(start.host, e)\n const width = Math.abs(css.x - start.css.x)\n const height = Math.abs(css.y - start.css.y)\n if (width >= MIN_CSS && height >= MIN_CSS) {\n const rect = start.transform.fromCssRect({\n left: Math.min(start.css.x, css.x),\n top: Math.min(start.css.y, css.y),\n width,\n height,\n })\n const a = ctx.store.add(\n ctx.toolStyle.resolve('redact', { type: 'redact', page: start.page, rect })\n )\n made(ctx, [a.id])\n } else {\n fromSelection()\n }\n clear()\n },\n onKeyDown(e) {\n // The keyboard path for text marks: select text, then Enter.\n if (!!ctx && isViewportEnter(e, ctx.root) && fromSelection()) e.preventDefault()\n },\n }\n}\n","import { createSelectionEdit, type SelectionEdit } from './selection-edit'\n\nimport type { Tool } from './controller'\n\n/**\n * Rectangle select: a drag on empty space draws a marquee that selects the annotations it\n * touches (`Shift` adds to the selection). Presses on annotations select, move and resize them\n * as `select-text` does (selection-edit.ts).\n */\nexport function selectTool(): Tool {\n let edit: SelectionEdit | undefined\n return {\n id: 'select',\n cursor: 'default',\n activate(ctx) {\n edit = createSelectionEdit(ctx, { marquee: true })\n },\n deactivate() {\n edit?.reset()\n edit = undefined\n },\n onPointerDown: (e, hit, id) => edit?.onPointerDown(e, hit, id),\n onPointerMove: (e, hit) => edit?.onPointerMove(e, hit),\n onPointerUp: (e, hit) => edit?.onPointerUp(e, hit),\n onPointerCancel: () => edit?.onPointerCancel(),\n onKeyDown: (e) => edit?.onKeyDown(e),\n }\n}\n","import { createSelectionEdit, type SelectionEdit } from './selection-edit'\n\nimport type { Tool } from './controller'\n\n/**\n * The default tool. Text selection stays native: presses on text, and drags across text\n * markup, select text. Presses on other annotations select them, and drags move and resize\n * them (selection-edit.ts). There is no marquee.\n */\nexport function selectTextTool(): Tool {\n let edit: SelectionEdit | undefined\n return {\n id: 'select-text',\n cursor: 'auto',\n activate(ctx) {\n edit = createSelectionEdit(ctx)\n },\n deactivate() {\n edit?.reset()\n edit = undefined\n },\n onPointerDown: (e, hit, id) => edit?.onPointerDown(e, hit, id),\n onPointerMove: (e, hit) => edit?.onPointerMove(e, hit),\n onPointerUp: (e, hit) => edit?.onPointerUp(e, hit),\n onPointerCancel: () => edit?.onPointerCancel(),\n onKeyDown: (e) => edit?.onKeyDown(e),\n }\n}\n","// Drag draws a shape between the press and the release; a click, or Enter on the viewport,\n// places a default-size one. Enter places no loupe or mask: they are pointer-only. The live\n// draft is `position:absolute; pointer-events:none`, a box over the shape's bounds holding an\n// SVG preview: geometry only, the look comes from the theme\n// (`.ink-draft[data-ink-draft='shape']`).\nimport {\n calloutStroke,\n freeTextBox,\n withCalloutBounds,\n} from '../../model/annotations/callout'\nimport { isBubble } from '../../model/annotations/edit'\nimport {\n constrain,\n DEFAULT_SHAPE_OPTIONS,\n defaultEnds,\n isPointerOnlyKind,\n shapeInput,\n type ShapeOptions,\n} from '../../model/annotations/shape-geometry'\nimport { closedEditor, editFreeTextIn } from '../freetext-editor'\n\nimport {\n clampedCssIn,\n isViewportEnter,\n type PageHit,\n type Tool,\n type ToolContext,\n} from './controller'\n\nimport type {\n Annotation,\n AnnotationInput,\n FreeTextAnnotation,\n} from '../../model/annotations/types'\nimport type { Point } from '../../model/geometry'\n\nexport {\n DEFAULT_CORNER_RADIUS,\n DEFAULT_SHAPE_SIZE,\n SHAPE_KINDS,\n type ShapeKind,\n type ShapeOptions,\n} from '../../model/annotations/shape-geometry'\n\n/** Smallest drag, in CSS px on its longer axis, that draws a shape rather than counting as a click. */\nconst MIN_CSS = 3\n\nconst SVG_NS = 'http://www.w3.org/2000/svg'\n\nexport function shapeTool(): Tool<ShapeOptions> {\n let ctx: ToolContext | undefined\n let start: PageHit | undefined\n let draft: HTMLElement | undefined\n\n const clear = (): void => {\n draft?.remove()\n draft = undefined\n start = undefined\n }\n\n const options = (c: ToolContext): ShapeOptions => ({\n ...DEFAULT_SHAPE_OPTIONS,\n ...c.options<ShapeOptions>(),\n })\n\n /** The input for a drag from `a` to `b` (user space), with Shift's constraint applied. */\n const inputFor = (\n c: ToolContext,\n page: number,\n a: Point,\n b: Point,\n shift: boolean\n ): AnnotationInput | undefined => {\n const o = options(c)\n return shapeInput(o.kind, page, a, shift ? constrain(o.kind, a, b) : b, o)\n }\n\n /** The input with the shape group's style and, for a bubble, the text group's text style. */\n const styled = (c: ToolContext, input: AnnotationInput): AnnotationInput => {\n if (input.type === 'line') {\n // The line style menu's ends win; until it picks them an arrow has an open tail.\n const line = c.toolStyle.resolve('shape', input)\n const arrow = input.intent === 'LineArrow'\n return {\n ...line,\n head: line.head ?? 'None',\n tail: line.tail ?? (arrow ? 'OpenArrow' : 'None'),\n }\n }\n if (input.type !== 'freetext') return c.toolStyle.resolve('shape', input)\n // The group's width must not lose to the bubble's default one, so it is filled last.\n const shape = c.toolStyle.resolve('shape', { ...input, width: undefined })\n const blank: AnnotationInput & { type: 'freetext' } = {\n type: 'freetext',\n page: input.page,\n contents: '',\n }\n const text = c.toolStyle.resolve('text', blank)\n const out = {\n ...shape,\n width: shape.width ?? input.width,\n defaultStyle: { ...text.defaultStyle, ...input.defaultStyle },\n }\n if (!input.callout || !input.rect) return out\n // The bounds were fit to the bubble's default width: refit them to the group's.\n const box = freeTextBox({ rect: input.rect, fringe: input.fringe })\n const { width } = calloutStroke(out as FreeTextAnnotation)\n return { ...out, ...withCalloutBounds(box, input.callout, width, input.head) }\n }\n\n /** Stops waiting for a bubble the host has not applied yet. */\n let waiting: (() => void) | undefined\n\n const openEditor = (c: ToolContext, a: Annotation): boolean => {\n const el = c.root.querySelector<HTMLElement>(\n `[data-annotation=\"${CSS.escape(a.id)}\"]`\n )\n return (\n el !== null &&\n editFreeTextIn(c.store, el, a.id, c.viewport.transformFor(a.page), {\n // Escape ends the bubble's edit and the tool's use, unless the tool has gone already.\n onClose: (how) => {\n if (how === 'escape' && ctx === c) c.done()\n },\n }) !== undefined\n )\n }\n\n /**\n * Opens the in-place editor on a new bubble. When a controlled host has not applied it yet,\n * the editor opens once it does.\n */\n const edit = (c: ToolContext, a: Annotation): void => {\n waiting?.()\n waiting = undefined\n if (openEditor(c, a)) return\n const stop = c.store.list.subscribe(() => {\n if (!c.store.get(a.id)) return\n stop()\n if (waiting === stop) waiting = undefined\n openEditor(c, a)\n })\n waiting = stop\n }\n\n const add = (c: ToolContext, input: AnnotationInput | undefined): void => {\n if (!input) return\n const created = c.store.add(styled(c, input))\n c.store.select([created.id])\n c.made([created.id])\n if (isBubble(created)) edit(c, created)\n }\n\n const paint = (c: ToolContext, from: PageHit, e: PointerEvent): void => {\n const css = clampedCssIn(from.host, e)\n const user = from.transform.fromCss(css)\n const input = inputFor(c, from.page, from.user, user, e.shiftKey)\n if (!input) return\n const t = from.transform\n let box: { left: number; top: number; width: number; height: number }\n let points: Point[] | undefined\n let kind: 'rect' | 'ellipse' | 'path' = 'path'\n if (\n input.type === 'square' ||\n input.type === 'circle' ||\n input.type === 'freetext' ||\n input.type === 'loupe' ||\n input.type === 'mask'\n ) {\n if (!input.rect) return\n // A bubble previews its text box; its tail comes with the bubble itself.\n box = t.toCssRect(\n input.type === 'freetext'\n ? freeTextBox({ rect: input.rect, fringe: input.fringe })\n : input.rect\n )\n kind =\n input.type === 'circle' ||\n input.type === 'loupe' ||\n (input.type === 'mask' && input.shape === 'ellipse')\n ? 'ellipse'\n : 'rect'\n } else {\n if (input.type === 'line') points = [t.toCss(input.start), t.toCss(input.end)]\n else if (input.type === 'polygon') points = input.vertices.map((v) => t.toCss(v))\n else return\n const xs = points.map((p) => p.x)\n const ys = points.map((p) => p.y)\n const left = Math.min(...xs)\n const top = Math.min(...ys)\n box = {\n left,\n top,\n width: Math.max(...xs) - left,\n height: Math.max(...ys) - top,\n }\n }\n if (!draft) {\n draft = from.host.ownerDocument.createElement('div')\n draft.className = 'ink-draft'\n draft.dataset.inkDraft = 'shape'\n draft.style.position = 'absolute'\n draft.style.pointerEvents = 'none'\n from.host.append(draft)\n }\n draft.dataset.inkShape = options(c).kind\n draft.style.left = `${box.left}px`\n draft.style.top = `${box.top}px`\n draft.style.width = `${box.width}px`\n draft.style.height = `${box.height}px`\n const doc = from.host.ownerDocument\n const svg = doc.createElementNS(SVG_NS, 'svg')\n svg.setAttribute('width', String(box.width))\n svg.setAttribute('height', String(box.height))\n svg.style.overflow = 'visible'\n const node =\n kind === 'path'\n ? doc.createElementNS(SVG_NS, input.type === 'line' ? 'polyline' : 'polygon')\n : doc.createElementNS(SVG_NS, kind)\n if (kind === 'path') {\n node.setAttribute(\n 'points',\n (points ?? []).map((p) => `${p.x - box.left},${p.y - box.top}`).join(' ')\n )\n } else if (kind === 'ellipse') {\n node.setAttribute('cx', String(box.width / 2))\n node.setAttribute('cy', String(box.height / 2))\n node.setAttribute('rx', String(box.width / 2))\n node.setAttribute('ry', String(box.height / 2))\n } else {\n node.setAttribute('width', String(box.width))\n node.setAttribute('height', String(box.height))\n if ((input.type === 'square' || input.type === 'freetext') && input.cornerRadius)\n node.setAttribute('rx', String(t.toCssLength(input.cornerRadius)))\n }\n svg.append(node)\n draft.replaceChildren(svg)\n }\n\n return {\n id: 'shape',\n kind: 'one-shot',\n cursor: 'crosshair',\n styleGroup: 'shape',\n defaultOptions: { ...DEFAULT_SHAPE_OPTIONS },\n activate(c) {\n ctx = c\n },\n deactivate() {\n clear()\n waiting?.()\n waiting = undefined\n ctx = undefined\n },\n onPointerDown(e, hit, annotationId) {\n // A press that ended a bubble's edit only ends it.\n if (!hit || annotationId !== undefined || closedEditor(e)) return\n start = hit\n // Keeps the press from starting a text selection.\n e.preventDefault()\n return true\n },\n onPointerMove(e) {\n if (!ctx || !start) return\n // No button down: the release was missed, so drop the draft. A host scrolled out of the\n // mounted range is gone with it.\n if (e.buttons === 0 || !start.host.isConnected) {\n clear()\n return\n }\n paint(ctx, start, e)\n },\n onPointerCancel() {\n clear()\n },\n onPointerUp(e) {\n if (!ctx || !start) return\n const from = start\n if (!from.host.isConnected) {\n clear()\n return\n }\n const css = clampedCssIn(from.host, e)\n const long = Math.max(Math.abs(css.x - from.css.x), Math.abs(css.y - from.css.y))\n if (long >= MIN_CSS) {\n add(\n ctx,\n inputFor(ctx, from.page, from.user, from.transform.fromCss(css), e.shiftKey)\n )\n } else {\n const [a, b] = defaultEnds(\n options(ctx).kind,\n from.user,\n from.transform.page.rotate\n )\n add(ctx, inputFor(ctx, from.page, a, b, false))\n }\n clear()\n },\n onKeyDown(e) {\n if (!ctx || !isViewportEnter(e, ctx.root)) return\n // The loupe and the mask are pointer-only, like area redaction.\n if (isPointerOnlyKind(options(ctx).kind)) return\n e.preventDefault()\n const page = ctx.viewport.currentPage.get()\n const { box, rotate } = ctx.viewport.transformFor(page).page\n const [a, b] = defaultEnds(\n options(ctx).kind,\n { x: box.x + box.width / 2, y: box.y + box.height / 2 },\n rotate\n )\n add(ctx, inputFor(ctx, page, a, b, false))\n },\n }\n}\n","// Places the chosen signature template. A click puts it centred on the press, about 150 pt\n// wide; Enter in the viewport puts it at the centre of the current page. It is turned against\n// the page's own /Rotate, so it reads upright on the page as the file displays it; a view\n// rotation is the viewer's, and turns it with the page like any annotation. Ink takes the\n// `ink` group's colour at the template's own width; an image is placed as it is. Either way\n// the new annotation is selected and one undo step.\nimport {\n DEFAULT_SIGNATURE_WIDTH,\n placeSignature,\n type SignatureOptions,\n type SignatureTemplate,\n} from '../../model/signatures'\n\nimport { isViewportEnter, type PageHit, type Tool, type ToolContext } from './controller'\n\nimport type { Point } from '../../model/geometry'\nimport type { PageRotation } from '../../model/pages'\n\nexport type { SignatureOptions }\n\nexport function signatureTool(): Tool<SignatureOptions> {\n let ctx: ToolContext | undefined\n let down: PageHit | undefined\n /** Bumped on deactivate, so a load still pending from an earlier use places nothing. */\n let generation = 0\n\n const place = (\n c: ToolContext,\n t: SignatureTemplate,\n page: number,\n at: Point,\n rotation: PageRotation\n ): void => {\n const input = placeSignature(t, page, at, DEFAULT_SIGNATURE_WIDTH, rotation)\n const a = c.store.add(\n input.type === 'ink' ? c.toolStyle.resolve('ink', input) : input\n )\n c.store.select([a.id])\n c.made([a.id])\n }\n\n /**\n * Places the selected template, from the library at once, or after reloading it when the\n * template was saved since the last load. False when there is nothing to place.\n */\n const placeSelected = (\n c: ToolContext,\n page: number,\n at: Point,\n rotation: PageRotation\n ): boolean => {\n const id = c.options<SignatureOptions>().templateId\n const library = c.signatures\n if (id === undefined || !library) return false\n const t = library.get(id)\n if (t) {\n place(c, t, page, at, rotation)\n return true\n }\n const gen = generation\n void library.refresh().then(() => {\n // The tool may have been switched (even away and back), or the template removed.\n const later = library.get(id)\n if (\n later &&\n ctx === c &&\n gen === generation &&\n c.options<SignatureOptions>().templateId === id\n )\n place(c, later, page, at, rotation)\n })\n return true\n }\n\n return {\n id: 'signature',\n kind: 'one-shot',\n cursor: 'copy',\n defaultOptions: {},\n activate(c) {\n ctx = c\n },\n deactivate() {\n ctx = undefined\n down = undefined\n generation++\n },\n onPointerDown(_e, hit, annotationId) {\n down = annotationId === undefined ? hit : undefined\n return down !== undefined\n },\n onPointerMove(e) {\n // The release was missed: treat it as a cancel.\n if (e.buttons === 0) down = undefined\n },\n onPointerCancel() {\n down = undefined\n },\n onPointerUp(_e, hit) {\n const pressed = down\n down = undefined\n if (!ctx || !pressed || !hit || hit.page !== pressed.page) return\n placeSelected(ctx, hit.page, hit.user, hit.transform.page.rotate)\n },\n onKeyDown(e) {\n if (!ctx || !isViewportEnter(e, ctx.root)) return\n const page = ctx.viewport.currentPage.get()\n const t = ctx.viewport.transformFor(page)\n const { box } = t.page\n const centre = { x: box.x + box.width / 2, y: box.y + box.height / 2 }\n if (placeSelected(ctx, page, centre, t.page.rotate)) e.preventDefault()\n },\n }\n}\n","// Freehand ink that tidies itself. It captures and previews strokes as `draw` does, but each\n// stroke stands alone: sketch never joins strokes. On release the stroke is added as ink, then\n// `recogniseStroke` scores it; a fit at `RECOGNISE_THRESHOLD` or better replaces the ink with\n// the clean shape, styled from the `shape` group. Two undo steps: the ink, then the swap (one\n// `history.batch`), so one undo brings the stroke back and a second removes it.\n//\n// A controlled host applies the ink later, or never. The swap waits until the ink is in the\n// list, then a task more, so the host's own history records the ink as a step before the swap.\n// Deactivating the tool cancels a swap still waiting.\nimport { DEFAULT_SHAPE_OPTIONS, shapeInput } from '../../model/annotations/shape-geometry'\nimport {\n recogniseStroke,\n RECOGNISE_THRESHOLD,\n type Recognised,\n} from '../../model/recognise'\n\nimport { freehandTool } from './freehand'\n\nimport type { Tool, ToolContext } from './controller'\nimport type { AnnotationInput } from '../../model/annotations/types'\n\n/** How long the swap waits for a controlled host to apply the ink before giving up. */\nconst APPLY_WAIT_MS = 2000\n\n/**\n * The smallest stroke, in CSS px across its longer side, that can become a shape. A click or\n * its jitter stays a dot of ink, as with `draw`, rather than an invisible sliver of a line.\n */\nconst MIN_SHAPE_PX = 4\n\n/** The longer side of the box `points` span, in the units they are in. */\nfunction extent(points: readonly { x: number; y: number }[]): number {\n const xs = points.map((p) => p.x)\n const ys = points.map((p) => p.y)\n return Math.max(Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys))\n}\n\n/** The annotation a recognised stroke becomes. */\nfunction recognisedInput(shape: Recognised, page: number): AnnotationInput | undefined {\n switch (shape.kind) {\n case 'line':\n case 'arrow':\n return shapeInput(shape.kind, page, shape.start, shape.end, DEFAULT_SHAPE_OPTIONS)\n case 'rectangle':\n case 'ellipse': {\n const { x, y, width, height } = shape.rect\n return shapeInput(\n shape.kind,\n page,\n { x, y },\n { x: x + width, y: y + height },\n DEFAULT_SHAPE_OPTIONS\n )\n }\n // The recogniser already tidied the vertices: a polygon keeps the corners the stroke had,\n // a star is regular.\n case 'polygon':\n case 'star':\n return { type: 'polygon', page, vertices: shape.vertices }\n }\n}\n\n/**\n * Runs `fn` once the annotation `id` is in the list and the host has had a task to record it.\n * Gives up (calling `onGiveUp`) when the host has not applied it in `APPLY_WAIT_MS`. Returns a\n * cancel that drops whatever is still pending.\n */\nfunction whenApplied(\n c: ToolContext,\n id: string,\n fn: () => void,\n onGiveUp: () => void\n): () => void {\n if (c.store.get(id)) {\n fn()\n return () => undefined\n }\n let swap: ReturnType<typeof setTimeout> | undefined\n // Every timer and the subscription exist before anything can call `cancel`.\n const giveUp = setTimeout(() => {\n cancel()\n onGiveUp()\n }, APPLY_WAIT_MS)\n let stop: (() => void) | undefined = c.store.list.subscribe(() => {\n if (!c.store.get(id)) return\n cancel()\n swap = setTimeout(fn, 0)\n })\n function cancel(): void {\n stop?.()\n stop = undefined\n clearTimeout(giveUp)\n clearTimeout(swap)\n }\n return cancel\n}\n\nexport function sketchTool(): Tool {\n /** Cancels for swaps still waiting on a controlled host. */\n const pending = new Set<() => void>()\n return freehandTool({\n id: 'sketch',\n // Switching tools or tearing the viewer down drops any swap still waiting: the stroke\n // stays ink, and nothing fires against a store that may be gone.\n deactivate() {\n for (const cancel of pending) cancel()\n pending.clear()\n },\n commit(c, s) {\n const ink = c.store.add(\n c.toolStyle.resolve('ink', {\n type: 'ink',\n page: s.page,\n inklist: [s.points],\n ...(s.pressure ? { pressure: [s.pressure] } : {}),\n })\n )\n if (c.viewport.transformFor(s.page).toCssLength(extent(s.points)) < MIN_SHAPE_PX)\n return\n const fit = recogniseStroke(s.points)\n if (!fit || fit.score < RECOGNISE_THRESHOLD) return\n const input = recognisedInput(fit.shape, s.page)\n if (!input) return\n const shape = c.toolStyle.resolve('shape', input)\n const batch = (fn: () => void): void => (c.history ? c.history.batch(fn) : fn())\n // Uncontrolled, the swap runs straight away, before `whenApplied` returns.\n let ran = false\n let cancel = (): void => undefined\n cancel = whenApplied(\n c,\n ink.id,\n () => {\n ran = true\n pending.delete(cancel)\n // Undone, or changed, before the swap: leave the stroke as it is. A host may hand back\n // copies, so the check is by modification time, not identity.\n if (c.store.get(ink.id)?.modifiedAt !== ink.modifiedAt) return\n batch(() => {\n c.store.remove(ink.id)\n c.store.add(shape)\n })\n },\n () => pending.delete(cancel)\n )\n if (!ran) pending.add(cancel)\n },\n })\n}\n","import { createToolStyle, type ToolStyle } from '../../model/annotations/tool-style'\nimport { writable } from '../../model/readable'\n\nimport {\n createToolController as createWith,\n type Tool,\n type ToolControllerOptions,\n type ToolController,\n type ToolId,\n} from './controller'\nimport { drawTool } from './draw'\nimport { DEFAULT_FREETEXT_WIDTH, freetextTool } from './freetext'\nimport { highlightTool } from './highlight'\nimport { noteTool } from './note'\nimport { redactAreaTool } from './redact-area'\nimport { selectTool } from './select'\nimport { selectTextTool } from './select-text'\nimport { shapeTool } from './shape'\nimport { signatureTool } from './signature'\nimport { sketchTool } from './sketch'\n\nimport type { AnnotationStore } from '../../model/annotations/store'\n\nexport type {\n BuiltinToolId,\n PageHit,\n Tool,\n ToolContext,\n ToolController,\n ToolControllerOptions,\n ToolId,\n ToolKind,\n} from './controller'\nexport { hitFor } from './controller'\nexport { createToolOptions, type ToolOptions } from './options'\nexport {\n DEFAULT_FREETEXT_WIDTH,\n drawTool,\n freetextTool,\n highlightTool,\n noteTool,\n redactAreaTool,\n selectTextTool,\n selectTool,\n shapeTool,\n signatureTool,\n sketchTool,\n}\nexport type { SignatureOptions } from './signature'\nexport {\n DEFAULT_HIGHLIGHT_OPTIONS,\n MARKUP_KINDS,\n type HighlightOptions,\n type MarkupKind,\n} from './highlight'\nexport {\n DEFAULT_CORNER_RADIUS,\n DEFAULT_SHAPE_SIZE,\n SHAPE_KINDS,\n type ShapeKind,\n type ShapeOptions,\n} from './shape'\n\n/** Fresh instances of every built-in tool. */\nexport function builtinTools(): Tool[] {\n return [\n selectTextTool(),\n selectTool(),\n highlightTool(),\n redactAreaTool(),\n sketchTool(),\n drawTool(),\n noteTool(),\n shapeTool(),\n freetextTool(),\n signatureTool(),\n ]\n}\n\n/** The built-in tools with a host's tools added, a host tool replacing a built-in by id. */\nexport function withHostTools(host: readonly Tool[] = []): Tool[] {\n const byId = new Map(builtinTools().map((t) => [t.id, t]))\n for (const t of host) byId.set(t.id, t)\n return [...byId.values()]\n}\n\n/** Listens on `ctx.root` and routes pointer and key events to the active tool. */\nexport function createToolController(\n opts: Omit<ToolControllerOptions, 'tools'> & { tools?: Tool[] }\n): ToolController {\n return createWith({ ...opts, tools: opts.tools ?? builtinTools() })\n}\n\nexport interface ToolStyleTracker {\n readonly toolStyle: ToolStyle\n /** Call when the active tool changes: the style's active group follows it. */\n setTool(id: ToolId): void\n}\n\n/**\n * A `ToolStyle` whose active group is the style group of the active tool among `tools` (the\n * built-ins plus a host's). The engine makes one when it is not handed a style; a binding\n * makes its own per document, so its style controls work before the viewport mounts.\n */\nexport function trackToolStyle(opts: {\n store: AnnotationStore\n history: { batch(fn: () => void): void }\n /** Host tools, as passed to `mountViewer`. */\n tools?: readonly Tool[] | undefined\n tool?: ToolId | undefined\n}): ToolStyleTracker {\n const groups = new Map(withHostTools(opts.tools).map((t) => [t.id, t.styleGroup]))\n const active = writable<ToolId>(opts.tool ?? 'select-text')\n const toolStyle = createToolStyle({\n store: opts.store,\n history: opts.history,\n activeGroup: () => groups.get(active.get()),\n active,\n })\n return { toolStyle, setTool: (id) => active.set(id) }\n}\n","// The swatches the colour menus offer: a row of common colours, a row of greys, and a tonal\n// grid. Every value is upper-case #RRGGBB, so a style's colour compares to a swatch directly.\n\nexport interface Palette {\n /** 12 swatches, the top row. */\n readonly common: readonly string[]\n /** 12 greys, white to black. */\n readonly greys: readonly string[]\n /** 8 rows of 12 hue columns (red round to rose in 30 degree steps), dark to light. */\n readonly grid: readonly (readonly string[])[]\n}\n\nexport const PALETTE: Palette = {\n common: [\n '#FF3B30',\n '#FF9500',\n '#FFCC00',\n '#34C759',\n '#00C7BE',\n '#32ADE6',\n '#007AFF',\n '#5856D6',\n '#AF52DE',\n '#FF2D55',\n '#A2845E',\n '#8E8E93',\n ],\n greys: [\n '#FFFFFF',\n '#E8E8E8',\n '#D1D1D1',\n '#B9B9B9',\n '#A2A2A2',\n '#8B8B8B',\n '#747474',\n '#5D5D5D',\n '#464646',\n '#2E2E2E',\n '#171717',\n '#000000',\n ],\n grid: [\n [\n '#590D0D',\n '#59330D',\n '#59590D',\n '#33590D',\n '#0D590D',\n '#0D5933',\n '#0D5959',\n '#0D3359',\n '#0D0D59',\n '#330D59',\n '#590D59',\n '#590D33',\n ],\n [\n '#861313',\n '#864D13',\n '#868613',\n '#4D8613',\n '#138613',\n '#13864D',\n '#138686',\n '#134D86',\n '#131386',\n '#4D1386',\n '#861386',\n '#86134D',\n ],\n [\n '#B31919',\n '#B36619',\n '#B3B319',\n '#66B319',\n '#19B319',\n '#19B366',\n '#19B3B3',\n '#1966B3',\n '#1919B3',\n '#6619B3',\n '#B319B3',\n '#B31966',\n ],\n [\n '#DF2020',\n '#DF8020',\n '#DFDF20',\n '#80DF20',\n '#20DF20',\n '#20DF80',\n '#20DFDF',\n '#2080DF',\n '#2020DF',\n '#8020DF',\n '#DF20DF',\n '#DF2080',\n ],\n [\n '#E64C4C',\n '#E6994C',\n '#E6E64C',\n '#99E64C',\n '#4CE64C',\n '#4CE699',\n '#4CE6E6',\n '#4C99E6',\n '#4C4CE6',\n '#994CE6',\n '#E64CE6',\n '#E64C99',\n ],\n [\n '#EC7979',\n '#ECB379',\n '#ECEC79',\n '#B3EC79',\n '#79EC79',\n '#79ECB3',\n '#79ECEC',\n '#79B3EC',\n '#7979EC',\n '#B379EC',\n '#EC79EC',\n '#EC79B3',\n ],\n [\n '#F2A6A6',\n '#F2CCA6',\n '#F2F2A6',\n '#CCF2A6',\n '#A6F2A6',\n '#A6F2CC',\n '#A6F2F2',\n '#A6CCF2',\n '#A6A6F2',\n '#CCA6F2',\n '#F2A6F2',\n '#F2A6CC',\n ],\n [\n '#F9D2D2',\n '#F9E6D2',\n '#F9F9D2',\n '#E6F9D2',\n '#D2F9D2',\n '#D2F9E6',\n '#D2F9F9',\n '#D2E6F9',\n '#D2D2F9',\n '#E6D2F9',\n '#F9D2F9',\n '#F9D2E6',\n ],\n ],\n}\n","// Vocabulary the framework packages share: labels, zoom levels and the props they hand to\n// host-rendered content. Core owns these so Vue and React cannot drift apart.\nimport { isKnown, LINE_ENDINGS } from '../model/annotations/pdf-names'\n\nimport { PALETTE } from './palette'\n\nimport type {\n HighlightOptions,\n MarkupKind,\n ShapeKind,\n ShapeOptions,\n ToolId,\n} from './tools'\nimport type { CurrentStyle, StyleKey, StyleProps } from '../model/annotations/tool-style'\nimport type {\n Annotation,\n LineEnding,\n NoteAnnotation,\n TextMarkupAnnotation,\n} from '../model/annotations/types'\nimport type { SignatureOptions, SignatureTemplate } from '../model/signatures'\n\n/**\n * Accessible names of the built-in tools, as the toolbar buttons announce them. A host tool has\n * no entry: its button takes the host's `label`, else the tool id.\n */\nexport const TOOL_LABELS: Readonly<Partial<Record<ToolId, string>>> = {\n 'select-text': 'Select text',\n select: 'Rectangle select',\n highlight: 'Highlight',\n 'redact-area': 'Mark for redaction',\n sketch: 'Sketch',\n draw: 'Draw',\n note: 'Add note',\n shape: 'Shape',\n freetext: 'Text',\n signature: 'Sign',\n}\n\n/**\n * The font families a text box offers by default: the PDF standard families, which a PDF\n * writer can use without embedding a font. Hosts pass their own list as `fonts`.\n */\nexport const FONT_FAMILIES: readonly string[] = ['Helvetica', 'Times', 'Courier']\n\n/**\n * The fonts a typed signature offers by default: the browser's own handwriting family. Hosts\n * load handwriting fonts and pass them as `signatureFonts`.\n */\nexport const SIGNATURE_FONTS: readonly string[] = ['cursive']\n\n/** Zoom levels the zoom select offers, as scale factors. */\nexport const ZOOM_LEVELS: readonly number[] = [0.5, 0.75, 1, 1.25, 1.5, 2, 3, 4]\n\n/** Stroke weights the line style menu offers, in points. */\nexport const LINE_WEIGHTS: readonly number[] = [0.5, 1, 2, 3, 4, 6, 8]\n\n/** The dash pattern the menu's dashed choice writes, in points. */\nexport const DASH_PATTERN: readonly number[] = [3, 3]\n\n/** The ending the menu's arrowhead choices draw. */\nexport const ARROWHEAD_ENDING: LineEnding = 'OpenArrow'\n\nexport type ArrowheadChoice = 'none' | 'start' | 'end' | 'both'\n\n/** The arrowhead choices in menu order, with the style each one writes (`head` is the start). */\nexport const ARROWHEAD_CHOICES: readonly {\n value: ArrowheadChoice\n label: string\n patch: Pick<StyleProps, 'head' | 'tail'>\n}[] = [\n { value: 'none', label: 'No arrowheads', patch: { head: 'None', tail: 'None' } },\n {\n value: 'start',\n label: 'Arrowhead at start',\n patch: { head: ARROWHEAD_ENDING, tail: 'None' },\n },\n {\n value: 'end',\n label: 'Arrowhead at end',\n patch: { head: 'None', tail: ARROWHEAD_ENDING },\n },\n {\n value: 'both',\n label: 'Arrowheads at both ends',\n patch: { head: ARROWHEAD_ENDING, tail: ARROWHEAD_ENDING },\n },\n]\n\n/**\n * Which arrowhead choice a style shows, `'mixed'` when the selection disagrees, else `undefined`.\n * Only an ending Inkbar draws counts: one it does not know draws as `None`.\n */\nexport function arrowheadChoice(\n head: LineEnding | 'mixed' | undefined,\n tail: LineEnding | 'mixed' | undefined\n): ArrowheadChoice | 'mixed' | undefined {\n if (head === undefined && tail === undefined) return undefined\n if (head === 'mixed' || tail === 'mixed') return 'mixed'\n const drawn = (e: LineEnding | undefined) =>\n e !== undefined && e !== 'None' && isKnown(LINE_ENDINGS, e)\n const start = drawn(head)\n const end = drawn(tail)\n return start ? (end ? 'both' : 'start') : end ? 'end' : 'none'\n}\n\nexport interface LineStyleMenuItem {\n key: string\n label: string\n checked: boolean\n /** What choosing the item writes through the tool style. */\n patch: StyleProps\n}\n\nexport interface LineStyleMenuSection {\n label: string\n /** The selection or active tool supports none of the section's props. */\n disabled: boolean\n items: LineStyleMenuItem[]\n}\n\nexport interface LineStyleMenuModel {\n /** False when nothing supports weight, pattern or endings: the trigger disables. */\n enabled: boolean\n /** The selection disagrees on weight, pattern or endings. */\n mixed: boolean\n sections: LineStyleMenuSection[]\n}\n\n/**\n * What the line style menu shows for a style: sections of checkable items, each section\n * disabled when `supported` lacks its props. A section whose value is mixed checks nothing.\n * Shared by the bindings and the vanilla menu so they cannot drift apart.\n */\nexport function lineStyleMenuModel(\n current: CurrentStyle,\n supported: ReadonlySet<StyleKey>\n): LineStyleMenuModel {\n const canWeight = supported.has('width')\n const canDash = supported.has('dashes')\n const canEnds = supported.has('head') || supported.has('tail')\n const dashed = Array.isArray(current.dashes) && current.dashes.length > 0\n const ends = arrowheadChoice(current.head, current.tail)\n return {\n enabled: canWeight || canDash || canEnds,\n mixed: (['width', 'dashes', 'head', 'tail'] as const).some(\n (k) => current[k] === 'mixed'\n ),\n sections: [\n {\n label: 'Weight',\n disabled: !canWeight,\n items: LINE_WEIGHTS.map((w) => ({\n key: String(w),\n label: `${w} pt`,\n checked: current.width === w,\n patch: { width: w },\n })),\n },\n {\n label: 'Pattern',\n disabled: !canDash,\n items: [\n {\n key: 'solid',\n label: 'Solid',\n checked: current.dashes === null,\n patch: { dashes: null },\n },\n {\n key: 'dashed',\n label: 'Dashed',\n checked: dashed,\n patch: { dashes: [...DASH_PATTERN] },\n },\n ],\n },\n {\n label: 'Arrowheads',\n disabled: !canEnds,\n items: ARROWHEAD_CHOICES.map((c) => ({\n key: c.value,\n label: c.label,\n checked: ends === c.value,\n patch: c.patch,\n })),\n },\n ],\n }\n}\n\n/** The colour props a colour menu can set. */\nexport type ColorProperty = 'border' | 'fill' | 'textColor'\n\n/** Accessible names of the colour menus, by property. */\nexport const COLOR_LABELS: Readonly<Record<ColorProperty, string>> = {\n border: 'Border colour',\n fill: 'Fill colour',\n textColor: 'Text colour',\n}\n\n/** Columns of the swatch grid: the arrow keys move by this much between rows. */\nexport const COLOR_COLUMNS = 12\n\nexport interface ColorMenuSwatch {\n /** Unique within the menu. */\n key: string\n /** The swatch's accessible name: its hex value. */\n label: string\n color: string\n checked: boolean\n patch: StyleProps\n}\n\n/** What the trigger's swatch shows. */\nexport type ColorTrigger =\n | { kind: 'color'; color: string }\n /** No fill. */\n | { kind: 'none' }\n /** The selection disagrees. */\n | { kind: 'mixed' }\n /** Nothing to show: the menu is disabled or the style has no value. */\n | { kind: 'empty' }\n\nexport interface ColorMenuModel {\n label: string\n /** False when nothing supports the property: the trigger disables. */\n enabled: boolean\n mixed: boolean\n trigger: ColorTrigger\n /** Common colours, greys, then the tonal grid, `COLOR_COLUMNS` to a row. */\n swatches: ColorMenuSwatch[]\n /** The \"No fill\" choice, for `fill` only. */\n noFill: { checked: boolean; patch: StyleProps } | null\n /** The colour the custom picker starts on. */\n customValue: string\n /** What picking `hex` in the custom picker writes. */\n custom(hex: string): StyleProps\n}\n\n/**\n * What a colour menu shows for a style: the palette with the matching swatch checked, \"No fill\"\n * for `fill`, and the trigger's swatch. Shared by the bindings and the vanilla menu. `fallback`\n * is the colour new annotations get while the style leaves it unset: the trigger shows it\n * rather than an empty swatch.\n */\nexport function colorMenuModel(\n property: ColorProperty,\n current: CurrentStyle,\n supported: ReadonlySet<StyleKey>,\n fallback?: string\n): ColorMenuModel {\n const value = current[property]\n const enabled = supported.has(property)\n const color =\n typeof value === 'string' && value !== 'mixed' ? value.toUpperCase() : undefined\n const flat = [\n ...PALETTE.common.map((c, i) => [`common-${i}`, c] as const),\n ...PALETTE.greys.map((c, i) => [`grey-${i}`, c] as const),\n ...PALETTE.grid.flatMap((row, r) =>\n row.map((c, i) => [`grid-${r}-${i}`, c] as const)\n ),\n ]\n const patchFor = (c: string): StyleProps => ({ [property]: c })\n const trigger: ColorTrigger = !enabled\n ? { kind: 'empty' }\n : value === 'mixed'\n ? { kind: 'mixed' }\n : value === null\n ? { kind: 'none' }\n : typeof value === 'string'\n ? { kind: 'color', color: value }\n : fallback !== undefined\n ? { kind: 'color', color: fallback }\n : { kind: 'empty' }\n return {\n label: COLOR_LABELS[property],\n enabled,\n mixed: value === 'mixed',\n trigger,\n swatches: flat.map(([key, c]) => ({\n key,\n label: c,\n color: c,\n checked: color === c,\n patch: patchFor(c),\n })),\n noFill:\n property === 'fill' ? { checked: value === null, patch: { fill: null } } : null,\n customValue: color ?? fallback?.toUpperCase() ?? '#000000',\n custom: (hex) => patchFor(hex.toUpperCase()),\n }\n}\n\n/** The smallest, largest and default text size in points, and what one step changes. */\nexport const FONT_SIZE_MIN = 1\nexport const FONT_SIZE_MAX = 144\nexport const FONT_SIZE_DEFAULT = 12\nexport const FONT_SIZE_STEP = 1\n\n/** A typed size as the menu stores it: a whole number of points within the range. */\nexport function clampFontSize(size: number): number {\n return Math.min(FONT_SIZE_MAX, Math.max(FONT_SIZE_MIN, Math.round(size)))\n}\n\nexport type TextToggleKey = 'bold' | 'italic' | 'underline'\nexport type TextAlignKey = 'left' | 'center' | 'right' | 'justify'\n\nexport interface TextStyleToggle {\n key: TextToggleKey\n label: string\n /** `'mixed'` when the selection disagrees. */\n pressed: boolean | 'mixed'\n /** What pressing writes: the opposite of `pressed`, and on for a mix. */\n patch: StyleProps\n}\n\nexport interface TextAlignChoice {\n key: TextAlignKey\n label: string\n checked: boolean\n /** The one radio in the Tab order: the checked one, else the first. */\n tabStop: boolean\n patch: StyleProps\n}\n\nexport interface TextStyleMenuModel {\n label: string\n /** False when nothing supports text style: the trigger disables. */\n enabled: boolean\n mixed: boolean\n font: {\n label: string\n /** The family, or `''` when the selection disagrees. */\n value: string\n /** The families on offer, each once; a current family outside the list is added. */\n options: string[]\n patch(family: string): StyleProps\n }\n size: {\n label: string\n /** The size, the default when the style sets none, or `null` when the selection disagrees. */\n value: number | null\n min: number\n max: number\n step: number\n /** What committing a typed size writes, or `null` when it changes nothing. */\n commit(raw: number): StyleProps | null\n /** What a stepper press writes, or `null` at the end of the range. */\n nudge(direction: 1 | -1): StyleProps | null\n }\n toggles: TextStyleToggle[]\n align: { label: string; choices: TextAlignChoice[] }\n}\n\nconst TEXT_KEYS: readonly StyleKey[] = [\n 'fontFamily',\n 'fontSize',\n 'fontWeight',\n 'fontStyle',\n 'textDecoration',\n 'textAlign',\n]\n\nconst ALIGN_KEYS: readonly TextAlignKey[] = ['left', 'center', 'right', 'justify']\n\nconst ALIGN_LABELS: Readonly<Record<TextAlignKey, string>> = {\n left: 'Align left',\n center: 'Align centre',\n right: 'Align right',\n justify: 'Justify',\n}\n\n/**\n * What the text style menu shows for a style: the font, size, bold/italic/underline and\n * alignment, each with the patch choosing it. `fonts` is the list the host offers.\n */\nexport function textStyleMenuModel(\n current: CurrentStyle,\n supported: ReadonlySet<StyleKey>,\n fonts: readonly string[]\n): TextStyleMenuModel {\n const family = current.fontFamily\n const size = current.fontSize\n // A style with no size yet (a fresh group) shows the size a new box gets.\n const value =\n size === 'mixed' ? null : typeof size === 'number' ? size : FONT_SIZE_DEFAULT\n const toggle = (\n key: TextToggleKey,\n label: string,\n prop: 'fontWeight' | 'fontStyle' | 'textDecoration',\n on: string,\n off: string\n ): TextStyleToggle => {\n const now = current[prop]\n const pressed = now === 'mixed' ? 'mixed' : now === on\n return { key, label, pressed, patch: { [prop]: pressed === true ? off : on } }\n }\n const nudge = (direction: 1 | -1): StyleProps | null => {\n const next = clampFontSize((value ?? FONT_SIZE_DEFAULT) + direction * FONT_SIZE_STEP)\n return next === value ? null : { fontSize: next }\n }\n return {\n label: 'Text style',\n enabled: TEXT_KEYS.some((k) => supported.has(k)),\n // The panel holds the text colour too, so a mix of colours shows on the trigger.\n mixed: [...TEXT_KEYS, 'textColor' as const].some((k) => current[k] === 'mixed'),\n font: {\n label: 'Font',\n value: typeof family === 'string' && family !== 'mixed' ? family : '',\n options: [\n ...new Set(\n typeof family === 'string' && family !== 'mixed' ? [...fonts, family] : fonts\n ),\n ],\n patch: (f) => ({ fontFamily: f }),\n },\n size: {\n label: 'Font size',\n value,\n min: FONT_SIZE_MIN,\n max: FONT_SIZE_MAX,\n step: FONT_SIZE_STEP,\n commit: (raw) => {\n if (!Number.isFinite(raw)) return null\n const next = clampFontSize(raw)\n return next === value ? null : { fontSize: next }\n },\n nudge,\n },\n toggles: [\n toggle('bold', 'Bold', 'fontWeight', 'bold', 'normal'),\n toggle('italic', 'Italic', 'fontStyle', 'italic', 'normal'),\n toggle('underline', 'Underline', 'textDecoration', 'underline', 'none'),\n ],\n align: {\n label: 'Alignment',\n choices: ALIGN_KEYS.map((key, i) => ({\n key,\n label: ALIGN_LABELS[key],\n checked: current.textAlign === key,\n tabStop:\n current.textAlign === key ||\n (i === 0 && !ALIGN_KEYS.includes(current.textAlign as TextAlignKey)),\n patch: { textAlign: key },\n })),\n },\n }\n}\n\n/** Accessible names of the shape kinds, as the shape menu announces them. */\nexport const SHAPE_LABELS: Readonly<Record<ShapeKind, string>> = {\n line: 'Line',\n arrow: 'Arrow',\n rectangle: 'Rectangle',\n roundedRectangle: 'Rounded rectangle',\n ellipse: 'Ellipse',\n bubble: 'Speech bubble',\n star: 'Star',\n polygon: 'Polygon',\n loupe: 'Loupe',\n mask: 'Mask',\n ovalMask: 'Oval mask',\n}\n\n/** Accessible names of the text markup kinds, as the highlight menu announces them. */\nexport const MARKUP_LABELS: Readonly<Record<MarkupKind, string>> = {\n highlight: 'Highlight',\n underline: 'Underline',\n strikeout: 'Strikethrough',\n squiggly: 'Squiggly underline',\n}\n\nexport interface HighlightMenuItem {\n kind: MarkupKind\n label: string\n checked: boolean\n}\n\nexport interface HighlightMenuModel {\n /** The kind the main button makes. */\n kind: MarkupKind\n /** The main button's accessible name. */\n label: string\n /** The kinds on offer, in menu order, with the current one checked. */\n items: HighlightMenuItem[]\n}\n\n/** What the highlight menu shows for the highlight tool's options. */\nexport function highlightMenuModel(\n options: Partial<HighlightOptions>,\n kinds: readonly MarkupKind[]\n): HighlightMenuModel {\n const kind =\n options.kind !== undefined && kinds.includes(options.kind)\n ? options.kind\n : (kinds[0] ?? 'highlight')\n return {\n kind,\n label: MARKUP_LABELS[kind],\n items: kinds.map((k) => ({ kind: k, label: MARKUP_LABELS[k], checked: k === kind })),\n }\n}\n\n/** Columns of the shape grid: the arrow keys move by this much between rows. */\nexport const SHAPE_COLUMNS = 2\n\nexport interface ShapeMenuItem {\n kind: ShapeKind\n label: string\n checked: boolean\n}\n\nexport interface ShapeMenuModel {\n /** The kind the main button draws. */\n kind: ShapeKind\n /** The main button's accessible name. */\n label: string\n /** The kinds on offer, in menu order, with the current one checked. */\n items: ShapeMenuItem[]\n}\n\n/**\n * What the shape menu shows for the shape tool's options, over the kinds in `kinds`\n * (`SHAPE_KINDS`). A kind that is not on offer falls back to `rectangle` when that is offered,\n * else to the first.\n */\nexport function shapeMenuModel(\n options: Partial<ShapeOptions>,\n kinds: readonly ShapeKind[]\n): ShapeMenuModel {\n const kind =\n options.kind !== undefined && kinds.includes(options.kind)\n ? options.kind\n : (kinds.find((k) => k === 'rectangle') ?? kinds[0] ?? 'rectangle')\n return {\n kind,\n label: `Shape: ${SHAPE_LABELS[kind]}`,\n items: kinds.map((k) => ({ kind: k, label: SHAPE_LABELS[k], checked: k === kind })),\n }\n}\n\n/** The overlay's per-annotation state, as on its `data-state` attribute. */\nexport type AnnotationState = 'idle' | 'hover' | 'selected'\n\n/**\n * What a host-rendered annotation receives: Vue's `annotation` slot and React's\n * `renderAnnotation`.\n */\nexport interface AnnotationSlotProps {\n annotation: Annotation\n state: AnnotationState\n locked: boolean\n select: () => void\n remove: () => void\n}\n\n/** The thread popover's accessible name: \"Note thread\" for a note, \"Comment thread\" for markup. */\nexport function threadPopoverLabel(root: Pick<Annotation, 'type'>): string {\n return root.type === 'text' ? 'Note thread' : 'Comment thread'\n}\n\n/**\n * The thread popover's delete button. It removes the root and its replies, so on text markup\n * it says it deletes the highlight, not only the comment.\n */\nexport function threadDeleteLabel(root: Pick<Annotation, 'type'>): string {\n return root.type === 'text' ? 'Delete' : 'Delete highlight'\n}\n\n/** What a host-rendered comment thread receives: a note's, or text markup's. */\nexport interface ThreadPopoverSlotProps {\n root: NoteAnnotation | TextMarkupAnnotation\n replies: Annotation[]\n reply: (text: string) => void\n update: (contents: string) => void\n remove: () => void\n close: () => void\n}\n\n/** The signature controls' words, shared so every binding announces the same names. */\nexport const SIGNATURE_LABELS = {\n /** The menu's group and main button. */\n sign: 'Sign',\n trigger: 'Choose signature',\n menu: 'Signatures',\n saved: 'Saved signatures',\n create: 'Create signature',\n /** The dialog's title. */\n dialog: 'Create signature',\n tabs: 'Signature source',\n draw: 'Draw',\n type: 'Type',\n image: 'Image',\n pad: 'Signature pad',\n clear: 'Clear',\n name: 'Name',\n namePlaceholder: 'Your name',\n fonts: 'Font',\n file: 'Image file',\n cancel: 'Cancel',\n save: 'Save',\n} as const\n\n/** The dialog's tabs, in order. */\nexport const SIGNATURE_TABS = ['draw', 'type', 'image'] as const\nexport type SignatureTab = (typeof SIGNATURE_TABS)[number]\n\nexport interface SignatureMenuItem {\n id: string\n /** `Signature 1`, `Signature 2`… in saved order. */\n label: string\n /** The remove button's accessible name. */\n removeLabel: string\n checked: boolean\n template: SignatureTemplate\n}\n\nexport interface SignatureMenuModel {\n /** The template the tool places, when it is still saved. */\n selected: SignatureTemplate | undefined\n items: SignatureMenuItem[]\n}\n\n/** What the signature menu shows for the saved templates and the signature tool's options. */\nexport function signatureMenuModel(\n templates: readonly SignatureTemplate[],\n options: SignatureOptions\n): SignatureMenuModel {\n const items = templates.map((template, i) => ({\n id: template.id,\n label: `Signature ${i + 1}`,\n removeLabel: `Remove signature ${i + 1}`,\n checked: template.id === options.templateId,\n template,\n }))\n return { selected: items.find((i) => i.checked)?.template, items }\n}\n","// Keyboard support the style menus share across the bindings and the vanilla factories. Items\n// are `[role=\"menuitemradio\"]` (or `menuitem`) buttons that are not focus stops themselves\n// (`tabindex=\"-1\"`): the menu moves focus between them, and Tab leaves the menu.\n//\n// An element with `data-ink-menu-columns=\"N\"` lays its items out as a grid N wide: ArrowLeft\n// and ArrowRight move within a row, ArrowUp and ArrowDown between rows, and past the first or\n// last row they carry on to the items before or after the grid.\n\nconst ITEMS =\n ':is([role=\"menuitemradio\"], [role=\"menuitem\"]):not(:disabled):not([aria-disabled=\"true\"])'\n\n/** The menu's enabled items in document order. */\nexport function menuItems(root: ParentNode): HTMLElement[] {\n return [...root.querySelectorAll<HTMLElement>(ITEMS)]\n}\n\n/** Focuses the first checked item, else the first enabled one. */\nexport function focusInitialMenuItem(root: ParentNode): void {\n const items = menuItems(root)\n const target =\n items.find((el) => el.getAttribute('aria-checked') === 'true') ?? items[0]\n target?.focus({ preventScroll: true })\n}\n\n/** The index to focus for a key, or -1 when the key means nothing here. */\nfunction nextIndex(key: string, items: HTMLElement[], i: number): number {\n const last = items.length - 1\n if (key === 'Home') return 0\n if (key === 'End') return last\n const grid = items[i]?.closest<HTMLElement>('[data-ink-menu-columns]')\n const cols = Number(grid?.dataset.inkMenuColumns)\n if (grid && cols > 0) {\n const cells = items.filter((el) => grid.contains(el))\n const first = items.indexOf(cells[0]!)\n const end = first + cells.length - 1\n const at = i - first\n if (key === 'ArrowRight')\n return at % cols === cols - 1 || at === cells.length - 1 ? i : i + 1\n if (key === 'ArrowLeft') return at % cols === 0 ? i : i - 1\n if (key === 'ArrowDown')\n return at + cols < cells.length ? i + cols : end === last ? 0 : end + 1\n if (key === 'ArrowUp')\n return at - cols >= 0 ? i - cols : first === 0 ? last : first - 1\n return -1\n }\n if (key === 'ArrowDown') return i < 0 || i === last ? 0 : i + 1\n if (key === 'ArrowUp') return i <= 0 ? last : i - 1\n return -1\n}\n\n/**\n * ArrowDown and ArrowUp move between enabled items and wrap; Home and End go to the ends.\n * Inside a grid the arrow keys move in both directions.\n */\nexport function handleMenuKeys(e: KeyboardEvent, root: ParentNode): void {\n if (e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey) return\n const items = menuItems(root)\n if (items.length === 0) return\n const next = nextIndex(\n e.key,\n items,\n items.indexOf(document.activeElement as HTMLElement)\n )\n if (next < 0) return\n e.preventDefault()\n items[next]!.focus({ preventScroll: true })\n}\n\n/**\n * Arrow keys inside a `role=\"radiogroup\"`: the next (or previous) enabled `role=\"radio\"`\n * takes focus and is chosen, wrapping at the ends, as a native radio group does.\n */\nexport function handleRadioKeys(e: KeyboardEvent, group: ParentNode): void {\n if (e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return\n const forward = e.key === 'ArrowRight' || e.key === 'ArrowDown'\n if (!forward && e.key !== 'ArrowLeft' && e.key !== 'ArrowUp') return\n const radios = [...group.querySelectorAll<HTMLElement>('[role=\"radio\"]:not(:disabled)')]\n const at = radios.indexOf(document.activeElement as HTMLElement)\n if (at < 0) return\n e.preventDefault()\n const next = radios[(at + (forward ? 1 : -1) + radios.length) % radios.length]!\n next.focus({ preventScroll: true })\n next.click()\n}\n\n/**\n * Arrow keys, Home and End inside a `role=\"tablist\"`: the next (or previous) enabled\n * `role=\"tab\"` takes focus and is chosen, wrapping at the ends.\n */\nexport function handleTabKeys(e: KeyboardEvent, tablist: ParentNode): void {\n if (e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return\n const tabs = [\n ...tablist.querySelectorAll<HTMLElement>(\n '[role=\"tab\"]:not(:disabled):not([aria-disabled=\"true\"])'\n ),\n ]\n const at = tabs.indexOf(document.activeElement as HTMLElement)\n if (at < 0) return\n const last = tabs.length - 1\n const next =\n e.key === 'ArrowRight' || e.key === 'ArrowDown'\n ? at === last\n ? 0\n : at + 1\n : e.key === 'ArrowLeft' || e.key === 'ArrowUp'\n ? at === 0\n ? last\n : at - 1\n : e.key === 'Home'\n ? 0\n : e.key === 'End'\n ? last\n : -1\n if (next < 0) return\n e.preventDefault()\n tabs[next]!.focus({ preventScroll: true })\n tabs[next]!.click()\n}\n\nconst TABBABLE = [\n 'a[href]',\n 'button:not(:disabled)',\n 'input:not(:disabled):not([type=\"hidden\"])',\n 'select:not(:disabled)',\n 'textarea:not(:disabled)',\n '[tabindex]',\n]\n .map((s) => `${s}:not([tabindex=\"-1\"])`)\n .join(', ')\n\n/**\n * Keeps Tab inside `container`, a modal: Tab from its last stop goes to its first, and\n * Shift+Tab from the first to the last.\n */\nexport function trapTab(e: KeyboardEvent, container: HTMLElement): void {\n if (e.key !== 'Tab' || e.defaultPrevented) return\n const stops = [...container.querySelectorAll<HTMLElement>(TABBABLE)].filter(\n (el) => !el.matches(':disabled') && el.getClientRects().length > 0\n )\n if (stops.length === 0) {\n e.preventDefault()\n return\n }\n const first = stops[0]!\n const last = stops[stops.length - 1]!\n const active = document.activeElement\n if (e.shiftKey && (active === first || !container.contains(active))) {\n e.preventDefault()\n last.focus()\n } else if (!e.shiftKey && (active === last || !container.contains(active))) {\n e.preventDefault()\n first.focus()\n }\n}\n","/** The overlay element drawn for annotation `id` under `root`, if it is in the DOM. */\nexport function annotationElementFor(root: ParentNode, id: string): HTMLElement | null {\n return root.querySelector<HTMLElement>(`[data-annotation=\"${CSS.escape(id)}\"]`)\n}\n\n/**\n * Resolves the overlay element for `id` and keeps resolving while `root`'s subtree changes:\n * the overlay creates and removes these elements outside any framework (a page mounts as it\n * scrolls into view), so a popover anchored to one has to follow. Calls `onChange` once now\n * and again whenever the answer changes. The returned function stops observing.\n */\nexport function observeAnnotationElement(\n root: HTMLElement,\n id: string,\n onChange: (el: HTMLElement | null) => void\n): () => void {\n let last: HTMLElement | null | undefined\n const resolve = (): void => {\n const found = annotationElementFor(root, id)\n if (found === last) return\n last = found\n onChange(found)\n }\n resolve()\n const observer = new MutationObserver(resolve)\n observer.observe(root, { childList: true, subtree: true })\n return () => observer.disconnect()\n}\n","/*\n * Shared behaviour for popovers anchored to an overlay annotation element. There is no popover\n * trigger, so the primitive library's own focus return has nothing to return to.\n */\nimport { annotationElementFor } from './annotation-element'\n\n/**\n * A press that will activate an annotation is not a dismissal: the popover follows the\n * activation. Mirrors the overlay's rule: a press on the annotation element or on its drawn\n * shape activates; a press on a custom element's own content belongs to that content.\n */\nexport function shouldKeepOpenOnAnnotation(target: EventTarget | null): boolean {\n if (!(target instanceof Element)) return false\n const annotation = target.closest('[data-annotation]')\n if (!annotation) return false\n return target === annotation || !annotation.hasAttribute('data-custom')\n}\n\nexport interface FocusReturnOptions {\n root: () => HTMLElement | null\n /** The activated annotation id when the popover closes. */\n activated: () => string | null\n}\n\nexport interface FocusReturn {\n /**\n * Call just before removing the anchor's annotation: remembers where focus goes instead,\n * the next annotation on the page in reading order (the next one matching `prefer`\n * first), else the previous one, else the scroll element.\n */\n beforeRemove(anchor: HTMLElement | null, prefer?: string): void\n /** The popover's close-auto-focus handler. Prevents the default and places focus itself. */\n onCloseAutoFocus(event: Event, anchor: HTMLElement | null): void\n}\n\nexport function createFocusReturn(opts: FocusReturnOptions): FocusReturn {\n let fallbacks: HTMLElement[] = []\n /** Set by `beforeRemove`: the close comes from removing the anchor's annotation. */\n let removing = false\n\n return {\n beforeRemove(anchor, prefer) {\n fallbacks = []\n removing = true\n // The overlay keeps its elements in reading order, so DOM order is reading order.\n const siblings = anchor?.parentElement\n ? [...anchor.parentElement.children].filter(\n (el): el is HTMLElement =>\n el instanceof HTMLElement && el.hasAttribute('data-annotation')\n )\n : []\n const i = anchor ? siblings.indexOf(anchor) : -1\n if (i >= 0) {\n const after = siblings.slice(i + 1)\n const preferred = prefer ? after.filter((el) => el.matches(prefer)) : []\n fallbacks.push(...preferred, ...after, ...siblings.slice(0, i).reverse())\n }\n },\n onCloseAutoFocus(event, anchor) {\n event.preventDefault()\n const plan = fallbacks\n const removed = removing\n fallbacks = []\n removing = false\n const root = opts.root()\n if (!root) return\n // Activation moved to another annotation that is on screen: its popover takes focus. An\n // id whose element is gone (the host removed it) does not count.\n const activated = opts.activated()\n if (activated !== null && annotationElementFor(root, activated)) return\n // The close can be reported more than once; focus already returned to the document stays.\n const active = root.ownerDocument.activeElement\n if (active && active !== root && root.contains(active)) return\n const scroll = root.querySelector<HTMLElement>('[data-ink-scroll]')\n // After a removal the anchor may still be connected (a controlled host has not applied\n // the change yet), but it is on its way out: go straight to what follows it.\n const candidates = removed ? [...plan, scroll] : [anchor, ...plan, scroll]\n candidates.find((el) => el?.isConnected)?.focus({ preventScroll: true })\n },\n }\n}\n","/** `document.createElement` with attributes and children. */\nexport function h<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n attrs: Record<string, string> = {},\n ...children: (Node | string)[]\n): HTMLElementTagNameMap[K] {\n const el = document.createElement(tag)\n for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value)\n el.append(...children)\n return el\n}\n\nexport function button(label: string, onClick: () => void): HTMLButtonElement {\n const b = h('button', { type: 'button' }, label)\n b.addEventListener('click', onClick)\n return b\n}\n","/*\n * Panels anchored to an annotation's overlay element: the note thread, and any card an app\n * opens next to an annotation.\n */\nimport { observeAnnotationElement } from '../annotation-element'\nimport { shouldKeepOpenOnAnnotation, type FocusReturn } from '../popover-focus'\n\nimport { h } from './dom'\n\n/** Space between the anchor and the panel, and between the panel and the window edge. */\nconst GAP = 6\nconst MARGIN = 8\nconst TABBABLE = 'button, input, select, textarea, a[href], [tabindex]'\n\n/** Options for `createPopover`. */\nexport interface PopoverOptions {\n /** The viewer root (`[data-ink-root]`): anchors are looked up and focus returns inside it. */\n root: HTMLElement\n /**\n * Attributes for the panel, such as `class`, `aria-label` or the app's own `data-*` keys.\n * `role` and `data-ink-popover` are always set by `createPopover`.\n */\n attrs: Record<string, string>\n /** Where focus goes when the panel hides: `createFocusReturn` over the same root. */\n focusReturn: FocusReturn\n /**\n * Called on Escape inside the panel or the viewer, and on a press outside the panel that will\n * not activate another annotation. Hide the panel (or clear the activation) here.\n */\n onDismiss(): void\n}\n\n/** A panel anchored to one annotation at a time; see `createPopover`. */\nexport interface Popover {\n /** The panel element, on `<body>`. Fill it with the card's content. */\n readonly panel: HTMLElement\n /** The anchored annotation's element, or null while it is not in the DOM (page unmounted). */\n readonly anchor: HTMLElement | null\n /**\n * Anchors the panel to annotation `id`. The panel shows whenever that annotation's element\n * is in the DOM, and follows it when it is replaced.\n */\n show(id: string): void\n /** Hides the panel, then returns focus through `focusReturn`. */\n hide(): void\n /** Removes the panel and its listeners. */\n destroy(): void\n}\n\n/**\n * Positions `panel` (fixed) below the `anchor` rectangle, or above it when only that fits,\n * kept inside the window. For panels anchored to something other than an annotation.\n */\nexport function placePanel(panel: HTMLElement, anchor: DOMRect): void {\n const { innerWidth: vw, innerHeight: vh } = window\n // Fixed at the corner before measuring: a panel still in the flow is as wide as the body,\n // and one left where it was is squeezed by the window edge.\n panel.style.position = 'fixed'\n panel.style.left = '0px'\n panel.style.top = '0px'\n const w = panel.offsetWidth\n const ht = panel.offsetHeight\n let top = anchor.bottom + GAP\n if (top + ht > vh - MARGIN && anchor.top - GAP - ht >= MARGIN)\n top = anchor.top - GAP - ht\n top = Math.max(MARGIN, Math.min(top, vh - ht - MARGIN))\n const left = Math.max(MARGIN, Math.min(anchor.left, vw - w - MARGIN))\n panel.style.left = `${left}px`\n panel.style.top = `${top}px`\n}\n\n/**\n * Creates a non-modal `role=\"dialog\"` panel on `<body>`, marked `data-ink-popover` so the theme\n * gives it its tokens, that an app anchors to an annotation with `show(id)` (for instance on\n * `viewer.activated`). The panel follows the annotation's element as pages mount and unmount:\n * it hides while the element is gone and comes back with it. Tab loops inside the panel, and\n * Escape or a press outside calls `onDismiss`. Call `destroy` when done.\n */\nexport function createPopover(opts: PopoverOptions): Popover {\n const { root, focusReturn } = opts\n const panel = h('div', {\n ...opts.attrs,\n role: 'dialog',\n 'data-ink-popover': '',\n hidden: '',\n })\n document.body.append(panel)\n let anchoredId: string | null = null\n let anchor: HTMLElement | null = null\n let stopObserving: () => void = () => undefined\n /** The element that had focus in the panel when the anchor went away. */\n let stranded: HTMLElement | null = null\n\n const place = (): void => {\n if (!anchor || panel.hidden) return\n placePanel(panel, anchor.getBoundingClientRect())\n }\n\n // The anchor changes size on zoom; the panel when its content changes.\n const resizes = new ResizeObserver(place)\n resizes.observe(panel)\n\n const onAnchor = (el: HTMLElement | null, closing = false): void => {\n if (anchor) resizes.unobserve(anchor)\n anchor = el\n if (!el) {\n const active = document.activeElement\n if (\n !closing &&\n !panel.hidden &&\n active instanceof HTMLElement &&\n panel.contains(active)\n ) {\n // Hiding the panel would drop focus to the body: keep the keyboard in the viewer.\n const scroll = root.querySelector<HTMLElement>('[data-ink-scroll]')\n if (scroll) {\n stranded = active\n scroll.focus({ preventScroll: true })\n }\n }\n panel.hidden = true\n return\n }\n resizes.observe(el)\n const wasHidden = panel.hidden\n panel.hidden = false\n place()\n if (wasHidden && stranded) {\n const back = stranded\n stranded = null\n const scroll = root.querySelector<HTMLElement>('[data-ink-scroll]')\n if (panel.contains(back) && document.activeElement === scroll)\n back.focus({ preventScroll: true })\n }\n }\n\n const onKey = (e: KeyboardEvent): void => {\n if (e.key !== 'Escape' || panel.hidden || e.defaultPrevented) return\n // An Escape meant for a host's own dialog elsewhere on the page is not ours.\n const target = e.target\n if (!(target instanceof Node) || !(panel.contains(target) || root.contains(target)))\n return\n e.preventDefault()\n opts.onDismiss()\n }\n const onPress = (e: PointerEvent): void => {\n if (panel.hidden || panel.contains(e.target as Node)) return\n // A press that will activate an annotation hands over to it instead of closing.\n if (shouldKeepOpenOnAnnotation(e.target)) return\n opts.onDismiss()\n }\n // Focus loops inside the panel.\n const onTab = (e: KeyboardEvent): void => {\n if (e.key !== 'Tab' || e.altKey || e.ctrlKey || e.metaKey) return\n const tabbable = [...panel.querySelectorAll<HTMLElement>(TABBABLE)].filter(\n (el) => !(el as HTMLButtonElement).disabled && el.tabIndex >= 0\n )\n const first = tabbable[0]\n const last = tabbable.at(-1)\n if (!first || !last) return\n const active = document.activeElement\n if (e.shiftKey ? active !== first : active !== last) return\n e.preventDefault()\n ;(e.shiftKey ? last : first).focus()\n }\n panel.addEventListener('keydown', onTab)\n document.addEventListener('keydown', onKey)\n document.addEventListener('pointerdown', onPress, true)\n // The viewer's scroll element and any scrolling ancestor in the host page.\n document.addEventListener('scroll', place, true)\n window.addEventListener('resize', place)\n\n return {\n panel,\n get anchor() {\n return anchor\n },\n show(id) {\n if (id === anchoredId) return\n stopObserving()\n anchoredId = id\n stopObserving = observeAnnotationElement(root, id, onAnchor)\n },\n hide() {\n if (anchoredId === null) return\n stopObserving()\n stopObserving = () => undefined\n anchoredId = null\n const back = anchor\n stranded = null\n onAnchor(null, true)\n // After the change that closed the popover has settled (a removed anchor is out of the\n // DOM, a cleared activation is cleared). A popover reopened meanwhile keeps focus where it\n // is.\n queueMicrotask(() => {\n if (anchoredId !== null || !panel.isConnected) return\n focusReturn.onCloseAutoFocus(\n new Event('closeautofocus', { cancelable: true }),\n back\n )\n })\n },\n destroy() {\n stopObserving()\n resizes.disconnect()\n document.removeEventListener('keydown', onKey)\n document.removeEventListener('pointerdown', onPress, true)\n panel.removeEventListener('keydown', onTab)\n document.removeEventListener('scroll', place, true)\n window.removeEventListener('resize', place)\n panel.remove()\n },\n }\n}\n","/*\n * The wiring every viewer needs: a viewport over the scroll element, page layers in each page\n * host it creates, page-error tracking, the tool controller and keyboard shortcuts. Framework\n * bindings and `createViewer` sit on top: they render their own chrome and get pages and\n * errors back through the callbacks.\n */\nimport { InkError, isInkError } from '../model/errors'\nimport {\n createMemorySignatureStore,\n createSignatureLibrary,\n type SignatureLibrary,\n type SignatureStore,\n} from '../model/signatures'\n\nimport { createPageMount, type PageLayer, type PageMount } from './page-mount'\nimport { getSelectionQuads } from './selection'\nimport {\n createToolController,\n createToolOptions,\n trackToolStyle,\n withHostTools,\n type Tool,\n type ToolController,\n type ToolId,\n type ToolOptions,\n} from './tools'\nimport { FONT_FAMILIES, SIGNATURE_FONTS } from './ui'\nimport { createViewport, type Viewport, type ZoomValue } from './viewport'\nimport { attachViewportKeys } from './viewport-keys'\n\nimport type { LayoutMode } from './layout'\nimport type { DecorateAnnotation } from './overlay'\nimport type { PageTransform, ViewRotation } from './transform'\nimport type { ToolStyle } from '../model/annotations/tool-style'\nimport type { InkDocument } from '../model/document'\nimport type { Point } from '../model/geometry'\n\n/** A user-space point on a page, used to put the scroll position back after a rebuild. */\ninterface ScrollAnchor {\n page: number\n user: Point\n /** Whether the vertical position is restored too, not only the horizontal one. */\n vertical: boolean\n}\n\nexport interface MountViewerOptions {\n container: HTMLElement\n document: InkDocument\n zoom?: ZoomValue\n page?: number\n mode?: LayoutMode\n rotation?: ViewRotation\n gap?: number\n buffer?: number\n tool?: ToolId\n /**\n * Host tools, added to the built-ins. A host tool with a built-in's id replaces it. The same\n * instances are reused when the engine rebuilds.\n */\n tools?: Tool[]\n /**\n * The tools' options (the shape kind, the highlight kind…). A binding or `createViewer` passes\n * one it keeps for its own life, so options persist across documents, as for the life of the\n * viewer. By default the engine makes one, which lasts as long as the engine.\n */\n toolOptions?: ToolOptions\n /**\n * The style the tools create with. A binding passes its own, made with `trackToolStyle` and\n * its own history (and keeps its active group in step with the tool). By default the engine\n * makes one over the document's history.\n */\n toolStyle?: ToolStyle\n /**\n * The history the tools group a gesture's changes with (a group move, a sketch's swap to its\n * shape). A binding passes its own, so a controlled host's undo steps match the gesture. By\n * default the document's history.\n */\n toolHistory?: { batch(fn: () => void): void }\n /**\n * The font families text boxes offer, replacing the default `FONT_FAMILIES` (the PDF\n * standard families). Fonts beyond those are the PDF writer's to embed.\n */\n fonts?: string[]\n /**\n * Where signature templates live. Default: memory, gone on reload\n * (`createMemorySignatureStore`). `createLocalSignatureStore` keeps them in the browser.\n */\n signatures?: SignatureStore\n /**\n * The templates the `signature` tool and the signature controls share. A binding or\n * `createViewer` passes its own, so they outlive one document; it wins over `signatures`.\n * A function is read each time the library is needed, so a host that swaps its library\n * after mount reaches the tool too.\n */\n signatureLibrary?: SignatureLibrary | (() => SignatureLibrary)\n /**\n * The handwriting fonts a typed signature offers. The host loads them (`@font-face`).\n * Default `SIGNATURE_FONTS`.\n */\n signatureFonts?: string[]\n /** Annotation content is rendered by the host (custom slots). Changing it needs `rebuild`. */\n customAnnotations?: boolean\n /**\n * The app's own data attributes, classes and description for each annotation element, to\n * style or find its marks: `{ data: { 'my-flag': 'on' } }` writes `data-my-flag=\"on\"`.\n * Decorations re-apply whenever the annotations change; when the function's output changes\n * for another reason (app state it reads), call `redecorate()`. Core's attributes and `ink-`\n * classes cannot be overridden.\n */\n decorateAnnotation?: DecorateAnnotation\n onActivate?(id: string): void\n /**\n * After every (re)build: subscribe to the new viewport and controller here. It fires inside\n * `mountViewer` before it returns, and after the build's `onPageMount` calls.\n */\n onBuild?(viewport: Viewport, tools: ToolController): void\n /**\n * The viewport mounts pages synchronously, so a build's `onPageMount` calls fire before its\n * `onBuild` (on the first build, before `mountViewer` returns). Do not read `engine.viewport`\n * or `engine.tools` here: during a rebuild they still point at the destroyed objects. Use\n * the arguments, or wait for `onBuild`.\n */\n onPageMount?(page: number, mount: PageMount, host: HTMLElement): void\n /** Same ordering rule as `onPageMount`: do not read `engine.viewport` or `engine.tools`. */\n onPageUnmount?(page: number): void\n /**\n * `error` when a page's canvas or text layer fails; `null` once every failed layer recovers.\n * Unmounting a failed page does not emit `null`: hosts that track errors by page must clear\n * them in `onPageUnmount`. Same ordering rule as `onPageMount`: do not read `engine.viewport`\n * or `engine.tools`.\n */\n onPageError?(page: number, error: InkError | null): void\n}\n\nexport interface ViewerEngine {\n readonly viewport: Viewport\n readonly tools: ToolController\n /**\n * The style each group creates with, shared by the tools and the style controls. It lives as\n * long as the engine, across rebuilds.\n */\n readonly toolStyle: ToolStyle\n /** The font families text boxes offer: the `fonts` option, else `FONT_FAMILIES`. */\n readonly fonts: readonly string[]\n /** The signature templates: the host's current library, or the engine's own. */\n readonly signatures: SignatureLibrary\n /** The fonts a typed signature offers: the `signatureFonts` option, else `SIGNATURE_FONTS`. */\n readonly signatureFonts: readonly string[]\n readonly pages: ReadonlyMap<number, PageMount>\n /**\n * Recreates the viewport for construction-only options, keeping zoom, page, mode, rotation\n * and tool. The scroll position is kept too: the user-space point at the top-left of the\n * visible area stays there. When that corner is in a gap rather than on a page, the page below\n * the gap lands where `scrollToPage` puts it, with the new gap above it.\n */\n rebuild(opts: { gap?: number; buffer?: number; customAnnotations?: boolean }): void\n /**\n * Runs `decorateAnnotation` again for every mounted annotation element, without re-rendering\n * anything else. Call it when the decorations would change but no annotation did.\n */\n redecorate(): void\n destroy(): void\n}\n\nexport function mountViewer(opts: MountViewerOptions): ViewerEngine {\n const { container: el, document: doc } = opts\n const pages = new Map<number, PageMount>()\n let gap = opts.gap\n let buffer = opts.buffer\n let custom = opts.customAnnotations ?? false\n let viewport: Viewport\n let tools: ToolController\n let stopKeys: () => void = () => undefined\n let stopActive: () => void = () => undefined\n let destroyed = false\n const hostTools = opts.tools ?? []\n /** Option values outlive rebuilds: every controller shares this registry. */\n const toolOptions = opts.toolOptions ?? createToolOptions()\n /** Without a host style, the engine's own follows the active tool across rebuilds. */\n const tracker = opts.toolStyle\n ? undefined\n : trackToolStyle({\n store: doc.annotations,\n history: opts.toolHistory ?? doc.history,\n tools: hostTools,\n tool: opts.tool,\n })\n const toolStyle = opts.toolStyle ?? (tracker as NonNullable<typeof tracker>).toolStyle\n const host = opts.signatureLibrary\n const own = host\n ? undefined\n : createSignatureLibrary(opts.signatures ?? createMemorySignatureStore())\n /** The library now: a host getter is read each time, so a swapped library takes effect. */\n const signatures = (): SignatureLibrary =>\n typeof host === 'function' ? host() : (host ?? (own as SignatureLibrary))\n void signatures().refresh()\n\n function mountPage(page: number, host: HTMLElement, transform: PageTransform): void {\n /** Layers that failed and have not rendered since; the error clears when this empties. */\n const failed = new Set<PageLayer>()\n let error: InkError | null = null\n const isCustom = custom\n const mount = createPageMount({\n document: doc,\n page,\n host,\n transform,\n store: doc.annotations,\n onActivate: (id) => opts.onActivate?.(id),\n isCustom: () => isCustom,\n decorate: (a) => opts.decorateAnnotation?.(a),\n onError: (cause, layer) => {\n failed.add(layer)\n // The first failure wins: a canvas and a text layer failing together report once.\n if (error) return\n error = isInkError(cause)\n ? cause\n : new InkError(\n 'InvalidPdf',\n cause instanceof Error ? cause.message : String(cause),\n { page },\n cause\n )\n host.setAttribute('data-state', 'error')\n opts.onPageError?.(page, error)\n },\n onRendered: (layer) => {\n failed.delete(layer)\n if (!error || failed.size > 0) return\n error = null\n host.removeAttribute('data-state')\n opts.onPageError?.(page, null)\n },\n })\n pages.set(page, mount)\n opts.onPageMount?.(page, mount, host)\n }\n\n function unmountPage(page: number): void {\n const mount = pages.get(page)\n if (!mount) return\n pages.delete(page)\n opts.onPageUnmount?.(page)\n mount.destroy()\n }\n\n /** The client point at the top-left of the container's visible content area. */\n function viewTopLeft(): Point {\n const r = el.getBoundingClientRect()\n return { x: r.left + el.clientLeft, y: r.top + el.clientTop }\n }\n\n /** The client point of the pages element's top-left: the origin of the layout's page boxes. */\n function layoutOrigin(): Point | undefined {\n const pagesEl = el.querySelector<HTMLElement>(':scope > [data-ink-pages]')\n if (!pagesEl) return undefined\n const r = pagesEl.getBoundingClientRect()\n return { x: r.left, y: r.top }\n }\n\n /**\n * Where the view sits before a rebuild: the user-space point under the top-left of the\n * visible area, on the page whose box contains it. When the top of the view is in a gap or a\n * margin, only the horizontal position is kept, and the page lands where `scrollToPage` puts\n * it, the new gap above it (a view resting at a page boundary stays at that boundary).\n */\n function scrollAnchor(vp: Viewport): ScrollAnchor | undefined {\n const o = layoutOrigin()\n if (!o) return undefined\n const corner = viewTopLeft()\n const x = corner.x - o.x\n const y = corner.y - o.y\n const boxes = vp.layout.get().boxes\n const inside = boxes.find((b) => y >= b.top && y < b.top + b.height)\n // In a gap or margin: the page just below it, which the view reaches first. Past the\n // last page there is none, so the current page stands in.\n const box =\n inside ??\n boxes.find((b) => b.top > y) ??\n boxes.find((b) => b.index === vp.currentPage.get())\n if (!box) return undefined\n // Transforms are affine, so a point left or right of the page maps back exactly too.\n const user = vp.transformFor(box.index).fromCss({ x: x - box.left, y: y - box.top })\n return { page: box.index, user, vertical: inside !== undefined }\n }\n\n /** Scrolls so the anchor's point sits under the top-left of the visible area again. */\n function restoreScroll(vp: Viewport, anchor: ScrollAnchor): void {\n const o = layoutOrigin()\n const box = vp.layout.get().boxes.find((b) => b.index === anchor.page)\n if (!o || !box) return\n const css = vp.transformFor(anchor.page).toCss(anchor.user)\n const corner = viewTopLeft()\n el.scrollLeft += o.x + box.left + css.x - corner.x\n if (anchor.vertical) el.scrollTop += o.y + box.top + css.y - corner.y\n }\n\n function build(state: {\n zoom: ZoomValue\n page: number | undefined\n mode: LayoutMode | undefined\n rotation: ViewRotation | undefined\n tool: ToolId | undefined\n anchor?: ScrollAnchor | undefined\n }): void {\n const vp = createViewport({\n container: el,\n document: doc,\n zoom: state.zoom,\n ...(state.mode === undefined ? {} : { mode: state.mode }),\n ...(state.rotation === undefined ? {} : { rotation: state.rotation }),\n ...(gap === undefined ? {} : { gap }),\n ...(buffer === undefined ? {} : { buffer }),\n onMount: mountPage,\n onUpdate: (page, _host, transform) => pages.get(page)?.update(transform),\n onUnmount: unmountPage,\n })\n const list = withHostTools(hostTools)\n const tc = createToolController({\n ...(state.tool === undefined ? {} : { initial: state.tool }),\n tools: list,\n options: toolOptions,\n ctx: {\n toolStyle,\n store: doc.annotations,\n viewport: vp,\n root: el,\n selectionQuads: () =>\n getSelectionQuads(el, (host) => {\n const page = Number(host.dataset.page)\n return { page, transform: vp.transformFor(page) }\n }),\n clearSelection: () =>\n el.ownerDocument.defaultView?.getSelection()?.removeAllRanges(),\n onActivate: (id) => opts.onActivate?.(id),\n history: opts.toolHistory ?? doc.history,\n get signatures() {\n return signatures()\n },\n },\n })\n viewport = vp\n tools = tc\n if (tracker) {\n tracker.setTool(tc.active.get())\n stopActive = tc.active.subscribe((id) => tracker.setTool(id))\n }\n stopKeys = attachViewportKeys(el, { viewport: vp, pageCount: () => doc.pages.length })\n // A view resting in a gap lands on the page below it, not on the most visible page.\n // The scroll position resets on teardown, so the guard below must not skip a gap anchor.\n if (state.anchor && !state.anchor.vertical) vp.scrollToPage(state.anchor.page)\n else if (state.page !== undefined && state.page !== vp.currentPage.get())\n vp.scrollToPage(state.page)\n if (state.anchor) restoreScroll(vp, state.anchor)\n opts.onBuild?.(vp, tc)\n }\n\n function teardown(): void {\n stopKeys()\n stopActive()\n tools.destroy()\n // The viewport unmounts every page it mounted, which destroys the page mounts.\n viewport.destroy()\n for (const page of [...pages.keys()]) unmountPage(page)\n }\n\n build({\n zoom: opts.zoom ?? 'fit-width',\n page: opts.page,\n mode: opts.mode,\n rotation: opts.rotation,\n tool: opts.tool,\n })\n\n return {\n get viewport() {\n return viewport\n },\n get tools() {\n return tools\n },\n toolStyle,\n fonts: opts.fonts ? [...opts.fonts] : FONT_FAMILIES,\n get signatures() {\n return signatures()\n },\n signatureFonts: opts.signatureFonts ? [...opts.signatureFonts] : SIGNATURE_FONTS,\n pages,\n rebuild(next) {\n if (destroyed) return\n const state = {\n zoom: viewport.zoom.get(),\n page: viewport.currentPage.get(),\n mode: viewport.mode.get(),\n rotation: viewport.rotation.get(),\n tool: tools.active.get(),\n anchor: scrollAnchor(viewport),\n }\n teardown()\n if (next.gap !== undefined) gap = next.gap\n if (next.buffer !== undefined) buffer = next.buffer\n if (next.customAnnotations !== undefined) custom = next.customAnnotations\n build(state)\n },\n redecorate() {\n if (destroyed) return\n for (const mount of pages.values()) mount.overlay.redecorate()\n },\n destroy() {\n if (destroyed) return\n destroyed = true\n teardown()\n },\n }\n}\n","/*\n * The thread for the activated note or text markup, anchored to the root's overlay element.\n * Activating a reply opens the whole thread from its root. Closing (Close, Escape, a press\n * outside) clears the activation.\n *\n * A new note, or a highlight, has no text. While its root is empty (and unlocked) the form\n * writes the root's own `contents`, labelled \"Comment\", and the thread list stays hidden until\n * there is something in it; after that the form adds replies. A note closed, or left for\n * another annotation, while still empty and without replies is removed; markup stays, since\n * the mark is the point. The thread list re-renders on every store change; the form, and the\n * draft in it, stays until the popover moves to another thread or the root is gone.\n */\nimport {\n isAbandonedNote,\n isThreadRoot,\n threadOf,\n threadRoot,\n type ThreadRoot,\n} from '../../model/annotations/threads'\nimport { threadDeleteLabel, threadPopoverLabel } from '../ui'\n\nimport { button, h } from './dom'\nimport { createPopover } from './popover'\n\nimport type { AnnotationStore } from '../../model/annotations/store'\nimport type { Annotation } from '../../model/annotations/types'\nimport type { Writable } from '../../model/readable'\nimport type { FocusReturn } from '../popover-focus'\n\nexport interface ThreadPopoverOptions {\n root: HTMLElement\n store: AnnotationStore\n activated: Writable<string | null>\n focusReturn: FocusReturn\n}\n\nexport function createThreadPopover(opts: ThreadPopoverOptions): { destroy(): void } {\n const { root, store, activated, focusReturn } = opts\n const popover = createPopover({\n root,\n attrs: {\n class: 'ink-thread-popover',\n 'data-ink-thread-popover': '',\n 'aria-label': 'Note thread',\n },\n focusReturn,\n onDismiss: close,\n })\n const thread = h('ol', { class: 'ink-thread', 'data-ink-thread': '' })\n let form: ThreadForm | null = null\n /** The thread root shown now. */\n let current: string | null = null\n /** Roots given text or a reply here: never dropped as abandoned. */\n const written = new Set<string>()\n /** Notes already removed from here, so they are not removed twice. */\n const dropped = new Set<string>()\n\n function shown(): ThreadRoot | null {\n const a = current ? store.get(current) : undefined\n return a && isThreadRoot(a) ? a : null\n }\n\n function target(): ThreadRoot | null {\n const list = store.list.get()\n const id = activated.get()\n const a = id === null ? undefined : list.find((x) => x.id === id)\n return a ? threadRoot(list, a) : null\n }\n\n const editingRoot = (n: ThreadRoot): boolean => !n.locked && !n.contents?.trim()\n\n /** A note that closing now would remove. */\n function isEmptyRoot(n: ThreadRoot): boolean {\n return !written.has(n.id) && isAbandonedNote(n, store.list.get())\n }\n\n function dropIfEmpty(id: string): void {\n const list = store.list.get()\n const a = list.find((x) => x.id === id)\n if (!a || dropped.has(id) || written.has(id) || !isAbandonedNote(a, list)) return\n dropped.add(id)\n store.remove(id)\n }\n\n function renderThread(n: ThreadRoot): void {\n const items = threadOf(store.list.get(), n)\n if (editingRoot(n) && items.length === 1) {\n thread.remove()\n return\n }\n thread.replaceChildren(...items.map(threadItem))\n if (!thread.isConnected) popover.panel.prepend(thread)\n }\n\n function update(): void {\n const n = target()\n const id = n?.id ?? null\n if (id === current) {\n if (n && form) {\n renderThread(n)\n form.sync(n)\n }\n return\n }\n const previous = current\n current = id\n if (n) {\n const hadFocus = popover.panel.contains(document.activeElement)\n const opening = popover.panel.hidden\n form = createThreadForm(n, { submit, remove: removeThread, close })\n popover.panel.replaceChildren(form.element)\n popover.panel.setAttribute('aria-label', threadPopoverLabel(n))\n renderThread(n)\n popover.show(n.id)\n if ((opening || hadFocus) && !popover.panel.hidden) form.textarea.focus()\n } else {\n form = null\n popover.hide()\n }\n // Activation moved on from a note that never got any text: drop it. This can re-enter\n // `update`, which finds `current` already settled.\n if (previous !== null) dropIfEmpty(previous)\n }\n\n function submit(text: string): void {\n const n = shown()\n if (!n) return\n written.add(n.id)\n if (editingRoot(n)) store.update(n.id, { contents: text })\n else\n store.add({\n type: 'text',\n page: n.page,\n rect: n.rect,\n contents: text,\n inReplyTo: n.id,\n })\n }\n\n /** Locked roots cannot be removed: Delete is not offered for them. */\n function removeThread(): void {\n const n = shown()\n if (!n || n.locked) return\n focusReturn.beforeRemove(popover.anchor)\n dropped.add(n.id)\n store.remove(n.id)\n activated.set(null)\n }\n\n function close(): void {\n const n = shown()\n if (n && isEmptyRoot(n)) focusReturn.beforeRemove(popover.anchor)\n // `update` hides the popover and drops the note if it is still empty.\n activated.set(null)\n }\n\n const stops = [store.list.subscribe(update), activated.subscribe(update)]\n update()\n\n return {\n destroy() {\n for (const stop of stops) stop()\n popover.destroy()\n },\n }\n}\n\nfunction threadItem(a: Annotation): HTMLLIElement {\n return h(\n 'li',\n {\n class: 'ink-thread-item',\n 'data-ink-thread-item': '',\n ...(a.inReplyTo ? { 'data-reply': '' } : {}),\n },\n h('span', { class: 'ink-thread-author' }, a.author ?? 'Anonymous'),\n h(\n 'time',\n { class: 'ink-thread-time', datetime: a.createdAt },\n new Date(a.createdAt).toLocaleString()\n ),\n h('p', { class: 'ink-thread-text' }, a.contents ?? '')\n )\n}\n\ninterface ThreadForm {\n readonly element: HTMLFormElement\n readonly textarea: HTMLTextAreaElement\n /** Follows the root's state: \"Comment\" while its own text is empty, \"Reply\" after. */\n sync(n: ThreadRoot): void\n}\n\nfunction createThreadForm(\n n: ThreadRoot,\n actions: { submit: (text: string) => void; remove: () => void; close: () => void }\n): ThreadForm {\n const textarea = h('textarea', { rows: '2' })\n const send = h('button', { type: 'submit' })\n const remove = button(threadDeleteLabel(n), actions.remove)\n const actionRow = h(\n 'div',\n { class: 'ink-thread-actions' },\n send,\n remove,\n button('Close', actions.close)\n )\n const element = h(\n 'form',\n { class: 'ink-thread-reply', 'data-ink-thread-reply': '' },\n textarea,\n actionRow\n )\n const syncSend = (): void => {\n send.disabled = !textarea.value.trim()\n }\n textarea.addEventListener('input', syncSend)\n element.addEventListener('submit', (e) => {\n e.preventDefault()\n const text = textarea.value.trim()\n if (!text) return\n // Cleared first: the store change re-renders the thread straight away.\n textarea.value = ''\n syncSend()\n actions.submit(text)\n })\n\n function sync(root: ThreadRoot): void {\n const label = !root.locked && !root.contents?.trim() ? 'Comment' : 'Reply'\n textarea.setAttribute('aria-label', label)\n textarea.placeholder = label\n send.textContent = label\n if (root.locked) remove.remove()\n else if (!remove.isConnected) send.after(remove)\n }\n sync(n)\n syncSend()\n return { element, textarea, sync }\n}\n","/*\n * A viewer without a framework: opens a document, mounts the engine and renders the note\n * thread popover, with the bindings' markup so `@inkbar/theme` styles it unchanged.\n * Toolbars are the host's, built from the controls in ./controls.\n */\nimport {\n cssVariableDefaults,\n type AnnotationDefaults,\n} from '../../model/annotations/defaults'\nimport {\n openDocument,\n type InkDocument,\n type InkStatus,\n type OpenOptions,\n} from '../../model/document'\nimport { InkError, isInkError } from '../../model/errors'\nimport { readonly, writable, type Readable } from '../../model/readable'\nimport {\n createMemorySignatureStore,\n createSignatureLibrary,\n} from '../../model/signatures'\nimport { createFocusReturn } from '../popover-focus'\nimport { createToolOptions } from '../tools'\nimport { mountViewer, type MountViewerOptions, type ViewerEngine } from '../viewer-engine'\n\nimport { h } from './dom'\nimport { createThreadPopover } from './thread-popover'\n\nimport type { DocumentSource } from '../../model/source'\nimport type { PdfAssets } from '../../pdfjs/types'\nimport type { ToolController } from '../tools'\nimport type { Viewport } from '../viewport'\n\n/**\n * The engine options, less what the viewer owns: the container, the document, the tool style\n * (bound to one document's store, so each engine makes its own), and the tool options and\n * signature library (one for the viewer's life).\n */\nexport interface CreateViewerOptions extends Omit<\n MountViewerOptions,\n | 'container'\n | 'document'\n | 'toolStyle'\n | 'toolHistory'\n | 'toolOptions'\n | 'signatureLibrary'\n> {\n source: DocumentSource\n assets: PdfAssets\n /** User password for encrypted files. `open` can pass its own for one load. */\n password?: string\n /** Default: read from the theme's CSS variables on the viewer root. */\n defaults?: AnnotationDefaults\n history?: OpenOptions['history']\n /** The thread popover for notes and text markup. Default true. */\n threads?: boolean\n onReady?(this: void, doc: InkDocument): void\n onError?(this: void, error: InkError): void\n}\n\nexport interface Viewer {\n /** The root element (`[data-ink-root]`) the viewer rendered into the host element. */\n readonly element: HTMLElement\n readonly status: Readable<InkStatus>\n readonly document: Readable<InkDocument | null>\n /** Set while a document is ready; `null` otherwise. */\n readonly engine: Readable<ViewerEngine | null>\n /**\n * The current viewport and tool controller; `null` while no document is ready. Both change\n * when the engine rebuilds, so read them here rather than holding on to `engine.viewport`.\n */\n readonly viewport: Readable<Viewport | null>\n readonly tools: Readable<ToolController | null>\n /**\n * The activated annotation's id: the one last clicked, or activated with Enter or Space.\n * The note thread opens from it, and an app can anchor its own popover (`createPopover`) to\n * it. `null` when none is, and again once that annotation is removed or the document closes.\n */\n readonly activated: Readable<string | null>\n /**\n * Activates annotation `id`, or clears the activation with `null` (closing the thread\n * popover). Unlike a click, it does not select the annotation or call `onActivate`. An id\n * not in the open document's annotations is ignored.\n */\n setActivated(id: string | null): void\n /**\n * Opens another document in place; the previous one is destroyed. Latest call wins.\n * `password` is used for this load only; without it, the constructor's `password` applies.\n */\n open(source: DocumentSource, opts?: { password?: string }): void\n destroy(): void\n}\n\nexport function createViewer(el: HTMLElement, opts: CreateViewerOptions): Viewer {\n const {\n source: initial,\n assets,\n password,\n defaults,\n history,\n threads: withThreads = true,\n onReady,\n onError,\n onActivate,\n onBuild,\n onPageMount,\n onPageUnmount,\n onPageError,\n // Not options (see the type), but a caller without types could still pass them.\n toolStyle: _toolStyle,\n toolOptions: _toolOptions,\n signatureLibrary: _signatureLibrary,\n signatures: signatureStore,\n ...view\n } = opts as CreateViewerOptions &\n Pick<MountViewerOptions, 'toolStyle' | 'toolOptions' | 'signatureLibrary'>\n /** One library for the viewer's life, so templates and the menu outlive each document. */\n const signatures = createSignatureLibrary(\n signatureStore ?? createMemorySignatureStore()\n )\n /** Tool options persist for the viewer's life; the tool style is per document. */\n const toolOptions = createToolOptions()\n const status = writable<InkStatus>({ state: 'idle' })\n const current = writable<InkDocument | null>(null)\n const engine = writable<ViewerEngine | null>(null)\n const viewport = writable<Viewport | null>(null)\n const tools = writable<ToolController | null>(null)\n /** The activated annotation: the note thread opens from it. */\n const activated = writable<string | null>(null)\n\n const root = h('div', { 'data-ink-root': '', 'data-state': 'idle' })\n const scroll = h('div', {\n class: 'ink-scroll',\n 'data-ink-scroll': '',\n tabindex: '0',\n role: 'document',\n 'aria-label': 'Document',\n })\n const viewportRoot = h(\n 'div',\n { class: 'ink-viewport-root', 'data-ink-viewport-root': '', 'data-state': 'idle' },\n scroll\n )\n root.append(viewportRoot)\n el.append(root)\n\n const focusReturn = createFocusReturn({\n root: () => root,\n activated: () => activated.get(),\n })\n\n let statusEl: HTMLElement | null = null\n function renderStatus(s: InkStatus): void {\n root.dataset.state = s.state\n viewportRoot.dataset.state = s.state\n statusEl?.remove()\n statusEl = null\n if (s.state === 'loading') {\n statusEl = h(\n 'div',\n { class: 'ink-status', role: 'status', 'aria-live': 'polite' },\n 'Loading document…'\n )\n } else if (s.state === 'error') {\n // The engine's message is not written for readers: it stays on the code's tooltip.\n statusEl = h(\n 'div',\n { class: 'ink-status ink-error', role: 'alert' },\n h('p', { class: 'ink-error-title' }, 'This document could not be opened.'),\n h(\n 'p',\n {},\n h('code', { class: 'ink-error-code', title: s.error.message }, s.error.code)\n )\n )\n }\n if (statusEl) viewportRoot.prepend(statusEl)\n }\n function setStatus(s: InkStatus): void {\n renderStatus(s)\n status.set(s)\n }\n\n /** Mounts the engine and the thread popover for a ready document; returns their teardown. */\n function start(doc: InkDocument): () => void {\n const store = doc.annotations\n const threads = withThreads\n ? createThreadPopover({ root, store, activated, focusReturn })\n : null\n // An activated annotation that has gone (removed, undone) is no longer activated, so it\n // does not reopen its popover if it comes back.\n const stopList = store.list.subscribe(() => {\n const id = activated.get()\n if (id !== null && !store.get(id)) activated.set(null)\n })\n const hosts = new Map<number, HTMLElement>()\n const errors = new Map<number, HTMLElement>()\n const clearError = (page: number): void => {\n errors.get(page)?.remove()\n errors.delete(page)\n }\n const mounted = mountViewer({\n ...view,\n container: scroll,\n document: doc,\n toolOptions,\n signatureLibrary: signatures,\n onActivate: (id) => {\n activated.set(id)\n onActivate?.(id)\n },\n onBuild: (vp, tc) => {\n // Tools first: a viewport subscriber may read the tools.\n tools.set(tc)\n viewport.set(vp)\n onBuild?.(vp, tc)\n },\n onPageMount: (page, mount, host) => {\n hosts.set(page, host)\n onPageMount?.(page, mount, host)\n },\n // A failed page that unmounts reports no recovery: its error goes with it.\n onPageUnmount: (page) => {\n hosts.delete(page)\n clearError(page)\n onPageUnmount?.(page)\n },\n onPageError: (page, error) => {\n clearError(page)\n const host = hosts.get(page)\n if (error && host) {\n const shown = h(\n 'div',\n { class: 'ink-page-error', 'data-ink-page-error': '', role: 'alert' },\n h('p', {}, `Page ${page + 1} could not be shown.`),\n h('code', { class: 'ink-error-code' }, error.code)\n )\n host.append(shown)\n errors.set(page, shown)\n }\n onPageError?.(page, error)\n },\n })\n engine.set(mounted)\n return () => {\n stopList()\n threads?.destroy()\n activated.set(null)\n engine.set(null)\n mounted.destroy()\n viewport.set(null)\n tools.set(null)\n }\n }\n\n let loads = 0\n let destroyed = false\n let stop: () => void = () => undefined\n\n /** Tears down the open document, if any, and destroys it. */\n function close(): void {\n stop()\n stop = () => undefined\n const doc = current.get()\n current.set(null)\n doc?.destroy()\n }\n\n function open(source: DocumentSource, openOpts?: { password?: string }): void {\n if (destroyed) return\n const load = ++loads\n close()\n setStatus({ state: 'loading' })\n // The theme's colour variables are read from the root, which is in the page by now.\n openDocument(source, {\n assets,\n password: openOpts?.password ?? password,\n defaults: defaults ?? cssVariableDefaults(root),\n history,\n }).then(\n (doc) => {\n // A later `open` or `destroy` superseded this load.\n if (load !== loads) {\n doc.destroy()\n return\n }\n current.set(doc)\n const s = doc.status.get()\n if (s.state === 'error') {\n setStatus(s)\n onError?.(s.error)\n return\n }\n // The status leaves the layout before the engine measures the scroll element, and the\n // engine is set before anyone hears `ready`.\n renderStatus({ state: 'ready' })\n stop = start(doc)\n status.set({ state: 'ready' })\n // A status subscriber may have opened another document already.\n if (load === loads) onReady?.(doc)\n },\n (cause: unknown) => {\n // Only a programmer error (missing assets) rejects; it gets the error state too.\n if (load !== loads) return\n const error = isInkError(cause)\n ? cause\n : new InkError(\n 'InvalidPdf',\n cause instanceof Error ? cause.message : String(cause),\n {},\n cause\n )\n setStatus({ state: 'error', error })\n onError?.(error)\n }\n )\n }\n\n open(initial)\n\n return {\n element: root,\n status: readonly(status),\n document: readonly(current),\n engine: readonly(engine),\n viewport: readonly(viewport),\n tools: readonly(tools),\n activated: readonly(activated),\n setActivated(id) {\n if (id === null || current.get()?.annotations.get(id)) activated.set(id)\n },\n open,\n destroy() {\n if (destroyed) return\n destroyed = true\n loads++\n close()\n root.remove()\n },\n }\n}\n","/*\n * Toolbar controls for createViewer, with the classes and data attributes of the bindings'\n * components so `@inkbar/theme` styles them. Each control follows a viewer: it is disabled\n * while no document is ready and picks up the new viewport after every engine rebuild. A\n * control lives as long as its viewer.\n *\n * Buttons show an icon from `@inkbar/icons`; replace their children with your own and the\n * accessible name stays. Put controls in a `createToolbar()` bar, and put the bar where it\n * belongs: `viewer.element.prepend(bar)` above the document, `append` below it.\n */\nimport {\n ChevronLeft,\n ChevronRight,\n Highlighter,\n ICON_ATTRIBUTES,\n MessageSquare,\n PenLine,\n PenTool,\n Signature,\n Redo2,\n Square,\n SquareDashedMousePointer,\n TextCursor,\n Type,\n Undo2,\n ZoomIn,\n ZoomOut,\n type IconNode,\n} from '@inkbar/icons'\n\nimport { TOOL_LABELS, ZOOM_LEVELS } from '../ui'\n\nimport { h } from './dom'\n\nimport type { InkDocument } from '../../model/document'\nimport type { Readable } from '../../model/readable'\nimport type { ToolController, ToolId } from '../tools'\nimport type { Viewport } from '../viewport'\nimport type { Viewer } from './create-viewer'\n\ntype Control = HTMLButtonElement | HTMLSelectElement | HTMLInputElement\n\n/**\n * Runs `connect` for every value `source` takes while it is set, undoing the previous run's\n * subscriptions first, and disables `control` while it is `null`.\n */\nfunction follow<T>(\n source: Readable<T | null>,\n control: Control,\n connect: (value: T, watch: <V>(r: Readable<V>, fn: (value: V) => void) => void) => void,\n reset?: () => void\n): void {\n let stops: (() => void)[] = []\n const watch = <V>(r: Readable<V>, fn: (value: V) => void): void => {\n fn(r.get())\n stops.push(r.subscribe(fn))\n }\n const run = (value: T | null): void => {\n for (const s of stops) s()\n stops = []\n control.disabled = value === null\n if (value === null) reset?.()\n else connect(value, watch)\n }\n run(source.get())\n source.subscribe(run)\n}\n\nconst SVG = 'http://www.w3.org/2000/svg'\n\nconst TOOL_ICONS: Readonly<Partial<Record<ToolId, IconNode>>> = {\n 'select-text': TextCursor,\n select: SquareDashedMousePointer,\n highlight: Highlighter,\n 'redact-area': Square,\n sketch: PenTool,\n draw: PenLine,\n note: MessageSquare,\n freetext: Type,\n signature: Signature,\n}\n\n/**\n * An `<svg>` drawing `icon` from `@inkbar/icons`, hidden from assistive technology: the\n * control it sits in carries the name. The theme sizes it with `--ink-icon-size`.\n */\nexport function createIcon(icon: IconNode): SVGSVGElement {\n const svg = document.createElementNS(SVG, 'svg')\n const attrs = {\n ...ICON_ATTRIBUTES,\n width: '18',\n height: '18',\n class: 'ink-icon',\n 'aria-hidden': 'true',\n }\n for (const [k, v] of Object.entries(attrs)) svg.setAttribute(k, v)\n for (const [tag, shape] of icon) {\n const child = document.createElementNS(SVG, tag)\n for (const [k, v] of Object.entries(shape)) child.setAttribute(k, v)\n svg.append(child)\n }\n return svg\n}\n\nfunction button(\n label: string,\n attrs: Record<string, string>,\n icon: IconNode | undefined\n): HTMLButtonElement {\n const b = h('button', { type: 'button', ...attrs, 'aria-label': label, title: label })\n if (icon) b.append(createIcon(icon))\n return b\n}\n\n/**\n * A toolbar following the WAI-ARIA toolbar pattern: its buttons share one Tab stop, with\n * arrow keys, Home and End to move between them. Fields and selects are Tab stops of their\n * own and keep their keys. Buttons added later join in.\n */\nexport function createToolbar(opts: { label?: string } = {}): HTMLElement {\n const bar = h('div', {\n class: 'ink-toolbar',\n 'data-ink-toolbar': '',\n role: 'toolbar',\n 'aria-label': opts.label ?? 'Document tools',\n 'aria-orientation': 'horizontal',\n })\n rovingTabindex(bar)\n return bar\n}\n\n/** A divider between groups of controls in a horizontal toolbar. Not focusable. */\nexport function createToolbarSeparator(): HTMLDivElement {\n return h('div', {\n role: 'separator',\n 'aria-orientation': 'vertical',\n class: 'ink-toolbar-separator',\n 'data-ink-toolbar-separator': '',\n })\n}\n\n/** Undoes the last change to the document's annotations; disabled when there is none. */\nexport function createUndo(viewer: Viewer): HTMLButtonElement {\n return historyButton(viewer, 'undo')\n}\n\n/** Redoes the last undone change; disabled when there is none. */\nexport function createRedo(viewer: Viewer): HTMLButtonElement {\n return historyButton(viewer, 'redo')\n}\n\nfunction historyButton(viewer: Viewer, action: 'undo' | 'redo'): HTMLButtonElement {\n const label = action === 'undo' ? 'Undo' : 'Redo'\n const b = button(\n label,\n { class: `ink-${action}`, [`data-ink-${action}`]: '' },\n action === 'undo' ? Undo2 : Redo2\n )\n b.addEventListener('click', () => viewer.document.get()?.history[action]())\n follow<InkDocument>(viewer.document, b, (doc, watch) =>\n watch(action === 'undo' ? doc.history.canUndo : doc.history.canRedo, (can) => {\n b.disabled = !can\n })\n )\n return b\n}\n\n/**\n * Sets the tool; pressed while it is the active one. A host tool's button has no icon (append\n * your own) and is named by `label`, else by the tool id.\n */\nexport function createToolButton(\n viewer: Viewer,\n tool: ToolId,\n opts: { label?: string } = {}\n): HTMLButtonElement {\n const label = opts.label ?? TOOL_LABELS[tool] ?? tool\n const b = button(\n label,\n { class: 'ink-tool-button', 'data-ink-tool-button': '', 'data-tool': tool },\n TOOL_ICONS[tool]\n )\n const show = (active: ToolId | null): void => {\n const on = active === tool\n b.dataset.state = on ? 'on' : 'off'\n b.setAttribute('aria-pressed', String(on))\n }\n b.addEventListener('click', () => viewer.tools.get()?.set(tool))\n follow<ToolController>(\n viewer.tools,\n b,\n (tools, watch) => watch(tools.active, show),\n () => show(null)\n )\n return b\n}\n\nexport function createZoomIn(viewer: Viewer): HTMLButtonElement {\n const b = button('Zoom in', { class: 'ink-zoom-in', 'data-ink-zoom-in': '' }, ZoomIn)\n b.addEventListener('click', () => viewer.viewport.get()?.zoomBy(1.25))\n follow(viewer.viewport, b, () => undefined)\n return b\n}\n\nexport function createZoomOut(viewer: Viewer): HTMLButtonElement {\n const b = button(\n 'Zoom out',\n { class: 'ink-zoom-out', 'data-ink-zoom-out': '' },\n ZoomOut\n )\n b.addEventListener('click', () => viewer.viewport.get()?.zoomBy(0.8))\n follow(viewer.viewport, b, () => undefined)\n return b\n}\n\n/** Fit width, fit page and the zoom levels; a zoom between levels gets an option of its own. */\nexport function createZoomSelect(viewer: Viewer): HTMLSelectElement {\n const custom = h('option', { value: 'custom' })\n const select = h(\n 'select',\n { class: 'ink-zoom-select', 'data-ink-zoom-select': '', 'aria-label': 'Zoom' },\n h('option', { value: 'fit-width' }, 'Fit width'),\n h('option', { value: 'fit-page' }, 'Fit page'),\n ...ZOOM_LEVELS.map((l) =>\n h('option', { value: String(l) }, `${Math.round(l * 100)}%`)\n )\n )\n select.addEventListener('change', () => {\n const v = select.value\n const viewport = viewer.viewport.get()\n if (v === 'fit-width' || v === 'fit-page') viewport?.setZoom(v)\n else if (v !== 'custom') viewport?.setZoom(Number(v))\n })\n follow<Viewport>(\n viewer.viewport,\n select,\n (viewport, watch) =>\n watch(viewport.zoom, (z) => {\n const level =\n typeof z === 'number'\n ? ZOOM_LEVELS.find((l) => Math.abs(l - z) < 0.001)\n : undefined\n if (typeof z === 'number' && level === undefined) {\n custom.textContent = `${Math.round(z * 100)}%`\n // In order among the levels.\n const after = [...select.options].find(\n (o) => o !== custom && Number(o.value) > z\n )\n select.insertBefore(custom, after ?? null)\n select.value = 'custom'\n } else {\n custom.remove()\n select.value = typeof z === 'number' ? String(level) : z\n }\n }),\n () => {\n custom.remove()\n select.value = 'fit-width'\n }\n )\n return select\n}\n\n/**\n * The current page, 1-based. Enter or leaving the field goes to the page typed; a number out\n * of range puts the current page back.\n */\nexport function createPageInput(viewer: Viewer): HTMLInputElement {\n const input = h('input', {\n class: 'ink-page-input',\n 'data-ink-page-input': '',\n type: 'number',\n inputmode: 'numeric',\n 'aria-label': 'Page',\n min: '1',\n })\n const commit = (): void => {\n const viewport = viewer.viewport.get()\n const doc = viewer.document.get()\n if (!viewport || !doc) return\n const n = Number(input.value)\n const current = viewport.currentPage.get()\n if (Number.isInteger(n) && n >= 1 && n <= doc.pages.length) {\n if (n - 1 !== current) viewport.scrollToPage(n - 1)\n } else input.value = String(current + 1)\n }\n // `change` fires on blur after typing and on each arrow-key or spinner step.\n input.addEventListener('change', commit)\n input.addEventListener('keydown', (e) => {\n if (e.key !== 'Enter' || e.defaultPrevented) return\n e.preventDefault()\n commit()\n })\n follow<Viewport>(\n viewer.viewport,\n input,\n (viewport, watch) => {\n input.max = String(viewer.document.get()?.pages.length ?? 1)\n watch(viewport.currentPage, (p) => (input.value = String(p + 1)))\n },\n () => (input.value = '')\n )\n return input\n}\n\n/** \"of 12\": the page count, announced when it changes. */\nexport function createPageCount(viewer: Viewer): HTMLSpanElement {\n const span = h('span', {\n class: 'ink-page-count',\n 'data-ink-page-count': '',\n 'aria-live': 'polite',\n })\n const show = (): void => {\n const doc = viewer.document.get()\n span.textContent = doc && viewer.viewport.get() ? `of ${doc.pages.length}` : ''\n }\n show()\n viewer.viewport.subscribe(show)\n return span\n}\n\n/** Disabled on the first page. */\nexport function createPrevPage(viewer: Viewer): HTMLButtonElement {\n return pageButton(viewer, -1)\n}\n\n/** Disabled on the last page. */\nexport function createNextPage(viewer: Viewer): HTMLButtonElement {\n return pageButton(viewer, 1)\n}\n\nfunction pageButton(viewer: Viewer, step: -1 | 1): HTMLButtonElement {\n const b =\n step < 0\n ? button(\n 'Previous page',\n { class: 'ink-prev-page', 'data-ink-prev-page': '' },\n ChevronLeft\n )\n : button(\n 'Next page',\n { class: 'ink-next-page', 'data-ink-next-page': '' },\n ChevronRight\n )\n b.addEventListener('click', () => {\n const viewport = viewer.viewport.get()\n viewport?.scrollToPage(viewport.currentPage.get() + step)\n })\n follow<Viewport>(viewer.viewport, b, (viewport, watch) => {\n const last = (viewer.document.get()?.pages.length ?? 1) - 1\n watch(viewport.currentPage, (p) => {\n b.disabled = step < 0 ? p <= 0 : p >= last\n })\n })\n return b\n}\n\n/** Roving items, as in the bindings' Radix toolbar: buttons only. */\nconst ITEMS = 'button'\n\n/**\n * One Tab stop across the enabled buttons in `bar`: the current one has `tabindex=\"0\"`, the\n * rest `-1`. ArrowLeft and ArrowRight move between them and wrap, Home and End go to the ends.\n * Inputs, selects and textareas, built in or added by the host, keep their own tabindex (a\n * Tab stop of their own by default) and their own arrow, Home and End keys.\n */\nfunction rovingTabindex(bar: HTMLElement): { sync(): void; destroy(): void } {\n let current: HTMLElement | null = null\n const items = (): HTMLElement[] =>\n [...bar.querySelectorAll<HTMLButtonElement>(ITEMS)].filter(\n (el) => !el.disabled && !el.closest('[hidden]')\n )\n const sync = (): void => {\n const list = items()\n if (!current || !list.includes(current)) current = list[0] ?? null\n for (const el of bar.querySelectorAll<HTMLElement>(ITEMS))\n el.tabIndex = el === current ? 0 : -1\n // Fields are left alone: they are Tab stops by default, and a host's tabindex on one stays.\n }\n const onFocusIn = (e: FocusEvent): void => {\n const target = e.target as HTMLElement\n if (!items().includes(target)) return\n current = target\n sync()\n }\n const onKeyDown = (e: KeyboardEvent): void => {\n if (e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey) return\n const list = items()\n const i = list.indexOf(e.target as HTMLElement)\n if (i < 0) return\n const last = list.length - 1\n const next =\n e.key === 'ArrowRight'\n ? i === last\n ? 0\n : i + 1\n : e.key === 'ArrowLeft'\n ? i === 0\n ? last\n : i - 1\n : e.key === 'Home'\n ? 0\n : e.key === 'End'\n ? last\n : -1\n if (next < 0) return\n e.preventDefault()\n list[next]!.focus()\n }\n // Host-added buttons, and buttons a host enables or disables, join the rotation.\n const observer = new MutationObserver(sync)\n observer.observe(bar, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['disabled', 'hidden'],\n })\n bar.addEventListener('focusin', onFocusIn)\n bar.addEventListener('keydown', onKeyDown)\n sync()\n return {\n sync,\n destroy() {\n observer.disconnect()\n bar.removeEventListener('focusin', onFocusIn)\n bar.removeEventListener('keydown', onKeyDown)\n },\n }\n}\n","/*\n * A menu anchored to a trigger button, shared by the vanilla style controls. The shell owns\n * the panel (`role=\"menu\"`, created on open and removed on close), its placement (the\n * popover's), and dismissal: an outside press, focus leaving, or Escape (which returns focus\n * to the trigger). ArrowDown on the trigger opens it with the first enabled item focused.\n * It closes when the trigger becomes disabled. Items are `[role=\"menuitemradio\"]` buttons;\n * ArrowUp, ArrowDown, Home and End move between them.\n */\nimport { focusInitialMenuItem, handleMenuKeys, menuItems } from '../menu-keys'\n\nimport { h } from './dom'\nimport { placePanel } from './popover'\n\nexport interface MenuOptions {\n label: string\n /** Extra attributes for the panel. */\n attrs?: Record<string, string>\n /**\n * The panel's role. `menu` (the default) is a list of items with arrow-key movement; `dialog`\n * is for a panel of mixed widgets, which take Tab and their own keys, and opens on the first\n * focusable one.\n */\n role?: 'menu' | 'dialog'\n /** The element the panel lines up under. Default `trigger`; a split button passes itself. */\n anchor?: HTMLElement\n /**\n * Whether `target` belongs to a menu nested in this one (its panel sits outside this panel\n * in the DOM). Presses, focus and Escape inside it neither dismiss this menu nor close it.\n */\n owns?(target: Node): boolean\n /** Builds the items on first call and updates them in place after; called on open and `refresh`. */\n render(menu: HTMLElement): void\n}\n\nexport interface Menu {\n readonly isOpen: boolean\n /** Re-renders an open menu, and closes it if the trigger has become disabled. */\n refresh(): void\n close(restoreFocus?: boolean): void\n}\n\nconst FOCUSABLE =\n 'select:not(:disabled), input:not(:disabled), button:not(:disabled):not([tabindex=\"-1\"])'\n\nexport function createMenu(trigger: HTMLButtonElement, opts: MenuOptions): Menu {\n const role = opts.role ?? 'menu'\n let panel: HTMLElement | null = null\n let teardown: (() => void) | null = null\n\n const place = (): void => {\n if (panel) placePanel(panel, (opts.anchor ?? trigger).getBoundingClientRect())\n }\n\n function close(restoreFocus = false): void {\n if (!panel) return\n teardown?.()\n teardown = null\n panel.remove()\n panel = null\n trigger.setAttribute('aria-expanded', 'false')\n trigger.dataset.state = 'closed'\n if (restoreFocus) trigger.focus()\n }\n\n function open(focus: 'initial' | 'first'): void {\n if (panel || trigger.disabled) return\n const el = h('div', {\n role,\n 'aria-label': opts.label,\n class: 'ink-select-content ink-menu-content',\n 'data-ink-select-content': '',\n ...opts.attrs,\n })\n panel = el\n el.style.visibility = 'hidden'\n document.body.append(el)\n opts.render(el)\n place()\n el.style.visibility = ''\n trigger.setAttribute('aria-expanded', 'true')\n trigger.dataset.state = 'open'\n if (role === 'dialog')\n el.querySelector<HTMLElement>(FOCUSABLE)?.focus({ preventScroll: true })\n else if (focus === 'first') menuItems(el)[0]?.focus({ preventScroll: true })\n else focusInitialMenuItem(el)\n\n const onKey = (e: KeyboardEvent): void => {\n const nested = opts.owns?.(e.target as Node) === true\n if (e.key === 'Escape') {\n // The nested menu closes itself; this one stays.\n if (nested) return\n e.preventDefault()\n close(true)\n } else if (role === 'menu' && el.contains(e.target as Node)) handleMenuKeys(e, el)\n }\n const outside = (t: Node): boolean =>\n !el.contains(t) && !trigger.contains(t) && opts.owns?.(t) !== true\n const onPress = (e: PointerEvent): void => {\n if (outside(e.target as Node)) close()\n }\n const onFocus = (e: FocusEvent): void => {\n if (outside(e.target as Node)) close()\n }\n document.addEventListener('keydown', onKey, true)\n document.addEventListener('pointerdown', onPress, true)\n document.addEventListener('focusin', onFocus)\n window.addEventListener('resize', place)\n document.addEventListener('scroll', place, true)\n teardown = () => {\n document.removeEventListener('keydown', onKey, true)\n document.removeEventListener('pointerdown', onPress, true)\n document.removeEventListener('focusin', onFocus)\n window.removeEventListener('resize', place)\n document.removeEventListener('scroll', place, true)\n }\n }\n\n trigger.addEventListener('click', () => (panel ? close(true) : open('initial')))\n trigger.addEventListener('keydown', (e) => {\n // An enclosing menu that already moved focus on this key keeps it.\n if (e.key !== 'ArrowDown' || e.defaultPrevented || panel || trigger.disabled) return\n e.preventDefault()\n open('first')\n })\n\n return {\n get isOpen() {\n return panel !== null\n },\n refresh() {\n if (!panel) return\n if (trigger.disabled) close()\n else {\n opts.render(panel)\n place()\n }\n },\n close,\n }\n}\n","/*\n * The line style menu for createViewer: the same markup, classes and data attributes as the\n * bindings' `InkLineStyleMenu`, so `@inkbar/theme` styles both. The trigger follows the\n * viewer's tool style (disabled while nothing supports line style, `data-mixed` when the\n * selection disagrees); the panel is created on open and removed on close.\n */\nimport { Check, Minus } from '@inkbar/icons'\n\nimport { lineStyleMenuModel, type LineStyleMenuModel } from '../ui'\n\nimport { createIcon } from './controls'\nimport { h } from './dom'\nimport { createMenu } from './menu'\n\nimport type { Viewer } from './create-viewer'\nimport type { ToolStyle } from '../../model/annotations/tool-style'\n\n/** A button that opens the line style menu: weight, solid or dashed, and arrowheads. */\nexport function createLineStyleMenu(viewer: Viewer): HTMLButtonElement {\n const trigger = h('button', {\n type: 'button',\n class: 'ink-menu-trigger ink-line-style-menu',\n 'data-ink-line-style-menu': '',\n 'data-state': 'closed',\n 'aria-label': 'Line style',\n title: 'Line style',\n 'aria-haspopup': 'menu',\n 'aria-expanded': 'false',\n })\n trigger.append(createIcon(Minus))\n trigger.disabled = true\n\n let style: ToolStyle | null = null\n let stops: (() => void)[] = []\n\n const model = (): LineStyleMenuModel =>\n lineStyleMenuModel(style?.current.get() ?? {}, style?.supported.get() ?? new Set())\n\n function refresh(): void {\n const m = model()\n trigger.disabled = !m.enabled\n if (m.mixed) trigger.setAttribute('data-mixed', '')\n else trigger.removeAttribute('data-mixed')\n menu.refresh()\n }\n\n /** Builds the panel's sections on the first call; later calls update them in place. */\n function paint(root: HTMLElement, m: LineStyleMenuModel): void {\n const menu = root\n if (menu.childElementCount === 0) {\n for (const section of m.sections) {\n const group = h(\n 'div',\n { role: 'group', class: 'ink-menu-group', 'aria-label': section.label },\n h('div', { class: 'ink-menu-label', 'aria-hidden': 'true' }, section.label)\n )\n for (const item of section.items) {\n const b = h(\n 'button',\n {\n type: 'button',\n role: 'menuitemradio',\n class: 'ink-select-item ink-menu-item',\n 'data-ink-select-item': '',\n tabindex: '-1',\n 'data-key': item.key,\n },\n item.label\n )\n b.addEventListener('click', () => {\n const found = model()\n .sections.flatMap((s) => s.items)\n .find((i) => i.key === item.key && i.label === item.label)\n if (found) style?.set(found.patch)\n })\n group.append(b)\n }\n menu.append(group)\n }\n }\n m.sections.forEach((section, i) => {\n const group = menu.children[i] as HTMLElement\n group.toggleAttribute('data-disabled', section.disabled)\n if (section.disabled) group.setAttribute('aria-disabled', 'true')\n else group.removeAttribute('aria-disabled')\n section.items.forEach((item, j) => {\n const b = group.children[j + 1] as HTMLButtonElement\n b.disabled = section.disabled\n b.setAttribute('aria-checked', String(item.checked))\n b.dataset.state = item.checked ? 'checked' : 'unchecked'\n const mark = b.querySelector('.ink-select-indicator')\n if (item.checked && !mark) {\n const span = h('span', { class: 'ink-select-indicator' })\n span.append(createIcon(Check))\n b.append(span)\n } else if (!item.checked) mark?.remove()\n })\n })\n }\n\n const menu = createMenu(trigger, {\n label: 'Line style',\n attrs: { 'data-ink-menu': 'line-style' },\n render: (root) => paint(root, model()),\n })\n\n const follow = (engine: { toolStyle: ToolStyle } | null): void => {\n for (const stop of stops) stop()\n stops = []\n style = engine?.toolStyle ?? null\n if (style)\n stops = [style.current.subscribe(refresh), style.supported.subscribe(refresh)]\n // The panel's old style is gone with the old document.\n if (!style) menu.close()\n refresh()\n }\n follow(viewer.engine.get())\n viewer.engine.subscribe(follow)\n return trigger\n}\n","/*\n * The colour menus for createViewer: the same markup, classes and data attributes as the\n * bindings' `InkColorMenu`, so `@inkbar/theme` styles both. The trigger shows the current\n * colour as a swatch and follows the viewer's tool style (disabled while nothing supports the\n * property); the panel is created on open and removed on close.\n */\nimport { Check } from '@inkbar/icons'\n\nimport {\n COLOR_COLUMNS,\n colorMenuModel,\n type ColorMenuModel,\n type ColorProperty,\n} from '../ui'\n\nimport { createIcon } from './controls'\nimport { h } from './dom'\nimport { createMenu } from './menu'\n\nimport type { Viewer } from './create-viewer'\nimport type {\n CurrentStyle,\n StyleGroup,\n StyleKey,\n StyleProps,\n ToolStyle,\n} from '../../model/annotations/tool-style'\nimport type { Readable } from '../../model/readable'\n\nexport interface ColorMenuOptions {\n property: ColorProperty\n /** Accessible name; defaults to \"Border colour\", \"Fill colour\" or \"Text colour\". */\n label?: string\n /**\n * Scopes the menu to one style group (`ToolStyle.scoped`): it shows and sets that group's\n * colour whatever tool is active, and recolours the selection only when it is all in the group.\n */\n group?: StyleGroup\n /** The colour new annotations get while the style leaves it unset; the trigger shows it. */\n fallback?: Readable<string | undefined>\n}\n\n/** Sets a swatch element's kind and colour from the model's trigger. */\nfunction paintSwatch(swatch: HTMLElement, model: ColorMenuModel): void {\n const t = model.trigger\n swatch.dataset.kind = t.kind\n if (t.kind === 'color') {\n swatch.dataset.color = t.color\n swatch.style.setProperty('--ink-swatch', t.color)\n } else {\n delete swatch.dataset.color\n swatch.style.removeProperty('--ink-swatch')\n }\n}\n\nfunction checkmark(): HTMLElement {\n const span = h('span', { class: 'ink-select-indicator' })\n span.append(createIcon(Check))\n return span\n}\n\n/** A button that opens a colour menu for one colour property of the selection or tool. */\nexport function createColorMenu(\n viewer: Viewer,\n opts: ColorMenuOptions\n): HTMLButtonElement {\n const { property } = opts\n const name = opts.label ?? colorMenuModel(property, {}, new Set()).label\n const trigger = h('button', {\n type: 'button',\n class: 'ink-menu-trigger ink-color-menu',\n 'data-ink-color-menu': property,\n 'data-state': 'closed',\n 'aria-label': name,\n title: name,\n 'aria-haspopup': 'menu',\n 'aria-expanded': 'false',\n })\n const swatch = h('span', {\n class: 'ink-swatch',\n 'data-ink-swatch': '',\n 'data-property': property,\n 'aria-hidden': 'true',\n })\n trigger.append(swatch)\n trigger.disabled = true\n\n /** What the menu reads and writes: the whole tool style, or one group's view of it. */\n let style: {\n current: Readable<CurrentStyle>\n supported: Readable<ReadonlySet<StyleKey>>\n set(patch: StyleProps): void\n } | null = null\n let stops: (() => void)[] = []\n\n const model = (): ColorMenuModel =>\n colorMenuModel(\n property,\n style?.current.get() ?? {},\n style?.supported.get() ?? new Set(),\n opts.fallback?.get()\n )\n\n function refresh(): void {\n const m = model()\n trigger.disabled = !m.enabled\n if (m.mixed) trigger.setAttribute('data-mixed', '')\n else trigger.removeAttribute('data-mixed')\n paintSwatch(swatch, m)\n if (picker && !trigger.isConnected) picker.remove()\n menu.refresh()\n }\n\n /**\n * The native colour input lives beside the trigger, not in the panel: the panel is removed\n * when the menu closes, and a pick that arrives after that must still land. Created on\n * first use and reused.\n */\n let picker: HTMLInputElement | null = null\n function pickerInput(): HTMLInputElement {\n if (!picker) {\n picker = h('input', {\n type: 'color',\n class: 'ink-color-input',\n 'aria-label': 'Custom colour',\n 'data-ink-color-input': property,\n tabindex: '-1',\n })\n picker.addEventListener('change', () => style?.set(model().custom(picker!.value)))\n }\n picker.value = model().customValue.toLowerCase()\n if (picker.parentNode !== trigger.parentNode || !picker.isConnected)\n if (trigger.parentNode) trigger.after(picker)\n else document.body.append(picker)\n return picker\n }\n\n function paint(root: HTMLElement, m: ColorMenuModel): void {\n if (root.childElementCount === 0) {\n if (m.noFill) {\n const b = h(\n 'button',\n {\n type: 'button',\n role: 'menuitemradio',\n class: 'ink-select-item ink-menu-item',\n 'data-ink-select-item': '',\n 'data-key': 'no-fill',\n tabindex: '-1',\n },\n 'No fill'\n )\n b.addEventListener('click', () => {\n const found = model().noFill\n if (found) style?.set(found.patch)\n })\n root.append(b)\n }\n const grid = h('div', {\n role: 'group',\n 'aria-label': 'Colours',\n class: 'ink-color-grid',\n 'data-ink-menu-columns': String(COLOR_COLUMNS),\n })\n for (const sw of m.swatches) {\n const b = h('button', {\n type: 'button',\n role: 'menuitemradio',\n class: 'ink-swatch-item',\n 'aria-label': sw.label,\n 'data-key': sw.key,\n tabindex: '-1',\n })\n b.style.setProperty('--ink-swatch', sw.color)\n b.addEventListener('click', () => {\n const found = model().swatches.find((s) => s.key === sw.key)\n if (found) style?.set(found.patch)\n })\n grid.append(b)\n }\n root.append(grid)\n const custom = h(\n 'button',\n {\n type: 'button',\n role: 'menuitem',\n class: 'ink-select-item ink-menu-item',\n 'data-ink-select-item': '',\n 'data-key': 'custom',\n tabindex: '-1',\n },\n 'Custom…'\n )\n custom.addEventListener('click', () => pickerInput().click())\n root.append(custom)\n }\n const noFill = root.querySelector<HTMLElement>('[data-key=\"no-fill\"]')\n if (noFill && m.noFill) mark(noFill, m.noFill.checked, true)\n const cells = root.querySelectorAll<HTMLElement>('.ink-swatch-item')\n m.swatches.forEach((sw, i) => mark(cells[i]!, sw.checked, false))\n if (picker) picker.value = m.customValue.toLowerCase()\n }\n\n /** Reflects checked state on an item; `withMark` adds the check icon (labelled items). */\n function mark(el: HTMLElement, checked: boolean, withMark: boolean): void {\n el.setAttribute('aria-checked', String(checked))\n el.dataset.state = checked ? 'checked' : 'unchecked'\n if (!withMark) return\n const existing = el.querySelector('.ink-select-indicator')\n if (checked && !existing) el.append(checkmark())\n else if (!checked) existing?.remove()\n }\n\n const menu = createMenu(trigger, {\n label: opts.label ?? model().label,\n attrs: { 'data-ink-menu': `color-${property}` },\n render: (root) => paint(root, model()),\n })\n\n const follow = (engine: { toolStyle: ToolStyle } | null): void => {\n for (const stop of stops) stop()\n stops = []\n const tool = engine?.toolStyle ?? null\n style = tool && opts.group ? tool.scoped(opts.group) : tool\n if (style)\n stops = [style.current.subscribe(refresh), style.supported.subscribe(refresh)]\n if (!style) menu.close()\n refresh()\n }\n follow(viewer.engine.get())\n viewer.engine.subscribe(follow)\n opts.fallback?.subscribe(refresh)\n return trigger\n}\n","/*\n * The text style menu for createViewer: the same markup, classes and data attributes as the\n * bindings' `InkTextStyleMenu`, so `@inkbar/theme` styles both. The trigger follows the\n * viewer's tool style (disabled while nothing supports text style, `data-mixed` when the\n * selection disagrees); the panel is created on open and removed on close. It holds a font\n * select, the text colour menu, a size input with a stepper, bold/italic/underline toggles\n * and an alignment radio group.\n */\nimport {\n ALargeSmall,\n AlignCenter,\n AlignJustify,\n AlignLeft,\n AlignRight,\n Bold,\n Italic,\n Minus,\n Plus,\n Underline,\n} from '@inkbar/icons'\n\nimport { handleRadioKeys } from '../menu-keys'\nimport { FONT_FAMILIES, textStyleMenuModel, type TextStyleMenuModel } from '../ui'\n\nimport { createColorMenu } from './color-menu'\nimport { createIcon } from './controls'\nimport { h } from './dom'\nimport { createMenu } from './menu'\n\nimport type { Viewer } from './create-viewer'\nimport type { ToolStyle } from '../../model/annotations/tool-style'\n\nconst TOGGLE_ICONS = { bold: Bold, italic: Italic, underline: Underline }\nconst ALIGN_ICONS = {\n left: AlignLeft,\n center: AlignCenter,\n right: AlignRight,\n justify: AlignJustify,\n}\n\nfunction iconButton(label: string, icon: Parameters<typeof createIcon>[0]) {\n const b = h('button', {\n type: 'button',\n class: 'ink-text-style-button',\n 'aria-label': label,\n title: label,\n })\n const svg = createIcon(icon)\n svg.setAttribute('width', '16')\n svg.setAttribute('height', '16')\n b.append(svg)\n return b\n}\n\n/** A button that opens the text style menu: font, size, colour, emphasis and alignment. */\nexport function createTextStyleMenu(viewer: Viewer): HTMLButtonElement {\n const trigger = h('button', {\n type: 'button',\n class: 'ink-menu-trigger ink-text-style-menu',\n 'data-ink-text-style-menu': '',\n 'data-state': 'closed',\n 'aria-label': 'Text style',\n title: 'Text style',\n 'aria-haspopup': 'dialog',\n 'aria-expanded': 'false',\n })\n trigger.append(createIcon(ALargeSmall))\n trigger.disabled = true\n\n let style: ToolStyle | null = null\n let stops: (() => void)[] = []\n\n const model = (): TextStyleMenuModel =>\n textStyleMenuModel(\n style?.current.get() ?? {},\n style?.supported.get() ?? new Set(),\n viewer.engine.get()?.fonts ?? FONT_FAMILIES\n )\n\n // One text colour menu for the life of the control; each panel adopts its trigger.\n const colour = createColorMenu(viewer, { property: 'textColor' })\n\n let select: HTMLSelectElement | null = null\n let input: HTMLInputElement | null = null\n /** True while the size holds text the user has typed and not yet committed. */\n let drafting = false\n\n function commitSize(): void {\n if (!drafting || !input) return\n drafting = false\n if (input.value.trim() !== '') {\n const patch = model().size.commit(Number(input.value))\n if (patch) style?.set(patch)\n }\n input.value = model().size.value === null ? '' : String(model().size.value)\n }\n function nudge(direction: 1 | -1): void {\n drafting = false\n const patch = model().size.nudge(direction)\n if (patch) style?.set(patch)\n }\n\n function build(root: HTMLElement, m: TextStyleMenuModel): void {\n select = h('select', { class: 'ink-text-style-font', 'aria-label': m.font.label })\n select.addEventListener('change', () => style?.set(model().font.patch(select!.value)))\n\n input = h('input', {\n type: 'number',\n class: 'ink-text-style-input',\n 'aria-label': m.size.label,\n min: String(m.size.min),\n max: String(m.size.max),\n step: String(m.size.step),\n })\n input.addEventListener('input', () => (drafting = true))\n input.addEventListener('blur', commitSize)\n input.addEventListener('keydown', (e) => {\n if (e.key !== 'Enter') return\n e.preventDefault()\n commitSize()\n })\n const less = iconButton('Decrease font size', Minus)\n const more = iconButton('Increase font size', Plus)\n less.addEventListener('click', () => nudge(-1))\n more.addEventListener('click', () => nudge(1))\n const size = h(\n 'div',\n { class: 'ink-text-style-size', role: 'group', 'aria-label': 'Size' },\n less,\n input,\n more\n )\n\n const emphasis = h('div', {\n class: 'ink-text-style-row',\n role: 'group',\n 'aria-label': 'Emphasis',\n })\n for (const t of m.toggles) {\n const b = iconButton(t.label, TOGGLE_ICONS[t.key])\n b.dataset.key = t.key\n b.addEventListener('click', () => {\n const found = model().toggles.find((x) => x.key === t.key)\n if (found) style?.set(found.patch)\n })\n emphasis.append(b)\n }\n\n const align = h('div', {\n class: 'ink-text-style-row',\n role: 'radiogroup',\n 'aria-label': m.align.label,\n })\n align.addEventListener('keydown', (e) => handleRadioKeys(e, align))\n for (const c of m.align.choices) {\n const b = iconButton(c.label, ALIGN_ICONS[c.key])\n b.setAttribute('role', 'radio')\n b.dataset.key = c.key\n b.addEventListener('click', () => {\n const found = model().align.choices.find((x) => x.key === c.key)\n if (found) style?.set(found.patch)\n })\n align.append(b)\n }\n\n root.append(\n select,\n h('div', { class: 'ink-text-style-row' }, colour, size),\n emphasis,\n align\n )\n }\n\n function paint(root: HTMLElement, m: TextStyleMenuModel): void {\n if (root.childElementCount === 0) build(root, m)\n const sel = select!\n const options = m.font.value === '' ? ['', ...m.font.options] : m.font.options\n if (\n sel.options.length !== options.length ||\n options.some((o, i) => sel.options[i]!.value !== o)\n ) {\n sel.replaceChildren(\n ...options.map((o) => {\n const opt = h('option', { value: o }, o === '' ? 'Mixed' : o)\n if (o === '') {\n opt.disabled = true\n opt.hidden = true\n }\n return opt\n })\n )\n }\n sel.value = m.font.value\n if (!drafting) input!.value = m.size.value === null ? '' : String(m.size.value)\n root\n .querySelectorAll<HTMLElement>('[role=\"group\"][aria-label=\"Emphasis\"] button')\n .forEach((b) => {\n const t = m.toggles.find((x) => x.key === b.dataset.key)!\n b.setAttribute('aria-pressed', String(t.pressed))\n b.dataset.state = t.pressed === true ? 'on' : 'off'\n if (t.pressed === 'mixed') b.setAttribute('data-mixed', '')\n else b.removeAttribute('data-mixed')\n })\n root.querySelectorAll<HTMLElement>('[role=\"radio\"]').forEach((b) => {\n const c = m.align.choices.find((x) => x.key === b.dataset.key)!\n b.setAttribute('aria-checked', String(c.checked))\n b.dataset.state = c.checked ? 'on' : 'off'\n b.tabIndex = c.tabStop ? 0 : -1\n })\n }\n\n function refresh(): void {\n const m = model()\n trigger.disabled = !m.enabled\n if (m.mixed) trigger.setAttribute('data-mixed', '')\n else trigger.removeAttribute('data-mixed')\n menu.refresh()\n }\n\n const menu = createMenu(trigger, {\n label: 'Text style',\n role: 'dialog',\n attrs: {\n 'data-ink-menu': 'text-style',\n class: 'ink-select-content ink-menu-content ink-text-style-content',\n },\n owns: (t) =>\n t instanceof Element && t.closest('[data-ink-menu=\"color-textColor\"]') !== null,\n render: (root) => paint(root, model()),\n })\n\n const follow = (engine: { toolStyle: ToolStyle } | null): void => {\n for (const stop of stops) stop()\n stops = []\n style = engine?.toolStyle ?? null\n if (style)\n stops = [style.current.subscribe(refresh), style.supported.subscribe(refresh)]\n // The panel's old style is gone with the old document.\n if (!style) menu.close()\n refresh()\n }\n follow(viewer.engine.get())\n viewer.engine.subscribe(follow)\n return trigger\n}\n","// The icon each shape kind draws in the shape menu, shared by the vanilla menu and the\n// framework bindings so a kind has one icon everywhere.\nimport {\n Circle,\n CircleDashed,\n Hexagon,\n MessageCircle,\n MoveUpRight,\n RectangleHorizontal,\n Search,\n Slash,\n Square,\n SquareDashed,\n Star,\n type IconNode,\n} from '@inkbar/icons'\n\nimport type { ShapeKind } from './tools'\n\nexport const SHAPE_ICONS: Readonly<Record<ShapeKind, IconNode>> = {\n line: Slash,\n arrow: MoveUpRight,\n rectangle: Square,\n roundedRectangle: RectangleHorizontal,\n ellipse: Circle,\n bubble: MessageCircle,\n star: Star,\n polygon: Hexagon,\n loupe: Search,\n mask: SquareDashed,\n ovalMask: CircleDashed,\n}\n","/*\n * The shape menu for createViewer: a split button with the same markup, classes and data\n * attributes as the bindings' `InkShapeMenu`, so `@inkbar/theme` styles both. The main button\n * activates the shape tool with the current kind and draws that kind's icon; the chevron\n * opens a two-column grid of kinds. Choosing one switches to the shape tool with that kind.\n */\nimport { ChevronDown } from '@inkbar/icons'\n\nimport { SHAPE_ICONS } from '../shape-icons'\nimport { SHAPE_KINDS, type ShapeKind, type ToolController } from '../tools'\nimport { SHAPE_COLUMNS, shapeMenuModel, type ShapeMenuModel } from '../ui'\n\nimport { createIcon } from './controls'\nimport { h } from './dom'\nimport { createMenu } from './menu'\n\nimport type { Viewer } from './create-viewer'\n\n/** A split button: the main part draws with the current shape kind, the chevron picks the kind. */\nexport function createShapeMenu(viewer: Viewer): HTMLElement {\n const main = h('button', {\n type: 'button',\n class: 'ink-tool-button ink-shape-button',\n 'data-ink-tool-button': '',\n 'data-ink-shape-button': '',\n 'data-tool': 'shape',\n 'data-state': 'off',\n 'aria-pressed': 'false',\n })\n const trigger = h('button', {\n type: 'button',\n class: 'ink-menu-trigger ink-shape-menu-trigger',\n 'data-ink-shape-menu-trigger': '',\n 'data-state': 'closed',\n 'aria-label': 'Choose shape',\n title: 'Choose shape',\n 'aria-haspopup': 'menu',\n 'aria-expanded': 'false',\n })\n trigger.append(createIcon(ChevronDown))\n const root = h(\n 'div',\n {\n class: 'ink-split-button ink-shape-menu',\n 'data-ink-shape-menu': '',\n role: 'group',\n 'aria-label': 'Shape',\n },\n main,\n trigger\n )\n main.disabled = true\n trigger.disabled = true\n\n let tools: ToolController | null = null\n let stops: (() => void)[] = []\n let shownKind: ShapeKind | null = null\n\n const model = (): ShapeMenuModel =>\n shapeMenuModel(tools?.options('shape').get() ?? {}, SHAPE_KINDS)\n\n function refresh(): void {\n const m = model()\n main.disabled = trigger.disabled = tools === null\n main.setAttribute('aria-label', m.label)\n main.title = m.label\n main.dataset.kind = m.kind\n if (shownKind !== m.kind) {\n main.replaceChildren(createIcon(SHAPE_ICONS[m.kind]))\n shownKind = m.kind\n }\n const on = tools?.active.get() === 'shape'\n main.dataset.state = on ? 'on' : 'off'\n main.setAttribute('aria-pressed', String(on))\n menu.refresh()\n }\n\n function paint(panel: HTMLElement, m: ShapeMenuModel): void {\n if (panel.childElementCount === 0) {\n const grid = h('div', {\n role: 'group',\n 'aria-label': 'Shapes',\n class: 'ink-shape-grid',\n 'data-ink-menu-columns': String(SHAPE_COLUMNS),\n })\n for (const item of m.items) {\n const b = h(\n 'button',\n {\n type: 'button',\n role: 'menuitemradio',\n class: 'ink-select-item ink-menu-item ink-shape-item',\n 'data-ink-select-item': '',\n 'data-key': item.kind,\n tabindex: '-1',\n },\n item.label\n )\n b.prepend(createIcon(SHAPE_ICONS[item.kind]))\n b.addEventListener('click', () => {\n tools?.set('shape', { kind: item.kind })\n menu.close(true)\n })\n grid.append(b)\n }\n panel.append(grid)\n }\n const cells = panel.querySelectorAll<HTMLElement>('.ink-shape-item')\n m.items.forEach((item, i) => {\n cells[i]!.setAttribute('aria-checked', String(item.checked))\n cells[i]!.dataset.state = item.checked ? 'checked' : 'unchecked'\n })\n }\n\n const menu = createMenu(trigger, {\n label: 'Shapes',\n anchor: root,\n attrs: { 'data-ink-menu': 'shape' },\n render: (panel) => paint(panel, model()),\n })\n\n main.addEventListener('click', () => tools?.set('shape'))\n\n const follow = (next: ToolController | null): void => {\n for (const stop of stops) stop()\n stops = []\n tools = next\n if (tools)\n stops = [tools.active.subscribe(refresh), tools.options('shape').subscribe(refresh)]\n if (!tools) menu.close()\n refresh()\n }\n follow(viewer.tools.get())\n viewer.tools.subscribe(follow)\n return root\n}\n","// The icon each text markup kind draws in the highlight menu, shared by the vanilla menu and\n// the framework bindings so a kind has one icon everywhere.\nimport {\n Highlighter,\n SpellCheck2,\n Strikethrough,\n Underline,\n type IconNode,\n} from '@inkbar/icons'\n\nimport type { MarkupKind } from './tools'\n\nexport const MARKUP_ICONS: Readonly<Record<MarkupKind, IconNode>> = {\n highlight: Highlighter,\n underline: Underline,\n strikeout: Strikethrough,\n squiggly: SpellCheck2,\n}\n","/*\n * The highlight menu for createViewer: a split button with the same markup, classes and data\n * attributes as the bindings' `InkHighlightMenu`, so `@inkbar/theme` styles both. The main\n * button activates the highlight tool with the current markup kind and draws that kind's icon;\n * the chevron opens a menu of kinds plus the markup colour. Choosing a kind switches to the\n * highlight tool with that kind. The colour is a nested colour menu scoped to the `markup`\n * style group, so it works whatever tool is active.\n */\nimport { ChevronDown } from '@inkbar/icons'\n\nimport { writable } from '../../model/readable'\nimport { MARKUP_ICONS } from '../markup-icons'\nimport { MARKUP_KINDS, type MarkupKind, type ToolController } from '../tools'\nimport { highlightMenuModel, type HighlightMenuModel } from '../ui'\n\nimport { createColorMenu } from './color-menu'\nimport { createIcon } from './controls'\nimport { h } from './dom'\nimport { createMenu } from './menu'\n\nimport type { Viewer } from './create-viewer'\n\n/** The nested colour menu's accessible name. */\nconst COLOUR_LABEL = 'Highlight colour'\n\n/** A split button: the main part marks text with the current kind, the chevron picks it. */\nexport function createHighlightMenu(viewer: Viewer): HTMLElement {\n const main = h('button', {\n type: 'button',\n class: 'ink-tool-button ink-highlight-button',\n 'data-ink-tool-button': '',\n 'data-ink-highlight-button': '',\n 'data-tool': 'highlight',\n 'data-state': 'off',\n 'aria-pressed': 'false',\n })\n const trigger = h('button', {\n type: 'button',\n class: 'ink-menu-trigger ink-highlight-menu-trigger',\n 'data-ink-highlight-menu-trigger': '',\n 'data-state': 'closed',\n 'aria-label': 'Choose highlight',\n title: 'Choose highlight',\n 'aria-haspopup': 'menu',\n 'aria-expanded': 'false',\n })\n trigger.append(createIcon(ChevronDown))\n const root = h(\n 'div',\n {\n class: 'ink-split-button ink-highlight-menu',\n 'data-ink-highlight-menu': '',\n role: 'group',\n 'aria-label': 'Highlight',\n },\n main,\n trigger\n )\n main.disabled = true\n trigger.disabled = true\n\n /** The colour the chosen kind gets while the markup style leaves it unset. */\n const defaultColour = writable<string | undefined>(undefined)\n // One colour menu for the life of the control; each panel adopts its trigger.\n const colour = createColorMenu(viewer, {\n property: 'border',\n group: 'markup',\n label: COLOUR_LABEL,\n fallback: defaultColour,\n })\n colour.setAttribute('role', 'menuitem')\n colour.tabIndex = -1\n\n let tools: ToolController | null = null\n let stops: (() => void)[] = []\n let shownKind: MarkupKind | null = null\n\n const model = (): HighlightMenuModel =>\n highlightMenuModel(tools?.options('highlight').get() ?? {}, MARKUP_KINDS)\n\n function refresh(): void {\n const m = model()\n main.disabled = trigger.disabled = tools === null\n main.setAttribute('aria-label', m.label)\n main.title = m.label\n main.dataset.kind = m.kind\n if (shownKind !== m.kind) {\n main.replaceChildren(createIcon(MARKUP_ICONS[m.kind]))\n shownKind = m.kind\n }\n const on = tools?.active.get() === 'highlight'\n main.dataset.state = on ? 'on' : 'off'\n main.setAttribute('aria-pressed', String(on))\n defaultColour.set(viewer.document.get()?.annotations.defaults.color(m.kind))\n menu.refresh()\n }\n\n function paint(panel: HTMLElement, m: HighlightMenuModel): void {\n if (panel.childElementCount === 0) {\n const kinds = h('div', {\n role: 'group',\n 'aria-label': 'Kinds',\n class: 'ink-highlight-kinds',\n })\n for (const item of m.items) {\n const b = h(\n 'button',\n {\n type: 'button',\n role: 'menuitemradio',\n class: 'ink-select-item ink-menu-item ink-highlight-item',\n 'data-ink-select-item': '',\n 'data-key': item.kind,\n tabindex: '-1',\n },\n item.label\n )\n b.prepend(createIcon(MARKUP_ICONS[item.kind]))\n b.addEventListener('click', () => {\n tools?.set('highlight', { kind: item.kind })\n menu.close(true)\n })\n kinds.append(b)\n }\n const colourRow = h(\n 'div',\n { role: 'group', 'aria-label': 'Colour', class: 'ink-highlight-colour' },\n h(\n 'span',\n { class: 'ink-highlight-colour-label', 'aria-hidden': 'true' },\n 'Colour'\n ),\n colour\n )\n panel.append(\n kinds,\n h('div', { role: 'separator', class: 'ink-select-separator' }),\n colourRow\n )\n }\n const cells = panel.querySelectorAll<HTMLElement>('.ink-highlight-item')\n m.items.forEach((item, i) => {\n cells[i]!.setAttribute('aria-checked', String(item.checked))\n cells[i]!.dataset.state = item.checked ? 'checked' : 'unchecked'\n })\n }\n\n const menu = createMenu(trigger, {\n label: 'Highlights',\n anchor: root,\n attrs: { 'data-ink-menu': 'highlight' },\n owns: (t) =>\n t instanceof Element && t.closest('[data-ink-menu=\"color-border\"]') !== null,\n render: (panel) => paint(panel, model()),\n })\n\n main.addEventListener('click', () => tools?.set('highlight'))\n\n const follow = (next: ToolController | null): void => {\n for (const stop of stops) stop()\n stops = []\n tools = next\n if (tools)\n stops = [\n tools.active.subscribe(refresh),\n tools.options('highlight').subscribe(refresh),\n viewer.document.subscribe(refresh),\n ]\n if (!tools) menu.close()\n refresh()\n }\n follow(viewer.tools.get())\n viewer.tools.subscribe(follow)\n return root\n}\n","// Making signature templates in the browser: a pad to draw one, a name typed in a handwriting\n// font, or an image file. The pad samples like the `draw` tool (coalesced events, pen and touch\n// pressure) and paints with its renderer, so a drawn signature looks the same placed.\nimport { readonly, writable, type Readable } from '../model/readable'\nimport {\n createImageTemplate,\n createInkTemplate,\n type SignatureTemplate,\n} from '../model/signatures'\n\nimport { outlinePath, strokeOutline } from './ink-stroke'\nimport { pressureOf, reportsPressure } from './tools/freehand'\n\nimport type { Point } from '../model/geometry'\n\nconst SVG_NS = 'http://www.w3.org/2000/svg'\n\n/** The pad's stroke width, CSS px. */\nconst PAD_STROKE = 3\n\nexport interface SignaturePad {\n /** The drawing surface, `svg.ink-signature-pad`, filling the host. */\n readonly element: SVGSVGElement\n /** True while nothing is drawn. */\n readonly empty: Readable<boolean>\n clear(): void\n /** The drawing as an ink template with a new id; undefined while the pad is empty. */\n toTemplate(): SignatureTemplate | undefined\n destroy(): void\n}\n\ninterface PadStroke {\n points: Point[]\n pressure: number[]\n path: SVGPathElement\n}\n\n/**\n * A drawing pad in `host`. Each press-drag-release is a stroke; the theme colours it through\n * `path.ink-stroke` (`fill: currentColor` by default).\n */\nexport function createSignaturePad(host: HTMLElement): SignaturePad {\n const doc = host.ownerDocument\n const svg = doc.createElementNS(SVG_NS, 'svg')\n svg.classList.add('ink-signature-pad')\n svg.dataset.inkSignaturePad = ''\n svg.setAttribute('width', '100%')\n svg.setAttribute('height', '100%')\n svg.setAttribute('aria-hidden', 'true')\n // Structural: the pad owns its touches, so a finger draws instead of scrolling.\n svg.style.touchAction = 'none'\n svg.style.display = 'block'\n host.append(svg)\n\n const strokes: PadStroke[] = []\n const empty = writable(true)\n let live: { id: number; stroke: PadStroke } | undefined\n\n const at = (e: PointerEvent): Point => {\n const r = svg.getBoundingClientRect()\n return { x: e.clientX - r.left, y: e.clientY - r.top }\n }\n const paint = (s: PadStroke): void => {\n const pressure = reportsPressure(s.pressure) ? s.pressure : undefined\n s.path.setAttribute('d', outlinePath(strokeOutline(s.points, pressure, PAD_STROKE)))\n }\n const sample = (s: PadStroke, e: PointerEvent): void => {\n s.points.push(at(e))\n s.pressure.push(pressureOf(e) ?? 0.5)\n }\n\n const onDown = (e: PointerEvent): void => {\n if (!e.isPrimary || e.button !== 0 || live) return\n e.preventDefault()\n const path = doc.createElementNS(SVG_NS, 'path')\n path.classList.add('ink-stroke')\n svg.append(path)\n const stroke: PadStroke = { points: [], pressure: [], path }\n sample(stroke, e)\n paint(stroke)\n live = { id: e.pointerId, stroke }\n try {\n svg.setPointerCapture(e.pointerId)\n } catch {\n // A synthetic pointer: the stroke still works while it stays over the pad.\n }\n }\n const onMove = (e: PointerEvent): void => {\n if (!live || e.pointerId !== live.id) return\n if (e.buttons === 0) {\n finish()\n return\n }\n const coalesced = e.getCoalescedEvents?.() ?? []\n for (const ev of coalesced.length > 0 ? coalesced : [e]) sample(live.stroke, ev)\n paint(live.stroke)\n }\n const finish = (e?: PointerEvent): void => {\n if (!live) return\n const s = live.stroke\n live = undefined\n const last = s.points[s.points.length - 1]!\n const end = e ? at(e) : last\n // A release reports no pressure: it repeats the last sample's.\n if (end.x !== last.x || end.y !== last.y) {\n s.points.push(end)\n s.pressure.push(s.pressure[s.pressure.length - 1]!)\n }\n paint(s)\n strokes.push(s)\n empty.set(false)\n }\n const onUp = (e: PointerEvent): void => {\n if (live && e.pointerId === live.id) finish(e)\n }\n const onCancel = (e: PointerEvent): void => {\n if (!live || e.pointerId !== live.id) return\n live.stroke.path.remove()\n live = undefined\n }\n /** Capture gone mid-stroke: keep what was drawn, as a touch sends no move to end it. */\n const onLostCapture = (e: PointerEvent): void => {\n if (live && e.pointerId === live.id) finish()\n }\n svg.addEventListener('pointerdown', onDown)\n svg.addEventListener('pointermove', onMove)\n svg.addEventListener('pointerup', onUp)\n svg.addEventListener('pointercancel', onCancel)\n svg.addEventListener('lostpointercapture', onLostCapture)\n\n return {\n element: svg,\n empty: readonly(empty),\n clear() {\n live?.stroke.path.remove()\n live = undefined\n for (const s of strokes.splice(0)) s.path.remove()\n empty.set(true)\n },\n toTemplate() {\n if (strokes.length === 0) return undefined\n // CSS y grows downwards; a template's grows upwards.\n const inklist = strokes.map((s) => s.points.map((p) => ({ x: p.x, y: -p.y })))\n const pressured = strokes.some((s) => reportsPressure(s.pressure))\n return createInkTemplate(\n inklist,\n pressured ? strokes.map((s) => [...s.pressure]) : undefined\n )\n },\n destroy() {\n svg.removeEventListener('pointerdown', onDown)\n svg.removeEventListener('pointermove', onMove)\n svg.removeEventListener('pointerup', onUp)\n svg.removeEventListener('pointercancel', onCancel)\n svg.removeEventListener('lostpointercapture', onLostCapture)\n svg.remove()\n },\n }\n}\n\n/** CSS generic families, which a font shorthand must not quote. */\nconst GENERIC_FAMILIES = new Set([\n 'serif',\n 'sans-serif',\n 'monospace',\n 'cursive',\n 'fantasy',\n 'system-ui',\n 'ui-serif',\n 'ui-sans-serif',\n 'ui-monospace',\n 'ui-rounded',\n 'math',\n 'emoji',\n 'fangsong',\n])\n\n/** `font` as a CSS font-family value: quoted unless it is a generic family. */\nexport function fontFamilyValue(font: string): string {\n return GENERIC_FAMILIES.has(font) ? font : `\"${font.replace(/[\"\\\\]/g, '\\\\$&')}\"`\n}\n\nexport interface TypedSignatureOptions {\n /** The image's height in pixels. Default 96. */\n height?: number\n /** The ink colour. Default `#151820`, the theme's ink. */\n color?: string\n}\n\ninterface Rendered {\n url: string\n width: number\n height: number\n}\n\nasync function drawTyped(\n name: string,\n font: string,\n opts: TypedSignatureOptions = {}\n): Promise<Rendered> {\n const text = name.trim()\n if (text === '') throw new RangeError('A typed signature needs a name')\n const height = opts.height ?? 96\n const size = height * 0.625\n const margin = height / 8\n const shorthand = `${size}px ${fontFamilyValue(font)}`\n try {\n // Draws in the fallback font if the face never arrives.\n await document.fonts.load(shorthand, text)\n } catch {\n // Unavailable: the canvas uses the fallback.\n }\n const canvas = document.createElement('canvas')\n const measure = canvas.getContext('2d')\n if (!measure) throw new Error('Canvas 2D is unavailable')\n measure.font = shorthand\n const m = measure.measureText(text)\n const left = m.actualBoundingBoxLeft\n const width = Math.ceil(left + m.actualBoundingBoxRight + margin * 2)\n canvas.width = width\n canvas.height = height\n // Resizing a canvas resets its state.\n const ctx = canvas.getContext('2d')!\n ctx.font = shorthand\n ctx.fillStyle = opts.color ?? '#151820'\n ctx.textBaseline = 'middle'\n ctx.fillText(text, margin + left, height / 2)\n return { url: canvas.toDataURL('image/png'), width, height }\n}\n\n/**\n * `name` drawn in `font` on a transparent canvas, as a PNG data URL. Waits for the font to load\n * (`document.fonts.load`) first. Rejects with a RangeError for an empty name.\n */\nexport async function renderTypedSignature(\n name: string,\n font: string,\n opts?: TypedSignatureOptions\n): Promise<string> {\n return (await drawTyped(name, font, opts)).url\n}\n\n/** A typed signature as an image template, with a new id. */\nexport async function createTypedSignature(\n name: string,\n font: string,\n opts?: TypedSignatureOptions\n): Promise<SignatureTemplate> {\n const r = await drawTyped(name, font, opts)\n return createImageTemplate(r.url, r.width / r.height)\n}\n\n/** The image types a signature image may be. */\nexport const SIGNATURE_IMAGE_TYPES: readonly string[] = ['image/png', 'image/jpeg']\n\n/** The longest side, in pixels, an image signature is stored at. */\nexport const SIGNATURE_IMAGE_MAX_SIDE = 1000\n\n/**\n * The longest data URL, in characters, an image signature may be once scaled. Templates live\n * in host storage (`localStorage` holds about 5 MB) and are copied into every placed stamp.\n */\nexport const SIGNATURE_IMAGE_MAX_LENGTH = 3_000_000\n\n/**\n * An image file (a scan of a signature) as an image template. The image is drawn again at no\n * more than `SIGNATURE_IMAGE_MAX_SIDE` pixels on its long side, as a PNG (a JPEG stays a JPEG,\n * as photos compress far better that way), so a phone photo does not fill the store. Rejects\n * with a TypeError for anything but a PNG or JPEG, and a RangeError when the result is still\n * longer than `SIGNATURE_IMAGE_MAX_LENGTH`.\n */\nexport async function createImageSignature(file: Blob): Promise<SignatureTemplate> {\n if (!SIGNATURE_IMAGE_TYPES.includes(file.type))\n throw new TypeError('A signature image must be a PNG or JPEG')\n const source = URL.createObjectURL(file)\n try {\n const img = new Image()\n img.src = source\n try {\n await img.decode()\n } catch {\n throw new TypeError('The image could not be read')\n }\n const { naturalWidth: w, naturalHeight: h } = img\n if (w === 0 || h === 0) throw new TypeError('The image is empty')\n const scale = Math.min(1, SIGNATURE_IMAGE_MAX_SIDE / Math.max(w, h))\n const canvas = document.createElement('canvas')\n canvas.width = Math.max(1, Math.round(w * scale))\n canvas.height = Math.max(1, Math.round(h * scale))\n const ctx = canvas.getContext('2d')\n if (!ctx) throw new Error('Canvas 2D is unavailable')\n ctx.imageSmoothingQuality = 'high'\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height)\n const url =\n file.type === 'image/jpeg'\n ? canvas.toDataURL('image/jpeg', 0.9)\n : canvas.toDataURL('image/png')\n if (url.length > SIGNATURE_IMAGE_MAX_LENGTH)\n throw new RangeError('The signature image is too large')\n return createImageTemplate(url, canvas.width / canvas.height)\n } finally {\n URL.revokeObjectURL(source)\n }\n}\n\n/** The preview's height in its own units; the width follows the template's aspect. */\nconst PREVIEW_HEIGHT = 100\nconst PREVIEW_STROKE = 4\n\n/**\n * An ink template drawn for a menu: one filled outline per stroke (the `draw` renderer) in a\n * `viewBox` of the template's aspect, with room for the stroke. Paint `paths` with\n * `fill: currentColor`.\n */\nexport function signaturePreview(t: SignatureTemplate & { kind: 'ink' }): {\n viewBox: string\n paths: string[]\n} {\n const h = PREVIEW_HEIGHT\n const w = h * t.aspect\n const pad = PREVIEW_STROKE\n const paths = t.inklist.map((stroke, i) =>\n outlinePath(\n strokeOutline(\n stroke.map((p) => ({ x: p.x * w, y: (1 - p.y) * h })),\n t.pressure?.[i],\n PREVIEW_STROKE\n )\n )\n )\n const r = (n: number): number => Math.round(n * 100) / 100\n return { viewBox: `${-pad} ${-pad} ${r(w + pad * 2)} ${r(h + pad * 2)}`, paths }\n}\n","// The state behind the \"Create signature\" dialog, shared by every binding and the vanilla\n// dialog: which tab is open, the pad, the typed name and font, the chosen image, and whether\n// Save can go. The bindings render it; nothing here touches their markup.\nimport { readonly, writable, type Readable } from '../model/readable'\n\nimport {\n createImageSignature,\n createSignaturePad,\n createTypedSignature,\n type SignaturePad,\n} from './signature-pad'\nimport { SIGNATURE_FONTS, type SignatureTab } from './ui'\n\nimport type { SignatureLibrary, SignatureTemplate } from '../model/signatures'\n\nexport interface SignatureDraftState {\n tab: SignatureTab\n /** True while the pad has nothing on it. */\n padEmpty: boolean\n name: string\n font: string\n /** The chosen image, read and checked. */\n image: SignatureTemplate | undefined\n /** Why the chosen file was refused, for the Image tab to show. */\n imageError: string | undefined\n /** Why the last save failed (the store refused it, full or offline), for the dialog to show. */\n saveError: string | undefined\n /** True when the open tab has something to save. */\n canSave: boolean\n saving: boolean\n}\n\nexport interface SignatureDraft {\n readonly state: Readable<SignatureDraftState>\n readonly fonts: readonly string[]\n setTab(tab: SignatureTab): void\n setName(name: string): void\n setFont(font: string): void\n /** Mounts the pad in `host`; returns its teardown. One pad at a time. */\n attachPad(host: HTMLElement): () => void\n clearPad(): void\n /** Reads an image file for the Image tab. */\n chooseFile(file: Blob | undefined): Promise<void>\n /**\n * Builds the open tab's template and saves it to `library`. Resolves with it, or undefined\n * when there is nothing to save, the save failed (setting `saveError`), or the draft was\n * destroyed before the save finished.\n */\n save(library: SignatureLibrary): Promise<SignatureTemplate | undefined>\n /** Back to an empty Draw tab. */\n reset(): void\n destroy(): void\n}\n\nexport function createSignatureDraft(\n opts: { fonts?: readonly string[] } = {}\n): SignatureDraft {\n const fonts = opts.fonts && opts.fonts.length > 0 ? [...opts.fonts] : SIGNATURE_FONTS\n const initial = (): SignatureDraftState => ({\n tab: 'draw',\n padEmpty: true,\n name: '',\n font: fonts[0]!,\n image: undefined,\n imageError: undefined,\n saveError: undefined,\n canSave: false,\n saving: false,\n })\n const state = writable<SignatureDraftState>(initial())\n let pad: SignaturePad | undefined\n let stopPad: (() => void) | undefined\n /** Only the latest file read lands. */\n let reads = 0\n /** Set by `destroy`: a save that finishes later selects nothing. */\n let destroyed = false\n\n const ready = (s: SignatureDraftState): boolean =>\n s.tab === 'draw'\n ? !s.padEmpty\n : s.tab === 'type'\n ? s.name.trim() !== ''\n : s.image !== undefined\n const patch = (p: Partial<SignatureDraftState>): void => {\n const next = { ...state.get(), ...p }\n state.set({ ...next, canSave: !next.saving && ready(next) })\n }\n\n const detachPad = (): void => {\n stopPad?.()\n stopPad = undefined\n pad?.destroy()\n pad = undefined\n }\n\n return {\n state: readonly(state),\n fonts,\n setTab: (tab) => patch({ tab }),\n setName: (name) => patch({ name }),\n setFont: (font) => patch({ font }),\n attachPad(host) {\n // Mounting again revives a destroyed draft, as React's StrictMode remounts do.\n destroyed = false\n detachPad()\n const p = createSignaturePad(host)\n pad = p\n stopPad = p.empty.subscribe((padEmpty) => patch({ padEmpty }))\n patch({ padEmpty: p.empty.get() })\n return () => {\n if (pad === p) detachPad()\n }\n },\n clearPad() {\n pad?.clear()\n },\n async chooseFile(file) {\n const n = ++reads\n if (!file) {\n patch({ image: undefined, imageError: undefined })\n return\n }\n // The old image goes at once, so Save waits for the new one.\n patch({ image: undefined, imageError: undefined })\n try {\n const image = await createImageSignature(file)\n if (n === reads) patch({ image, imageError: undefined })\n } catch (e) {\n if (n === reads)\n patch({\n image: undefined,\n imageError:\n e instanceof RangeError\n ? 'This image is too large. Choose a smaller one.'\n : 'Choose a PNG or JPEG image.',\n })\n }\n },\n async save(library) {\n const s = state.get()\n if (!s.canSave) return undefined\n patch({ saving: true, saveError: undefined })\n try {\n const t =\n s.tab === 'draw'\n ? pad?.toTemplate()\n : s.tab === 'type'\n ? await createTypedSignature(s.name, s.font)\n : s.image\n if (!t) return undefined\n await library.save(t)\n // Closed while saving: the template stays in the library, but nothing acts on it.\n return destroyed ? undefined : t\n } catch {\n patch({\n saveError: 'The signature could not be saved. Try again, or try a smaller one.',\n })\n return undefined\n } finally {\n patch({ saving: false })\n }\n },\n reset() {\n reads++\n pad?.clear()\n state.set({ ...initial(), padEmpty: pad ? pad.empty.get() : true })\n },\n destroy() {\n destroyed = true\n reads++\n detachPad()\n },\n }\n}\n","/*\n * The \"Create signature\" dialog for createViewer, with the same markup, classes and data\n * attributes as the bindings' `InkSignatureDialog`, so `@inkbar/theme` styles both. A modal:\n * Tab stays inside it, Escape or a press on the overlay closes it, and focus goes back where it\n * came from. Draw, Type and Image tabs each make a template; Save stores it in the viewer's\n * signature library and selects it for the `signature` tool.\n */\nimport { handleRadioKeys, handleTabKeys, trapTab } from '../menu-keys'\nimport { createSignatureDraft, type SignatureDraftState } from '../signature-draft'\nimport { fontFamilyValue } from '../signature-pad'\nimport {\n SIGNATURE_FONTS,\n SIGNATURE_LABELS,\n SIGNATURE_TABS,\n type SignatureTab,\n} from '../ui'\n\nimport { h } from './dom'\n\nimport type { Viewer } from './create-viewer'\n\nexport interface SignatureDialogOptions {\n /** The fonts the Type tab offers. Default: the viewer's `signatureFonts`. */\n fonts?: string[]\n}\n\nexport interface SignatureDialog {\n readonly isOpen: boolean\n /** Opens the dialog. On close, focus goes to `returnFocus`, else to what had it before. */\n open(opts?: { returnFocus?: HTMLElement | null }): void\n close(): void\n destroy(): void\n}\n\nlet dialogs = 0\n\nexport function createSignatureDialog(\n viewer: Viewer,\n opts: SignatureDialogOptions = {}\n): SignatureDialog {\n const uid = `ink-signature-dialog-${++dialogs}`\n let teardown: (() => void) | null = null\n\n function close(): void {\n teardown?.()\n teardown = null\n }\n\n function open(o: { returnFocus?: HTMLElement | null } = {}): void {\n if (teardown) return\n const returnTo =\n o.returnFocus ??\n (document.activeElement instanceof HTMLElement ? document.activeElement : null)\n const draft = createSignatureDraft({\n fonts: opts.fonts ?? viewer.engine.get()?.signatureFonts ?? SIGNATURE_FONTS,\n })\n\n const tabs = new Map<SignatureTab, HTMLButtonElement>()\n const panels = new Map<SignatureTab, HTMLElement>()\n const tablist = h('div', {\n role: 'tablist',\n 'aria-label': SIGNATURE_LABELS.tabs,\n class: 'ink-tabs',\n })\n for (const tab of SIGNATURE_TABS) {\n const b = h(\n 'button',\n {\n type: 'button',\n role: 'tab',\n id: `${uid}-tab-${tab}`,\n 'aria-controls': `${uid}-panel-${tab}`,\n class: 'ink-tab',\n 'data-key': tab,\n },\n SIGNATURE_LABELS[tab]\n )\n b.addEventListener('click', () => draft.setTab(tab))\n tabs.set(tab, b)\n tablist.append(b)\n panels.set(\n tab,\n h('div', {\n role: 'tabpanel',\n id: `${uid}-panel-${tab}`,\n 'aria-labelledby': `${uid}-tab-${tab}`,\n class: 'ink-tab-panel',\n 'data-key': tab,\n })\n )\n }\n tablist.addEventListener('keydown', (e) => handleTabKeys(e, tablist))\n\n // Draw\n const padHost = h('div', {\n class: 'ink-signature-pad-host',\n 'data-ink-signature-pad-host': '',\n role: 'img',\n 'aria-label': SIGNATURE_LABELS.pad,\n })\n const clear = h(\n 'button',\n { type: 'button', class: 'ink-button', 'data-ink-signature-clear': '' },\n SIGNATURE_LABELS.clear\n )\n clear.addEventListener('click', () => draft.clearPad())\n panels.get('draw')!.append(padHost, h('div', { class: 'ink-dialog-row' }, clear))\n const detachPad = draft.attachPad(padHost)\n\n // Type\n const name = h('input', {\n type: 'text',\n class: 'ink-input',\n 'data-ink-signature-name': '',\n autocomplete: 'name',\n placeholder: SIGNATURE_LABELS.namePlaceholder,\n })\n name.addEventListener('input', () => draft.setName(name.value))\n const fontGroup = h('div', {\n role: 'radiogroup',\n 'aria-label': SIGNATURE_LABELS.fonts,\n class: 'ink-signature-fonts',\n })\n const fontSamples = draft.fonts.map((font) => {\n const b = h('button', {\n type: 'button',\n role: 'radio',\n class: 'ink-signature-font',\n 'data-key': font,\n 'aria-label': font,\n })\n const sample = h('span', { class: 'ink-signature-font-sample' })\n // The font is the option itself, so it is set on the element, not left to the theme.\n sample.style.fontFamily = fontFamilyValue(font)\n b.append(sample)\n b.addEventListener('click', () => draft.setFont(font))\n fontGroup.append(b)\n return sample\n })\n fontGroup.addEventListener('keydown', (e) => handleRadioKeys(e, fontGroup))\n panels\n .get('type')!\n .append(\n h('label', { class: 'ink-field' }, h('span', {}, SIGNATURE_LABELS.name), name),\n fontGroup\n )\n\n // Image\n const file = h('input', {\n type: 'file',\n accept: 'image/png,image/jpeg',\n class: 'ink-input',\n 'data-ink-signature-file': '',\n })\n file.addEventListener('change', () => void draft.chooseFile(file.files?.[0]))\n const preview = h('img', { class: 'ink-signature-image', alt: '' })\n const imageError = h('p', { class: 'ink-field-error', role: 'alert' })\n panels\n .get('image')!\n .append(\n h('label', { class: 'ink-field' }, h('span', {}, SIGNATURE_LABELS.file), file),\n preview,\n imageError\n )\n\n // Actions\n const saveError = h('p', {\n class: 'ink-field-error',\n role: 'alert',\n 'data-ink-signature-save-error': '',\n })\n const cancel = h(\n 'button',\n { type: 'button', class: 'ink-button', 'data-ink-signature-cancel': '' },\n SIGNATURE_LABELS.cancel\n )\n cancel.addEventListener('click', () => close())\n const save = h(\n 'button',\n {\n type: 'button',\n class: 'ink-button',\n 'data-variant': 'primary',\n 'data-ink-signature-save': '',\n },\n SIGNATURE_LABELS.save\n )\n save.addEventListener('click', () => {\n const library = viewer.engine.get()?.signatures\n if (!library) return\n draft.save(library).then(\n (t) => {\n if (!t) return\n viewer.tools.get()?.set('signature', { templateId: t.id })\n close()\n },\n () => {\n // The host's store refused it: the dialog stays open to try again.\n }\n )\n })\n\n const title = h(\n 'h2',\n { id: `${uid}-title`, class: 'ink-dialog-title' },\n SIGNATURE_LABELS.dialog\n )\n const content = h(\n 'div',\n {\n role: 'dialog',\n 'aria-modal': 'true',\n 'aria-labelledby': `${uid}-title`,\n class: 'ink-dialog ink-signature-dialog',\n 'data-ink-signature-dialog': '',\n 'data-state': 'open',\n tabindex: '-1',\n },\n title,\n tablist,\n ...panels.values(),\n saveError,\n h('div', { class: 'ink-dialog-actions' }, cancel, save)\n )\n const overlay = h('div', {\n class: 'ink-dialog-overlay',\n 'data-ink-dialog-overlay': '',\n 'data-state': 'open',\n })\n overlay.addEventListener('pointerdown', () => close())\n\n const paint = (s: SignatureDraftState): void => {\n for (const [tab, b] of tabs) {\n const on = tab === s.tab\n b.setAttribute('aria-selected', String(on))\n b.dataset.state = on ? 'active' : 'inactive'\n b.tabIndex = on ? 0 : -1\n panels.get(tab)!.hidden = !on\n }\n clear.disabled = s.padEmpty\n draft.fonts.forEach((font, i) => {\n const sample = fontSamples[i]!\n const b = sample.parentElement!\n const on = font === s.font\n b.setAttribute('aria-checked', String(on))\n b.dataset.state = on ? 'checked' : 'unchecked'\n b.tabIndex = on ? 0 : -1\n sample.textContent = s.name.trim() || SIGNATURE_LABELS.namePlaceholder\n })\n if (s.image?.kind === 'image') {\n preview.src = s.image.imagedata\n preview.hidden = false\n } else {\n preview.removeAttribute('src')\n preview.hidden = true\n }\n imageError.textContent = s.imageError ?? ''\n imageError.hidden = s.imageError === undefined\n saveError.textContent = s.saveError ?? ''\n saveError.hidden = s.saveError === undefined\n save.disabled = !s.canSave || !viewer.engine.get()\n }\n const stopState = draft.state.subscribe(paint)\n paint(draft.state.get())\n\n const onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n close()\n return\n }\n trapTab(e, content)\n }\n // Focus that escapes (a click on the page behind) comes back in.\n const onFocus = (e: FocusEvent): void => {\n if (!content.contains(e.target as Node)) tabs.get(draft.state.get().tab)?.focus()\n }\n document.addEventListener('keydown', onKey, true)\n document.addEventListener('focusin', onFocus)\n document.body.append(overlay, content)\n tabs.get('draw')!.focus({ preventScroll: true })\n\n teardown = () => {\n document.removeEventListener('keydown', onKey, true)\n document.removeEventListener('focusin', onFocus)\n stopState()\n detachPad()\n draft.destroy()\n overlay.remove()\n content.remove()\n if (returnTo?.isConnected) returnTo.focus({ preventScroll: true })\n }\n }\n\n return {\n get isOpen() {\n return teardown !== null\n },\n open,\n close,\n destroy: close,\n }\n}\n","/*\n * The signature menu for createViewer: a split button with the same markup, classes and data\n * attributes as the bindings' `InkSignatureMenu`, so `@inkbar/theme` styles both. The main\n * button activates the signature tool with the chosen template (or opens the menu when none is\n * chosen); the chevron opens the saved signatures, each with a remove button, and \"Create\n * signature\", which opens the signature dialog.\n */\nimport { ChevronDown, Plus, Signature, Trash2 } from '@inkbar/icons'\n\nimport { signaturePreview } from '../signature-pad'\nimport { SIGNATURE_LABELS, signatureMenuModel, type SignatureMenuModel } from '../ui'\n\nimport { createIcon } from './controls'\nimport { h } from './dom'\nimport { createMenu } from './menu'\nimport { createSignatureDialog, type SignatureDialogOptions } from './signature-dialog'\n\nimport type { Viewer } from './create-viewer'\nimport type { SignatureLibrary, SignatureTemplate } from '../../model/signatures'\nimport type { ToolController } from '../tools'\nimport type { ViewerEngine } from '../viewer-engine'\n\nconst SVG_NS = 'http://www.w3.org/2000/svg'\n\n/** A template drawn small: ink as an SVG of filled outlines, an image as an `<img>`. */\nexport function createSignaturePreview(t: SignatureTemplate): HTMLElement {\n const box = h('span', { class: 'ink-signature-preview', 'data-kind': t.kind })\n if (t.kind === 'image') {\n box.append(h('img', { src: t.imagedata, alt: '', draggable: 'false' }))\n return box\n }\n const { viewBox, paths } = signaturePreview(t)\n const svg = document.createElementNS(SVG_NS, 'svg')\n svg.setAttribute('viewBox', viewBox)\n svg.setAttribute('aria-hidden', 'true')\n for (const d of paths) {\n const path = document.createElementNS(SVG_NS, 'path')\n path.setAttribute('d', d)\n path.setAttribute('fill', 'currentColor')\n svg.append(path)\n }\n box.append(svg)\n return box\n}\n\nexport function createSignatureMenu(\n viewer: Viewer,\n opts: SignatureDialogOptions = {}\n): HTMLElement {\n const main = h('button', {\n type: 'button',\n class: 'ink-tool-button ink-signature-button',\n 'data-ink-tool-button': '',\n 'data-ink-signature-button': '',\n 'data-tool': 'signature',\n 'data-state': 'off',\n 'aria-pressed': 'false',\n 'aria-label': SIGNATURE_LABELS.sign,\n title: SIGNATURE_LABELS.sign,\n })\n main.append(createIcon(Signature))\n const trigger = h('button', {\n type: 'button',\n class: 'ink-menu-trigger ink-signature-menu-trigger',\n 'data-ink-signature-menu-trigger': '',\n 'data-state': 'closed',\n 'aria-label': SIGNATURE_LABELS.trigger,\n title: SIGNATURE_LABELS.trigger,\n 'aria-haspopup': 'menu',\n 'aria-expanded': 'false',\n })\n trigger.append(createIcon(ChevronDown))\n const root = h(\n 'div',\n {\n class: 'ink-split-button ink-signature-menu',\n 'data-ink-signature-menu': '',\n role: 'group',\n 'aria-label': SIGNATURE_LABELS.sign,\n },\n main,\n trigger\n )\n main.disabled = true\n trigger.disabled = true\n\n const dialog = createSignatureDialog(viewer, opts)\n let tools: ToolController | null = null\n let library: SignatureLibrary | null = null\n let stops: (() => void)[] = []\n /** The ids the open panel shows, to rebuild it only when the list changes. */\n let shown = ''\n\n const model = (): SignatureMenuModel =>\n signatureMenuModel(\n library?.templates.get() ?? [],\n tools?.options('signature').get() ?? {}\n )\n\n function refresh(): void {\n main.disabled = trigger.disabled = tools === null\n const on = tools?.active.get() === 'signature'\n main.dataset.state = on ? 'on' : 'off'\n main.setAttribute('aria-pressed', String(on))\n menu.refresh()\n }\n\n /** Removes a template; focus moves to the signature now in its row, else \"Create signature\". */\n function remove(panel: HTMLElement, id: string): void {\n const row = model().items.findIndex((i) => i.id === id)\n library?.remove(id).then(\n () => {\n if (!menu.isOpen) return\n const rows = panel.querySelectorAll<HTMLElement>('.ink-signature-item')\n const next =\n rows[Math.min(row, rows.length - 1)] ??\n panel.querySelector<HTMLElement>('[data-ink-signature-create]')\n next?.focus({ preventScroll: true })\n },\n () => {\n // The store refused: the row stays, and `removeError` shows in the menu.\n }\n )\n }\n\n function paint(panel: HTMLElement, m: SignatureMenuModel): void {\n const ids = m.items.map((i) => i.id).join(' ')\n // A fresh panel is a fresh opening: an old removal error is not news any more.\n if (panel.childElementCount === 0) library?.clearRemoveError()\n if (panel.childElementCount === 0 || ids !== shown) {\n shown = ids\n const list = h('div', {\n role: 'group',\n 'aria-label': SIGNATURE_LABELS.saved,\n class: 'ink-signature-list',\n 'data-ink-menu-columns': '2',\n })\n for (const item of m.items) {\n const choose = h('button', {\n type: 'button',\n role: 'menuitemradio',\n class: 'ink-select-item ink-menu-item ink-signature-item',\n 'data-ink-select-item': '',\n 'data-key': item.id,\n 'aria-label': item.label,\n tabindex: '-1',\n })\n choose.append(createSignaturePreview(item.template))\n choose.addEventListener('click', () => {\n tools?.set('signature', { templateId: item.id })\n menu.close(true)\n })\n const drop = h('button', {\n type: 'button',\n role: 'menuitem',\n class: 'ink-menu-item ink-signature-remove',\n 'data-ink-signature-remove': '',\n 'data-key': item.id,\n 'aria-label': item.removeLabel,\n title: item.removeLabel,\n tabindex: '-1',\n })\n drop.append(createIcon(Trash2))\n drop.addEventListener('click', () => remove(panel, item.id))\n list.append(choose, drop)\n }\n const create = h(\n 'button',\n {\n type: 'button',\n role: 'menuitem',\n class: 'ink-select-item ink-menu-item ink-signature-create',\n 'data-ink-select-item': '',\n 'data-ink-signature-create': '',\n tabindex: '-1',\n },\n SIGNATURE_LABELS.create\n )\n create.prepend(createIcon(Plus))\n create.addEventListener('click', () => {\n menu.close()\n dialog.open({ returnFocus: main })\n })\n panel.replaceChildren(\n ...(m.items.length > 0\n ? [list, h('div', { role: 'separator', class: 'ink-select-separator' })]\n : []),\n create,\n h('p', {\n class: 'ink-field-error ink-signature-remove-error',\n role: 'alert',\n 'data-ink-signature-remove-error': '',\n })\n )\n }\n const error = panel.querySelector<HTMLElement>('[data-ink-signature-remove-error]')!\n const message = library?.removeError.get()\n error.textContent = message ?? ''\n error.hidden = message === undefined\n for (const item of m.items) {\n const el = panel.querySelector<HTMLElement>(\n `.ink-signature-item[data-key=\"${CSS.escape(item.id)}\"]`\n )\n el?.setAttribute('aria-checked', String(item.checked))\n if (el) el.dataset.state = item.checked ? 'checked' : 'unchecked'\n }\n }\n\n const menu = createMenu(trigger, {\n label: SIGNATURE_LABELS.menu,\n anchor: root,\n attrs: { 'data-ink-menu': 'signature' },\n render: (panel) => paint(panel, model()),\n })\n\n main.addEventListener('click', () => {\n if (!tools) return\n if (model().selected) tools.set('signature')\n else trigger.click()\n })\n\n const follow = (next: ToolController | null): void => {\n for (const stop of stops) stop()\n stops = []\n tools = next\n if (tools)\n stops = [\n tools.active.subscribe(refresh),\n tools.options('signature').subscribe(refresh),\n ]\n if (!tools) {\n menu.close()\n dialog.close()\n }\n refresh()\n }\n // The library lives as long as the viewer, but reaches the menu with the first engine.\n let stopLibrary: () => void = () => undefined\n const followLibrary = (engine: ViewerEngine | null): void => {\n const next = engine?.signatures ?? null\n if (next === library) return\n stopLibrary()\n library = next\n const stops = library\n ? [library.templates.subscribe(refresh), library.removeError.subscribe(refresh)]\n : []\n stopLibrary = () => stops.forEach((stop) => stop())\n refresh()\n }\n follow(viewer.tools.get())\n viewer.tools.subscribe(follow)\n followLibrary(viewer.engine.get())\n viewer.engine.subscribe(followLibrary)\n return root\n}\n"],"mappings":"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,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;CACjF,MAAM,SAAS,SAAiB,KAAK,QAAQ,aAAa;CAO1D,OAAO;EAAE,WANS,gBAAgB;GAChC,OAAO,KAAK;GACZ,SAAS,KAAK;GACd,mBAAmB,OAAO,IAAI,OAAO,IAAI,CAAC;GAC1C;EACF,CACiB;EAAG,UAAU,OAAO,OAAO,IAAI,EAAE;CAAE;AACtD;;;AC5GA,MAAa,UAAmB;CAC9B,QAAQ;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,MAAM;EACJ;GACE;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;CACF;AACF;;;;;;;ACjIA,MAAa,cAAyD;CACpE,eAAe;CACf,QAAQ;CACR,WAAW;CACX,eAAe;CACf,QAAQ;CACR,MAAM;CACN,MAAM;CACN,OAAO;CACP,UAAU;CACV,WAAW;AACb;;;;;AAMA,MAAa,gBAAmC;CAAC;CAAa;CAAS;AAAS;;;;;AAMhF,MAAa,kBAAqC,CAAC,SAAS;;AAG5D,MAAa,cAAiC;CAAC;CAA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"}
|
|
1
|
+
{"version":3,"file":"dom.mjs","names":["isCancellation","SVG","CORNERS","fmt","isCancellation","SVG","readingOrder","button","TABBABLE","EMPTY","guard","createToolController","SVG_NS","MIN_CSS","MIN_CSS","SVG_NS","createWith","ITEMS","button","SVG_NS"],"sources":["../src/dom/transform.ts","../src/dom/layout.ts","../src/dom/viewport.ts","../src/dom/viewport-keys.ts","../src/dom/dpr-watch.ts","../src/dom/page-renderer.ts","../src/pdfjs/text-layer.ts","../src/dom/text-layer.ts","../src/dom/selection.ts","../src/dom/ink-stroke.ts","../src/dom/overlay-render.ts","../src/dom/freetext-editor.ts","../src/pdfjs/render-region.ts","../src/dom/loupe-layer.ts","../src/dom/mask-layer.ts","../src/dom/overlay.ts","../src/dom/plugins/api/command.ts","../src/dom/annotation-element.ts","../src/dom/popover-focus.ts","../src/dom/viewer/dom.ts","../src/dom/viewer/popover.ts","../src/dom/plugins/api/card.ts","../src/dom/plugins/api/marks.ts","../src/dom/plugins/api/links.ts","../src/dom/plugins/api/records.ts","../src/dom/plugins/api/api.ts","../src/dom/plugins/define.ts","../src/dom/plugins/commands.ts","../src/dom/plugins/layer.ts","../src/dom/plugins/host.ts","../src/dom/page-mount.ts","../src/dom/tools/options.ts","../src/dom/tools/selection-edit.ts","../src/dom/tools/controller.ts","../src/dom/tools/freehand.ts","../src/dom/tools/draw.ts","../src/dom/tools/freetext.ts","../src/dom/tools/highlight.ts","../src/dom/tools/note.ts","../src/dom/tools/redact-area.ts","../src/dom/tools/select.ts","../src/dom/tools/select-text.ts","../src/dom/tools/shape.ts","../src/dom/tools/signature.ts","../src/dom/tools/sketch.ts","../src/dom/tools/index.ts","../src/dom/palette.ts","../src/dom/ui.ts","../src/dom/menu-keys.ts","../src/dom/viewer-engine.ts","../src/dom/viewer/thread-popover.ts","../src/dom/viewer/create-viewer.ts","../src/dom/viewer/controls.ts","../src/dom/viewer/menu.ts","../src/dom/viewer/style-menu.ts","../src/dom/viewer/color-menu.ts","../src/dom/viewer/text-style-menu.ts","../src/dom/shape-icons.ts","../src/dom/viewer/shape-menu.ts","../src/dom/markup-icons.ts","../src/dom/viewer/highlight-menu.ts","../src/dom/signature-pad.ts","../src/dom/signature-draft.ts","../src/dom/viewer/signature-dialog.ts","../src/dom/viewer/signature-menu.ts"],"sourcesContent":["import {\n applyMatrix,\n invertMatrix,\n type Matrix,\n type Point,\n type Quad,\n type Rect,\n} from '../model/geometry'\n\nimport type { PageInfo } from '../model/pages'\n\nexport type ViewRotation = 0 | 90 | 180 | 270\n\n/** CSS box: `left`,`top` from the rendered page's top-left corner, in CSS pixels. */\nexport interface CssRect {\n left: number\n top: number\n width: number\n height: number\n}\n\nexport interface PageTransform {\n readonly page: PageInfo\n /** The viewer zoom the transform was built for. 1 is one CSS pixel per user-space unit at /UserUnit 1. */\n readonly zoom: number\n /**\n * CSS pixels per user-space unit: `zoom × page.userUnit`. This is PDF.js `PageViewport.scale`\n * and the value its text and annotation layers read from `--total-scale-factor`.\n */\n readonly scale: number\n /** Rotation the viewer applied on top of the page's own /Rotate. */\n readonly rotation: ViewRotation\n /** The page's /Rotate plus the viewer rotation. */\n readonly totalRotation: ViewRotation\n /** Rendered page width in CSS pixels at this zoom and total rotation. */\n readonly cssWidth: number\n /** Rendered page height in CSS pixels at this zoom and total rotation. */\n readonly cssHeight: number\n /** User space to CSS pixels. Same matrix PDF.js builds for `getViewport`. */\n readonly matrix: Matrix\n toCss(p: Point): Point\n toCssRect(r: Rect): CssRect\n toCssQuad(q: Quad): Quad\n /** Converts a length in user-space units (stroke width, font size) to CSS pixels: zoom times `/UserUnit`. */\n toCssLength(points: number): number\n fromCss(p: Point): Point\n fromCssRect(r: CssRect): Rect\n /** Converts a length in CSS pixels to user-space units. */\n fromCssLength(px: number): number\n}\n\n/** Folds any integer multiple of 90 onto 0, 90, 180 or 270. Throws `RangeError` otherwise. */\nexport function normalizeRotation(deg: number): ViewRotation {\n if (!Number.isFinite(deg) || deg % 90 !== 0) {\n throw new RangeError(`rotation must be a multiple of 90, got ${deg}`)\n }\n return (((deg % 360) + 360) % 360) as ViewRotation\n}\n\n/**\n * Port of PDF.js `PageViewport` (display/page_viewport.js) with offsetX = offsetY = 0 and\n * dontFlip = false. Using the same maths keeps the canvas, text layer and overlay aligned.\n */\nexport function createPageTransform(\n page: PageInfo,\n zoom: number,\n viewRotation: ViewRotation = 0\n): PageTransform {\n const rotation = normalizeRotation(viewRotation)\n const totalRotation = normalizeRotation(page.rotate + rotation)\n // PDF.js PageViewport does `scale *= userUnit`; zoom 1 is one user-space unit, so 1 point only when userUnit is 1.\n const scale = zoom * page.userUnit\n const x0 = page.box.x\n const y0 = page.box.y\n const x1 = page.box.x + page.box.width\n const y1 = page.box.y + page.box.height\n const centerX = (x1 + x0) / 2\n const centerY = (y1 + y0) / 2\n let rotateA: number\n let rotateB: number\n let rotateC: number\n let rotateD: number\n switch (totalRotation) {\n case 180:\n rotateA = -1\n rotateB = 0\n rotateC = 0\n rotateD = 1\n break\n case 90:\n rotateA = 0\n rotateB = 1\n rotateC = 1\n rotateD = 0\n break\n case 270:\n rotateA = 0\n rotateB = -1\n rotateC = -1\n rotateD = 0\n break\n default:\n rotateA = 1\n rotateB = 0\n rotateC = 0\n rotateD = -1\n }\n let offsetCanvasX: number\n let offsetCanvasY: number\n let cssWidth: number\n let cssHeight: number\n if (rotateA === 0) {\n offsetCanvasX = Math.abs(centerY - y0) * scale\n offsetCanvasY = Math.abs(centerX - x0) * scale\n cssWidth = Math.abs(y1 - y0) * scale\n cssHeight = Math.abs(x1 - x0) * scale\n } else {\n offsetCanvasX = Math.abs(centerX - x0) * scale\n offsetCanvasY = Math.abs(centerY - y0) * scale\n cssWidth = Math.abs(x1 - x0) * scale\n cssHeight = Math.abs(y1 - y0) * scale\n }\n const matrix: Matrix = [\n rotateA * scale,\n rotateB * scale,\n rotateC * scale,\n rotateD * scale,\n offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,\n offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY,\n ]\n const inverse = invertMatrix(matrix)\n const toCss = (p: Point): Point => applyMatrix(matrix, p)\n const fromCss = (p: Point): Point => applyMatrix(inverse, p)\n\n const bounds = (\n points: Point[]\n ): { x: number; y: number; width: number; height: number } => {\n const xs = points.map((p) => p.x)\n const ys = points.map((p) => p.y)\n const x = Math.min(...xs)\n const y = Math.min(...ys)\n return { x, y, width: Math.max(...xs) - x, height: Math.max(...ys) - y }\n }\n\n return {\n page,\n zoom,\n scale,\n rotation,\n totalRotation,\n cssWidth,\n cssHeight,\n matrix,\n toCss,\n fromCss,\n toCssRect(r) {\n const b = bounds([\n toCss({ x: r.x, y: r.y }),\n toCss({ x: r.x + r.width, y: r.y }),\n toCss({ x: r.x, y: r.y + r.height }),\n toCss({ x: r.x + r.width, y: r.y + r.height }),\n ])\n return { left: b.x, top: b.y, width: b.width, height: b.height }\n },\n toCssQuad(q) {\n return { p1: toCss(q.p1), p2: toCss(q.p2), p3: toCss(q.p3), p4: toCss(q.p4) }\n },\n toCssLength: (points) => points * scale,\n fromCssRect(r) {\n return bounds([\n fromCss({ x: r.left, y: r.top }),\n fromCss({ x: r.left + r.width, y: r.top }),\n fromCss({ x: r.left, y: r.top + r.height }),\n fromCss({ x: r.left + r.width, y: r.top + r.height }),\n ])\n },\n fromCssLength: (px) => px / scale,\n }\n}\n","import { createPageTransform, type ViewRotation } from './transform'\n\nimport type { PageInfo } from '../model/pages'\n\nexport type LayoutMode = 'single' | 'continuous'\n\n/** Where one page sits inside the pages element, in CSS pixels. */\nexport interface CssPageBox {\n index: number\n left: number\n top: number\n width: number\n height: number\n}\n\n/** Every laid-out page plus the size of the pages element, in CSS pixels. */\nexport interface CssLayout {\n boxes: CssPageBox[]\n width: number\n height: number\n}\n\nexport interface CssLayoutInput {\n pages: readonly PageInfo[]\n zoom: number\n rotation: ViewRotation\n /** Gap above, between and below pages, CSS px. */\n gap: number\n mode: LayoutMode\n /** The page shown in `single` mode. */\n current: number\n /** The container's content width (client width less padding), CSS px. Narrower pages are centred. */\n containerWidth: number\n}\n\nfunction cssSize(page: PageInfo, zoom: number, rotation: ViewRotation) {\n const t = createPageTransform(page, zoom, rotation)\n return { width: t.cssWidth, height: t.cssHeight }\n}\n\n/** Stacks pages vertically, centred horizontally, with `gap` around each. */\nexport function computeCssLayout(input: CssLayoutInput): CssLayout {\n const pages =\n input.mode === 'single'\n ? input.pages.filter((p) => p.index === input.current)\n : input.pages\n const sizes = pages.map((p) => cssSize(p, input.zoom, input.rotation))\n // A reduce, not Math.max(...spread): spreading hundreds of thousands of pages overflows the stack.\n const width = sizes.reduce((max, s) => Math.max(max, s.width), input.containerWidth)\n let top = input.gap\n const boxes = pages.map((p, i): CssPageBox => {\n const s = sizes[i]!\n const box = {\n index: p.index,\n left: (width - s.width) / 2,\n top,\n width: s.width,\n height: s.height,\n }\n top += s.height + input.gap\n return box\n })\n return { boxes, width, height: top }\n}\n\n/** The zoom at which `page` fits a container of the given CSS size, less `padding` on each side. */\nexport function fitZoomCss(\n page: PageInfo,\n rotation: ViewRotation,\n container: { width: number; height: number },\n mode: 'fit-width' | 'fit-page',\n padding: number\n): number {\n const size = cssSize(page, 1, rotation)\n const byWidth = (container.width - padding * 2) / size.width\n if (mode === 'fit-width') return Math.max(0.05, byWidth)\n const byHeight = (container.height - padding * 2) / size.height\n return Math.max(0.05, Math.min(byWidth, byHeight))\n}\n\n/**\n * Indexes of pages intersecting [scrollTop, scrollTop + viewportHeight], extended by\n * `buffer` pages each side. Past the end it returns the last page plus its buffer.\n */\nexport function visibleRangeCss(\n layout: CssLayout,\n scrollTop: number,\n viewportHeight: number,\n buffer: number\n): number[] {\n const boxes = layout.boxes\n if (boxes.length === 0) return []\n const bottom = scrollTop + viewportHeight\n let first = boxes.findIndex((b) => b.top + b.height >= scrollTop)\n if (first === -1) first = boxes.length - 1\n let last = first\n while (last + 1 < boxes.length && boxes[last + 1]!.top <= bottom) last++\n const from = Math.max(0, first - buffer)\n const to = Math.min(boxes.length - 1, last + buffer)\n return boxes.slice(from, to + 1).map((b) => b.index)\n}\n\n/** The page with the most visible height in the viewport; the first page on a tie. */\nexport function mostVisiblePageCss(\n layout: CssLayout,\n scrollTop: number,\n viewportHeight: number\n): number {\n let best = layout.boxes[0]?.index ?? 0\n let bestArea = -1\n const bottom = scrollTop + viewportHeight\n for (const b of layout.boxes) {\n const visible = Math.max(\n 0,\n Math.min(b.top + b.height, bottom) - Math.max(b.top, scrollTop)\n )\n if (visible > bestArea) {\n bestArea = visible\n best = b.index\n }\n }\n return best\n}\n","/*\n * Inline styles. The headless DOM layer sets only what it cannot work without:\n * - container: `overflow: auto`, and `position: relative` when its computed position is static;\n * - pages element: `position: relative`, plus `width`/`height` from the layout;\n * - page hosts: `position: absolute` and `left`/`top`/`width`/`height` from the layout;\n * - page hosts: the `--scale-factor` (zoom) and `--total-scale-factor` (zoom × /UserUnit)\n * custom properties.\n * Nothing cosmetic (colours, borders, backgrounds, fonts) is ever set inline; that belongs to\n * the stylesheet. `destroy()` restores the container's overflow and position.\n */\nimport { readonly, writable, type Readable } from '../model/readable'\n\nimport {\n computeCssLayout,\n fitZoomCss,\n mostVisiblePageCss,\n visibleRangeCss,\n type CssLayout,\n type CssPageBox,\n type LayoutMode,\n} from './layout'\nimport { createPageTransform, type PageTransform, type ViewRotation } from './transform'\n\nimport type { InkDocument } from '../model/document'\nimport type { Point, Rect } from '../model/geometry'\n\nexport type ZoomValue = number | 'fit-width' | 'fit-page'\n\nexport interface ViewportOptions {\n container: HTMLElement\n document: InkDocument\n /** Default `'fit-width'`. */\n zoom?: ZoomValue\n /** Default `'continuous'`. */\n mode?: LayoutMode\n /** Default 0. */\n rotation?: ViewRotation\n /** Gap between pages, and the page padding used by fit modes, CSS px. Default 16. */\n gap?: number\n /** Pages to keep mounted either side of the visible range. Default 2. */\n buffer?: number\n /** Default 0.1. */\n minZoom?: number\n /** Default 8. */\n maxZoom?: number\n onMount(page: number, host: HTMLElement, transform: PageTransform): void\n onUpdate(page: number, host: HTMLElement, transform: PageTransform): void\n onUnmount(page: number, host: HTMLElement): void\n}\n\n/** The mounted page under a client point. The tools layer adds `user` and `css` (`PageHit`). */\nexport interface ViewportHit {\n page: number\n host: HTMLElement\n transform: PageTransform\n}\n\nexport interface Viewport {\n readonly zoom: Readable<ZoomValue>\n /** Effective numeric zoom, with fit modes resolved. */\n readonly scale: Readable<number>\n readonly currentPage: Readable<number>\n readonly mounted: Readable<readonly number[]>\n readonly layout: Readable<CssLayout>\n readonly rotation: Readable<ViewRotation>\n readonly mode: Readable<LayoutMode>\n /** `anchorCss` is relative to the container's top-left inside its border, CSS px; defaults to its centre. */\n setZoom(zoom: ZoomValue, anchorCss?: Point): void\n zoomBy(factor: number, anchorCss?: Point): void\n setMode(mode: LayoutMode): void\n setRotation(rotation: ViewRotation): void\n scrollToPage(index: number, opts?: { behavior?: ScrollBehavior }): void\n /** Scrolls so `rect` (user space on `page`) is visible, centring it when it was not. */\n scrollToRect(page: number, rect: Rect, opts?: { behavior?: ScrollBehavior }): void\n transformFor(page: number): PageTransform\n hostFor(page: number): HTMLElement | undefined\n /** The mounted page under a viewport (client) point, if any. */\n pageAtCss(clientX: number, clientY: number): ViewportHit | undefined\n destroy(): void\n}\n\nfunction sameList(a: readonly number[], b: readonly number[]): boolean {\n return a.length === b.length && a.every((v, i) => v === b[i])\n}\n\nexport function createViewport(opts: ViewportOptions): Viewport {\n const { container, document: doc } = opts\n const gap = opts.gap ?? 16\n const buffer = opts.buffer ?? 2\n const minZoom = opts.minZoom ?? 0.1\n const maxZoom = opts.maxZoom ?? 8\n const clamp = (z: number): number => Math.min(maxZoom, Math.max(minZoom, z))\n\n const zoom = writable<ZoomValue>(\n typeof opts.zoom === 'number' ? clamp(opts.zoom) : (opts.zoom ?? 'fit-width')\n )\n const scale = writable(1)\n const rotation = writable<ViewRotation>(opts.rotation ?? 0)\n const mode = writable<LayoutMode>(opts.mode ?? 'continuous')\n const currentPage = writable(0)\n const mounted = writable<readonly number[]>([])\n const layout = writable<CssLayout>({ boxes: [], width: 0, height: 0 })\n\n const previousStyle = {\n overflow: container.style.overflow,\n position: container.style.position,\n }\n container.dataset.inkViewport = ''\n container.style.overflow = 'auto'\n if (getComputedStyle(container).position === 'static')\n container.style.position = 'relative'\n\n const pagesEl = container.ownerDocument.createElement('div')\n pagesEl.className = 'ink-pages'\n pagesEl.dataset.inkPages = ''\n pagesEl.style.position = 'relative'\n container.append(pagesEl)\n\n const hosts = new Map<number, HTMLElement>()\n const transforms = new Map<number, PageTransform>()\n let lastSize = { width: -1, height: -1 }\n let destroyed = false\n\n function boxFor(page: number, l = layout.get()): CssPageBox | undefined {\n return l.boxes.find((b) => b.index === page)\n }\n\n /** Where the pages element starts inside the container's scrollable content (its padding). */\n function origin(): Point {\n return { x: pagesEl.offsetLeft, y: pagesEl.offsetTop }\n }\n\n /** The container's content box, CSS px: client size less padding. The pages element sits inside it. */\n function innerSize(): { width: number; height: number } {\n const cs = getComputedStyle(container)\n const px = (v: string): number => Number.parseFloat(v) || 0\n return {\n width: container.clientWidth - px(cs.paddingLeft) - px(cs.paddingRight),\n height: container.clientHeight - px(cs.paddingTop) - px(cs.paddingBottom),\n }\n }\n\n function resolveScale(): number {\n const z = zoom.get()\n if (typeof z === 'number') return clamp(z)\n const page = doc.pages[currentPage.get()] ?? doc.pages[0]\n if (!page) return 1\n return clamp(fitZoomCss(page, rotation.get(), innerSize(), z, gap))\n }\n\n function transformFor(page: number): PageTransform {\n let t = transforms.get(page)\n if (!t) {\n const info = doc.pages[page]\n if (!info) throw new RangeError(`page ${page} out of range`)\n t = createPageTransform(info, scale.get(), rotation.get())\n transforms.set(page, t)\n }\n return t\n }\n\n function layoutOnce(): void {\n scale.set(resolveScale())\n transforms.clear()\n const l = computeCssLayout({\n pages: doc.pages,\n zoom: scale.get(),\n rotation: rotation.get(),\n gap,\n mode: mode.get(),\n current: currentPage.get(),\n containerWidth: innerSize().width,\n })\n pagesEl.style.width = `${l.width}px`\n pagesEl.style.height = `${l.height}px`\n layout.set(l)\n }\n\n /**\n * Recomputes the layout. Sizing the pages element can add or remove a scrollbar, which\n * changes the client width the layout (and a fit zoom) was based on, so it runs again\n * once when that happens.\n */\n function relayout(): void {\n const width = container.clientWidth\n layoutOnce()\n if (container.clientWidth !== width) layoutOnce()\n lastSize = { width: container.clientWidth, height: container.clientHeight }\n const l = layout.get()\n for (const [page, host] of hosts) {\n if (!boxFor(page, l)) continue\n place(page, host, l)\n opts.onUpdate(page, host, transformFor(page))\n }\n sync()\n }\n\n function place(page: number, host: HTMLElement, l: CssLayout): void {\n const box = boxFor(page, l)\n if (!box) return\n const t = transformFor(page)\n host.style.left = `${box.left}px`\n host.style.top = `${box.top}px`\n host.style.width = `${t.cssWidth}px`\n host.style.height = `${t.cssHeight}px`\n // As in PDF.js's viewer: --scale-factor is the zoom, --total-scale-factor also folds in\n // /UserUnit (pdf_viewer.css: calc(var(--scale-factor) * var(--user-unit))).\n host.style.setProperty('--scale-factor', String(t.zoom))\n host.style.setProperty('--total-scale-factor', String(t.scale))\n host.dataset.rotation = String(t.totalRotation)\n }\n\n /** Mounts and unmounts hosts for the scroll position, and updates the current page. */\n function sync(): void {\n if (destroyed) return\n const l = layout.get()\n const top = container.scrollTop - origin().y\n const wanted = visibleRangeCss(l, top, container.clientHeight, buffer)\n const wantedSet = new Set(wanted)\n for (const [page, host] of [...hosts]) {\n if (wantedSet.has(page)) continue\n hosts.delete(page)\n opts.onUnmount(page, host)\n host.remove()\n }\n for (const page of wanted) {\n if (hosts.has(page)) continue\n const host = container.ownerDocument.createElement('div')\n host.className = 'ink-page'\n host.dataset.page = String(page)\n host.style.position = 'absolute'\n place(page, host, l)\n hosts.set(page, host)\n pagesEl.append(host)\n opts.onMount(page, host, transformFor(page))\n }\n if (!sameList(mounted.get(), wanted)) mounted.set(wanted)\n if (mode.get() === 'continuous') {\n currentPage.set(mostVisiblePageCss(l, top, container.clientHeight))\n }\n }\n\n let scrollFrame = 0\n const onScroll = (): void => {\n if (scrollFrame) return\n scrollFrame = requestAnimationFrame(() => {\n scrollFrame = 0\n sync()\n })\n }\n container.addEventListener('scroll', onScroll, { passive: true })\n\n const ro = new ResizeObserver(() => {\n if (destroyed) return\n if (\n container.clientWidth === lastSize.width &&\n container.clientHeight === lastSize.height\n ) {\n return\n }\n withAnchor(undefined, () => undefined)\n })\n ro.observe(container)\n\n function pageAtCss(clientX: number, clientY: number): ViewportHit | undefined {\n for (const [page, host] of hosts) {\n const r = host.getBoundingClientRect()\n if (\n clientX >= r.left &&\n clientX <= r.right &&\n clientY >= r.top &&\n clientY <= r.bottom\n ) {\n return { page, host, transform: transformFor(page) }\n }\n }\n return undefined\n }\n\n /**\n * The page box an anchor at layout-space `y` belongs to: the one whose vertical span\n * contains it, otherwise the nearest one (an anchor in a gap or past either end).\n */\n function anchorBox(l: CssLayout, y: number): CssPageBox | undefined {\n let best: CssPageBox | undefined\n let bestDistance = Infinity\n for (const b of l.boxes) {\n const distance =\n y < b.top ? b.top - y : y > b.top + b.height ? y - b.top - b.height : 0\n if (distance < bestDistance) {\n best = b\n bestDistance = distance\n }\n }\n return best\n }\n\n /**\n * Keeps the user-space point under `anchorCss` still while `change` alters the layout.\n * The anchor is taken in layout space, so it holds in the margins and gaps too: there it\n * is extrapolated from the nearest page's transform, which is affine, so the point maps\n * back exactly. The browser may still clamp the scroll at the content edges.\n */\n function withAnchor(anchorCss: Point | undefined, change: () => void): void {\n const anchor = anchorCss ?? {\n x: container.clientWidth / 2,\n y: container.clientHeight / 2,\n }\n // Read everything from the old layout before relayout() clears the cached transforms.\n const o = origin()\n const x = container.scrollLeft + anchor.x - o.x\n const y = container.scrollTop + anchor.y - o.y\n const old = anchorBox(layout.get(), y)\n const user = old\n ? transformFor(old.index).fromCss({ x: x - old.left, y: y - old.top })\n : undefined\n change()\n relayout()\n if (!old || !user) return\n const box = boxFor(old.index)\n if (!box) return\n const after = transformFor(old.index).toCss(user)\n const o2 = origin()\n container.scrollLeft = o2.x + box.left + after.x - anchor.x\n container.scrollTop = o2.y + box.top + after.y - anchor.y\n sync()\n }\n\n const viewport: Viewport = {\n zoom: readonly(zoom),\n scale: readonly(scale),\n currentPage: readonly(currentPage),\n mounted: readonly(mounted),\n layout: readonly(layout),\n rotation: readonly(rotation),\n mode: readonly(mode),\n setZoom(z, anchorCss) {\n withAnchor(anchorCss, () => zoom.set(typeof z === 'number' ? clamp(z) : z))\n },\n zoomBy(factor, anchorCss) {\n viewport.setZoom(clamp(scale.get() * factor), anchorCss)\n },\n setMode(m) {\n if (m === mode.get()) return\n // Catch up with a scroll whose frame has not run yet, then keep that page: relayout()\n // re-derives the current page from the scroll position, which the new mode changes.\n if (mode.get() === 'continuous') sync()\n const page = currentPage.get()\n mode.set(m)\n relayout()\n viewport.scrollToPage(page)\n },\n setRotation(r) {\n withAnchor(undefined, () => rotation.set(r))\n },\n scrollToPage(index, o) {\n const page = Math.max(0, Math.min(doc.pages.length - 1, index))\n const behavior = o?.behavior ?? 'auto'\n if (mode.get() === 'single') {\n // Also relayout when the layout shows another page, even if currentPage already matches.\n if (page !== currentPage.get() || layout.get().boxes[0]?.index !== page) {\n currentPage.set(page)\n relayout()\n }\n container.scrollTo({ top: 0, behavior })\n sync()\n return\n }\n const box = boxFor(page)\n if (!box) return\n container.scrollTo({ top: Math.max(0, origin().y + box.top - gap), behavior })\n sync()\n },\n scrollToRect(page, rect, o) {\n if (mode.get() === 'single' && currentPage.get() !== page) {\n currentPage.set(page)\n relayout()\n }\n const box = boxFor(page)\n if (!box) return\n const css = transformFor(page).toCssRect(rect)\n const at = origin()\n const to: ScrollToOptions = { behavior: o?.behavior ?? 'auto' }\n const top = at.y + box.top + css.top\n if (\n top < container.scrollTop ||\n top + css.height > container.scrollTop + container.clientHeight\n ) {\n to.top = Math.max(0, top - (container.clientHeight - css.height) / 2)\n }\n const left = at.x + box.left + css.left\n if (\n left < container.scrollLeft ||\n left + css.width > container.scrollLeft + container.clientWidth\n ) {\n to.left = Math.max(0, left - (container.clientWidth - css.width) / 2)\n }\n if (to.top !== undefined || to.left !== undefined) container.scrollTo(to)\n sync()\n },\n transformFor,\n hostFor: (page) => hosts.get(page),\n pageAtCss,\n destroy() {\n if (destroyed) return\n destroyed = true\n ro.disconnect()\n container.removeEventListener('scroll', onScroll)\n if (scrollFrame) cancelAnimationFrame(scrollFrame)\n for (const [page, host] of hosts) {\n opts.onUnmount(page, host)\n host.remove()\n }\n hosts.clear()\n transforms.clear()\n pagesEl.remove()\n delete container.dataset.inkViewport\n container.style.overflow = previousStyle.overflow\n container.style.position = previousStyle.position\n },\n }\n\n relayout()\n return viewport\n}\n","import type { Viewport } from './viewport'\n\nexport interface ViewportKeysOptions {\n viewport: Viewport\n /** Read on every key, so it follows the open document. */\n pageCount: () => number\n}\n\n/** Factor `+`/`=` zoom in by; `-` zooms out by its inverse. */\nconst ZOOM_STEP = 1.25\n\n/** Keys typed here belong to the element, not the viewport. */\nconst IGNORE =\n 'input, textarea, select, [contenteditable]:not([contenteditable=\"false\"]), [data-annotation]'\n\n/**\n * Keyboard shortcuts for a focused viewport container: `+` or `=` and `-` zoom, `Home` and\n * `End` go to the first and last page, `PageDown` and `PageUp` to the next and previous.\n * Events from inputs, editable content and annotation elements, chords with Ctrl, Meta or\n * Alt (browser zoom stays the browser's), and events already handled are left alone. Only\n * handled keys are prevented. Returns a function that removes the listener.\n */\nexport function attachViewportKeys(\n el: HTMLElement,\n opts: ViewportKeysOptions\n): () => void {\n const { viewport } = opts\n const onKeydown = (e: KeyboardEvent): void => {\n if (e.defaultPrevented || e.ctrlKey || e.metaKey || e.altKey) return\n if (e.target instanceof Element && e.target.closest(IGNORE)) return\n switch (e.key) {\n case '+':\n case '=':\n viewport.zoomBy(ZOOM_STEP)\n break\n case '-':\n viewport.zoomBy(1 / ZOOM_STEP)\n break\n case 'Home':\n viewport.scrollToPage(0)\n break\n case 'End':\n viewport.scrollToPage(opts.pageCount() - 1)\n break\n case 'PageDown':\n viewport.scrollToPage(viewport.currentPage.get() + 1)\n break\n case 'PageUp':\n viewport.scrollToPage(viewport.currentPage.get() - 1)\n break\n default:\n return\n }\n e.preventDefault()\n }\n el.addEventListener('keydown', onKeydown)\n return () => el.removeEventListener('keydown', onKeydown)\n}\n","// Watches the device pixel ratio for the layers that render at it: the page canvas and the\n// loupes. The media query matches only the ratio it was built for, so it is rebuilt after\n// every change. During a browser-zoom or screen transition the query can fire while\n// devicePixelRatio still reports the old value, so each change also schedules follow-up checks.\n\nconst RECHECK_MS = [100, 500]\n\nexport interface DprWatch {\n /** Watches for a change away from `dpr`, the ratio just rendered at. */\n watch(dpr: number): void\n destroy(): void\n}\n\n/**\n * Calls `onChange` when `view`'s device pixel ratio moves away from the one last passed to\n * `watch`. `current` reads the ratio now. Does nothing where `matchMedia` is missing.\n */\nexport function watchDevicePixelRatio(\n view: Window | null | undefined,\n current: () => number,\n onChange: () => void\n): DprWatch {\n let query: MediaQueryList | undefined\n let watched: number | undefined\n let rechecks: ReturnType<typeof setTimeout>[] = []\n let destroyed = false\n\n const clearRechecks = (): void => {\n rechecks.forEach(clearTimeout)\n rechecks = []\n }\n const fire = (): void => {\n if (destroyed) return\n arm(current(), true)\n onChange()\n clearRechecks()\n rechecks = RECHECK_MS.map((ms) =>\n setTimeout(() => {\n if (!destroyed && current() !== watched) fire()\n }, ms)\n )\n }\n function arm(dpr: number, force = false): void {\n if (destroyed || !view?.matchMedia) return\n if (dpr === watched && !force) return\n watched = dpr\n query?.removeEventListener('change', fire)\n query = view.matchMedia(`(resolution: ${dpr}dppx)`)\n query.addEventListener('change', fire)\n }\n\n return {\n watch: (dpr) => arm(dpr),\n destroy() {\n destroyed = true\n query?.removeEventListener('change', fire)\n query = undefined\n clearRechecks()\n },\n }\n}\n","// Inline styles here are structural only: the wrapper fills the page host and clips\n// (`position:absolute; inset:0; overflow:hidden`), and each canvas is pinned to the top-left\n// with its CSS size set from the transform (`position:absolute; left:0; top:0; width; height`).\n// Everything cosmetic (background, shadow, border) belongs to the theme.\nimport { watchDevicePixelRatio } from './dpr-watch'\n\nimport type { PageTransform } from './transform'\nimport type { InkDocument } from '../model/document'\nimport type { PdfjsRenderTask } from '../pdfjs/types'\n\nexport interface PageRendererOptions {\n document: InkDocument\n /** Zero-based page index. */\n page: number\n /** The page host (`div.ink-page`); the renderer appends its canvas layer to it. */\n host: HTMLElement\n transform: PageTransform\n /**\n * Fixed device pixel ratio. When omitted, `window.devicePixelRatio` is read at every render\n * and the page re-renders when it changes (browser zoom, moving to another screen).\n */\n devicePixelRatio?: number\n onRendered?(): void\n /** Called for any render failure other than a superseded render's cancellation. */\n onError?(error: unknown): void\n}\n\nexport interface PageRenderer {\n readonly element: HTMLElement\n /**\n * Resolves once the most recent `update` has painted, failed (see `onError`) or the\n * renderer was destroyed. Never rejects. A promise read before a later `update` resolves\n * together with that later render, so every promise handed out settles.\n */\n readonly rendered: Promise<void>\n update(transform: PageTransform): void\n destroy(): void\n}\n\nconst isCancellation = (error: unknown): boolean =>\n (error as { name?: unknown } | null)?.name === 'RenderingCancelledException'\n\nexport function createPageRenderer(opts: PageRendererOptions): PageRenderer {\n const { document: doc, page, host } = opts\n const view = host.ownerDocument.defaultView\n const currentDpr = (): number =>\n opts.devicePixelRatio ??\n (view && view.devicePixelRatio > 0 ? view.devicePixelRatio : 1)\n const wrapper = host.ownerDocument.createElement('div')\n wrapper.className = 'ink-canvas-layer'\n wrapper.dataset.inkCanvasLayer = ''\n wrapper.style.cssText = 'position:absolute;inset:0;overflow:hidden;'\n host.append(wrapper)\n\n let current: HTMLCanvasElement | undefined\n let latest = opts.transform\n let task: PdfjsRenderTask | undefined\n let destroyed = false\n let generation = 0\n\n // One deferred per busy period: renders that supersede each other share it, and it\n // resolves when the newest one settles.\n let resolvePending: (() => void) | undefined\n let rendered: Promise<void> = Promise.resolve()\n\n function settle() {\n resolvePending?.()\n resolvePending = undefined\n }\n\n /**\n * Drops a canvas for good. Zeroing it frees its bitmap now rather than at garbage\n * collection; Safari caps the total canvas memory, which a long scroll would otherwise hit.\n */\n function release(canvas: HTMLCanvasElement): void {\n canvas.width = 0\n canvas.height = 0\n canvas.remove()\n }\n\n function sizeCanvas(canvas: HTMLCanvasElement, transform: PageTransform) {\n canvas.style.width = `${transform.cssWidth}px`\n canvas.style.height = `${transform.cssHeight}px`\n }\n\n async function render(transform: PageTransform): Promise<void> {\n const gen = ++generation\n latest = transform\n const dpr = currentDpr()\n dprWatch?.watch(dpr)\n task?.cancel()\n task = undefined\n if (!resolvePending) {\n rendered = new Promise<void>((resolve) => (resolvePending = resolve))\n }\n // The previous bitmap stays visible, stretched to the new size, until the new one lands.\n if (current) sizeCanvas(current, transform)\n let canvas: HTMLCanvasElement | undefined\n try {\n const pdfPage = await doc._pdfjs.getPage(page)\n if (destroyed || gen !== generation) return\n const { AnnotationMode } = doc._pdfjs.module\n const viewport = pdfPage.getViewport({\n scale: transform.zoom,\n rotation: transform.totalRotation,\n })\n canvas = host.ownerDocument.createElement('canvas')\n canvas.dataset.inkCanvas = ''\n canvas.setAttribute('aria-hidden', 'true')\n canvas.width = Math.round(transform.cssWidth * dpr)\n canvas.height = Math.round(transform.cssHeight * dpr)\n canvas.style.cssText = 'position:absolute;left:0;top:0;'\n sizeCanvas(canvas, transform)\n const ownTask = pdfPage.render({\n canvas,\n viewport,\n // Pages are paper: an opaque white canvas, whatever the theme puts behind it.\n background: '#ffffff',\n annotationMode: AnnotationMode.ENABLE,\n ...(dpr === 1 ? {} : { transform: [dpr, 0, 0, dpr, 0, 0] }),\n })\n task = ownTask\n await ownTask.promise\n if (task === ownTask) task = undefined\n if (destroyed || gen !== generation) {\n release(canvas)\n return\n }\n if (current) release(current)\n current = canvas\n wrapper.append(canvas)\n opts.onRendered?.()\n } catch (error) {\n if (canvas && canvas !== current) release(canvas)\n const superseded = destroyed || gen !== generation\n if (!(superseded && isCancellation(error)) && !destroyed) opts.onError?.(error)\n } finally {\n if (gen === generation) settle()\n }\n }\n\n // Re-render when the device pixel ratio changes, unless the caller fixed it.\n const dprWatch =\n opts.devicePixelRatio === undefined\n ? watchDevicePixelRatio(view, currentDpr, () => void render(latest))\n : undefined\n\n void render(opts.transform)\n\n return {\n element: wrapper,\n get rendered() {\n return rendered\n },\n update(transform) {\n if (destroyed) return\n void render(transform)\n },\n destroy() {\n if (destroyed) return\n destroyed = true\n dprWatch?.destroy()\n task?.cancel()\n task = undefined\n if (current) release(current)\n current = undefined\n wrapper.remove()\n settle()\n },\n }\n}\n","// The only file that touches PDF.js's `TextLayer`. It takes the already-loaded PDF.js module\n// instead of importing `#pdfjs`, so `@inkbar/core/dom` can re-export the text layer without\n// evaluating PDF.js at import time.\nimport type { PdfjsModule, PdfjsPage, PdfjsViewport } from './types'\n\nexport interface MountedTextLayer {\n update(viewport: PdfjsViewport): void\n cancel(): void\n}\n\nexport interface MountPdfjsTextLayerOptions {\n /** The loaded PDF.js module, i.e. `InkDocument._pdfjs.module`. */\n module: PdfjsModule\n pdfPage: PdfjsPage\n container: HTMLElement\n viewport: PdfjsViewport\n /** Aborting cancels the render (and any later use of the layer). */\n signal?: AbortSignal\n}\n\n/**\n * Renders the page's text into `container` as positioned spans. The constructor sizes the\n * container from `--total-scale-factor` and sets `data-main-rotation`; CSS (the theme) turns\n * those into the final layout. Rejects with PDF.js's `AbortException` if `signal` aborts first.\n * On any rejection the layer is cancelled and detached from `signal`.\n */\nexport async function mountPdfjsTextLayer(\n opts: MountPdfjsTextLayerOptions\n): Promise<MountedTextLayer> {\n const layer = new opts.module.TextLayer({\n textContentSource: opts.pdfPage.streamTextContent({\n includeMarkedContent: false,\n disableNormalization: true,\n }),\n container: opts.container,\n viewport: opts.viewport,\n })\n const mounted: MountedTextLayer = {\n update(viewport) {\n layer.update({ viewport })\n },\n cancel() {\n layer.cancel()\n },\n }\n const onAbort = (): void => layer.cancel()\n opts.signal?.addEventListener('abort', onAbort, { once: true })\n if (opts.signal?.aborted) layer.cancel()\n try {\n await layer.render()\n } catch (error) {\n // A failed layer is dropped here: cancelled, and no longer held by the caller's signal, so\n // a retry on the same signal does not keep every failed attempt alive.\n opts.signal?.removeEventListener('abort', onAbort)\n layer.cancel()\n throw error\n }\n return mounted\n}\n","// Inline styles here are structural only: the layer covers the page host\n// (`position:absolute; inset:0`) and its text must stay selectable whatever the page around it\n// sets (`user-select:text`). PDF.js sets the layer's width/height from `--total-scale-factor`.\n// Span styling (transparent colour, absolute positioning, font sizing, rotation transforms)\n// is the theme's job.\nimport { mountPdfjsTextLayer, type MountedTextLayer } from '../pdfjs/text-layer'\n\nimport type { PageTransform } from './transform'\nimport type { InkDocument } from '../model/document'\n\nexport interface TextLayerOptions {\n document: InkDocument\n /** Zero-based page index. */\n page: number\n /** The page host (`div.ink-page`), which must carry `--total-scale-factor`. */\n host: HTMLElement\n transform: PageTransform\n /**\n * Mount or update failures. Cancellation by `destroy` is not reported. If it throws, the\n * exception is rethrown asynchronously; `ready` still resolves.\n */\n onError?(error: unknown): void\n /** The layer mounted, or applied an `update`, without error. */\n onRendered?(): void\n}\n\nexport interface TextLayerHandle {\n readonly element: HTMLElement\n /** Resolves once the latest mount or `update` has applied. Never rejects. */\n readonly ready: Promise<void>\n update(transform: PageTransform): void\n destroy(): void\n}\n\nexport function createTextLayer(opts: TextLayerOptions): TextLayerHandle {\n const { document: doc, page } = opts\n const el = opts.host.ownerDocument.createElement('div')\n el.className = 'ink-text-layer'\n el.dataset.inkTextLayer = ''\n el.style.cssText = 'position:absolute;inset:0;user-select:text;'\n opts.host.append(el)\n\n const abort = new AbortController()\n let mounted: MountedTextLayer | undefined\n\n const viewportFor = async (transform: PageTransform) => {\n const pdfPage = await doc._pdfjs.getPage(page)\n return {\n pdfPage,\n viewport: pdfPage.getViewport({\n scale: transform.zoom,\n rotation: transform.totalRotation,\n }),\n }\n }\n\n // A throwing `onError` must not reject `ready`: its exception is rethrown from a microtask,\n // so it still surfaces as an uncaught error.\n const report = (error: unknown) => {\n if (abort.signal.aborted || !opts.onError) return\n try {\n opts.onError(error)\n } catch (thrown) {\n queueMicrotask(() => {\n throw thrown\n })\n }\n }\n\n const mount = async (transform: PageTransform): Promise<void> => {\n const { pdfPage, viewport } = await viewportFor(transform)\n if (abort.signal.aborted) return\n mounted = await mountPdfjsTextLayer({\n module: doc._pdfjs.module,\n pdfPage,\n container: el,\n viewport,\n signal: abort.signal,\n })\n if (!abort.signal.aborted) opts.onRendered?.()\n }\n\n let ready: Promise<void> = mount(opts.transform).catch(report)\n\n return {\n element: el,\n get ready() {\n return ready\n },\n update(transform) {\n if (abort.signal.aborted) return\n ready = ready\n .then(async () => {\n if (abort.signal.aborted) return\n // A mount that failed is tried again, so the layer can recover with the page.\n if (!mounted) {\n el.replaceChildren()\n await mount(transform)\n return\n }\n const { viewport } = await viewportFor(transform)\n if (abort.signal.aborted) return\n mounted.update(viewport)\n opts.onRendered?.()\n })\n .catch(report)\n },\n destroy() {\n if (abort.signal.aborted) return\n abort.abort()\n el.remove()\n },\n }\n}\n","import { mergeLineRects } from '../model/selection'\n\nimport type { PageTransform } from './transform'\nimport type { Quad, Rect } from '../model/geometry'\n\nexport interface SelectionQuads {\n /** Zero-based page index. */\n page: number\n /** One user-space quad per selected line, top to bottom. */\n quads: Quad[]\n text: string\n}\n\n/**\n * Converts viewport-relative CSS-pixel rects (from `getClientRects()`) to user-space rects on\n * the page rendered in `host`. Empty rects are skipped.\n */\nexport function cssRectsToUserRects(\n rects: Iterable<DOMRect>,\n host: HTMLElement,\n transform: PageTransform\n): Rect[] {\n const h = host.getBoundingClientRect()\n const out: Rect[] = []\n for (const r of rects) {\n if (r.width === 0 || r.height === 0) continue\n out.push(\n transform.fromCssRect({\n left: r.left - h.left,\n top: r.top - h.top,\n width: r.width,\n height: r.height,\n })\n )\n }\n return out\n}\n\n/**\n * Reads the live DOM selection and returns one entry per page it touches, with line-merged\n * user-space quads. Only text inside `[data-ink-text-layer]` under a `[data-page]` host counts;\n * `pageFor` maps a host to its page index and current transform.\n */\nexport function getSelectionQuads(\n root: HTMLElement,\n pageFor: (host: HTMLElement) => { page: number; transform: PageTransform } | undefined\n): SelectionQuads[] {\n const sel = root.ownerDocument.defaultView?.getSelection()\n if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return []\n const results = new Map<number, { rects: Rect[]; text: string[] }>()\n const layers = [...root.querySelectorAll<HTMLElement>('[data-ink-text-layer]')]\n if (root.matches('[data-ink-text-layer]')) layers.unshift(root)\n for (let i = 0; i < sel.rangeCount; i++) {\n const range = sel.getRangeAt(i)\n for (const layer of layers) {\n if (!range.intersectsNode(layer)) continue\n const host = layer.closest<HTMLElement>('[data-page]')\n if (!host) continue\n const info = pageFor(host)\n if (!info) continue\n const sub = range.cloneRange()\n if (!layer.contains(range.startContainer)) sub.setStart(layer, 0)\n if (!layer.contains(range.endContainer)) sub.setEnd(layer, layer.childNodes.length)\n const entry = results.get(info.page) ?? { rects: [], text: [] }\n entry.rects.push(...cssRectsToUserRects(sub.getClientRects(), host, info.transform))\n entry.text.push(rangeText(sub))\n results.set(info.page, entry)\n }\n }\n return [...results.entries()]\n .sort(([a], [b]) => a - b)\n .map(([page, { rects, text }]) => ({\n page,\n quads: mergeLineRects(rects),\n text: normaliseText(text.join('\\n')),\n }))\n .filter((r) => r.quads.length > 0)\n}\n\n/**\n * The range's text with each PDF.js `<br>` (an end of line) kept as a newline.\n * `Range.toString()` would run the lines together.\n */\nfunction rangeText(range: Range): string {\n const fragment = range.cloneContents()\n for (const br of fragment.querySelectorAll('br')) br.replaceWith('\\n')\n return fragment.textContent ?? ''\n}\n\n/**\n * Collapses runs of horizontal whitespace to one space and drops the spaces around a line\n * break. Breaks themselves are all kept, so a blank line (two breaks) survives.\n */\nfunction normaliseText(text: string): string {\n return text\n .replace(/[^\\S\\n]+/g, ' ')\n .replace(/ ?\\n ?/g, '\\n')\n .trim()\n}\n","// Turns the sampled points of an ink stroke into a smoothed, filled outline. Overlay rendering\n// and the draw tool's live preview share it, so a stroke looks the same while drawn and after.\nimport { getStroke } from 'perfect-freehand'\n\nimport type { Point } from '../model/geometry'\n\n/** Strokes started within this long of the last one join its annotation. */\nexport const JOIN_GAP_MS = 1000\n\n/**\n * The polygon around a stroke. `width` is the stroke width, in the points' own unit; without\n * `pressure` the line keeps an even width.\n */\nexport function strokeOutline(\n points: readonly Point[],\n pressure: readonly number[] | undefined,\n width: number\n): Point[] {\n const withPressure = pressure !== undefined\n const input = points.map(\n (p, i) => [p.x, p.y, pressure?.[i] ?? 0.5] as [number, number, number]\n )\n return getStroke(input, {\n size: width,\n thinning: withPressure ? 0.5 : 0,\n smoothing: 0.5,\n streamline: 0.5,\n simulatePressure: false,\n }).map(([x, y]) => ({ x, y }))\n}\n\n/** A closed SVG path `d` through `outline`; empty for an empty outline. */\nexport function outlinePath(outline: readonly Point[]): string {\n if (outline.length === 0) return ''\n const r = (n: number): string => String(Math.round(n * 100) / 100)\n return `M${outline.map((p) => `${r(p.x)},${r(p.y)}`).join('L')}Z`\n}\n","import { ICON_ATTRIBUTES, MessageSquareText } from '@inkbar/icons'\n\nimport {\n calloutStroke,\n freeTextBox,\n isStandardCallout,\n} from '../model/annotations/callout'\nimport { isBubble, isTextMarkup, WEDGE_HALF } from '../model/annotations/edit'\nimport { isKnown, LINE_ENDINGS } from '../model/annotations/pdf-names'\n\nimport { outlinePath, strokeOutline } from './ink-stroke'\nimport { normalizeRotation, type CssRect, type PageTransform } from './transform'\n\nimport type {\n Annotation,\n FreeTextAnnotation,\n LineEnding,\n StampAnnotation,\n TextMarkupAnnotation,\n} from '../model/annotations/types'\nimport type { Point, Quad } from '../model/geometry'\n\nconst SVG = 'http://www.w3.org/2000/svg'\n\n/** Side of an edit handle, CSS px. */\nconst HANDLE_PX = 8\nconst CORNERS = ['nw', 'ne', 'sw', 'se'] as const\n/** Width in CSS px of the band along a mask's edge that takes presses. */\nconst MASK_EDGE = 6\n/** Width in CSS px of the band straddling a text box's edge, which drags the box. */\nconst TEXT_EDGE = 6\n\n/**\n * Which edit handles an element shows: none, the four CSS corners of a box (`nw`, `ne`, `sw`,\n * `se`), or a line's two ends (`start`, `end`), all element-local CSS px.\n */\nexport type HandleSpec =\n | { kind: 'none' }\n | {\n kind: 'corners'\n /** The box's top-left corner; 0,0 (the element's own) when absent. */\n left?: number\n top?: number\n width: number\n height: number\n /** A callout's tip: one more handle, `callout`. */\n tail?: Point\n }\n | { kind: 'ends'; start: Point; end: Point }\n\n/**\n * Syncs an element's edit handles (`.ink-handle[data-handle]`) with `spec`. Each is an 8px\n * `position:absolute; pointer-events:auto` box centred on its point; its look is the theme's.\n */\nexport function syncHandles(node: HTMLElement, spec: HandleSpec): void {\n const existing = [...node.querySelectorAll<HTMLElement>(':scope > [data-handle]')]\n const names: readonly string[] =\n spec.kind === 'none'\n ? []\n : spec.kind === 'ends'\n ? ['start', 'end']\n : spec.tail\n ? [...CORNERS, 'callout']\n : CORNERS\n if (\n existing.length !== names.length ||\n existing.some((h, i) => h.dataset.handle !== names[i])\n ) {\n existing.forEach((h) => h.remove())\n existing.length = 0\n for (const name of names) {\n const h = node.ownerDocument.createElement('div')\n h.className = 'ink-handle'\n h.dataset.handle = name\n h.setAttribute('aria-hidden', 'true')\n h.style.cssText = `position:absolute;width:${HANDLE_PX}px;height:${HANDLE_PX}px;pointer-events:auto;`\n node.append(h)\n existing.push(h)\n }\n }\n for (const h of existing) {\n const name = h.dataset.handle!\n const at =\n spec.kind === 'ends'\n ? name === 'start'\n ? spec.start\n : spec.end\n : spec.kind === 'corners'\n ? name === 'callout' && spec.tail\n ? spec.tail\n : {\n x: (spec.left ?? 0) + (name[1] === 'w' ? 0 : spec.width),\n y: (spec.top ?? 0) + (name[0] === 'n' ? 0 : spec.height),\n }\n : { x: 0, y: 0 }\n h.style.left = `${at.x - HANDLE_PX / 2}px`\n h.style.top = `${at.y - HANDLE_PX / 2}px`\n }\n}\n\n/** Width in CSS px a thin stroke's invisible hit twin is widened to. */\nconst HIT_STROKE = 8\n\n/**\n * True when `a` is drawn as a stroke alone (a line, polyline, ink, or an unfilled square,\n * circle or polygon with a border), so a press beside the stroke would miss it. These get an\n * invisible, wider hit twin of their geometry.\n */\nfunction hasHitTwin(a: Annotation): boolean {\n switch (a.type) {\n case 'line':\n case 'polyline':\n case 'ink':\n return true\n case 'polygon':\n case 'square':\n case 'circle':\n return a.interiorColor === undefined && a.width > 0\n default:\n return false\n }\n}\n\n/** The width in CSS px of `a`'s hit twin: 8px, or the drawn stroke if that is wider. */\nfunction hitWidth(a: Annotation, t: PageTransform): number {\n return Math.max(HIT_STROKE, 'width' in a ? t.toCssLength(a.width) : 0)\n}\n\n/**\n * The CSS box an annotation's default visual occupies. Usually `toCssRect(a.rect)`. Stroked\n * paths (lines, polylines, polygons, ink) use the bounds of their own points instead of\n * `rect` (which may already carry stroke padding, as a derived ink rect does), padded once by\n * half their stroke width on every side, at least 1px in all, so a horizontal or vertical\n * line still has a box to draw and hit-test in. A shape with a hit twin (see `hasHitTwin`)\n * is padded by at least 4px more, so its wider hit area is not clipped. Custom elements do\n * not use this: they sit on `toCssRect(a.rect)`.\n */\nexport function annotationBox(a: Annotation, t: PageTransform): CssRect {\n const drawn = handleBox(a, t)\n if (!hasHitTwin(a)) return drawn\n const pad = hitPad(a, t)\n return {\n left: drawn.left - pad,\n top: drawn.top - pad,\n width: drawn.width + pad * 2,\n height: drawn.height + pad * 2,\n }\n}\n\n/**\n * How far past `handleBox` a shape with a hit twin extends its element: the twin's overhang\n * beyond the drawn stroke, and at least 4px.\n */\nfunction hitPad(a: Annotation, t: PageTransform): number {\n const overhang = Math.max(0, hitWidth(a, t) - t.toCssLength('width' in a ? a.width : 0))\n return Math.max(HIT_STROKE / 2, overhang / 2)\n}\n\n/**\n * The CSS box an annotation's edit handles and resizing work on: `annotationBox` without the\n * padding its hit twin needs. `toCssRect(a.rect)` for a rect-shaped annotation; the padded\n * bounds of its points for a stroked path.\n */\nexport function handleBox(a: Annotation, t: PageTransform): CssRect {\n const points =\n a.type === 'line'\n ? [a.start, a.end]\n : a.type === 'polyline' || a.type === 'polygon'\n ? a.vertices\n : a.type === 'ink'\n ? a.inklist.flat()\n : undefined\n if (!points || points.length === 0 || !('width' in a)) return t.toCssRect(a.rect)\n const box = t.toCssRect(pointBounds(points))\n const stroke = Math.max(t.toCssLength(a.width), 1)\n // Endings reach up to ENDING_SCALE strokes either side of their end.\n const pad = hasEndings(a) ? ENDING_SCALE * stroke : stroke / 2\n return {\n left: box.left - pad,\n top: box.top - pad,\n width: box.width + pad * 2,\n height: box.height + pad * 2,\n }\n}\n\n/** An ending's length, and its full width, as a multiple of the stroke width. */\nconst ENDING_SCALE = 3\n\n/** A name Inkbar does not draw is drawn as no ending; the annotation keeps it. */\nfunction drawable(kind: LineEnding | undefined): LineEnding {\n return kind !== undefined && isKnown(LINE_ENDINGS, kind) ? kind : 'None'\n}\n\nfunction endingKinds(a: Annotation): { head: LineEnding; tail: LineEnding } | undefined {\n return a.type === 'line' || a.type === 'polyline'\n ? { head: drawable(a.head), tail: drawable(a.tail) }\n : undefined\n}\n\nfunction hasEndings(a: Annotation): boolean {\n const e = endingKinds(a)\n return e !== undefined && (e.head !== 'None' || e.tail !== 'None')\n}\n\nconst fmt = (n: number): string => String(Math.round(n * 1000) / 1000 + 0)\n\n/**\n * SVG path data for a line ending at `at`, in the caller's coordinates (CSS px). `from` is the\n * other end of the segment the ending sits on, so the ending points from `from` towards `at`.\n * Sized from the stroke `width` (at least 1): arrows are 3 strokes long, the rest 3 across.\n * Returns an empty string for `none` or a zero-length segment.\n */\nexport function lineEndingPath(\n kind: LineEnding,\n at: Point,\n from: Point,\n width: number\n): string {\n const len = Math.hypot(at.x - from.x, at.y - from.y)\n if (!isKnown(LINE_ENDINGS, kind) || kind === 'None' || len === 0) return ''\n const size = ENDING_SCALE * Math.max(width, 1)\n const half = size / 2\n const dx = (at.x - from.x) / len\n const dy = (at.y - from.y) / len\n // Unit normal, 90 degrees clockwise on screen.\n const nx = -dy\n const ny = dx\n const pt = (along: number, across: number, o: Point = at): string =>\n `${fmt(o.x + dx * along + nx * across)} ${fmt(o.y + dy * along + ny * across)}`\n switch (kind) {\n case 'OpenArrow':\n return `M${pt(-size, -half)}L${pt(0, 0)}L${pt(-size, half)}`\n case 'ClosedArrow':\n return `M${pt(-size, -half)}L${pt(0, 0)}L${pt(-size, half)}Z`\n case 'ROpenArrow':\n return `M${pt(0, -half)}L${pt(-size, 0)}L${pt(0, half)}`\n case 'RClosedArrow':\n return `M${pt(0, -half)}L${pt(-size, 0)}L${pt(0, half)}Z`\n case 'Square':\n return `M${pt(-half, -half)}L${pt(half, -half)}L${pt(half, half)}L${pt(-half, half)}Z`\n case 'Diamond':\n return `M${pt(-half, 0)}L${pt(0, -half)}L${pt(half, 0)}L${pt(0, half)}Z`\n case 'Circle':\n return `M${pt(half, 0)}A${fmt(half)} ${fmt(half)} 0 1 0 ${pt(-half, 0)}A${fmt(half)} ${fmt(half)} 0 1 0 ${pt(half, 0)}Z`\n case 'Butt':\n return `M${pt(0, -half)}L${pt(0, half)}`\n case 'Slash': {\n // Tilted 30 degrees from the butt, as PDF draws it.\n const s = Math.sin(Math.PI / 6) * half\n const c = Math.cos(Math.PI / 6) * half\n return `M${pt(-s, -c)}L${pt(s, c)}`\n }\n default:\n return ''\n }\n}\n\n/** Endings that are solid shapes: filled with the stroke colour. */\nconst FILLED_ENDINGS: ReadonlySet<LineEnding> = new Set([\n 'ClosedArrow',\n 'RClosedArrow',\n 'Square',\n 'Circle',\n 'Diamond',\n])\n\nfunction pointBounds(points: readonly Point[]): {\n x: number\n y: number\n width: number\n height: number\n} {\n const xs = points.map((p) => p.x)\n const ys = points.map((p) => p.y)\n const x = Math.min(...xs)\n const y = Math.min(...ys)\n return { x, y, width: Math.max(...xs) - x, height: Math.max(...ys) - y }\n}\n\n/**\n * Draws the default visual for an annotation inside its positioned element. Coordinates are\n * relative to the element. Colour, opacity and stroke are SVG attributes, never inline style,\n * so a theme can override them with CSS.\n */\nexport function renderAnnotationContent(\n el: HTMLElement,\n a: Annotation,\n t: PageTransform\n): void {\n const doc = el.ownerDocument\n el.replaceChildren()\n const box = annotationBox(a, t)\n /** A user-space point in element-local CSS px. */\n const at = (p: Point): Point => {\n const c = t.toCss(p)\n return { x: c.x - box.left, y: c.y - box.top }\n }\n const local = (p: Point): string => {\n const c = at(p)\n return `${c.x},${c.y}`\n }\n const node = (name: string, attrs: Record<string, string | number>): SVGElement => {\n const n = doc.createElementNS(SVG, name)\n for (const [k, v] of Object.entries(attrs)) n.setAttribute(k, String(v))\n return n\n }\n\n if (a.type === 'text') {\n // The note's box is its shape: a transparent rect takes the hits, the icon is theme art.\n const svg = boxSvg(doc, box.width, box.height)\n const hit = node('rect', {\n x: 0,\n y: 0,\n width: box.width,\n height: box.height,\n fill: 'transparent',\n stroke: 'none',\n 'pointer-events': 'all',\n })\n hit.classList.add('ink-note-box')\n svg.append(hit)\n const icon = doc.createElement('span')\n icon.className = 'ink-note-icon'\n icon.dataset.icon = a.icon\n el.append(svg, icon)\n return\n }\n if (a.type === 'freetext') {\n if (isBubble(a)) {\n // One path draws the box and its tail; the text box sits above it with no look of its own.\n const svg = boxSvg(doc, box.width, box.height)\n svg.classList.add('ink-annotation-shape')\n svg.setAttribute('opacity', String(a.opacity))\n const path = node('path', {\n d: bubblePath(a, t),\n fill: a.color ?? 'none',\n stroke: a.width > 0 ? (a.borderColor ?? a.defaultStyle.color) : 'none',\n 'stroke-width': t.toCssLength(a.width),\n 'stroke-linejoin': 'round',\n 'pointer-events': 'visiblePainted',\n })\n path.classList.add('ink-bubble')\n dash(path, a.dashes, t)\n svg.append(path)\n el.append(svg)\n } else if (isStandardCallout(a)) {\n // The leader line runs from the tip to the box, with its ending at the tip.\n const svg = boxSvg(doc, box.width, box.height)\n svg.classList.add('ink-annotation-shape')\n svg.setAttribute('opacity', String(a.opacity))\n const stroke = calloutStroke(a)\n const sw = t.toCssLength(stroke.width)\n const line = node('polyline', {\n points: a.callout.map(local).join(' '),\n fill: 'none',\n stroke: stroke.color,\n 'stroke-width': sw,\n 'stroke-linejoin': 'round',\n 'stroke-linecap': 'butt',\n 'pointer-events': 'visiblePainted',\n })\n line.classList.add('ink-callout-line')\n // The leader line is dashed as the box's border is.\n dash(line, a.dashes, t)\n svg.append(line)\n const kind = drawable(a.head)\n const d = lineEndingPath(kind, at(a.callout[0]!), at(a.callout[1]!), sw)\n if (d) {\n const ending = node('path', {\n d,\n fill: FILLED_ENDINGS.has(kind) ? stroke.color : 'none',\n stroke: stroke.color,\n 'stroke-width': sw,\n 'stroke-linejoin': 'round',\n 'stroke-linecap': kind === 'Butt' || kind === 'Slash' ? 'butt' : 'round',\n 'pointer-events': 'visiblePainted',\n })\n ending.setAttribute('data-ending', 'head')\n svg.append(ending)\n }\n el.append(svg)\n }\n // HTML rather than SVG <text>: a text box must wrap, and SVG text does not.\n const text = doc.createElement('div')\n text.className = 'ink-free-text'\n text.textContent = a.contents\n styleFreeText(text, a, t)\n if (a.fringe) {\n // Inset from the element, which covers the whole rect.\n const inner = freeTextLocalBox(a, t)\n text.style.position = 'absolute'\n text.style.left = `${inner.left}px`\n text.style.top = `${inner.top}px`\n text.style.width = `${inner.width}px`\n text.style.height = `${inner.height}px`\n }\n // Structural: the element itself ignores the pointer, the text box takes it.\n text.style.pointerEvents = 'auto'\n el.append(text, edgeBand(doc, box, freeTextLocalBox(a, t)))\n appendSelectionFrame(el, a, t)\n return\n }\n\n if (a.type === 'stamp') {\n el.append(stampImage(doc, a, t, box))\n return\n }\n\n const svg = boxSvg(doc, box.width, box.height)\n svg.classList.add('ink-annotation-shape')\n /** Invisible wider copies of stroke-only geometry, added once the drawn shapes are. */\n const twins: SVGElement[] = []\n\n switch (a.type) {\n case 'highlight':\n for (const q of a.quads) {\n svg.append(\n node('polygon', {\n points: quadPoints(q).map(local).join(' '),\n fill: a.color,\n 'fill-opacity': a.opacity,\n })\n )\n }\n break\n case 'underline':\n case 'strikeout':\n case 'squiggly':\n svg.setAttribute('opacity', String(a.opacity))\n for (const q of a.quads) {\n const pts = markupLine(a.type, q)\n svg.append(\n node('polyline', {\n points: pts.map(local).join(' '),\n fill: 'none',\n stroke: a.color,\n 'stroke-width': t.toCssLength(markupStroke(q)),\n })\n )\n }\n break\n case 'redact': {\n const shapes = a.quads\n ? a.quads.map((q) =>\n node('polygon', { points: quadPoints(q).map(local).join(' ') })\n )\n : [node('rect', { x: 0, y: 0, width: box.width, height: box.height })]\n for (const s of shapes) {\n s.setAttribute('fill', a.interiorColor)\n s.setAttribute('fill-opacity', '0.15')\n s.setAttribute('stroke', a.color)\n s.setAttribute('stroke-width', String(t.toCssLength(1)))\n svg.append(s)\n }\n svg.setAttribute('opacity', String(a.opacity))\n break\n }\n case 'square':\n case 'circle': {\n const sw = t.toCssLength(a.width)\n // The element is the rect plus its hit twin's padding, if it has a twin.\n const pad = hasHitTwin(a) ? hitPad(a, t) : 0\n const w = box.width - pad * 2\n const h = box.height - pad * 2\n const geometry =\n a.type === 'square'\n ? {\n name: 'rect',\n attrs: {\n x: pad + sw / 2,\n y: pad + sw / 2,\n width: Math.max(0, w - sw),\n height: Math.max(0, h - sw),\n ...(a.cornerRadius ? { rx: t.toCssLength(a.cornerRadius) } : {}),\n },\n }\n : {\n name: 'ellipse',\n attrs: {\n cx: box.width / 2,\n cy: box.height / 2,\n rx: Math.max(0, w / 2 - sw / 2),\n ry: Math.max(0, h / 2 - sw / 2),\n },\n }\n const shape = node(geometry.name, geometry.attrs)\n shape.setAttribute('fill', a.interiorColor ?? 'none')\n shape.setAttribute('stroke', a.color)\n shape.setAttribute('stroke-width', String(sw))\n dash(shape, a.dashes, t)\n svg.append(shape)\n if (hasHitTwin(a))\n twins.push(hitTwin(node, geometry.name, geometry.attrs, hitWidth(a, t)))\n svg.setAttribute('opacity', String(a.opacity))\n break\n }\n case 'loupe': {\n // The rim, over the magnified canvas the overlay's loupe layer puts first in the\n // element. Its transparent fill takes presses anywhere on the lens.\n const sw = t.toCssLength(a.width)\n const rim = node('circle', {\n cx: box.width / 2,\n cy: box.height / 2,\n r: Math.max(0, Math.min(box.width, box.height) / 2 - sw / 2),\n fill: 'transparent',\n stroke: sw > 0 ? a.color : 'none',\n 'stroke-width': sw,\n })\n rim.classList.add('ink-loupe-rim')\n svg.append(rim)\n svg.setAttribute('opacity', String(a.opacity))\n break\n }\n case 'mask': {\n // The shape's outline as an invisible band just inside the edge: it takes presses on\n // the edge only, so the spotlight stays readable, selectable and annotatable, and the\n // dimmed area outside belongs to the page. The dimming is the mask layer's.\n const inset = MASK_EDGE / 2\n const shape =\n a.shape === 'ellipse'\n ? node('ellipse', {\n cx: box.width / 2,\n cy: box.height / 2,\n rx: Math.max(0, box.width / 2 - inset),\n ry: Math.max(0, box.height / 2 - inset),\n })\n : node('rect', {\n x: inset,\n y: inset,\n width: Math.max(0, box.width - MASK_EDGE),\n height: Math.max(0, box.height - MASK_EDGE),\n })\n shape.setAttribute('fill', 'none')\n shape.setAttribute('stroke', 'transparent')\n shape.setAttribute('stroke-width', String(MASK_EDGE))\n shape.classList.add('ink-mask-shape')\n svg.append(shape)\n break\n }\n case 'line':\n case 'polyline':\n case 'polygon': {\n const pts = a.type === 'line' ? [a.start, a.end] : a.vertices\n const stroked = node(a.type === 'polygon' ? 'polygon' : 'polyline', {\n points: pts.map(local).join(' '),\n fill: a.type === 'polygon' ? (a.interiorColor ?? 'none') : 'none',\n stroke: a.color,\n 'stroke-width': t.toCssLength(a.width),\n 'stroke-linejoin': 'round',\n })\n dash(stroked, a.dashes, t)\n svg.append(stroked)\n if (hasHitTwin(a)) {\n twins.push(\n hitTwin(\n node,\n stroked.tagName,\n { points: stroked.getAttribute('points')!, 'stroke-linejoin': 'round' },\n hitWidth(a, t)\n )\n )\n }\n const ends = endingKinds(a)\n if (ends && pts.length >= 2) {\n for (const [name, kind, tip, other] of [\n ['head', ends.head, pts[0]!, pts[1]!],\n ['tail', ends.tail, pts[pts.length - 1]!, pts[pts.length - 2]!],\n ] as const) {\n const d = lineEndingPath(kind, at(tip), at(other), t.toCssLength(a.width))\n if (!d) continue\n const ending = node('path', {\n d,\n fill: FILLED_ENDINGS.has(kind) ? a.color : 'none',\n stroke: a.color,\n 'stroke-width': t.toCssLength(a.width),\n 'stroke-linejoin': 'round',\n // A butt or slash ending is a cut across the line: a round cap would blunt it.\n 'stroke-linecap': kind === 'Butt' || kind === 'Slash' ? 'butt' : 'round',\n })\n ending.setAttribute('data-ending', name)\n svg.append(ending)\n twins.push(\n hitTwin(\n node,\n 'path',\n { d, 'stroke-linejoin': 'round', 'stroke-linecap': 'round' },\n hitWidth(a, t)\n )\n )\n }\n }\n svg.setAttribute('opacity', String(a.opacity))\n break\n }\n case 'ink':\n // Every stroke is a smoothed filled outline, thinned by pressure when there is some.\n // Dashes do not apply to a filled outline.\n a.inklist.forEach((path, i) => {\n const outline = strokeOutline(\n path.map(at),\n a.pressure?.[i],\n t.toCssLength(a.width)\n )\n svg.append(\n node('path', { class: 'ink-stroke', d: outlinePath(outline), fill: a.color })\n )\n twins.push(\n hitTwin(\n node,\n 'polyline',\n {\n points: path.map(local).join(' '),\n 'stroke-linejoin': 'round',\n 'stroke-linecap': 'round',\n },\n hitWidth(a, t)\n )\n )\n })\n svg.setAttribute('opacity', String(a.opacity))\n break\n }\n // Hits follow the painted shape, so a press beside it reaches the text layer underneath.\n for (const shape of svg.children) shape.setAttribute('pointer-events', 'visiblePainted')\n svg.append(...twins)\n el.append(svg)\n appendCommentMarker(el, a, t)\n}\n\n/**\n * An invisible copy of a stroke-only shape's geometry, `width` CSS px wide, that takes\n * presses on the stroke alone (`[data-ink-hit-stroke]`), so a thin line is easy to hit.\n */\nfunction hitTwin(\n node: (name: string, attrs: Record<string, string | number>) => SVGElement,\n name: string,\n attrs: Record<string, string | number>,\n width: number\n): SVGElement {\n const twin = node(name, attrs)\n twin.setAttribute('data-ink-hit-stroke', '')\n twin.setAttribute('fill', 'none')\n twin.setAttribute('stroke', 'transparent')\n twin.setAttribute('stroke-width', String(width))\n twin.setAttribute('pointer-events', 'stroke')\n return twin\n}\n\n/**\n * The band a press on a free text's edge lands on: an invisible `rect[data-ink-edge]` stroke\n * `TEXT_EDGE` px wide along the text box's edge, half inside it and half out, in its own SVG\n * over the element. A press inside the box edits it; one on the band selects and drags it.\n * It is there whether or not the box draws a border. Geometry only.\n */\nfunction edgeBand(doc: Document, el: CssRect, box: CssRect): SVGSVGElement {\n // A later sibling of the text box, so it paints above it once the theme positions it.\n const svg = boxSvg(doc, el.width, el.height)\n const band = doc.createElementNS(SVG, 'rect')\n band.setAttribute('x', String(box.left))\n band.setAttribute('y', String(box.top))\n band.setAttribute('width', String(box.width))\n band.setAttribute('height', String(box.height))\n band.setAttribute('fill', 'none')\n band.setAttribute('stroke', 'transparent')\n band.setAttribute('stroke-width', String(TEXT_EDGE))\n band.setAttribute('pointer-events', 'stroke')\n band.setAttribute('data-ink-edge', '')\n svg.append(band)\n return svg\n}\n\n/**\n * A stamp's `img.ink-stamp`, filling the element's box. The image is upright in user space\n * turned by the stamp's `rotation` (anticlockwise), and the page turns it again on screen\n * (clockwise), so it is drawn turned by the difference: a signature placed against the page's\n * turn reads upright. Size, position and turn are geometry, set inline; the opacity travels as\n * `--ink-opacity` for the theme.\n */\nfunction stampImage(\n doc: Document,\n a: StampAnnotation,\n t: PageTransform,\n box: CssRect\n): HTMLImageElement {\n const img = doc.createElement('img')\n img.className = 'ink-stamp'\n img.alt = ''\n img.draggable = false\n img.decoding = 'async'\n img.src = a.imagedata\n const turn = normalizeRotation(t.totalRotation - (a.rotation ?? 0))\n const sideways = turn === 90 || turn === 270\n const width = sideways ? box.height : box.width\n const height = sideways ? box.width : box.height\n img.style.position = 'absolute'\n img.style.left = `${(box.width - width) / 2}px`\n img.style.top = `${(box.height - height) / 2}px`\n img.style.width = `${width}px`\n img.style.height = `${height}px`\n if (turn !== 0) img.style.transform = `rotate(${turn}deg)`\n // Structural: the element itself ignores the pointer, the image takes it.\n img.style.pointerEvents = 'auto'\n img.style.setProperty('--ink-opacity', String(a.opacity))\n return img\n}\n\n/**\n * Styles a free-text box (`.ink-free-text`) from its annotation, as the theme reads it: the text\n * style, fill, border colour and width, corner radius and opacity travel as custom properties\n * (`--ink-font-size`, `--ink-font-family`, `--ink-font-weight`, `--ink-font-style`,\n * `--ink-text-decoration`, `--ink-text-color`, `--ink-fill`, `--ink-box-border`,\n * `--ink-border-width`, `--ink-corner-radius`, `--ink-opacity`); alignment as `data-align`,\n * and a border as `data-border` (`solid` or `dashed`, absent at width 0). Lengths are scaled to\n * CSS px. Shared by the overlay and the in-place editor, so both look the same.\n */\nexport function styleFreeText(\n node: HTMLElement,\n a: FreeTextAnnotation,\n t: PageTransform\n): void {\n const s = a.defaultStyle\n const set = (name: string, value: string | undefined): void => {\n if (value === undefined) node.style.removeProperty(name)\n else node.style.setProperty(name, value)\n }\n set('--ink-font-size', `${t.toCssLength(s.fontSize)}px`)\n set('--ink-font-family', cssString(s.fontFamily))\n set('--ink-font-weight', s.fontWeight)\n set('--ink-font-style', s.fontStyle)\n set('--ink-text-decoration', s.textDecoration)\n set('--ink-text-color', s.color)\n // A speech bubble's outline and fill are drawn by its path, not by the text box.\n const bubble = isBubble(a)\n set('--ink-fill', bubble ? undefined : a.color)\n // Not `--ink-border`, the interface's border token: a box with no border colour of its own\n // takes its text colour, as a bubble's outline does.\n set('--ink-box-border', bubble ? undefined : (a.borderColor ?? s.color))\n set(\n '--ink-border-width',\n !bubble && a.width > 0 ? `${t.toCssLength(a.width)}px` : undefined\n )\n set(\n '--ink-corner-radius',\n !bubble && a.cornerRadius ? `${t.toCssLength(a.cornerRadius)}px` : undefined\n )\n set('--ink-opacity', String(a.opacity))\n node.dataset.align = s.textAlign\n if (bubble) node.dataset.bubble = ''\n else delete node.dataset.bubble\n if (!bubble && a.width > 0) node.dataset.border = a.dashes?.length ? 'dashed' : 'solid'\n else delete node.dataset.border\n}\n\n/**\n * A free text's text box (`freeTextBox`) in CSS px, relative to the top-left of its rect on\n * screen, where its overlay element sits.\n */\nexport function freeTextLocalBox(a: FreeTextAnnotation, t: PageTransform): CssRect {\n const origin = t.toCssRect(a.rect)\n const box = t.toCssRect(freeTextBox(a))\n return {\n left: box.left - origin.left,\n top: box.top - origin.top,\n width: box.width,\n height: box.height,\n }\n}\n\n/**\n * The outline of a speech bubble as SVG path data in CSS px relative to `origin` (by default\n * the top-left of its rect on screen, where its overlay element sits): the rounded text box\n * (`freeTextBox`) with a wedge to the tip, `callout[0]`. The wedge leaves the box edge nearest\n * `callout`'s last point, at that point's position along it, kept clear of the corners.\n */\nexport function bubblePath(\n a: FreeTextAnnotation & { callout: readonly Point[] },\n t: PageTransform,\n origin: { left: number; top: number } = t.toCssRect(a.rect)\n): string {\n const css = t.toCssRect(freeTextBox(a))\n // Box-relative CSS px: the box's top-left is 0,0.\n const inBox = (p: Point): Point => {\n const c = t.toCss(p)\n return { x: c.x - css.left, y: c.y - css.top }\n }\n const tip = inBox(a.callout[0]!)\n const edge = inBox(a.callout[a.callout.length - 1]!)\n const w = css.width\n const h = css.height\n const r = Math.min(t.toCssLength(a.cornerRadius ?? 0), w / 2, h / 2)\n // The edge nearest the last point, as `nearestEdge` (model/annotations/edit.ts) picks it,\n // ties included (left, right, bottom, top on an unturned page); change both together.\n const gaps = {\n left: Math.abs(edge.x),\n right: Math.abs(edge.x - w),\n bottom: Math.abs(edge.y - h),\n top: Math.abs(edge.y),\n }\n const side = (Object.keys(gaps) as (keyof typeof gaps)[]).reduce((best, s) =>\n gaps[s] < gaps[best] ? s : best\n )\n const along = side === 'top' || side === 'bottom' ? w : h\n const half = Math.min(t.toCssLength(WEDGE_HALF), along / 4)\n const lo = Math.min(r + half, along / 2)\n const at = Math.min(\n Math.max(side === 'top' || side === 'bottom' ? edge.x : edge.y, lo),\n along - lo\n )\n const dx = css.left - origin.left\n const dy = css.top - origin.top\n const P = (x: number, y: number): string => `${fmt(x + dx)} ${fmt(y + dy)}`\n const arc = (x: number, y: number): string =>\n r > 0 ? `A${fmt(r)} ${fmt(r)} 0 0 1 ${P(x, y)}` : ''\n const spike = (x: number, y: number): string => `L${P(x, y)}L${P(tip.x, tip.y)}`\n return [\n `M${P(r, 0)}`,\n side === 'top' ? `${spike(at - half, 0)}L${P(at + half, 0)}` : '',\n `L${P(w - r, 0)}${arc(w, r)}`,\n side === 'right' ? `${spike(w, at - half)}L${P(w, at + half)}` : '',\n `L${P(w, h - r)}${arc(w - r, h)}`,\n side === 'bottom' ? `${spike(at + half, h)}L${P(at - half, h)}` : '',\n `L${P(r, h)}${arc(0, h - r)}`,\n side === 'left' ? `${spike(0, at + half)}L${P(0, at - half)}` : '',\n `L${P(0, r)}${arc(r, 0)}Z`,\n ].join('')\n}\n\n/**\n * Redraws an open bubble's outline as `a`, a draft of it (the editor's, as its box grows with\n * its text), in an element whose top-left is `origin` on screen. No-op on any other element.\n */\nexport function refitBubble(\n el: HTMLElement,\n a: FreeTextAnnotation,\n t: PageTransform,\n origin: { left: number; top: number }\n): void {\n const path = el.querySelector(':scope > svg > .ink-bubble')\n if (!path || !isBubble(a)) return\n path.setAttribute('d', bubblePath(a, t, origin))\n}\n\n/** Sets `stroke-dasharray` from a dash pattern in points, scaled to CSS px. */\nfunction dash(\n shape: Element,\n dashes: readonly number[] | undefined,\n t: PageTransform\n): void {\n if (!dashes || dashes.length === 0) return\n shape.setAttribute('stroke-dasharray', dashes.map((d) => t.toCssLength(d)).join(' '))\n}\n\n/**\n * An invisible hit area for an annotation the overlay does not draw (embedded ones, which\n * PDF.js paints on the canvas): polygons over its quads, or its rect. Selection chrome only.\n */\nexport function renderHitArea(el: HTMLElement, a: Annotation, t: PageTransform): void {\n drawHitArea(el, a, t)\n if (a.type === 'freetext') appendSelectionFrame(el, a, t)\n appendCommentMarker(el, a, t)\n}\n\n/**\n * For a free text inset by a fringe: a `div.ink-selection-frame` over its text box, where its\n * corner handles sit, and `data-framed` on the element, so the theme draws the selection\n * outline on the box rather than round the whole rect. Geometry only, `pointer-events:none`.\n */\nfunction appendSelectionFrame(\n el: HTMLElement,\n a: FreeTextAnnotation,\n t: PageTransform\n): void {\n el.toggleAttribute('data-framed', a.fringe !== undefined)\n if (!a.fringe) return\n const box = freeTextLocalBox(a, t)\n const frame = el.ownerDocument.createElement('div')\n frame.className = 'ink-selection-frame'\n frame.setAttribute('aria-hidden', 'true')\n frame.style.cssText =\n `position:absolute;pointer-events:none;left:${box.left}px;top:${box.top}px;` +\n `width:${box.width}px;height:${box.height}px;`\n el.append(frame)\n}\n\n/** True for text markup whose `contents` holds a comment. */\nexport function hasComment(a: Annotation): a is TextMarkupAnnotation {\n return isTextMarkup(a) && !!a.contents?.trim()\n}\n\n/**\n * Marks commented text markup with `span.ink-comment-marker`, holding a comment glyph, at the\n * last quad's top-right corner (its end in reading order), relative to the element. The theme\n * sizes and colours it.\n */\nfunction appendCommentMarker(el: HTMLElement, a: Annotation, t: PageTransform): void {\n if (!hasComment(a)) return\n const last = a.quads[a.quads.length - 1]\n if (!last) return\n const box = annotationBox(a, t)\n const at = t.toCss(last.p2)\n const marker = el.ownerDocument.createElement('span')\n marker.className = 'ink-comment-marker'\n marker.dataset.inkCommentMarker = ''\n marker.setAttribute('aria-hidden', 'true')\n marker.style.left = `${at.x - box.left}px`\n marker.style.top = `${at.y - box.top}px`\n const icon = el.ownerDocument.createElementNS(SVG, 'svg')\n for (const [k, v] of Object.entries(ICON_ATTRIBUTES)) icon.setAttribute(k, v)\n for (const [tag, attrs] of MessageSquareText) {\n const child = el.ownerDocument.createElementNS(SVG, tag)\n for (const [k, v] of Object.entries(attrs)) child.setAttribute(k, v)\n icon.append(child)\n }\n marker.append(icon)\n el.append(marker)\n}\n\nfunction drawHitArea(el: HTMLElement, a: Annotation, t: PageTransform): void {\n const doc = el.ownerDocument\n el.replaceChildren()\n const box = annotationBox(a, t)\n const svg = boxSvg(doc, box.width, box.height)\n svg.dataset.inkHit = ''\n const quads = 'quads' in a && a.quads ? a.quads : undefined\n const shapes = quads\n ? quads.map((q) => {\n const poly = doc.createElementNS(SVG, 'polygon')\n poly.setAttribute(\n 'points',\n quadPoints(q)\n .map((p) => {\n const c = t.toCss(p)\n return `${c.x - box.left},${c.y - box.top}`\n })\n .join(' ')\n )\n return poly\n })\n : [doc.createElementNS(SVG, 'rect')]\n for (const shape of shapes) {\n if (shape.tagName === 'rect') {\n shape.setAttribute('width', String(box.width))\n shape.setAttribute('height', String(box.height))\n }\n shape.setAttribute('fill', 'transparent')\n shape.setAttribute('stroke', 'none')\n shape.setAttribute('pointer-events', 'all')\n svg.append(shape)\n }\n el.append(svg)\n}\n\nfunction boxSvg(doc: Document, width: number, height: number): SVGSVGElement {\n const svg = doc.createElementNS(SVG, 'svg')\n svg.setAttribute('width', String(width))\n svg.setAttribute('height', String(height))\n svg.setAttribute('viewBox', `0 0 ${width} ${height}`)\n svg.setAttribute('overflow', 'visible')\n // Block, not inline: an inline SVG sits on the text baseline and drifts below a short box.\n // The theme positions it absolutely as well.\n svg.setAttribute('display', 'block')\n svg.setAttribute('aria-hidden', 'true')\n return svg\n}\n\n/** Quad corners in drawing order: p1 top-left, p2 top-right, p4 bottom-right, p3 bottom-left. */\nfunction quadPoints(q: Quad): Point[] {\n return [q.p1, q.p2, q.p4, q.p3]\n}\n\nconst lerp = (a: Point, b: Point, f: number): Point => ({\n x: a.x + (b.x - a.x) * f,\n y: a.y + (b.y - a.y) * f,\n})\nconst dist = (a: Point, b: Point): number => Math.hypot(b.x - a.x, b.y - a.y)\n\n/** Line thickness in points for a text markup: a fraction of the quad's height. */\nfunction markupStroke(q: Quad): number {\n return Math.max(0.5, dist(q.p1, q.p3) / 14)\n}\n\n/** The stroke for an underline, strikeout or squiggly, in user space. */\nfunction markupLine(type: 'underline' | 'strikeout' | 'squiggly', q: Quad): Point[] {\n if (type === 'strikeout') return [lerp(q.p1, q.p3, 0.5), lerp(q.p2, q.p4, 0.5)]\n const height = dist(q.p1, q.p3)\n // The baseline sits a little above the quad's bottom edge.\n const start = lerp(q.p3, q.p1, 0.1)\n const end = lerp(q.p4, q.p2, 0.1)\n if (type === 'underline') return [start, end]\n const length = dist(start, end)\n const amp = Math.max(0.5, height / 16)\n const step = amp * 2\n const steps = Math.max(1, Math.round(length / step))\n // Unit normal pointing from the bottom edge towards the top edge.\n const up = {\n x: (q.p1.x - q.p3.x) / (height || 1),\n y: (q.p1.y - q.p3.y) / (height || 1),\n }\n const pts: Point[] = []\n for (let i = 0; i <= steps; i++) {\n const p = lerp(start, end, i / steps)\n const s = i % 2 === 0 ? -amp : amp\n pts.push({ x: p.x + up.x * s, y: p.y + up.y * s })\n }\n return pts\n}\n\n/** A CSS string literal, so any PDF font name is a single family name. */\nfunction cssString(value: string): string {\n return `\"${value.replace(/[\"\\\\]/g, '\\\\$&').replace(/\\n/g, '\\\\a ')}\"`\n}\n","// In-place editing for a free-text box. The editor is a plain-text `contenteditable` laid over\n// the box inside its overlay element, styled from the annotation exactly as the box is\n// (`styleFreeText`), with the box itself hidden underneath. It grows downwards on screen as the\n// text needs more lines, and nothing reaches the store until it closes: a commit hands back the\n// text and the grown rect together, so the edit is one change and one undo step. A callout's\n// `rect` and `fringe` are refit around the grown box and its callout (`grownFreeText`).\n//\n// Inline styles here are structural or geometric only: the editor's position and minimum\n// height, the box's `visibility` while it is covered, and the element's grown height.\nimport { freeTextBox } from '../model/annotations/callout'\nimport { hasCallout, isBubble, resizedBox, withBox } from '../model/annotations/edit'\n\nimport { freeTextLocalBox, refitBubble, styleFreeText } from './overlay-render'\n\nimport type { PageTransform } from './transform'\nimport type { AnnotationStore } from '../model/annotations/store'\nimport type { Annotation, FreeTextAnnotation } from '../model/annotations/types'\nimport type { Point, Rect } from '../model/geometry'\n\nexport interface FreeTextEditor {\n /** Closes the editor, handing its text to `commit` (true) or calling `cancel` (false). */\n close(commit: boolean): void\n}\n\n/**\n * What closed an editor: Escape, a press outside it, focus leaving it, or a call to `close`\n * (a redraw, the page unmounting, the box being removed, a tool switch).\n */\nexport type EditorCloseReason = 'escape' | 'press' | 'focus' | 'api'\n\nexport interface FreeTextEditorOptions {\n transform: PageTransform\n /**\n * The edited text and the box's rect, grown to fit it (`grownFreeText`), in user space.\n * `grown` is the growth alone, in CSS px (0 when the box kept its height), for a caller whose\n * box may have moved or been resized while the editor was open. `how` says what closed it.\n */\n commit(contents: string, rect: Rect, grown: number, how: EditorCloseReason): void\n cancel(): void\n /** Where to put the caret, a client point (a click on the box); at the end when absent. */\n caret?: { clientX: number; clientY: number } | undefined\n}\n\n/** The open editor on each overlay element. */\nconst editors = new WeakMap<HTMLElement, FreeTextEditor>()\n/** Presses that closed an editor, so a tool can leave them alone. */\nconst closingPresses = new WeakSet<Event>()\n\n/** The editor open on an overlay element, if any. */\nexport function editorFor(el: HTMLElement): FreeTextEditor | undefined {\n return editors.get(el)\n}\n\n/** True when `e` is a press outside an editor that closed it. */\nexport function closedEditor(e: Event): boolean {\n return closingPresses.has(e)\n}\n\n/** Point within which a grown height counts as unchanged, CSS px. */\nconst SAME_PX = 0.5\n/** The editor's narrowest width, in ems of the box's font size, for a box inset to nothing. */\nconst MIN_WIDTH_EM = 2\n\n/**\n * Opens an editor on `el`, the overlay element showing `a` (or a stand-in for a box not in the\n * store yet), with the caret at `opts.caret` or after the text. `Escape` commits; a press\n * outside the editor, or focus leaving it, commits too.\n * Closing while the editor has focus hands focus to `el`. Keys typed in the\n * editor stop there, so no viewport or tool shortcut sees them. Opening a second editor on the\n * same element commits the first.\n */\nexport function editFreeText(\n el: HTMLElement,\n a: FreeTextAnnotation,\n opts: FreeTextEditorOptions\n): FreeTextEditor {\n editors.get(el)?.close(true)\n const doc = el.ownerDocument\n const view = doc.defaultView\n // The element covers the rect; the text box sits inside it, inset by any fringe.\n const base = opts.transform.toCssRect(a.rect)\n const inner = freeTextLocalBox(a, opts.transform)\n const box = el.querySelector<HTMLElement>(':scope > .ink-free-text')\n\n const field = doc.createElement('div')\n field.className = 'ink-free-text'\n field.dataset.inkEditor = ''\n field.setAttribute('role', 'textbox')\n field.setAttribute('aria-multiline', 'true')\n field.setAttribute('aria-label', 'Text box')\n styleFreeText(field, a, opts.transform)\n field.style.position = 'absolute'\n field.style.left = `${inner.left}px`\n field.style.top = `${inner.top}px`\n // A fringe can leave a box too narrow to type in: never narrower than a couple of letters.\n const floor = opts.transform.toCssLength(a.defaultStyle.fontSize * MIN_WIDTH_EM)\n field.style.width = a.fringe ? `${Math.max(inner.width, floor)}px` : '100%'\n field.style.height = 'auto'\n field.style.minHeight = `${inner.height}px`\n field.style.pointerEvents = 'auto'\n makeEditable(field)\n field.textContent = a.contents\n if (box) box.style.visibility = 'hidden'\n el.append(field)\n\n /** The box's CSS height for the text now in it: never less than it started at. */\n const height = (): number =>\n Math.max(inner.height, field.getBoundingClientRect().height)\n /** `a` with its box grown by `grown` CSS px. */\n const grownTo = (grown: number): FreeTextAnnotation =>\n grown === 0 ? a : { ...a, ...grownFreeText(a, grown, opts.transform) }\n const grow = (): void => {\n const h = height()\n el.style.height = `${base.height + h - inner.height}px`\n // A bubble's outline grows with its text.\n refitBubble(el, grownTo(h - inner.height), opts.transform, base)\n }\n const Observer = view?.ResizeObserver\n const observer = Observer ? new Observer(grow) : undefined\n observer?.observe(field)\n\n const read = (): string => {\n const text = field.innerText.replace(/\\r\\n?/g, '\\n')\n // A trailing line break is held open by a placeholder <br>, which reads as one more.\n return field.lastChild?.nodeName === 'BR' ? text.replace(/\\n$/, '') : text\n }\n /** How far the box grew, CSS px; 0 within `SAME_PX`. */\n const growth = (): number => {\n const grown = height() - inner.height\n return Math.abs(grown) < SAME_PX ? 0 : grown\n }\n\n let closed = false\n const finish = (commit: boolean, how: EditorCloseReason): void => {\n if (closed) return\n closed = true\n const contents = read()\n const grown = growth()\n const next = grownTo(grown).rect\n observer?.disconnect()\n view?.removeEventListener('pointerdown', onOutside, true)\n editors.delete(el)\n // While the editor has focus, it moves to the box before the editor goes, so it never\n // falls back to <body>. Focus that already left (a click on a control) stays where it is.\n if (field.contains(doc.activeElement)) el.focus({ preventScroll: true })\n field.remove()\n box?.style.removeProperty('visibility')\n el.style.height = `${base.height}px`\n refitBubble(el, a, opts.transform, base)\n if (commit) opts.commit(contents, next, grown, how)\n else opts.cancel()\n }\n\n const onOutside = (e: Event): void => {\n if (e.target instanceof Node && field.contains(e.target)) return\n closingPresses.add(e)\n finish(true, 'press')\n }\n view?.addEventListener('pointerdown', onOutside, true)\n field.addEventListener('keydown', (e) => {\n e.stopPropagation()\n if (e.key === 'Escape' && !e.isComposing) {\n e.preventDefault()\n finish(true, 'escape')\n }\n })\n field.addEventListener('focusout', (e) => {\n // A window losing focus (another tab, devtools) leaves the edit open.\n if (!doc.hasFocus()) return\n const to = e.relatedTarget\n if (to instanceof Node && field.contains(to)) return\n finish(true, 'focus')\n })\n // Plain text only, whatever the clipboard holds and whichever editing mode the browser has.\n field.addEventListener('paste', (e) => {\n e.preventDefault()\n insertText(field, e.clipboardData?.getData('text/plain') ?? '')\n })\n field.addEventListener('beforeinput', (e) => {\n if (e.inputType.startsWith('format')) e.preventDefault()\n })\n\n field.focus({ preventScroll: true })\n const selection = doc.getSelection()\n if (selection) {\n let range = opts.caret && caretIn(field, opts.caret)\n if (!range) {\n range = doc.createRange()\n range.selectNodeContents(field)\n range.collapse(false)\n }\n selection.removeAllRanges()\n selection.addRange(range)\n }\n grow()\n\n const editor: FreeTextEditor = { close: (commit) => finish(commit, 'api') }\n editors.set(el, editor)\n return editor\n}\n\n/**\n * True when `a` can be edited in place on its overlay element `el`: an unlocked free-text box\n * the overlay draws itself. Embedded boxes (painted on the canvas, with only a hit area here)\n * and host-rendered (`data-custom`) elements are not. Every edit path asks this.\n */\nexport function canEditFreeText(\n a: Annotation | undefined,\n el: Element | null | undefined\n): a is FreeTextAnnotation {\n return (\n a !== undefined &&\n a.type === 'freetext' &&\n !a.locked &&\n a.source !== 'pdf' &&\n !!el &&\n !el.hasAttribute('data-custom')\n )\n}\n\n/**\n * Opens an editor on the overlay element `el` for the free-text box `id`, wired to the store: a\n * commit is one `update` with the text and the grown rect (none when neither changed), and an\n * empty box is removed, as an abandoned note is. A speech bubble is the exception: its outline\n * shows without text, so it is kept. `onClose` runs after the store change, with what closed\n * the editor; `caret` is a client point to put the caret at (`editFreeText`). Returns\n * undefined when the box cannot be edited (`canEditFreeText`).\n */\nexport function editFreeTextIn(\n store: AnnotationStore,\n el: HTMLElement,\n id: string,\n transform: PageTransform,\n opts: {\n onClose?(how: EditorCloseReason): void\n caret?: { clientX: number; clientY: number }\n } = {}\n): FreeTextEditor | undefined {\n const a = store._getProposed(id) ?? store.get(id)\n if (!canEditFreeText(a, el)) return undefined\n const current = (): FreeTextAnnotation | undefined => {\n const now = store._getProposed(id) ?? store.get(id)\n return now?.type === 'freetext' ? now : undefined\n }\n const write = (contents: string, grown: number): void => {\n const now = current()\n if (!now) return\n if (contents.trim() === '' && !isBubble(now)) {\n store.remove(id)\n return\n }\n // The growth applies to the box as it is now: it may have moved while the editor was open.\n if (grown === 0) {\n if (contents !== now.contents) store.update(id, { contents })\n return\n }\n store.update(id, { contents, ...grownFreeText(now, grown, transform) })\n }\n return editFreeText(el, a, {\n transform,\n caret: opts.caret,\n commit(contents, _rect, grown, how) {\n write(contents, grown)\n opts.onClose?.(how)\n },\n cancel() {\n const now = current()\n if (now && now.contents.trim() === '' && !isBubble(now)) store.remove(id)\n opts.onClose?.('api')\n },\n })\n}\n\n/**\n * The patch that grows a free text's text box down the screen by `grown` CSS px, its top edge\n * fixed, with `rect` and `fringe` refit. A callout's last point moves with the box edge it sits\n * on. A bubble's tip below the box comes down with it; a standard callout's tip and bend stay on\n * what they point at.\n */\nexport function grownFreeText(\n a: FreeTextAnnotation,\n grown: number,\n t: PageTransform\n): Partial<FreeTextAnnotation> {\n const css = t.toCssRect(freeTextBox(a))\n const box = t.fromCssRect({ ...css, height: css.height + grown })\n if (!hasCallout(a)) return withBox(a, box)\n const resized = resizedBox(a, box)\n if (!isBubble(a) || t.toCss(a.callout[0]).y <= css.top + css.height) return resized\n const last = a.callout.length - 1\n const down = (p: Point): Point => {\n const c = t.toCss(p)\n return t.fromCss({ x: c.x, y: c.y + grown })\n }\n return withBox(\n a,\n box,\n resized.callout!.map((p, i) => (i === last ? p : down(p)))\n )\n}\n\n/**\n * A collapsed range at the text position under a client point, if that position is in `field`.\n * The editor lies over the box with the same look, so a point on the box lands on the same\n * character in the editor.\n */\nfunction caretIn(\n field: HTMLElement,\n at: { clientX: number; clientY: number }\n): Range | undefined {\n const doc = field.ownerDocument\n let node: Node | undefined\n let offset = 0\n if (typeof doc.caretPositionFromPoint === 'function') {\n const p = doc.caretPositionFromPoint(at.clientX, at.clientY)\n if (p) ({ offsetNode: node, offset } = p)\n } else if (typeof doc.caretRangeFromPoint === 'function') {\n const r = doc.caretRangeFromPoint(at.clientX, at.clientY)\n if (r) ({ startContainer: node, startOffset: offset } = r)\n }\n if (!node || !field.contains(node)) return undefined\n const range = doc.createRange()\n range.setStart(node, offset)\n range.collapse(true)\n return range\n}\n\n/** `plaintext-only` where the browser has it, else `true` (paste and formatting are then guarded). */\nfunction makeEditable(field: HTMLElement): void {\n try {\n field.contentEditable = 'plaintext-only'\n } catch {\n // Older engines throw on the value.\n }\n if (field.contentEditable !== 'plaintext-only') field.contentEditable = 'true'\n}\n\n/** Inserts `text` at the caret, replacing any selected text, and leaves the caret after it. */\nfunction insertText(field: HTMLElement, text: string): void {\n const doc = field.ownerDocument\n const selection = doc.getSelection()\n const node = doc.createTextNode(text)\n if (!selection || selection.rangeCount === 0) {\n field.append(node)\n return\n }\n const range = selection.getRangeAt(0)\n if (!field.contains(range.commonAncestorContainer)) {\n field.append(node)\n return\n }\n range.deleteContents()\n range.insertNode(node)\n range.setStartAfter(node)\n range.collapse(true)\n selection.removeAllRanges()\n selection.addRange(range)\n}\n","// Renders one region of a page, in PDF user space, into a canvas of its own: the loupe's\n// magnified view. The viewport is the page's own at `scale`, shifted so the region's top-left\n// corner lands on the canvas origin, so the region fills the canvas exactly.\nimport type { InkDocument } from '../model/document'\nimport type { Rect } from '../model/geometry'\n\nconst isCancellation = (error: unknown): boolean =>\n (error as { name?: unknown } | null)?.name === 'RenderingCancelledException'\n\n/**\n * Draws `userRect` of `page` (0-based) into `canvas` at `scale` device pixels per user-space\n * unit (times `/UserUnit`, as PDF.js applies it), turned by `rotation`: the page's /Rotate plus\n * any view rotation, the page's own /Rotate when omitted. The canvas is resized to the region,\n * so a 50 pt square at scale 4 gives a 200 × 200 canvas. Like the page canvas, the background\n * is white and embedded annotation appearances are drawn.\n *\n * Rejects with `signal.reason` once `signal` aborts; an abort mid-render cancels it, leaving\n * the canvas partly drawn.\n *\n * @internal\n */\nexport async function renderRegion(\n doc: InkDocument,\n page: number,\n userRect: Rect,\n scale: number,\n canvas: HTMLCanvasElement,\n signal?: AbortSignal,\n rotation?: number\n): Promise<void> {\n signal?.throwIfAborted()\n const pdfPage = await doc._pdfjs.getPage(page)\n signal?.throwIfAborted()\n const turn = rotation ?? pdfPage.rotate\n const full = pdfPage.getViewport({ scale, rotation: turn })\n // The region's corners on the unshifted canvas, in device pixels.\n const [x1, y1] = full.convertToViewportPoint(userRect.x, userRect.y) as [number, number]\n const [x2, y2] = full.convertToViewportPoint(\n userRect.x + userRect.width,\n userRect.y + userRect.height\n ) as [number, number]\n const viewport = pdfPage.getViewport({\n scale,\n rotation: turn,\n offsetX: -Math.min(x1, x2),\n offsetY: -Math.min(y1, y2),\n })\n canvas.width = Math.max(1, Math.round(Math.abs(x2 - x1)))\n canvas.height = Math.max(1, Math.round(Math.abs(y2 - y1)))\n const task = pdfPage.render({\n canvas,\n viewport,\n background: '#ffffff',\n annotationMode: doc._pdfjs.module.AnnotationMode.ENABLE,\n })\n const cancel = (): void => task.cancel()\n signal?.addEventListener('abort', cancel, { once: true })\n try {\n await task.promise\n } catch (error) {\n if (signal?.aborted && isCancellation(error)) throw signal.reason\n throw error\n } finally {\n signal?.removeEventListener('abort', cancel)\n }\n // Finished just as the signal aborted: the caller has moved on.\n signal?.throwIfAborted()\n}\n","// The loupe's magnified view: one canvas per loupe, first in the loupe's own annotation\n// element, under the rim the overlay draws. It holds the page region under the loupe's centre,\n// `magnification` times smaller than the loupe, rendered at the zoom times the device pixel\n// ratio times the magnification, so it fills the element at full sharpness. Page content only:\n// session annotations under the loupe are not magnified.\n//\n// Inline styles are structural: the canvas fills the element (`position:absolute; left:0;\n// top:0; width:100%; height:100%`), is clipped to the inscribed circle (`clip-path`) and leaves\n// the pointer to the rim (`pointer-events:none`).\nimport { renderRegion } from '../pdfjs/render-region'\n\nimport { watchDevicePixelRatio, type DprWatch } from './dpr-watch'\n\nimport type { PageTransform } from './transform'\nimport type { LoupeAnnotation } from '../model/annotations/types'\nimport type { InkDocument } from '../model/document'\nimport type { Rect } from '../model/geometry'\n\n/** Pause after a move, resize or zoom before a loupe re-renders, in ms. */\nexport const LOUPE_RENDER_DELAY = 100\n\nexport interface LoupeLayerOptions {\n document: InkDocument\n /**\n * Fixed device pixel ratio. When omitted, `window.devicePixelRatio` is read at every render\n * and the loupes re-render when it changes (browser zoom, moving to another screen).\n */\n devicePixelRatio?: number\n}\n\nexport interface LoupeLayer {\n /**\n * Puts the loupe's canvas first in `el`, its annotation element, and brings it up to date\n * with `a` at `t`. The first render starts at once; later ones wait for a pause of\n * `LOUPE_RENDER_DELAY` ms in the changes, and a change aborts a render in flight. The last\n * bitmap stays, stretched with the element, until the next one lands.\n */\n attach(el: HTMLElement, a: LoupeAnnotation, t: PageTransform): void\n /** Forgets a loupe that is gone, cancelling its render. */\n drop(id: string): void\n destroy(): void\n}\n\n/** The page region a loupe shows: its rect shrunk by the magnification about its centre. */\nexport function loupeRegion(a: Pick<LoupeAnnotation, 'rect' | 'magnification'>): Rect {\n const { rect, magnification } = a\n const width = rect.width / magnification\n const height = rect.height / magnification\n return {\n x: rect.x + (rect.width - width) / 2,\n y: rect.y + (rect.height - height) / 2,\n width,\n height,\n }\n}\n\ninterface Lens {\n canvas: HTMLCanvasElement\n /** What the canvas shows or is about to: the last scheduled render's inputs. */\n key: string | undefined\n timer: ReturnType<typeof setTimeout> | undefined\n controller: AbortController | undefined\n /** The last `attach`, replayed when the device pixel ratio changes. */\n last: { el: HTMLElement; a: LoupeAnnotation; t: PageTransform } | undefined\n}\n\n/** Frees a canvas's bitmap now rather than at garbage collection (Safari caps the total). */\nfunction release(canvas: HTMLCanvasElement): void {\n canvas.width = 0\n canvas.height = 0\n canvas.remove()\n}\n\nexport function createLoupeLayer(opts: LoupeLayerOptions): LoupeLayer {\n const lenses = new Map<string, Lens>()\n let destroyed = false\n let dprWatch: DprWatch | undefined\n\n const dprOf = (el: HTMLElement): number => {\n if (opts.devicePixelRatio !== undefined) return opts.devicePixelRatio\n const ratio = el.ownerDocument.defaultView?.devicePixelRatio ?? 1\n return ratio > 0 ? ratio : 1\n }\n\n const stop = (lens: Lens): void => {\n clearTimeout(lens.timer)\n lens.timer = undefined\n lens.controller?.abort()\n lens.controller = undefined\n }\n\n async function render(\n lens: Lens,\n page: number,\n region: Rect,\n scale: number,\n rotation: number\n ): Promise<void> {\n const controller = new AbortController()\n lens.controller = controller\n const doc = lens.canvas.ownerDocument\n const next = doc.createElement('canvas')\n try {\n await renderRegion(\n opts.document,\n page,\n region,\n scale,\n next,\n controller.signal,\n rotation\n )\n if (controller.signal.aborted || destroyed) return\n lens.canvas.width = next.width\n lens.canvas.height = next.height\n lens.canvas.getContext('2d')?.drawImage(next, 0, 0)\n } catch {\n // Aborted for a newer render, or failed: the last bitmap stays. A failure has nowhere\n // useful to go; the page canvas reports the document's render failures.\n } finally {\n release(next)\n if (lens.controller === controller) lens.controller = undefined\n }\n }\n\n function lensFor(el: HTMLElement, id: string): Lens {\n const known = lenses.get(id)\n if (known) return known\n const canvas = el.ownerDocument.createElement('canvas')\n canvas.className = 'ink-loupe-lens'\n canvas.dataset.inkLoupe = ''\n canvas.setAttribute('aria-hidden', 'true')\n canvas.style.cssText =\n 'position:absolute;left:0;top:0;width:100%;height:100%;' +\n 'clip-path:circle(50%);pointer-events:none;'\n // Blank until the first render lands.\n canvas.width = 0\n canvas.height = 0\n const lens: Lens = {\n canvas,\n key: undefined,\n timer: undefined,\n controller: undefined,\n last: undefined,\n }\n lenses.set(id, lens)\n return lens\n }\n\n function attach(el: HTMLElement, a: LoupeAnnotation, t: PageTransform): void {\n if (destroyed) return\n const lens = lensFor(el, a.id)\n lens.last = { el, a, t }\n if (el.firstChild !== lens.canvas) el.prepend(lens.canvas)\n const region = loupeRegion(a)\n const dpr = dprOf(el)\n if (opts.devicePixelRatio === undefined) {\n dprWatch ??= watchDevicePixelRatio(\n el.ownerDocument.defaultView,\n () => dprOf(el),\n () => {\n for (const { last } of [...lenses.values()])\n if (last) attach(last.el, last.a, last.t)\n }\n )\n dprWatch.watch(dpr)\n }\n const scale = t.zoom * dpr * a.magnification\n const rotation = t.totalRotation\n const key = JSON.stringify([a.page, region, scale, rotation])\n if (key === lens.key) return\n const first = lens.key === undefined\n lens.key = key\n stop(lens)\n if (first) {\n void render(lens, a.page, region, scale, rotation)\n return\n }\n lens.timer = setTimeout(() => {\n lens.timer = undefined\n void render(lens, a.page, region, scale, rotation)\n }, LOUPE_RENDER_DELAY)\n }\n\n return {\n attach,\n drop(id) {\n const lens = lenses.get(id)\n if (!lens) return\n stop(lens)\n release(lens.canvas)\n lenses.delete(id)\n },\n destroy() {\n if (destroyed) return\n destroyed = true\n dprWatch?.destroy()\n for (const lens of lenses.values()) {\n stop(lens)\n release(lens.canvas)\n }\n lenses.clear()\n },\n }\n}\n","// The mask's dimming: one SVG per page, between the page content (canvas, text layer) and the\n// annotation overlay, holding one even-odd path: the whole page, minus the mask's shape. The\n// mask annotation's own element (drawn by the overlay) is the shape's outline and takes the\n// hits; this layer never does.\n//\n// Inline styles and attributes are structural: the SVG is `position:absolute; left:0; top:0;\n// pointer-events:none` at the page's CSS size, and the path's fill is the mask's colour at its\n// `dim`.\nimport type { PageTransform } from './transform'\nimport type { MaskAnnotation } from '../model/annotations/types'\n\nconst SVG = 'http://www.w3.org/2000/svg'\n\nconst fmt = (n: number): string => String(Math.round(n * 1000) / 1000)\n\n/**\n * The path data of a mask's dimming at `t`, in CSS pixels from the page's top-left corner: the\n * page rectangle, then the shape (the rectangle, or the ellipse inscribed in it) as a second\n * subpath that the even-odd rule cuts out. `t.toCssRect` turns the shape's box with the page,\n * so this holds at any /Rotate and view rotation.\n */\nexport function maskPath(\n a: Pick<MaskAnnotation, 'rect' | 'shape'>,\n t: Pick<PageTransform, 'toCssRect' | 'cssWidth' | 'cssHeight'>\n): string {\n const w = t.cssWidth\n const h = t.cssHeight\n const page = `M0 0L${fmt(w)} 0L${fmt(w)} ${fmt(h)}L0 ${fmt(h)}Z`\n const { left, top, width, height } = t.toCssRect(a.rect)\n if (a.shape === 'ellipse') {\n const rx = width / 2\n const ry = height / 2\n const cy = top + ry\n const arc = `A${fmt(rx)} ${fmt(ry)} 0 1 0`\n return `${page}M${fmt(left)} ${fmt(cy)}${arc} ${fmt(left + width)} ${fmt(cy)}${arc} ${fmt(left)} ${fmt(cy)}Z`\n }\n const right = left + width\n const bottom = top + height\n return `${page}M${fmt(left)} ${fmt(top)}L${fmt(right)} ${fmt(top)}L${fmt(right)} ${fmt(bottom)}L${fmt(left)} ${fmt(bottom)}Z`\n}\n\nexport interface MaskLayer {\n /** Draws `mask` at `t`, or removes the layer when there is none. */\n update(mask: MaskAnnotation | undefined, t: PageTransform): void\n destroy(): void\n}\n\n/** The page's mask layer: its SVG goes into `host` just before `before`, the annotation overlay. */\nexport function createMaskLayer(host: HTMLElement, before: Node): MaskLayer {\n let svg: SVGSVGElement | undefined\n let path: SVGPathElement | undefined\n\n return {\n update(mask, t) {\n if (!mask) {\n svg?.remove()\n svg = undefined\n path = undefined\n return\n }\n if (!svg || !path) {\n const doc = host.ownerDocument\n svg = doc.createElementNS(SVG, 'svg')\n svg.classList.add('ink-mask-layer')\n svg.dataset.inkMaskLayer = ''\n svg.setAttribute('aria-hidden', 'true')\n svg.style.cssText = 'position:absolute;left:0;top:0;pointer-events:none;'\n path = doc.createElementNS(SVG, 'path')\n path.setAttribute('fill-rule', 'evenodd')\n path.setAttribute('clip-rule', 'evenodd')\n path.setAttribute('stroke', 'none')\n svg.append(path)\n }\n if (svg.parentNode !== host || svg.nextSibling !== before)\n host.insertBefore(svg, before)\n svg.setAttribute('width', String(t.cssWidth))\n svg.setAttribute('height', String(t.cssHeight))\n svg.setAttribute('viewBox', `0 0 ${t.cssWidth} ${t.cssHeight}`)\n path.setAttribute('d', maskPath(mask, t))\n path.setAttribute('fill', mask.color)\n path.setAttribute('fill-opacity', String(mask.dim))\n },\n destroy() {\n svg?.remove()\n svg = undefined\n path = undefined\n },\n }\n}\n","// Inline styles here are structural or geometric only: the container is\n// `position:absolute; inset:0; pointer-events:none` so it covers the page without eating\n// events, and each annotation element is `position:absolute` with `left/top/width/height`\n// from `annotationBox` (stroked paths padded once by their stroke, and thin ones by their wider\n// hit twin), or from\n// `PageTransform.toCssRect(a.rect)` for custom elements. Hit-testing\n// follows the drawn shape, not the box: elements are `pointer-events:none` and their shapes\n// opt back in (overlay-render.ts), so a press beside a shape still reaches the text layer.\n// Edit handles (`.ink-handle[data-handle]`) are 8px `position:absolute;\n// pointer-events:auto` boxes on the element's corners or a line's ends, placed with\n// left/top; their look is the theme's.\n// Custom elements are the exception and stay `pointer-events:auto`: the host draws them and\n// only it knows their shape. Every visual (colour, opacity, stroke, fill) is an SVG\n// attribute or a theme hook.\nimport { freeTextBox } from '../model/annotations/callout'\nimport {\n hasCallout,\n hasCornerHandles,\n hasRectGeometry,\n isTextMarkup,\n keepsAspect,\n resizedBox,\n resizedRect,\n translated,\n} from '../model/annotations/edit'\nimport { withoutReplies } from '../model/annotations/threads'\nimport { isProduction } from '../model/env'\n\nimport { canEditFreeText, editFreeTextIn, editorFor } from './freetext-editor'\nimport { createLoupeLayer } from './loupe-layer'\nimport { createMaskLayer } from './mask-layer'\nimport {\n annotationBox,\n handleBox,\n freeTextLocalBox,\n hasComment,\n renderAnnotationContent,\n renderHitArea,\n syncHandles,\n type HandleSpec,\n} from './overlay-render'\n\nimport type { PageTransform } from './transform'\nimport type { AnnotationStore } from '../model/annotations/store'\nimport type { Annotation, MaskAnnotation } from '../model/annotations/types'\nimport type { InkDocument } from '../model/document'\nimport type { Point } from '../model/geometry'\n\nexport interface OverlayOptions {\n host: HTMLElement\n /** 0-based page index this overlay shows. */\n page: number\n store: AnnotationStore\n transform: PageTransform\n /** Called when an annotation is clicked, or activated with Enter or Space. */\n onActivate?(id: string): void\n /** Return true to render only the positioned shell; the host (e.g. a Vue slot) fills it. */\n isCustom?(annotation: Annotation): boolean\n /**\n * The document the page belongs to. Loupes magnify its page content; without it they show\n * only their rim.\n */\n document?: InkDocument\n /** Fixed device pixel ratio for loupes; `window.devicePixelRatio` when omitted. */\n devicePixelRatio?: number\n /**\n * The app's own data attributes, classes and description for an annotation's element, read\n * whenever the annotations change and on `redecorate`. Core's own attributes and `ink-`\n * classes win over them.\n */\n decorate?: DecorateAnnotation\n}\n\n/**\n * Data attributes, classes and a description an app adds to an annotation's element, to style\n * or find its own marks. Each `data` key is written as `data-<key>`.\n */\nexport interface AnnotationDecoration {\n /** Written as data-<key>; keys are lower-case kebab (/^[a-z][a-z0-9-]*$/). */\n data?: Readonly<Record<string, string>>\n classes?: readonly string[]\n /**\n * Extra words screen readers announce after the element's label, such as \"Needs review\".\n * Written as `aria-description`.\n */\n description?: string\n}\n\n/** Returns the decoration for an annotation's element, or undefined for none. */\nexport type DecorateAnnotation = (\n annotation: Annotation\n) => AnnotationDecoration | undefined\n\nexport interface Overlay {\n readonly element: HTMLElement\n /** Repositions every element and redraws content for a new zoom or rotation. */\n update(transform: PageTransform): void\n elementFor(id: string): HTMLElement | undefined\n /** Runs `decorate` again for every element, for when its output changed but no annotation did. */\n redecorate(): void\n destroy(): void\n}\n\ntype State = 'idle' | 'hover' | 'selected'\n\n/** A text position: a node and an offset in it. */\ninterface Caret {\n node: Node\n offset: number\n}\n\n/** Pointer travel, CSS px, within which a press on text markup is still a click. */\nconst CLICK_SLOP = 3\n/** Longest press, ms, that still counts as a click on text markup. */\nconst CLICK_MS = 500\n\n/** Arrow keys as user-space unit steps (y grows upwards). */\nconst ARROW_STEPS: Record<string, { x: number; y: number }> = {\n ArrowRight: { x: 1, y: 0 },\n ArrowLeft: { x: -1, y: 0 },\n ArrowUp: { x: 0, y: 1 },\n ArrowDown: { x: 0, y: -1 },\n}\n\nconst LABELS: Record<Annotation['type'], string> = {\n highlight: 'Highlight',\n underline: 'Underline',\n strikeout: 'Strikethrough',\n squiggly: 'Squiggly underline',\n text: 'Note',\n freetext: 'Text box',\n square: 'Rectangle',\n circle: 'Ellipse',\n line: 'Line',\n polyline: 'Polyline',\n polygon: 'Polygon',\n ink: 'Drawing',\n stamp: 'Stamp',\n loupe: 'Loupe',\n mask: 'Mask',\n redact: 'Redaction',\n}\n\nfunction ariaLabel(a: Annotation): string {\n const base =\n a.subject === 'Signature' && (a.type === 'ink' || a.type === 'stamp')\n ? 'Signature'\n : LABELS[a.type]\n const named = hasComment(a) ? `${base} with comment` : base\n return a.author ? `${named} by ${a.author}` : named\n}\n\n/** Reading order in user space: top edge first (y grows upwards), then left edge. */\nfunction readingOrder(a: Annotation, b: Annotation): number {\n return b.rect.y + b.rect.height - (a.rect.y + a.rect.height) || a.rect.x - b.rect.x\n}\n\n/** A decoration's data key: lower-case kebab, as written after `data-`. */\nconst DECORATION_KEY = /^[a-z][a-z0-9-]*$/\n\n/**\n * `data-*` keys core writes on an annotation element or inside it; a decoration cannot set\n * them. `data-ink-*` is core's too.\n */\nconst RESERVED_DATA = new Set([\n 'annotation',\n 'type',\n 'source',\n 'locked',\n 'state',\n 'custom',\n 'handle',\n 'framed',\n 'align',\n 'bubble',\n 'border',\n 'icon',\n 'ending',\n])\n\n/** Skipped decoration keys and classes already warned about. */\nconst warnedDecorations = new Set<string>()\n\nfunction warnDecoration(what: string, why: string): void {\n if (isProduction() || warnedDecorations.has(what)) return\n warnedDecorations.add(what)\n console.warn(`[inkbar] annotation decoration: skipped ${what}: ${why}`)\n}\n\n/** What a decoration applied to an element last time, to take off what the next drops. */\ninterface Applied {\n data: Set<string>\n classes: Set<string>\n description: boolean\n}\n\nfunction usableData(key: string): boolean {\n if (!DECORATION_KEY.test(key)) {\n warnDecoration(`data key \"${key}\"`, 'keys are lower-case kebab')\n return false\n }\n if (RESERVED_DATA.has(key) || key === 'ink' || key.startsWith('ink-')) {\n warnDecoration(`data key \"${key}\"`, 'core sets it')\n return false\n }\n return true\n}\n\nfunction usableClass(name: string): boolean {\n if (name.startsWith('ink-')) {\n warnDecoration(`class \"${name}\"`, \"`ink-` classes are core's\")\n return false\n }\n // classList rejects empty and whitespace tokens.\n if (name === '' || /\\s/.test(name)) {\n warnDecoration(`class \"${name}\"`, 'not a single class name')\n return false\n }\n return true\n}\n\nfunction setFlag(node: HTMLElement, key: string, on: boolean): void {\n if (on) node.dataset[key] = ''\n else delete node.dataset[key]\n}\n\nexport function createOverlay(opts: OverlayOptions): Overlay {\n const { store, page } = opts\n const doc = opts.host.ownerDocument\n let transform = opts.transform\n const root = doc.createElement('div')\n root.className = 'ink-overlay'\n root.dataset.inkOverlay = ''\n root.style.cssText = 'position:absolute;inset:0;pointer-events:none;'\n opts.host.append(root)\n\n const elements = new Map<string, HTMLElement>()\n const masks = createMaskLayer(opts.host, root)\n const loupes = opts.document\n ? createLoupeLayer({\n document: opts.document,\n ...(opts.devicePixelRatio === undefined\n ? {}\n : { devicePixelRatio: opts.devicePixelRatio }),\n })\n : undefined\n /** What each element's content was last drawn from; absent when it has none of ours. */\n const drawn = new Map<string, { a: Annotation; t: PageTransform }>()\n const hovered = new Set<string>()\n /** The decoration each element last got, so a later one can drop what it no longer has. */\n const decorated = new WeakMap<HTMLElement, Applied>()\n let order: string[] = []\n let destroyed = false\n\n function stateOf(id: string, selected: ReadonlySet<string>): State {\n if (selected.has(id)) return 'selected'\n return hovered.has(id) ? 'hover' : 'idle'\n }\n\n function applyState(node: HTMLElement, id: string): void {\n const selected = new Set(store.selection.get())\n const anyHere = order.some((x) => selected.has(x))\n const state = stateOf(id, selected)\n node.dataset.state = state\n node.setAttribute('aria-pressed', String(state === 'selected'))\n node.tabIndex = !anyHere || state === 'selected' ? 0 : -1\n const a = store.get(id)\n syncHandles(\n node,\n a && !a.locked && state === 'selected' && editsSelection()\n ? handleSpec(node, a)\n : { kind: 'none' }\n )\n }\n\n /** `handleBox` relative to an element at `left`,`top`. */\n function handleLocalBox(a: Annotation, left: number, top: number) {\n const box = handleBox(a, transform)\n return {\n left: box.left - left,\n top: box.top - top,\n width: box.width,\n height: box.height,\n }\n }\n\n /**\n * Line ends for a line, corners for what a corner drag resizes (a free text's on its text\n * box), plus the tip for a callout, else none.\n */\n function handleSpec(node: HTMLElement, a: Annotation): HandleSpec {\n const left = parseFloat(node.style.left) || 0\n const top = parseFloat(node.style.top) || 0\n if (a.type === 'line') {\n const local = (p: Point): Point => {\n const c = transform.toCss(p)\n return { x: c.x - left, y: c.y - top }\n }\n return { kind: 'ends', start: local(a.start), end: local(a.end) }\n }\n if (!hasCornerHandles(a)) return { kind: 'none' }\n const corners =\n a.type === 'freetext'\n ? { kind: 'corners' as const, ...freeTextLocalBox(a, transform) }\n : {\n kind: 'corners' as const,\n // On the drawn shape, inside the padding its hit area may add.\n ...handleLocalBox(a, left, top),\n }\n if (!hasCallout(a)) return corners\n const tip = transform.toCss(a.callout[0])\n return { ...corners, tail: { x: tip.x - left, y: tip.y - top } }\n }\n\n /**\n * True while the tool controller marks the tool root (an ancestor) with a select tool,\n * `data-ink-tool=\"select\"` or `\"select-text\"`, or with `data-ink-made`: what a creation tool\n * just made can be moved and resized too.\n */\n function editsSelection(): boolean {\n const root = opts.host.closest('[data-ink-tool]')\n const tool = root?.getAttribute('data-ink-tool')\n return (\n tool === 'select' ||\n tool === 'select-text' ||\n root?.hasAttribute('data-ink-made') === true\n )\n }\n // Re-sync handles on a tool switch. The controller's root is normally the viewport\n // container; pages can mount before the controller marks it, so fall back to that.\n const toolRoot =\n opts.host.closest('[data-ink-tool]') ?? opts.host.closest('[data-ink-viewport]')\n const Observer = doc.defaultView?.MutationObserver\n let toolObserver: MutationObserver | undefined\n if (toolRoot && Observer) {\n toolObserver = new Observer(() => {\n if (destroyed) return\n for (const [id, node] of elements) applyState(node, id)\n })\n toolObserver.observe(toolRoot, {\n attributes: true,\n attributeFilter: ['data-ink-tool', 'data-ink-made'],\n })\n }\n\n function applyAttributes(node: HTMLElement, a: Annotation): void {\n node.dataset.type = a.type\n node.dataset.source = a.source\n setFlag(node, 'locked', a.locked === true)\n node.setAttribute('aria-label', ariaLabel(a))\n applyDecoration(node, a)\n }\n\n /** The app's data attributes, classes and description, from `decorate`; a throw adds none. */\n function applyDecoration(node: HTMLElement, a: Annotation): void {\n let decoration: AnnotationDecoration | undefined\n try {\n decoration = opts.decorate?.(a)\n } catch (error) {\n console.error(error)\n }\n const prev = decorated.get(node)\n if (!decoration && !prev) return\n const next: Applied = { data: new Set(), classes: new Set(), description: false }\n for (const [key, value] of Object.entries(decoration?.data ?? {})) {\n if (!usableData(key)) continue\n node.setAttribute(`data-${key}`, value)\n next.data.add(key)\n }\n for (const name of decoration?.classes ?? []) {\n if (!usableClass(name)) continue\n node.classList.add(name)\n next.classes.add(name)\n }\n if (decoration?.description) {\n node.setAttribute('aria-description', decoration.description)\n next.description = true\n } else if (prev?.description) node.removeAttribute('aria-description')\n for (const key of prev?.data ?? [])\n if (!next.data.has(key)) node.removeAttribute(`data-${key}`)\n for (const name of prev?.classes ?? [])\n if (!next.classes.has(name)) node.classList.remove(name)\n decorated.set(node, next)\n }\n\n function applyGeometry(node: HTMLElement, a: Annotation): void {\n // Custom elements hold host content laid out against the annotation's own rect.\n const box =\n opts.isCustom?.(a) === true\n ? transform.toCssRect(a.rect)\n : annotationBox(a, transform)\n node.style.left = `${box.left}px`\n node.style.top = `${box.top}px`\n node.style.width = `${box.width}px`\n node.style.height = `${box.height}px`\n }\n\n function applyContent(node: HTMLElement, a: Annotation): void {\n const custom = opts.isCustom?.(a) === true\n setFlag(node, 'custom', custom)\n node.style.pointerEvents = custom ? 'auto' : 'none'\n // Custom elements are the host's to fill: draw nothing.\n if (custom) {\n loupes?.drop(a.id)\n if (drawn.delete(a.id)) node.replaceChildren()\n return\n }\n const last = drawn.get(a.id)\n if (last?.a === a && last.t === transform) return\n // Embedded annotations are already painted on the canvas by PDF.js, so they get only an\n // invisible hit area.\n if (a.source === 'pdf') renderHitArea(node, a, transform)\n else renderAnnotationContent(node, a, transform)\n if (a.type === 'loupe') loupes?.attach(node, a, transform)\n drawn.set(a.id, { a, t: transform })\n }\n\n /**\n * Opens the in-place editor on a free-text box this overlay draws. False when it cannot be\n * edited: not free text, locked, embedded or host-rendered.\n */\n function edit(id: string): boolean {\n const a = store.get(id)\n const node = elements.get(id)\n if (!node || !canEditFreeText(a, node) || opts.isCustom?.(a) === true) return false\n if (editorFor(node)) return true\n return editFreeTextIn(store, node, id, transform) !== undefined\n }\n\n /** Commits every open editor: before a redraw that would lose it, or teardown. */\n function closeEditors(): void {\n for (const node of elements.values()) editorFor(node)?.close(true)\n }\n\n function activate(id: string): void {\n store.select([id])\n opts.onActivate?.(id)\n }\n\n /** The live press on text markup, until its release or cancel. */\n let markupPress: (() => void) | undefined\n\n /**\n * A press on text markup does nothing yet. A release within `CLICK_SLOP` px and `CLICK_MS`\n * of it selects and activates the markup (with `Shift`, toggles it in the selection); a\n * longer drag selects the text under it instead, from the press point to the pointer, as a\n * drag on the bare text would. Rectangle select claims markup presses before they get here.\n */\n function pressMarkup(e: PointerEvent, id: string): void {\n // The browser's own selection would start inside the overlay, not the text: drive it here.\n e.preventDefault()\n markupPress?.()\n const view = doc.defaultView\n if (!view) return\n const { clientX: x0, clientY: y0, pointerId, timeStamp: t0 } = e\n let anchor: Caret | undefined\n let dragging = false\n const mine = (ev: PointerEvent): boolean => ev.pointerId === pointerId\n const onMove = (ev: PointerEvent): void => {\n if (!mine(ev)) return\n if (ev.buttons === 0) return end()\n if (!dragging && Math.hypot(ev.clientX - x0, ev.clientY - y0) <= CLICK_SLOP) return\n dragging = true\n anchor ??= caretAt(x0, y0)\n const focus = caretAt(ev.clientX, ev.clientY)\n if (anchor && focus)\n doc\n .getSelection()\n ?.setBaseAndExtent(anchor.node, anchor.offset, focus.node, focus.offset)\n }\n const onUp = (ev: PointerEvent): void => {\n if (!mine(ev) || ev.button !== 0) return\n end()\n if (\n !dragging &&\n !destroyed &&\n Math.hypot(ev.clientX - x0, ev.clientY - y0) <= CLICK_SLOP &&\n ev.timeStamp - t0 <= CLICK_MS &&\n store.get(id)\n ) {\n if (!(e.shiftKey || ev.shiftKey)) return activate(id)\n // Shift-click adds the markup to the selection, or takes it out.\n const selected = store.selection.get()\n store.select(\n selected.includes(id) ? selected.filter((s) => s !== id) : [...selected, id]\n )\n }\n }\n const onCancel = (ev: PointerEvent): void => {\n if (mine(ev)) end()\n }\n const end = (): void => {\n view.removeEventListener('pointermove', onMove, true)\n view.removeEventListener('pointerup', onUp, true)\n view.removeEventListener('pointercancel', onCancel, true)\n if (markupPress === end) markupPress = undefined\n }\n // Capture on the window: the release still arrives when a tool captured the pointer or a\n // handler on the way stops it.\n view.addEventListener('pointermove', onMove, true)\n view.addEventListener('pointerup', onUp, true)\n view.addEventListener('pointercancel', onCancel, true)\n markupPress = end\n }\n\n /**\n * The text position under a client point on this page's text layer, looked up with the\n * overlay hidden so the markup on top does not answer instead.\n */\n function caretAt(x: number, y: number): Caret | undefined {\n const visibility = root.style.visibility\n root.style.visibility = 'hidden'\n let caret: Caret | undefined\n try {\n if (typeof doc.caretPositionFromPoint === 'function') {\n const p = doc.caretPositionFromPoint(x, y)\n if (p) caret = { node: p.offsetNode, offset: p.offset }\n } else if (typeof doc.caretRangeFromPoint === 'function') {\n const r = doc.caretRangeFromPoint(x, y)\n if (r) caret = { node: r.startContainer, offset: r.startOffset }\n }\n } finally {\n root.style.visibility = visibility\n }\n const layer = opts.host.querySelector('[data-ink-text-layer]')\n return caret && layer?.contains(caret.node) ? caret : undefined\n }\n\n function focusAt(index: number): void {\n const id = order[Math.max(0, Math.min(order.length - 1, index))]\n if (id !== undefined) elements.get(id)?.focus()\n }\n\n /**\n * `Shift+Arrow` moves the annotation 1 pt in user space (`Shift+Alt+Arrow` 10 pt; up is +y).\n * `Ctrl+Shift+Arrow` or `Meta+Shift+Arrow` resizes a rect-shaped one by 1 pt: Right and Down\n * grow it, Left and Up shrink it, keeping its top-left corner. A free text resizes its text\n * box, as its corner handles do. Locked items ignore both.\n * Returns true when the key was one of these chords.\n */\n function onEditKey(e: KeyboardEvent, id: string): boolean {\n const step = ARROW_STEPS[e.key]\n if (!step || !e.shiftKey) return false\n e.preventDefault()\n const a = store.get(id)\n if (!a || a.locked) return true\n if (e.ctrlKey || e.metaKey) {\n if (a.type === 'freetext')\n store.update(id, resizedBox(a, resizedRect(freeTextBox(a), step.x, -step.y)))\n else if (hasRectGeometry(a))\n store.update(id, { rect: resizedRect(a.rect, step.x, -step.y, keepsAspect(a)) })\n return true\n }\n const by = e.altKey ? 10 : 1\n store.update(id, translated(a, step.x * by, step.y * by))\n return true\n }\n\n function onKey(e: KeyboardEvent, id: string): void {\n if (onEditKey(e, id)) return\n switch (e.key) {\n case 'Enter':\n case ' ':\n e.preventDefault()\n // Enter on a free-text box edits it in place.\n if (e.key === 'Enter' && edit(id)) store.select([id])\n else activate(id)\n break\n case 'Delete':\n case 'Backspace': {\n // The overlay owns deletion from a focused annotation: it removes that one only, never\n // the rest of the selection. `preventDefault` tells the select tool to stand down.\n e.preventDefault()\n const a = store.get(id)\n if (a && !a.locked) store.remove(id)\n break\n }\n case 'Escape':\n e.preventDefault()\n store.select([])\n break\n case 'ArrowDown':\n case 'ArrowUp':\n e.preventDefault()\n focusAt(order.indexOf(id) + (e.key === 'ArrowDown' ? 1 : -1))\n break\n default:\n }\n }\n\n function create(id: string): HTMLElement {\n const node = doc.createElement('div')\n node.className = 'ink-annotation'\n node.dataset.annotation = id\n node.setAttribute('role', 'button')\n node.style.position = 'absolute'\n node.addEventListener('pointerenter', () => {\n hovered.add(id)\n applyState(node, id)\n })\n node.addEventListener('pointerleave', () => {\n hovered.delete(id)\n applyState(node, id)\n })\n node.addEventListener('pointerdown', (e) => {\n if (e.button !== 0) return\n // Presses in a free-text editor place the caret: they are the editor's.\n if (e.target instanceof Element && e.target.closest('[data-ink-editor]')) return\n // A press on a custom element's own content (a host's button, say) is that content's:\n // no selection, and it bubbles on to the host's delegated handlers.\n if (\n e.target !== node &&\n node.hasAttribute('data-custom') &&\n !(e.target instanceof Element && e.target.closest('[data-handle]'))\n )\n return\n // Text markup waits for the release: a drag across it is a text selection.\n const a = store.get(id)\n if (a && isTextMarkup(a)) {\n pressMarkup(e, id)\n return\n }\n // A tool listening on the page root must not start a drag from this press.\n e.stopPropagation()\n activate(id)\n })\n node.addEventListener('dblclick', (e) => {\n if (e.target instanceof Element && e.target.closest('[data-ink-editor]')) return\n if (edit(id)) e.preventDefault()\n })\n node.addEventListener('keydown', (e) => {\n // Keys typed in descendants (a custom element's buttons and inputs) are theirs.\n if (e.target !== node) return\n onKey(e, id)\n })\n return node\n }\n\n function render(): void {\n if (destroyed) return\n // Replies show in the thread popover only: no element, hit area or tab stop here.\n const current = withoutReplies(store.list.get())\n .filter((a) => a.page === page)\n .sort(readingOrder)\n const ids = new Set(current.map((a) => a.id))\n const active = doc.activeElement\n let focusId = [...elements].find(([, n]) => n === active)?.[0]\n /** The focused element is going away with nothing on this page to take over. */\n let focusRoot = false\n\n if (focusId !== undefined && !ids.has(focusId)) {\n // The focused element is going away: hand focus to the next survivor, else the previous.\n const i = order.indexOf(focusId)\n focusId =\n order.slice(i + 1).find((x) => ids.has(x)) ??\n order\n .slice(0, i)\n .reverse()\n .find((x) => ids.has(x))\n focusRoot = focusId === undefined\n }\n for (const [id, node] of elements) {\n if (ids.has(id)) continue\n // The box is gone (removed elsewhere, or undone): its edit goes with it.\n editorFor(node)?.close(false)\n node.remove()\n loupes?.drop(id)\n elements.delete(id)\n drawn.delete(id)\n hovered.delete(id)\n }\n\n masks.update(\n current.find((a): a is MaskAnnotation => a.type === 'mask'),\n transform\n )\n\n order = current.map((a) => a.id)\n for (const a of current) {\n let node = elements.get(a.id)\n if (!node) {\n node = create(a.id)\n elements.set(a.id, node)\n }\n applyAttributes(node, a)\n // An open editor owns the element's content and height until it closes; the element\n // still follows the page.\n if (editorFor(node)) {\n const height = node.style.height\n applyGeometry(node, a)\n node.style.height = height\n } else {\n applyGeometry(node, a)\n applyContent(node, a)\n }\n applyState(node, a.id)\n }\n\n // DOM order is tab order: keep it in reading order. Moving nodes blurs them, so only\n // re-append when the order actually changed.\n const inDom = [...root.children]\n if (\n inDom.length !== order.length ||\n order.some((id, i) => inDom[i] !== elements.get(id))\n ) {\n for (const id of order) root.append(elements.get(id)!)\n }\n if (focusId !== undefined) {\n const target = elements.get(focusId)\n if (target && doc.activeElement !== target) target.focus({ preventScroll: true })\n } else if (focusRoot) {\n // Last one on the page: back to the scroll element (as the popovers do), not <body>.\n const scroll = opts.host.closest<HTMLElement>('[data-ink-viewport]')\n if (scroll) {\n // A container the host did not make focusable still takes focus from script.\n if (!scroll.hasAttribute('tabindex')) scroll.tabIndex = -1\n scroll.focus({ preventScroll: true })\n }\n }\n }\n\n const offList = store.list.subscribe(render)\n const offSelection = store.selection.subscribe(() => {\n for (const [id, node] of elements) applyState(node, id)\n })\n render()\n\n return {\n element: root,\n update(next) {\n // An editor is laid out for one zoom and rotation: a change to either commits it first\n // (focus moves to its box). Any other relayout leaves it open.\n if (next.zoom !== transform.zoom || next.rotation !== transform.rotation)\n closeEditors()\n transform = next\n render()\n },\n elementFor: (id) => elements.get(id),\n redecorate() {\n if (destroyed) return\n for (const [id, node] of elements) {\n const a = store.get(id)\n if (a) applyDecoration(node, a)\n }\n },\n destroy() {\n if (destroyed) return\n closeEditors()\n destroyed = true\n markupPress?.()\n offList()\n offSelection()\n toolObserver?.disconnect()\n loupes?.destroy()\n masks.destroy()\n root.remove()\n elements.clear()\n drawn.clear()\n hovered.clear()\n order = []\n },\n }\n}\n","/*\n * `plugin.command`: a command whose run gets the document it started on and a signal that aborts\n * when that document goes away, and whose result or failure becomes its status message.\n */\nimport { isInkError } from '../../../model/errors'\nimport { readonly, writable } from '../../../model/readable'\n\nimport type { InkDocument } from '../../../model/document'\nimport type { Readable } from '../../../model/readable'\nimport type { Command, PluginContext } from '../define'\nimport type { IconNode } from '@inkbar/icons'\n\nexport interface CommandOptions {\n icon?: IconNode\n /** Default: a document is open and ready. */\n enabled?: Readable<boolean>\n /** The status after a failure. Default: \"Something went wrong.\" */\n errorStatus?: string\n}\n\nexport type CommandRun = (run: {\n /** The document open when the command started. */\n doc: InkDocument\n /** Aborts when that document closes or another opens. */\n signal: AbortSignal\n}) => string | void | Promise<string | void>\n\nconst DEFAULT_ERROR_STATUS = 'Something went wrong.'\n\n/** A failure that is the run being cancelled, not a bug: not logged, no error status. */\nfunction isCancellation(error: unknown): boolean {\n if (isInkError(error) && error.code === 'DocumentDestroyed') return true\n return error instanceof Error && error.name === 'AbortError'\n}\n\nexport function createCommand(\n ctx: PluginContext,\n id: string,\n label: string,\n run: CommandRun,\n opts: CommandOptions = {}\n): Command {\n const status = writable('')\n let controller: AbortController | null = null\n\n // The status belongs to one document; a run in flight is cancelled when that document closes,\n // another opens or the host is destroyed.\n ctx.onDocument(() => () => {\n controller?.abort()\n status.set('')\n })\n\n return ctx.commands.add({\n id,\n label,\n ...(opts.icon && { icon: opts.icon }),\n ...(opts.enabled && { enabled: opts.enabled }),\n status: readonly(status),\n async run() {\n const doc = ctx.document.get()\n if (!doc) return\n const own = new AbortController()\n controller = own\n status.set('')\n try {\n const result = await run({ doc, signal: own.signal })\n if (!own.signal.aborted) status.set(result ?? '')\n } catch (error) {\n if (own.signal.aborted || isCancellation(error)) return\n // Handled here, so the registry's own logging never sees it.\n console.error(error)\n status.set(opts.errorStatus ?? DEFAULT_ERROR_STATUS)\n } finally {\n if (controller === own) controller = null\n }\n },\n })\n}\n","/** The overlay element drawn for annotation `id` under `root`, if it is in the DOM. */\nexport function annotationElementFor(root: ParentNode, id: string): HTMLElement | null {\n return root.querySelector<HTMLElement>(`[data-annotation=\"${CSS.escape(id)}\"]`)\n}\n\n/**\n * Resolves the overlay element for `id` and keeps resolving while `root`'s subtree changes:\n * the overlay creates and removes these elements outside any framework (a page mounts as it\n * scrolls into view), so a popover anchored to one has to follow. Calls `onChange` once now\n * and again whenever the answer changes. The returned function stops observing.\n */\nexport function observeAnnotationElement(\n root: HTMLElement,\n id: string,\n onChange: (el: HTMLElement | null) => void\n): () => void {\n let last: HTMLElement | null | undefined\n const resolve = (): void => {\n const found = annotationElementFor(root, id)\n if (found === last) return\n last = found\n onChange(found)\n }\n resolve()\n const observer = new MutationObserver(resolve)\n observer.observe(root, { childList: true, subtree: true })\n return () => observer.disconnect()\n}\n","/*\n * Shared behaviour for popovers anchored to an overlay annotation element. There is no popover\n * trigger, so the primitive library's own focus return has nothing to return to.\n */\nimport { annotationElementFor } from './annotation-element'\n\n/**\n * A press that will activate an annotation is not a dismissal: the popover follows the\n * activation. Mirrors the overlay's rule: a press on the annotation element or on its drawn\n * shape activates; a press on a custom element's own content belongs to that content.\n */\nexport function shouldKeepOpenOnAnnotation(target: EventTarget | null): boolean {\n if (!(target instanceof Element)) return false\n const annotation = target.closest('[data-annotation]')\n if (!annotation) return false\n return target === annotation || !annotation.hasAttribute('data-custom')\n}\n\nexport interface FocusReturnOptions {\n root: () => HTMLElement | null\n /** The activated annotation id when the popover closes. */\n activated: () => string | null\n}\n\nexport interface FocusReturn {\n /**\n * Call just before removing the anchor's annotation: remembers where focus goes instead,\n * the next annotation on the page in reading order (the next one matching `prefer`\n * first), else the previous one, else the scroll element.\n */\n beforeRemove(anchor: HTMLElement | null, prefer?: string): void\n /** The popover's close-auto-focus handler. Prevents the default and places focus itself. */\n onCloseAutoFocus(event: Event, anchor: HTMLElement | null): void\n}\n\nexport function createFocusReturn(opts: FocusReturnOptions): FocusReturn {\n let fallbacks: HTMLElement[] = []\n /** Set by `beforeRemove`: the close comes from removing the anchor's annotation. */\n let removing = false\n\n return {\n beforeRemove(anchor, prefer) {\n fallbacks = []\n removing = true\n // The overlay keeps its elements in reading order, so DOM order is reading order.\n const siblings = anchor?.parentElement\n ? [...anchor.parentElement.children].filter(\n (el): el is HTMLElement =>\n el instanceof HTMLElement && el.hasAttribute('data-annotation')\n )\n : []\n const i = anchor ? siblings.indexOf(anchor) : -1\n if (i >= 0) {\n const after = siblings.slice(i + 1)\n const preferred = prefer ? after.filter((el) => el.matches(prefer)) : []\n fallbacks.push(...preferred, ...after, ...siblings.slice(0, i).reverse())\n }\n },\n onCloseAutoFocus(event, anchor) {\n event.preventDefault()\n const plan = fallbacks\n const removed = removing\n fallbacks = []\n removing = false\n const root = opts.root()\n if (!root) return\n // Activation moved to another annotation that is on screen: its popover takes focus. An\n // id whose element is gone (the host removed it) does not count.\n const activated = opts.activated()\n if (activated !== null && annotationElementFor(root, activated)) return\n // The close can be reported more than once; focus already returned to the document stays.\n const active = root.ownerDocument.activeElement\n if (active && active !== root && root.contains(active)) return\n const scroll = root.querySelector<HTMLElement>('[data-ink-scroll]')\n // After a removal the anchor may still be connected (a controlled host has not applied\n // the change yet), but it is on its way out: go straight to what follows it.\n const candidates = removed ? [...plan, scroll] : [anchor, ...plan, scroll]\n candidates.find((el) => el?.isConnected)?.focus({ preventScroll: true })\n },\n }\n}\n","/** `document.createElement` with attributes and children. */\nexport function h<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n attrs: Record<string, string> = {},\n ...children: (Node | string)[]\n): HTMLElementTagNameMap[K] {\n const el = document.createElement(tag)\n for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value)\n el.append(...children)\n return el\n}\n\nexport function button(label: string, onClick: () => void): HTMLButtonElement {\n const b = h('button', { type: 'button' }, label)\n b.addEventListener('click', onClick)\n return b\n}\n","/*\n * Panels anchored to an annotation's overlay element: the note thread, and any card an app\n * opens next to an annotation. A panel can also anchor to an element of the app's or a\n * plugin's own, such as a mark in a plugin layer.\n */\nimport { observeAnnotationElement } from '../annotation-element'\nimport { shouldKeepOpenOnAnnotation, type FocusReturn } from '../popover-focus'\n\nimport { h } from './dom'\n\n/** Space between the anchor and the panel, and between the panel and the window edge. */\nconst GAP = 6\nconst MARGIN = 8\nconst TABBABLE = 'button, input, select, textarea, a[href], [tabindex]'\n\n/** Options for `createPopover`. */\nexport interface PopoverOptions {\n /** The viewer root (`[data-ink-root]`): anchors are looked up and focus returns inside it. */\n root: HTMLElement\n /**\n * Attributes for the panel, such as `class`, `aria-label` or the app's own `data-*` keys.\n * `role` and `data-ink-popover` are always set by `createPopover`.\n */\n attrs: Record<string, string>\n /** Where focus goes when the panel hides: `createFocusReturn` over the same root. */\n focusReturn: FocusReturn\n /**\n * Called on Escape inside the panel or the viewer, and on a press outside the panel that will\n * not activate another annotation. Hide the panel (or clear the activation) here.\n */\n onDismiss(): void\n}\n\n/** A panel anchored to one annotation, or one element, at a time; see `createPopover`. */\nexport interface Popover {\n /** The panel element, on `<body>`. Fill it with the card's content. */\n readonly panel: HTMLElement\n /**\n * The anchored annotation's element (or the element passed to `showAt`), or null while it is\n * not in the DOM (page unmounted).\n */\n readonly anchor: HTMLElement | null\n /**\n * Anchors the panel to annotation `id`. The panel shows whenever that annotation's element\n * is in the DOM, and follows it when it is replaced.\n */\n show(id: string): void\n /**\n * Anchors the panel to `el`, for anchors that are not annotations (a plugin layer's mark).\n * The panel shows while `el` is under the viewer root and hides while it is not. On hide,\n * focus returns to `el` when it is still connected, else through `focusReturn`.\n */\n showAt(el: HTMLElement): void\n /** Hides the panel, then returns focus through `focusReturn`. */\n hide(): void\n /** Removes the panel and its listeners. */\n destroy(): void\n}\n\n/**\n * Positions `panel` (fixed) below the `anchor` rectangle, or above it when only that fits,\n * kept inside the window. For panels anchored to something other than an annotation.\n */\nexport function placePanel(panel: HTMLElement, anchor: DOMRect): void {\n const { innerWidth: vw, innerHeight: vh } = window\n // Fixed at the corner before measuring: a panel still in the flow is as wide as the body,\n // and one left where it was is squeezed by the window edge.\n panel.style.position = 'fixed'\n panel.style.left = '0px'\n panel.style.top = '0px'\n const w = panel.offsetWidth\n const ht = panel.offsetHeight\n let top = anchor.bottom + GAP\n if (top + ht > vh - MARGIN && anchor.top - GAP - ht >= MARGIN)\n top = anchor.top - GAP - ht\n top = Math.max(MARGIN, Math.min(top, vh - ht - MARGIN))\n const left = Math.max(MARGIN, Math.min(anchor.left, vw - w - MARGIN))\n panel.style.left = `${left}px`\n panel.style.top = `${top}px`\n}\n\n/**\n * Calls `onChange` with `el` while it is under `root` and null while it is not: once now, then\n * whenever that changes. Returns a function that stops observing.\n */\nfunction observeElement(\n root: HTMLElement,\n el: HTMLElement,\n onChange: (el: HTMLElement | null) => void\n): () => void {\n let last: HTMLElement | null | undefined\n const resolve = (): void => {\n const found = root.contains(el) ? el : null\n if (found === last) return\n last = found\n onChange(found)\n }\n resolve()\n const observer = new MutationObserver(resolve)\n observer.observe(root, { childList: true, subtree: true })\n return () => observer.disconnect()\n}\n\n/**\n * Creates a non-modal `role=\"dialog\"` panel on `<body>`, marked `data-ink-popover` so the theme\n * gives it its tokens, that an app anchors to an annotation with `show(id)` (for instance on\n * `viewer.activated`), or to any element in the viewer with `showAt(el)`. The panel follows the annotation's element as pages mount and unmount:\n * it hides while the element is gone and comes back with it. Tab loops inside the panel, and\n * Escape or a press outside calls `onDismiss`. Call `destroy` when done.\n */\nexport function createPopover(opts: PopoverOptions): Popover {\n const { root, focusReturn } = opts\n const panel = h('div', {\n ...opts.attrs,\n role: 'dialog',\n 'data-ink-popover': '',\n hidden: '',\n })\n document.body.append(panel)\n /** What the panel is anchored to: an annotation id, or an element from `showAt`. */\n let anchored: string | HTMLElement | null = null\n let anchor: HTMLElement | null = null\n let stopObserving: () => void = () => undefined\n /** The element that had focus in the panel when the anchor went away. */\n let stranded: HTMLElement | null = null\n\n const place = (): void => {\n if (!anchor || panel.hidden) return\n placePanel(panel, anchor.getBoundingClientRect())\n }\n\n // The anchor changes size on zoom; the panel when its content changes.\n const resizes = new ResizeObserver(place)\n resizes.observe(panel)\n\n const onAnchor = (el: HTMLElement | null, closing = false): void => {\n if (anchor) resizes.unobserve(anchor)\n anchor = el\n if (!el) {\n const active = document.activeElement\n if (\n !closing &&\n !panel.hidden &&\n active instanceof HTMLElement &&\n panel.contains(active)\n ) {\n // Hiding the panel would drop focus to the body: keep the keyboard in the viewer.\n const scroll = root.querySelector<HTMLElement>('[data-ink-scroll]')\n if (scroll) {\n stranded = active\n scroll.focus({ preventScroll: true })\n }\n }\n panel.hidden = true\n return\n }\n resizes.observe(el)\n const wasHidden = panel.hidden\n panel.hidden = false\n place()\n if (wasHidden && stranded) {\n const back = stranded\n stranded = null\n const scroll = root.querySelector<HTMLElement>('[data-ink-scroll]')\n if (panel.contains(back) && document.activeElement === scroll)\n back.focus({ preventScroll: true })\n }\n }\n\n const onKey = (e: KeyboardEvent): void => {\n if (e.key !== 'Escape' || panel.hidden || e.defaultPrevented) return\n // An Escape meant for a host's own dialog elsewhere on the page is not ours.\n const target = e.target\n if (!(target instanceof Node) || !(panel.contains(target) || root.contains(target)))\n return\n e.preventDefault()\n opts.onDismiss()\n }\n const onPress = (e: PointerEvent): void => {\n if (panel.hidden || panel.contains(e.target as Node)) return\n // A press that will activate an annotation hands over to it instead of closing.\n if (shouldKeepOpenOnAnnotation(e.target)) return\n opts.onDismiss()\n }\n // Focus loops inside the panel.\n const onTab = (e: KeyboardEvent): void => {\n if (e.key !== 'Tab' || e.altKey || e.ctrlKey || e.metaKey) return\n const tabbable = [...panel.querySelectorAll<HTMLElement>(TABBABLE)].filter(\n (el) => !(el as HTMLButtonElement).disabled && el.tabIndex >= 0\n )\n const first = tabbable[0]\n const last = tabbable.at(-1)\n if (!first || !last) return\n const active = document.activeElement\n if (e.shiftKey ? active !== first : active !== last) return\n e.preventDefault()\n ;(e.shiftKey ? last : first).focus()\n }\n panel.addEventListener('keydown', onTab)\n document.addEventListener('keydown', onKey)\n document.addEventListener('pointerdown', onPress, true)\n // The viewer's scroll element and any scrolling ancestor in the host page.\n document.addEventListener('scroll', place, true)\n window.addEventListener('resize', place)\n\n return {\n panel,\n get anchor() {\n return anchor\n },\n show(id) {\n if (id === anchored) return\n stopObserving()\n anchored = id\n stopObserving = observeAnnotationElement(root, id, onAnchor)\n },\n showAt(el) {\n if (el === anchored) return\n stopObserving()\n anchored = el\n stopObserving = observeElement(root, el, onAnchor)\n },\n hide() {\n if (anchored === null) return\n stopObserving()\n stopObserving = () => undefined\n const element = typeof anchored === 'string' ? null : anchored\n anchored = null\n const back = anchor\n stranded = null\n onAnchor(null, true)\n // After the change that closed the popover has settled (a removed anchor is out of the\n // DOM, a cleared activation is cleared). A popover reopened meanwhile keeps focus where it\n // is.\n queueMicrotask(() => {\n if (anchored !== null || !panel.isConnected) return\n if (element?.isConnected) {\n // Focus already back in the viewer (a press on another mark) stays there.\n const active = document.activeElement\n if (!(active && active !== root && root.contains(active)))\n element.focus({ preventScroll: true })\n return\n }\n focusReturn.onCloseAutoFocus(\n new Event('closeautofocus', { cancelable: true }),\n back\n )\n })\n },\n destroy() {\n stopObserving()\n resizes.disconnect()\n document.removeEventListener('keydown', onKey)\n document.removeEventListener('pointerdown', onPress, true)\n panel.removeEventListener('keydown', onTab)\n document.removeEventListener('scroll', place, true)\n window.removeEventListener('resize', place)\n panel.remove()\n },\n }\n}\n","/*\n * The card a mark opens: a core popover anchored to the mark, built from the plugin's\n * `CardSpec` and styled by the theme (`.ink-card` and its parts). One popover per viewer root,\n * made on first open. Each action is one undo step. After an action the card re-renders when\n * the mark stays; when it goes, the card closes and focus moves to the next mark, else the\n * previous one, else the viewport. Escape or a press outside closes it and focus goes back to\n * the mark.\n */\nimport { createFocusReturn } from '../../popover-focus'\nimport { createPopover, type Popover } from '../../viewer/popover'\n\nimport type { Records } from './records'\nimport type { RecordBase } from '../../../model/records'\nimport type { PluginContext } from '../define'\n\n/** What a mark's card shows. The theme styles it; `className` adds a class of your own. */\nexport interface CardSpec {\n /** The card's heading (`.ink-card-title`). */\n title: string\n /** The dialog's accessible name. Default: `title`. */\n label?: string\n /** A short line under the title (`.ink-card-meta`). */\n meta?: string\n /** A CSS colour for a dot before `meta` (`.ink-card-swatch`). */\n swatch?: string\n /** Text under the meta line (`.ink-card-body`). */\n body?: string\n /**\n * One button per key, in order (`.ink-card-actions`). The first takes focus on open and is\n * styled as the primary action. Each action runs synchronously in one undo step: writes after\n * an `await` fall outside it. When an action removes the mark, focus moves to the next of this\n * `marks()` handle's marks, else the previous, else the viewport.\n */\n actions: Record<string, () => void>\n /** Classes added to the card. */\n className?: string\n}\n\nexport interface CardOptions<T extends RecordBase> {\n /** The card for `record`. */\n spec(record: T): CardSpec\n /** Whether `record` still has a mark. */\n marked(record: T): boolean\n /** This handle's marks under `root`, in document order. */\n marks(root: HTMLElement): HTMLElement[]\n}\n\nexport interface Card<T extends RecordBase> {\n /** Shows `record`'s card next to `mark`, focusing its first action. */\n open(record: T, mark: HTMLElement): void\n /** Whether the card is open on `mark`, for its `aria-expanded`. */\n expanded(mark: HTMLElement): boolean\n}\n\nfunction el(tag: string, className: string, ...children: (Node | string)[]): HTMLElement {\n const e = document.createElement(tag)\n e.className = className\n e.append(...children)\n return e\n}\n\nexport function createCard<T extends RecordBase>(\n ctx: PluginContext,\n records: Records<T>,\n opts: CardOptions<T>\n): Card<T> {\n /** Made on first open, in the viewer root the mark is in. */\n let popover: Popover | null = null\n let root: HTMLElement | null = null\n /** The record on show. */\n let shown: string | null = null\n /** Set while an action runs: the action decides what happens after it. */\n let acting = false\n /** The mark whose card is open: its `aria-expanded` is true. */\n let expanded: HTMLElement | null = null\n\n const expand = (mark: HTMLElement | null) => {\n expanded?.setAttribute('aria-expanded', 'false')\n expanded = mark\n mark?.setAttribute('aria-expanded', 'true')\n }\n\n /** The shown record as it stands now, while it still has a mark. */\n const current = (): T | undefined => {\n const record = shown === null ? undefined : records.find(shown)\n return record && opts.marked(record) ? record : undefined\n }\n\n const close = () => {\n shown = null\n expand(null)\n popover?.hide()\n }\n\n /** Runs `fn` as one undo step, then re-renders, or closes and moves focus on. */\n const act = (fn: () => void) => {\n if (!popover || !root || shown === null) return\n const marks = opts.marks(root)\n const i = popover.anchor ? marks.indexOf(popover.anchor) : -1\n const after = i < 0 ? [] : [...marks.slice(i + 1), ...marks.slice(0, i).reverse()]\n acting = true\n try {\n ctx.history.batch(fn)\n } finally {\n acting = false\n }\n const record = current()\n if (record) return render(record)\n // Focus first: the close then leaves it where it is.\n after.find((m) => m.isConnected)?.focus({ preventScroll: true })\n close()\n }\n\n /** Fills the panel from `record`, keeping focus on the same action. */\n const render = (record: T) => {\n const spec = opts.spec(record)\n const panel = popover!.panel\n const buttons = () => [\n ...panel.querySelectorAll<HTMLButtonElement>('.ink-card-actions > button'),\n ]\n const focused = buttons().indexOf(document.activeElement as HTMLButtonElement)\n panel.className = spec.className ? `ink-card ${spec.className}` : 'ink-card'\n panel.setAttribute('aria-label', spec.label ?? spec.title)\n const parts: HTMLElement[] = [el('p', 'ink-card-title', spec.title)]\n if (spec.meta !== undefined) {\n const meta = el('p', 'ink-card-meta', spec.meta)\n if (spec.swatch !== undefined) {\n const swatch = el('span', 'ink-card-swatch')\n swatch.style.background = spec.swatch\n meta.prepend(swatch)\n }\n parts.push(meta)\n }\n if (spec.body !== undefined) parts.push(el('p', 'ink-card-body', spec.body))\n const actions = el('div', 'ink-card-actions')\n for (const [label, fn] of Object.entries(spec.actions)) {\n const button = el('button', '', label) as HTMLButtonElement\n button.type = 'button'\n button.addEventListener('click', () => act(fn))\n actions.append(button)\n }\n parts.push(actions)\n panel.replaceChildren(...parts)\n if (focused >= 0) {\n const now = buttons()\n ;(now[focused] ?? now[0])?.focus({ preventScroll: true })\n }\n }\n\n ctx.onDocument(() => {\n const stop = records.list.subscribe(() => {\n if (acting || shown === null) return\n const record = current()\n if (record) render(record)\n else close()\n })\n return () => {\n stop()\n shown = null\n expand(null)\n popover?.destroy()\n popover = null\n root = null\n }\n })\n\n return {\n open(record, mark) {\n const viewer = mark.closest<HTMLElement>('[data-ink-root]')\n if (!viewer) return\n if (viewer !== root) {\n popover?.destroy()\n root = viewer\n popover = createPopover({\n root: viewer,\n attrs: { class: 'ink-card' },\n focusReturn: createFocusReturn({ root: () => viewer, activated: () => null }),\n onDismiss: close,\n })\n }\n shown = record.id\n render(record)\n popover!.showAt(mark)\n expand(mark)\n popover!.panel.querySelector<HTMLElement>('.ink-card-actions > button')?.focus()\n },\n expanded: (mark) => mark === expanded,\n }\n}\n","/*\n * Marks drawn from records: one `<button>` per matching record on its page, in the plugin's\n * own layer, placed from the record's rect in user space through the page transform. Marks are\n * keyed by record id and reconciled in place, so a mark that stays keeps its element, and with\n * it focus, through a zoom, a rotation or another record's change. They redraw whenever the\n * records change (undo and redo included) and on `refresh()`. With `scrollToFirst()`, the viewer\n * scrolls to records as they start to get a mark.\n *\n * Presses and clicks on a mark are the plugin's: they go no further, so neither the active tool\n * nor listeners on the viewer's root see them. Enter and Space activate it, as on any button.\n */\nimport { createCard, type CardSpec } from './card'\n\nimport type { Records } from './records'\nimport type { Rect } from '../../../model/geometry'\nimport type { RecordBase, RecordChange } from '../../../model/records'\nimport type { PageTransform } from '../../transform'\nimport type { PluginContext } from '../define'\n\nexport interface MarksOptions<T extends RecordBase & { page: number }> {\n /** Where the record's mark goes on its page, in user space. */\n rect(record: T): Rect\n /** The mark's accessible name. */\n label(record: T): string\n /** Only records that pass get a mark. Default: all. */\n where?(record: T): boolean\n /**\n * Inline style for the mark, camel-case properties and `--custom` properties alike. Core draws\n * nothing else: the look is the plugin's CSS.\n */\n style?(record: T): Partial<CSSStyleDeclaration> & { [property: `--${string}`]: string }\n /** Classes every mark gets. */\n className?: string\n /**\n * More attributes (`data-*`, `aria-*`). `data-record`, `data-plugin` and `aria-label` stay\n * core's, and so do `aria-haspopup` and `aria-expanded` on a mark with a card; `style`,\n * `class` and `type` are skipped (use `style` and `className`).\n */\n attrs?(record: T): Record<string, string>\n /**\n * The card a mark opens when activated: a popover next to it, styled by the theme. Each\n * action is one undo step. The mark gets `aria-haspopup=\"dialog\"`, and `aria-expanded` true\n * while its card is open.\n */\n card?(record: T): CardSpec\n /** Runs when the mark is clicked, or activated with Enter or Space, after `card` opens. */\n onActivate?(record: T, mark: HTMLButtonElement): void\n}\n\nexport interface MarksHandle {\n /** Redraws every mark, for marks that read state outside the records. */\n refresh(): void\n /**\n * From now on, when records start to get a mark (added, or changed to pass `where`), the\n * viewer scrolls to the first of them in reading order, unless it is in view already. Records\n * a document opens with, and undo and redo, never scroll. Focus stays where it is. Returns\n * the handle.\n */\n scrollToFirst(): MarksHandle\n}\n\n/** Events stopped on a mark, so the viewer's root never sees a press on it. */\nconst STOPPED = ['pointerdown', 'pointerup', 'mousedown', 'mouseup', 'click'] as const\n\n/** Attributes the plugin's `attrs` cannot set: core sets them, or they have options of their own. */\nconst RESERVED = new Set(['style', 'class', 'type'])\n\n/** What a mark last had applied, so the next draw can drop what is no longer asked for. */\ninterface Applied<T> {\n record: T\n style: string[]\n attrs: string[]\n}\n\nexport function createMarks<T extends RecordBase & { page: number }>(\n ctx: PluginContext,\n records: Records<T>,\n opts: MarksOptions<T>\n): MarksHandle {\n const applied = new WeakMap<HTMLButtonElement, Applied<T>>()\n const marked = (record: T) => opts.where?.(record) ?? true\n\n const spec = opts.card?.bind(opts)\n const card =\n spec &&\n createCard(ctx, records, {\n spec,\n marked,\n marks: (root) =>\n [\n ...root.querySelectorAll<HTMLButtonElement>(\n `.ink-plugin-layer[data-plugin=\"${ctx.id}\"] > button`\n ),\n ].filter((mark) => applied.has(mark)),\n })\n\n /** What activating a mark does. */\n const activate = (record: T, mark: HTMLButtonElement) => {\n card?.open(record, mark)\n opts.onActivate?.(record, mark)\n }\n\n const create = (doc: Document): HTMLButtonElement => {\n const mark = doc.createElement('button')\n if (opts.className) mark.className = opts.className\n for (const type of STOPPED) mark.addEventListener(type, (e) => e.stopPropagation())\n // A button's click comes from Enter and Space too.\n mark.addEventListener('click', () => {\n const state = applied.get(mark)\n if (state) activate(state.record, mark)\n })\n return mark\n }\n\n /** Brings `mark` up to date with `record`, placed through `transform`. */\n const apply = (mark: HTMLButtonElement, record: T, transform: PageTransform) => {\n const prev = applied.get(mark)\n const style = (opts.style?.(record) ?? {}) as Record<string, string>\n const styleNames = Object.keys(style).map(toCssName)\n const attrs = Object.fromEntries(\n Object.entries(opts.attrs?.(record) ?? {}).filter(\n ([name]) => !RESERVED.has(name.toLowerCase())\n )\n )\n for (const name of prev?.style ?? [])\n if (!styleNames.includes(name)) mark.style.removeProperty(name)\n for (const key of prev?.attrs ?? []) if (!(key in attrs)) mark.removeAttribute(key)\n for (const [key, value] of Object.entries(style))\n mark.style.setProperty(toCssName(key), value)\n for (const [name, value] of Object.entries(attrs)) mark.setAttribute(name, value)\n // Core's own, whatever the plugin asked for.\n mark.type = 'button'\n mark.style.position = 'absolute'\n mark.dataset.record = record.id\n mark.dataset.plugin = ctx.id\n mark.setAttribute('aria-label', opts.label(record))\n if (card) {\n mark.setAttribute('aria-haspopup', 'dialog')\n mark.setAttribute('aria-expanded', String(card.expanded(mark)))\n }\n const r = transform.toCssRect(opts.rect(record))\n mark.style.left = `${r.left}px`\n mark.style.top = `${r.top}px`\n mark.style.width = `${r.width}px`\n mark.style.height = `${r.height}px`\n applied.set(mark, {\n record,\n style: styleNames,\n attrs: Object.keys(attrs),\n })\n }\n\n /**\n * Makes `el`'s marks match the page's records, in list order: marks that stay are moved,\n * new ones inserted, the rest removed.\n */\n const draw = (el: HTMLElement, page: number, transform: PageTransform) => {\n const list = records.list.get().filter((r) => r.page === page && marked(r))\n const ids = new Set(list.map((r) => r.id))\n const kept = new Map<string, HTMLButtonElement>()\n for (const mark of [...el.children] as HTMLButtonElement[]) {\n const id = mark.dataset.record\n if (id !== undefined && ids.has(id) && !kept.has(id)) kept.set(id, mark)\n else mark.remove()\n }\n let next = el.firstElementChild\n for (const record of list) {\n const mark = kept.get(record.id) ?? create(el.ownerDocument)\n apply(mark, record, transform)\n if (mark === next) next = mark.nextElementSibling\n else el.insertBefore(mark, next)\n }\n }\n\n let scrolling = false\n /** Ids that started to get a mark in the change under way, read once it settles. */\n const fresh = new Set<string>()\n\n /** Scrolls to the first fresh record still marked, so a batch of adds scrolls once. */\n const reveal = () => {\n const [first] = [...fresh]\n .map((id) => records.find(id))\n .filter((r): r is T => r !== undefined && marked(r))\n .sort(readingOrder((r) => opts.rect(r)))\n fresh.clear()\n if (first)\n ctx.scrollTo(first.page, opts.rect(first), {\n behavior: reducedMotion() ? 'instant' : 'smooth',\n })\n }\n\n /** Notes a record that starts to get a mark; replaces (undo, redo, reset) never count. */\n const watch = (change: RecordChange<T>) => {\n const record =\n change.kind === 'add'\n ? change.record\n : change.kind === 'update' && !marked(change.before)\n ? change.after\n : undefined\n if (!record || !marked(record)) return\n if (fresh.size === 0) queueMicrotask(reveal)\n fresh.add(record.id)\n }\n\n const layer = ctx.layer({ render: draw })\n ctx.onDocument(() => {\n const stopDraw = records.list.subscribe(() => layer.invalidate())\n const stopWatch = records.store()?.on('change', (change) => {\n if (scrolling) watch(change)\n })\n return () => {\n stopDraw()\n stopWatch?.()\n // A reveal still pending belongs to this document, not the next one.\n fresh.clear()\n }\n })\n const handle: MarksHandle = {\n refresh: () => layer.invalidate(),\n scrollToFirst() {\n scrolling = true\n return handle\n },\n }\n return handle\n}\n\n/** Page first, then top to bottom and left to right, by each record's rect in user space. */\nfunction readingOrder<T extends { page: number }>(rect: (record: T) => Rect) {\n return (a: T, b: T) => {\n const ra = rect(a)\n const rb = rect(b)\n return a.page - b.page || rb.y + rb.height - (ra.y + ra.height) || ra.x - rb.x\n }\n}\n\nfunction reducedMotion(): boolean {\n return globalThis.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false\n}\n\n/** `borderColor` → `border-color`, as `setProperty` takes it; `--custom` names stay as given. */\nfunction toCssName(key: string): string {\n return key.startsWith('--') ? key : key.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)\n}\n","/*\n * Links between a plugin's records and the annotations it creates from them. The link lives in\n * the annotation, as `custom.<plugin>.<records name> = <record id>`, so it survives a Gloss\n * export and import.\n */\nimport type { AnnotationEdit } from '../../../model/annotations/store'\nimport type {\n Annotation,\n AnnotationInput,\n AnnotationType,\n} from '../../../model/annotations/types'\nimport type { InkDocument } from '../../../model/document'\nimport type { RecordBase } from '../../../model/records'\n\n/** What `add` takes for annotations of type `K`. */\nexport type AnnotationInputOf<K extends AnnotationType> = AnnotationInput extends infer I\n ? I extends { type: infer U }\n ? K extends U\n ? I & { type: K }\n : never\n : never\n : never\n\ntype OmitEach<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never\n\nexport interface AnnotationLinkSpec<T extends RecordBase, K extends AnnotationType> {\n /** The annotation's fields for `record`. Without a colour it gets the type's default. */\n from(record: T): OmitEach<AnnotationInputOf<K>, 'type' | 'color'> & { color?: string }\n /** Runs once per linked annotation the user removes, inside that edit's undo step. */\n onRemoved?(record: T, annotation: Annotation): void\n /** Runs for each user update of a linked annotation, inside that edit's undo step. */\n onChanged?(record: T, annotation: Annotation): void\n}\n\nexport interface AnnotationLink<T extends RecordBase> {\n /** Adds an annotation made from `record` and linked to it; `undefined` with no document open. */\n add(record: T): Annotation | undefined\n /** The annotations of this link's type linked to `record`, in document order. */\n of(record: T): Annotation[]\n}\n\nexport interface LinkDeps<T extends RecordBase> {\n plugin: string\n /** The records name: the key under `custom.<plugin>`. */\n name: string\n onAnnotationEdit(fn: (edit: AnnotationEdit) => void): void\n /** The document the records belong to, or null while they are inert. */\n document(): InkDocument | null\n find(id: string): T | undefined\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/** Links `type` annotations to records; registers one `onAnnotationEdit` listener. */\nexport function createLink<T extends RecordBase, K extends AnnotationType>(\n deps: LinkDeps<T>,\n type: K,\n spec: AnnotationLinkSpec<T, K>\n): AnnotationLink<T> {\n const linkOf = (a: Annotation): string | undefined => {\n if (a.type !== type) return undefined\n const own = a.custom?.[deps.plugin]\n const id = isObject(own) ? own[deps.name] : undefined\n return typeof id === 'string' ? id : undefined\n }\n deps.onAnnotationEdit((edit) => {\n if (edit.kind === 'add') return\n const annotation = edit.kind === 'remove' ? edit.annotation : edit.after\n const id = linkOf(annotation)\n const record = id === undefined ? undefined : deps.find(id)\n if (!record) return\n if (edit.kind === 'remove') spec.onRemoved?.(record, annotation)\n else spec.onChanged?.(record, annotation)\n })\n return {\n add(record) {\n const doc = deps.document()\n if (!doc) return undefined\n const { color, custom, ...fields } = spec.from(record) as {\n color?: string\n custom?: Record<string, unknown>\n }\n const own = custom?.[deps.plugin]\n return doc.annotations.add({\n ...fields,\n type,\n color: color ?? doc.annotations.defaults.color(type),\n custom: {\n ...custom,\n [deps.plugin]: { ...(isObject(own) ? own : {}), [deps.name]: record.id },\n },\n } as AnnotationInput)\n },\n of(record) {\n const doc = deps.document()\n return doc ? doc.annotations.list.get().filter((a) => linkOf(a) === record.id) : []\n },\n }\n}\n","/*\n * A handle on one of a plugin's record stores that follows the open document, so a plugin\n * reads and writes its records without a null check. With no document open it reads empty and\n * its writes do nothing.\n */\nimport { derived, type Readable } from '../../../model/readable'\n\nimport { createLink, type AnnotationLink, type AnnotationLinkSpec } from './links'\n\nimport type { AnnotationEdit } from '../../../model/annotations/store'\nimport type { AnnotationType } from '../../../model/annotations/types'\nimport type { InkDocument } from '../../../model/document'\nimport type { RecordBase, RecordStore } from '../../../model/records'\n\nexport interface Records<T extends RecordBase> {\n /** The open document's records; `[]` while none is open. Emits when the document changes. */\n readonly list: Readable<readonly T[]>\n all(): readonly T[]\n find(id: string): T | undefined\n has(id: string): boolean\n /** Records whose fields equal (===) every field of `match`, or that pass it. */\n where(match: Partial<T> | ((record: T) => boolean)): T[]\n /**\n * Returns the stored record, or `undefined` with no document open. Throws\n * `InkError('DuplicateId')` when the id is taken; `addMissing` skips taken ids.\n *\n * Every write is one undo step, and `plugin.batch` makes several one step. A write after an\n * `await` goes to whatever document is open then: inside a command, write through `in(doc)`.\n */\n add(record: T): T | undefined\n /** Adds the records whose ids are not present yet, in one undo step; returns those added. */\n addMissing(records: readonly T[]): T[]\n update(id: string, patch: Partial<Omit<T, 'id'>>): T | undefined\n remove(id: string): T | undefined\n /**\n * The same handle bound to `doc`'s store, as it is when called. Empty and inert once `doc`\n * closes, and from the start when `doc` is not the open document.\n */\n in(doc: InkDocument): Records<T>\n /** The underlying store, or null; for anything the handle lacks. */\n store(): RecordStore<T> | null\n /**\n * Links these records to the `type` annotations made from them, as\n * `custom.<plugin>.<records name> = <record id>`. A record may have several. Each call listens\n * for annotation edits for the viewer's lifetime: call it in `setup`.\n */\n annotates<K extends AnnotationType>(\n type: K,\n spec: AnnotationLinkSpec<T, K>\n ): AnnotationLink<T>\n}\n\nconst EMPTY: readonly never[] = Object.freeze([])\n\n/** The list of whichever store `source` holds, `[]` for none; emits on swaps and changes. */\nfunction listOf<T extends RecordBase>(\n source: Readable<RecordStore<T> | null>\n): Readable<readonly T[]> {\n const read = (store: RecordStore<T> | null) => store?.list.get() ?? EMPTY\n return {\n get: () => read(source.get()),\n subscribe(fn) {\n let last = read(source.get())\n let stopList: (() => void) | undefined\n const emit = (next: readonly T[]) => {\n // A swap passes through null (`[]`) to the next store's list: one emit when both are empty.\n if (Object.is(next, last) || (next.length === 0 && last.length === 0)) return\n last = next\n fn(next)\n }\n const follow = (store: RecordStore<T> | null) => {\n stopList?.()\n stopList = store?.list.subscribe(emit)\n emit(read(store))\n }\n follow(source.get())\n const stopSource = source.subscribe(follow)\n return () => {\n stopSource()\n stopList?.()\n }\n },\n }\n}\n\nfunction matches<T extends RecordBase>(record: T, match: Partial<T>): boolean {\n return Object.entries(match).every(\n ([k, v]) => (record as Record<string, unknown>)[k] === v\n )\n}\n\nexport interface RecordsDeps {\n /** The plugin's `history.batch`. */\n batch(fn: () => void): void\n /**\n * The document the plugin's stores belong to now, or null. Not `ctx.document`, which changes\n * before the host swaps the stores.\n */\n storesDocument(): InkDocument | null\n /** The plugin's id. */\n plugin: string\n /** The records name. */\n name: string\n /** The plugin's `ctx.onAnnotationEdit`. */\n onAnnotationEdit(fn: (edit: AnnotationEdit) => void): void\n}\n\n/**\n * Builds a handle over `source`, a plugin store from `ctx.store`. Every call reads the store\n * `source` holds then.\n */\nexport function createRecords<T extends RecordBase>(\n deps: RecordsDeps,\n source: Readable<RecordStore<T> | null>,\n /** The handle `in` binds from: the unbound store, whatever this handle is bound to. */\n base: Readable<RecordStore<T> | null> = source\n): Records<T> {\n const current = () => source.get()\n const all = () => current()?.list.get() ?? EMPTY\n return {\n list: listOf(source),\n all,\n find: (id) => current()?.get(id),\n has: (id) => current()?.get(id) !== undefined,\n where: (match) =>\n all().filter(typeof match === 'function' ? match : (r) => matches(r, match)),\n add: (record) => current()?.add(record),\n addMissing(records) {\n const store = current()\n if (!store) return []\n const added: T[] = []\n deps.batch(() => {\n for (const record of records)\n if (!store.get(record.id)) added.push(store.add(record))\n })\n return added\n },\n update: (id, patch) => current()?.update(id, patch),\n remove: (id) => current()?.remove(id),\n in(doc) {\n // Captured now: the store only while `doc` is open, and that store only while it lasts\n // (closing `doc` swaps it for null or the next document's store).\n const captured = deps.storesDocument() === doc ? base.get() : null\n const bound = derived(base, (store) => (store && store === captured ? store : null))\n return createRecords(deps, bound, base)\n },\n store: current,\n annotates: (type, spec) =>\n createLink(\n {\n plugin: deps.plugin,\n name: deps.name,\n onAnnotationEdit: (fn) => deps.onAnnotationEdit(fn),\n document: () => (current() ? deps.storesDocument() : null),\n find: (id) => current()?.get(id),\n },\n type,\n spec\n ),\n }\n}\n","/*\n * The API a `definePlugin(id, setup)` plugin receives: its context plus shorthands for the\n * common jobs, each built on the public context alone.\n */\nimport { createCommand, type CommandOptions, type CommandRun } from './command'\nimport { createMarks, type MarksHandle, type MarksOptions } from './marks'\nimport { createRecords, type Records } from './records'\n\nimport type { InkDocument } from '../../../model/document'\nimport type { RecordBase } from '../../../model/records'\nimport type { Command, PluginContext, PluginStoreOptions } from '../define'\n\nexport interface PluginOptions {\n /** Store options by records name; `plugin.records(name)` picks them up. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- each name has its own record type\n records?: Record<string, PluginStoreOptions<any>>\n}\n\nexport interface PluginApi extends PluginContext {\n /**\n * A handle on the store `<plugin>.<name>` that follows the open document. Its options are\n * `opts` when given, else the host's `options.records[name]`. Call it once per name in\n * setup and keep the handle: a second call for the same name throws `InkError('DuplicateId')`.\n */\n records<T extends RecordBase>(name: string, opts?: PluginStoreOptions<T>): Records<T>\n /** Makes everything `fn` changes one undo step: `history.batch`. */\n batch(fn: () => void): void\n /**\n * Registers `<plugin>.<id>`. `run` gets the document open when it started and a signal that\n * aborts when that document closes or another opens. A returned string becomes the command's\n * status and `undefined` clears it; a failure is logged once and sets `errorStatus` (default\n * \"Something went wrong.\"). The status clears when the document changes.\n *\n * Inside a command, write through `records.in(doc)`.\n */\n command(id: string, label: string, run: CommandRun, opts?: CommandOptions): Command\n /**\n * Draws a `<button>` for each record that passes `where`, on page `record.page` at\n * `rect(record)`, in a layer of its own. The marks redraw when the records change; call\n * `refresh()` when they read state of your own that changed.\n */\n marks<T extends RecordBase & { page: number }>(\n records: Records<T>,\n opts: MarksOptions<T>\n ): MarksHandle\n}\n\nexport function createPluginApi(ctx: PluginContext, options: PluginOptions): PluginApi {\n let storesDocument: InkDocument | null = null\n // `onDocument` runs once the stores exist and cleans up after they are destroyed.\n ctx.onDocument((doc) => {\n storesDocument = doc\n return () => {\n storesDocument = null\n }\n })\n const batch = (fn: () => void) => ctx.history.batch(fn)\n return {\n ...ctx,\n records<T extends RecordBase>(name: string, opts?: PluginStoreOptions<T>) {\n const source = ctx.store<T>(name, opts ?? options.records?.[name])\n return createRecords<T>(\n {\n batch,\n storesDocument: () => storesDocument,\n plugin: ctx.id,\n name,\n onAnnotationEdit: (fn) => ctx.onAnnotationEdit(fn),\n },\n source\n )\n },\n batch,\n command: (id, label, run, opts) => createCommand(ctx, id, label, run, opts),\n marks: (records, opts) => createMarks(ctx, records, opts),\n }\n}\n","/*\n * A plugin is written once against `@inkbar/core` and runs in every binding. It contributes\n * commands, tools, decorations, page layers and its own record stores through the context its\n * `setup` receives; nothing it registers shows until the host places it (a command button, a\n * tool button). Everything it names is namespaced under its id: command `suggest` of plugin\n * `sandbox` is `sandbox.suggest`, and so are its tools and stores.\n */\nimport { InkError } from '../../model/errors'\n\nimport { createPluginApi, type PluginApi, type PluginOptions } from './api/api'\n\nimport type { AnnotationEdit } from '../../model/annotations/store'\nimport type { InkDocument } from '../../model/document'\nimport type { Rect } from '../../model/geometry'\nimport type { Readable } from '../../model/readable'\nimport type { RecordBase, RecordChange, RecordStore } from '../../model/records'\nimport type { DecorateAnnotation } from '../overlay'\nimport type { Tool } from '../tools/controller'\nimport type { PageTransform } from '../transform'\nimport type { IconNode } from '@inkbar/icons'\n\nexport interface InkPlugin {\n /** Lower-case kebab (/^[a-z][a-z0-9-]*$/); the namespace for everything the plugin adds. */\n readonly id: string\n /** Runs once per viewer. The returned function runs when the viewer is destroyed. */\n setup(ctx: PluginContext): void | (() => void)\n}\n\nexport interface CommandSpec {\n /** Namespaced to `<plugin>.<id>`. */\n id: string\n /** Names the command's button; must not be empty (`InkError('InvalidCommandLabel')`). */\n label: string\n icon?: IconNode\n /** Default: a document is open and ready. */\n enabled?: Readable<boolean>\n /** A short progress or result message, announced in a live region by the command button. */\n status?: Readable<string>\n /** May be async: the command is busy until the promise settles. */\n run(): void | Promise<void>\n}\n\nexport interface Command {\n /** `<plugin>.<spec id>`. */\n readonly id: string\n readonly label: string\n readonly icon: IconNode | undefined\n /** The spec's `enabled` (or a ready document), and not busy. */\n readonly enabled: Readable<boolean>\n /** True while the promise `run` returned is pending. */\n readonly busy: Readable<boolean>\n /** The spec's status, or `''` without one. */\n readonly status: Readable<string>\n /**\n * Does nothing while busy or disabled. Never rejects: a failure is logged, and one caused by\n * the document closing mid-run (`DocumentDestroyed`) is dropped silently.\n */\n run(): Promise<void>\n}\n\nexport interface LayerSpec {\n /** Draw into `el` for `page`. Called on mount, on every transform change and on invalidate. */\n render(el: HTMLElement, page: number, transform: PageTransform): void\n /** Optional teardown when the page unmounts. */\n destroy?(el: HTMLElement, page: number): void\n}\n\nexport interface PluginLayerHandle {\n /** Redraws `page`, or every mounted page without one. */\n invalidate(page?: number): void\n}\n\nexport interface PluginStoreOptions<T extends RecordBase> {\n /** The records a store starts with, called once for each document that opens. */\n initial?: (doc: InkDocument) => readonly T[]\n /** Called after every change with the list as it now stands. */\n onChange?: (list: readonly T[], change: RecordChange<T>) => void\n}\n\nexport interface PluginContext {\n /** The plugin's id. */\n readonly id: string\n readonly document: Readable<InkDocument | null>\n /**\n * The viewer's active history. `batch` makes everything `fn` changes, annotations and plugin\n * records alike, one undo step. Stores from `store` are tracked for you, and `onAnnotationEdit`\n * runs inside the edit's step.\n */\n readonly history: { batch(fn: () => void): void }\n /** The id of the activated annotation, or null. */\n readonly activated: Readable<string | null>\n setActivated(id: string | null): void\n /** The viewport container, or null while none is mounted. */\n readonly root: Readable<HTMLElement | null>\n commands: { add(spec: CommandSpec): Command }\n /** The tool's id becomes `<plugin>.<id>`. */\n tools: { add(tool: Tool): void }\n /** Composed after the host's own decoration and earlier plugins'; earlier ones win per key. */\n decorate(fn: DecorateAnnotation): void\n /**\n * Runs every decoration again for the open document's annotations. Decorations re-apply when\n * the annotations change; call this when one reads state of your own that changed instead.\n */\n redecorate(): void\n /**\n * A record store keyed `<plugin>.<name>`, created for each document that opens and tracked by\n * its history; null while no document is open. Inkbar keeps no plugin data: pass `initial`\n * and `onChange` to load and save it.\n */\n store<T extends RecordBase>(\n name: string,\n opts?: PluginStoreOptions<T>\n ): Readable<RecordStore<T> | null>\n /** Runs for each document that opens; the returned function runs when it closes. */\n onDocument(fn: (doc: InkDocument) => void | (() => void)): void\n /**\n * Runs for every user add, update and remove of an annotation, inside that edit's undo step,\n * so store changes made here undo with it. Never runs for undo and redo.\n */\n onAnnotationEdit(fn: (edit: AnnotationEdit) => void): void\n /** Adds a layer drawn on every mounted page, above the annotations. */\n layer(spec: LayerSpec): PluginLayerHandle\n /**\n * Scrolls the viewer so `rect` (user space on `page`) is in view, centring it when it was\n * not. Moves no focus. Does nothing while no document is shown.\n */\n scrollTo(page: number, rect: Rect, opts?: { behavior?: ScrollBehavior }): void\n}\n\n/** A factory's parameters: its options, optional only when `O` has no required field. */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- `{}` tests for no required field\ntype PluginFactoryArgs<O> = {} extends O\n ? [options?: O & PluginOptions]\n : [options: O & PluginOptions]\n\nconst PLUGIN_ID = /^[a-z][a-z0-9-]*$/\n\nfunction checkId(id: string): void {\n if (!PLUGIN_ID.test(id))\n throw new InkError(\n 'InvalidPluginId',\n `Plugin id ${JSON.stringify(id)} must be lower-case kebab`,\n {\n id,\n }\n )\n}\n\n/**\n * Checks the plugin's id and returns the plugin unchanged. Throws `InkError('InvalidPluginId')`\n * for an id that is not lower-case kebab.\n */\nexport function definePlugin(plugin: InkPlugin): InkPlugin\n/**\n * Checks the id now and returns a factory: `factory(options)` is a plugin whose setup receives\n * the plugin API and those options. Each call makes an independent plugin. The options may be\n * left out only when every field of `O` is optional.\n */\nexport function definePlugin<O extends object = object>(\n id: string,\n setup: (plugin: PluginApi, options: O & PluginOptions) => void | (() => void)\n): (...args: PluginFactoryArgs<O>) => InkPlugin\nexport function definePlugin<O extends object>(\n plugin: InkPlugin | string,\n setup?: (plugin: PluginApi, options: O & PluginOptions) => void | (() => void)\n): InkPlugin | ((options?: O & PluginOptions) => InkPlugin) {\n if (typeof plugin !== 'string') {\n checkId(plugin.id)\n return plugin\n }\n const id = plugin\n checkId(id)\n return (options = {} as O & PluginOptions) => ({\n id,\n setup: (ctx) => setup?.(createPluginApi(ctx, options), options),\n })\n}\n","import { InkError, isInkError } from '../../model/errors'\nimport { readonly, writable, type Readable } from '../../model/readable'\n\nimport type { Command, CommandSpec } from './define'\nimport type { InkDocument } from '../../model/document'\n\nexport interface CommandRegistry {\n readonly commands: ReadonlyMap<string, Command>\n /**\n * Registers `spec` as `<plugin>.<spec.id>`. Throws `InkError('DuplicateId')` when taken and\n * `InkError('InvalidCommandLabel')` for an empty label.\n */\n add(plugin: string, spec: CommandSpec): Command\n}\n\n/**\n * The error for a command id no plugin registered, naming the ids that were. Bindings log it\n * rather than throw, and show the control as it is before the plugins are set up.\n */\nexport function unknownCommand(id: string, registered: readonly string[]): InkError {\n const known = registered.length > 0 ? registered.join(', ') : 'none'\n return new InkError(\n 'UnknownCommand',\n `No plugin registered a command ${id} (registered: ${known})`,\n { id, registered }\n )\n}\n\nconst EMPTY: Readable<string> = { get: () => '', subscribe: () => () => {} }\n\n/**\n * A boolean readable computed from `sources`. Like `derived`, it subscribes to the sources only\n * while it has subscribers of its own; `watch` re-reads them, so a source can be swapped while\n * subscribed (a document's status when the document changes).\n */\nfunction computed(\n compute: () => boolean,\n watch: (changed: () => void) => () => void\n): Readable<boolean> {\n const subs = new Set<(v: boolean) => void>()\n let cached = false\n let stop: (() => void) | undefined\n const changed = () => {\n const next = compute()\n if (next === cached) return\n cached = next\n for (const sub of [...subs]) sub(next)\n }\n return {\n get: () => (stop ? cached : compute()),\n subscribe(sub) {\n if (!stop) {\n cached = compute()\n stop = watch(changed)\n }\n subs.add(sub)\n return () => {\n if (!subs.delete(sub) || subs.size > 0) return\n stop?.()\n stop = undefined\n }\n },\n }\n}\n\n/** True while `document` holds a document whose status is ready. */\nfunction documentReady(document: Readable<InkDocument | null>): Readable<boolean> {\n return computed(\n () => document.get()?.status.get().state === 'ready',\n (changed) => {\n let stopStatus: (() => void) | undefined\n const follow = (doc: InkDocument | null) => {\n stopStatus?.()\n stopStatus = doc?.status.subscribe(changed)\n changed()\n }\n const stopDocument = document.subscribe(follow)\n follow(document.get())\n return () => {\n stopDocument()\n stopStatus?.()\n }\n }\n )\n}\n\n/**\n * Plugin commands by namespaced id. A command is busy from `run()` until the promise its spec\n * returned settles, and is disabled meanwhile, so a double click runs it once.\n */\nexport function createCommandRegistry(opts: {\n document: Readable<InkDocument | null>\n}): CommandRegistry {\n const commands = new Map<string, Command>()\n const ready = documentReady(opts.document)\n\n return {\n commands,\n add(plugin, spec) {\n const id = `${plugin}.${spec.id}`\n if (commands.has(id))\n throw new InkError('DuplicateId', `A command with id ${id} already exists`, {\n id,\n })\n // The label names the command's button; without one it would have no accessible name.\n if (!spec.label.trim())\n throw new InkError('InvalidCommandLabel', `Command ${id} needs a label`, { id })\n const busy = writable(false)\n const allowed = spec.enabled ?? ready\n const enabled = computed(\n () => allowed.get() && !busy.get(),\n (changed) => {\n const stops = [allowed.subscribe(changed), busy.subscribe(changed)]\n return () => {\n for (const stop of stops) stop()\n }\n }\n )\n const command: Command = {\n id,\n label: spec.label,\n icon: spec.icon,\n enabled,\n busy: readonly(busy),\n status: spec.status ?? EMPTY,\n async run() {\n if (!enabled.get()) return\n busy.set(true)\n try {\n await spec.run()\n } catch (error) {\n // The document closing under a running command is expected, not a failure.\n if (!(isInkError(error) && error.code === 'DocumentDestroyed'))\n console.error(error)\n } finally {\n busy.set(false)\n }\n },\n }\n commands.set(id, command)\n return command\n },\n }\n}\n","/*\n * Plugin page layers. Each layer a plugin adds gets one element per mounted page of the main\n * viewport, `div.ink-plugin-layer[data-plugin=\"<id>\"]`, appended to the page host after the\n * annotation overlay and covering the page. The plugin draws into it in user space through the\n * page transform it is handed, which is the only conversion to CSS pixels it needs.\n *\n * A layer is drawn when its page mounts, whenever the page's transform changes (zoom,\n * rotation) and when the plugin invalidates it; it is torn down when the page unmounts. Layers\n * added after pages have mounted (from `onDocument`, say) appear on those pages at once.\n *\n * The layer element is `pointer-events: none`, so a press that misses the plugin's marks\n * reaches the overlay and the tools underneath. Its direct children default back to `auto`\n * through a rule core adopts into the layer's document (or shadow root), the same rule the\n * theme has: `:where(.ink-plugin-layer > *)`, so any rule of the plugin's own wins.\n * Presses and keys on those children are the plugin's: the tool controller leaves them alone.\n * Marks that take focus are Tab stops after the page's annotations, by DOM order.\n */\nimport type { LayerSpec, PluginLayerHandle } from './define'\nimport type { PageTransform } from '../transform'\n\n/** A layer as the host keeps it: the plugin's spec and the id of the plugin that added it. */\nexport type PluginLayer = LayerSpec & { readonly plugin: string }\n\n/**\n * What a layer source reports: a layer was added, or one asked to redraw.\n *\n * @internal For bindings, which mount plugin layers; not for plugin authors.\n */\nexport type LayerEvent =\n | { type: 'add'; layer: PluginLayer }\n | { type: 'invalidate'; layer: PluginLayer; page?: number | undefined }\n\n/**\n * Where page layers come from: a plugin host.\n *\n * @internal For bindings, which mount plugin layers; not for plugin authors.\n */\nexport interface LayerSource {\n readonly layers: readonly PluginLayer[]\n /** Calls `listener` for every layer added and every invalidate; returns a stop function. */\n watchLayers(listener: (event: LayerEvent) => void): () => void\n}\n\n/** The host's side of `ctx.layer`: records layers and passes their invalidates on. */\nexport interface LayerRegistry extends LayerSource {\n add(layer: PluginLayer): PluginLayerHandle\n}\n\nexport function createLayerRegistry(): LayerRegistry {\n const layers: PluginLayer[] = []\n const listeners = new Set<(event: LayerEvent) => void>()\n const emit = (event: LayerEvent) => {\n for (const listener of [...listeners]) listener(event)\n }\n return {\n layers,\n watchLayers(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n add(layer) {\n layers.push(layer)\n emit({ type: 'add', layer })\n return { invalidate: (page) => emit({ type: 'invalidate', layer, page }) }\n },\n }\n}\n\n/**\n * One page's plugin layers, made by `PluginLayers.mount`.\n *\n * @internal For bindings, which mount plugin layers; not for plugin authors.\n */\nexport interface PageLayers {\n update(transform: PageTransform): void\n destroy(): void\n}\n\n/** The plugin layers of one viewer's pages; see `createPluginLayers`. */\nexport interface PluginLayers {\n mount(page: number, host: HTMLElement, transform: PageTransform): PageLayers\n /** Stops following the source. Pages still mounted keep their layers until they unmount. */\n destroy(): void\n}\n\n/** Runs a plugin's drawing; a throw is logged so one plugin cannot break the page. */\nfunction guard(fn: () => void): void {\n try {\n fn()\n } catch (error) {\n console.error(error)\n }\n}\n\nconst CHILD_RULE = ':where(.ink-plugin-layer > *) { pointer-events: auto; }'\n/** One sheet per window: a constructed sheet can only be adopted in its own window. */\nconst childSheets = new WeakMap<object, CSSStyleSheet>()\n\n/**\n * Puts the children's `pointer-events: auto` rule in the document or shadow root `el` lives\n * in: an adopted sheet, again if the host has since replaced its adopted sheets, or one\n * `<style>` element where adopted sheets are missing. A layer not yet connected gets it on a\n * later draw, which calls this again.\n */\nfunction adoptChildRule(el: HTMLElement): void {\n if (!el.isConnected) return\n const root = el.getRootNode() as Document | ShadowRoot\n const doc = el.ownerDocument\n const win = doc.defaultView\n if (!root.adoptedStyleSheets || !win) {\n const parent = root === doc ? (doc.head ?? doc.documentElement) : root\n if ([...parent.children].some((c) => c.matches('style[data-ink-plugin-layer]')))\n return\n const style = doc.createElement('style')\n style.dataset.inkPluginLayer = ''\n style.textContent = CHILD_RULE\n parent.append(style)\n return\n }\n let sheet = childSheets.get(win)\n if (!sheet) {\n sheet = new win.CSSStyleSheet()\n sheet.replaceSync(CHILD_RULE)\n childSheets.set(win, sheet)\n }\n if (!root.adoptedStyleSheets.includes(sheet))\n root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet]\n}\n\ninterface MountedPage {\n host: HTMLElement\n transform: PageTransform\n elements: Map<PluginLayer, HTMLElement>\n}\n\n/**\n * Mounts `source`'s layers on the pages the engine mounts, and follows it: a layer added later\n * is drawn on every mounted page, and an invalidate redraws its page, or all of them.\n *\n * @internal For bindings, which mount plugin layers; plugin authors add a layer with\n * `ctx.layer`.\n */\nexport function createPluginLayers(source: LayerSource): PluginLayers {\n const pages = new Map<number, MountedPage>()\n\n const draw = (layer: PluginLayer, el: HTMLElement, page: number, t: PageTransform) => {\n adoptChildRule(el)\n guard(() => layer.render(el, page, t))\n }\n\n const add = (layer: PluginLayer, page: number, state: MountedPage) => {\n const el = state.host.ownerDocument.createElement('div')\n el.className = 'ink-plugin-layer'\n el.dataset.plugin = layer.plugin\n el.style.cssText = 'position:absolute;inset:0;pointer-events:none;'\n state.host.append(el)\n state.elements.set(layer, el)\n draw(layer, el, page, state.transform)\n }\n\n const stop = source.watchLayers((event) => {\n if (event.type === 'add') {\n for (const [page, state] of pages) add(event.layer, page, state)\n return\n }\n const redraw = (page: number, state: MountedPage) => {\n const el = state.elements.get(event.layer)\n if (el) draw(event.layer, el, page, state.transform)\n }\n if (event.page === undefined) for (const [page, state] of pages) redraw(page, state)\n else {\n const state = pages.get(event.page)\n if (state) redraw(event.page, state)\n }\n })\n\n return {\n mount(page, host, transform) {\n const state: MountedPage = { host, transform, elements: new Map() }\n pages.set(page, state)\n for (const layer of source.layers) add(layer, page, state)\n return {\n update(next) {\n state.transform = next\n for (const [layer, el] of state.elements) draw(layer, el, page, next)\n },\n destroy() {\n if (pages.get(page) === state) pages.delete(page)\n for (const [layer, el] of state.elements) {\n if (layer.destroy) guard(() => layer.destroy?.(el, page))\n el.remove()\n }\n state.elements.clear()\n },\n }\n },\n destroy: stop,\n }\n}\n","/*\n * The host runs each plugin's `setup` once and collects what it registers. Bindings and\n * `createViewer` build one per viewer and place its commands, tools, decoration and layers.\n *\n * Record stores and annotation reactions belong to a document. When a document opens the host\n * creates every requested store from its `initial`, has the history current then track it, and\n * registers every `onAnnotationEdit` with that history; then it runs the `onDocument`\n * callbacks. When the document closes it undoes that in order: untrack and unregister, destroy\n * the stores, then run the `onDocument` cleanups.\n */\nimport { InkError } from '../../model/errors'\nimport { readonly, writable, type Readable, type Writable } from '../../model/readable'\nimport { createRecordStore, type RecordBase, type RecordStore } from '../../model/records'\n\nimport { createCommandRegistry } from './commands'\nimport { createLayerRegistry, type LayerSource, type PluginLayer } from './layer'\n\nimport type {\n Command,\n InkPlugin,\n PluginContext,\n PluginLayerHandle,\n PluginStoreOptions,\n} from './define'\nimport type { PluginHistory } from '../../model/annotations/history'\nimport type { AnnotationEdit } from '../../model/annotations/store'\nimport type { InkDocument } from '../../model/document'\nimport type { AnnotationDecoration, DecorateAnnotation } from '../overlay'\nimport type { Tool } from '../tools/controller'\nimport type { Viewport } from '../viewport'\n\nexport interface PluginHostOptions {\n plugins: readonly InkPlugin[]\n document: Readable<InkDocument | null>\n /** The binding's active history, read when a document opens. */\n history: () => PluginHistory\n activated: Readable<string | null>\n setActivated(id: string | null): void\n root: Readable<HTMLElement | null>\n /** The host's own decoration, read on each call. */\n decorate?: () => DecorateAnnotation | undefined\n /** The viewer's viewport, read on each call; without one, `ctx.scrollTo` does nothing. */\n viewport?: () => Viewport | null | undefined\n}\n\nexport interface PluginHost extends LayerSource {\n readonly commands: ReadonlyMap<string, Command>\n command(id: string): Command | undefined\n readonly tools: readonly Tool[]\n /** The host's decoration first, then each plugin's in order; earlier ones win per key. */\n decorate: DecorateAnnotation\n /** Every layer added so far; `watchLayers` reports the ones added later and invalidates. */\n readonly layers: readonly PluginLayer[]\n /** Calls `listener` on every `ctx.redecorate()`; returns a stop function. */\n watchRedecorate(listener: () => void): () => void\n destroy(): void\n}\n\ninterface StoreRequest {\n key: string\n opts: PluginStoreOptions<RecordBase>\n current: Writable<RecordStore<RecordBase> | null>\n}\n\n/** What one open document holds; undone in reverse when it closes. */\ninterface Opened {\n doc: InkDocument\n stores: RecordStore<RecordBase>[]\n /** Untrack and unregister functions from the document's history. */\n detach: (() => void)[]\n cleanups: (() => void)[]\n}\n\n/**\n * `value` seen with `extra` laid over it, read-only. Everything else is read from and written to\n * `value` itself, and its methods are bound to it, so a method always runs on the original\n * (a class instance keeps its `#private` fields, and `this.id` is the plugin's own id).\n */\nfunction withProps<T extends object, U extends object>(value: T, extra: U): T & U {\n const bound = new Map<PropertyKey, { fn: unknown; bound: unknown }>()\n const own = (key: PropertyKey) => Object.hasOwn(extra, key)\n // An empty target, so a frozen `value` breaks no proxy invariant on the keys `extra` replaces;\n // only properties defined non-configurable through the proxy are mirrored onto it.\n return new Proxy(Object.create(null) as T & U, {\n get(_, key) {\n if (own(key)) return extra[key as keyof U]\n const v: unknown = Reflect.get(value, key, value)\n if (typeof v !== 'function') return v\n // The same bound function on each read, while the method stays the same.\n let entry = bound.get(key)\n if (entry?.fn !== v) {\n entry = { fn: v, bound: (v as (...a: unknown[]) => unknown).bind(value) }\n bound.set(key, entry)\n }\n return entry.bound\n },\n set: (_, key, v) => !own(key) && Reflect.set(value, key, v, value),\n defineProperty(target, key, d) {\n if (own(key) || !Reflect.defineProperty(value, key, d)) return false\n // A proxy may only report a non-configurable property its target has: mirror it there.\n const defined = Reflect.getOwnPropertyDescriptor(value, key)\n if (defined && !defined.configurable) Reflect.defineProperty(target, key, defined)\n return true\n },\n deleteProperty: (_, key) => !own(key) && Reflect.deleteProperty(value, key),\n has: (_, key) => own(key) || Reflect.has(value, key),\n ownKeys: () => [...new Set([...Reflect.ownKeys(value), ...Reflect.ownKeys(extra)])],\n getOwnPropertyDescriptor(target, key) {\n const d = Reflect.getOwnPropertyDescriptor(own(key) ? extra : value, key)\n // Configurable unless mirrored on the target as non-configurable (see `defineProperty`).\n const fixed = Reflect.getOwnPropertyDescriptor(target, key)?.configurable === false\n return d && { ...d, configurable: !fixed }\n },\n getPrototypeOf: () => Reflect.getPrototypeOf(value),\n })\n}\n\n/** Runs a plugin callback; a throw is logged so one plugin cannot break the others. */\nfunction guard<T>(fn: () => T): T | undefined {\n try {\n return fn()\n } catch (error) {\n console.error(error)\n return undefined\n }\n}\n\n/**\n * @internal For bindings and `createViewer`, which place a viewer's plugins; plugin authors use\n * `definePlugin` and never call it.\n */\nexport function createPluginHost(opts: PluginHostOptions): PluginHost {\n const seen = new Set<string>()\n for (const plugin of opts.plugins) {\n if (seen.has(plugin.id))\n throw new InkError(\n 'DuplicatePlugin',\n `A plugin with id ${plugin.id} is registered twice`,\n {\n id: plugin.id,\n }\n )\n seen.add(plugin.id)\n }\n\n const registry = createCommandRegistry({ document: opts.document })\n const tools: Tool[] = []\n const decorators: DecorateAnnotation[] = []\n const layers = createLayerRegistry()\n const requests: StoreRequest[] = []\n const documentFns: ((doc: InkDocument) => void | (() => void))[] = []\n const editFns: ((edit: AnnotationEdit) => void)[] = []\n const setupCleanups: (() => void)[] = []\n const redecorators = new Set<() => void>()\n let opened: Opened | null = null\n let destroyed = false\n\n /** Creates a requested store for the open document and has its history track it. */\n const openStore = (request: StoreRequest, state: Opened, history: PluginHistory) => {\n const store = createRecordStore(request.key, {\n initial: request.opts.initial?.(state.doc) ?? [],\n ...(request.opts.onChange && { onChange: request.opts.onChange }),\n })\n state.stores.push(store)\n state.detach.push(history.track(store))\n request.current.set(store)\n }\n\n const runOnDocument = (\n fn: (doc: InkDocument) => void | (() => void),\n state: Opened\n ) => {\n const cleanup = guard(() => fn(state.doc))\n if (typeof cleanup === 'function') state.cleanups.push(cleanup)\n }\n\n const open = (doc: InkDocument) => {\n const history = opts.history()\n const state: Opened = { doc, stores: [], detach: [], cleanups: [] }\n opened = state\n for (const request of requests) openStore(request, state, history)\n for (const fn of editFns) state.detach.push(history.react(fn))\n for (const fn of documentFns) runOnDocument(fn, state)\n }\n\n const close = () => {\n const state = opened\n if (!state) return\n opened = null\n for (const detach of state.detach) detach()\n for (const store of state.stores) store.destroy()\n for (const request of requests) request.current.set(null)\n for (const cleanup of state.cleanups.reverse()) guard(cleanup)\n }\n\n const contextFor = (plugin: InkPlugin): PluginContext => {\n const storeNames = new Set<string>()\n return {\n id: plugin.id,\n document: opts.document,\n history: { batch: (fn) => opts.history().batch(fn) },\n activated: opts.activated,\n setActivated: (id) => opts.setActivated(id),\n root: opts.root,\n commands: { add: (spec) => registry.add(plugin.id, spec) },\n tools: {\n add(tool) {\n const id = `${plugin.id}.${tool.id}`\n if (tools.some((t) => t.id === id))\n throw new InkError('DuplicateId', `A tool with id ${id} already exists`, {\n id,\n })\n tools.push(withProps(tool, { id }))\n },\n },\n decorate(fn) {\n decorators.push(fn)\n },\n redecorate() {\n for (const listener of [...redecorators]) listener()\n },\n store<T extends RecordBase>(name: string, storeOpts: PluginStoreOptions<T> = {}) {\n const key = `${plugin.id}.${name}`\n if (storeNames.has(name))\n throw new InkError('DuplicateId', `A store with key ${key} already exists`, {\n key,\n })\n storeNames.add(name)\n const request: StoreRequest = {\n key,\n opts: storeOpts as unknown as PluginStoreOptions<RecordBase>,\n current: writable<RecordStore<RecordBase> | null>(null),\n }\n requests.push(request)\n // Asked for while a document is open (from `onDocument`, say): create it now.\n if (opened) openStore(request, opened, opts.history())\n return readonly(request.current) as Readable<RecordStore<T> | null>\n },\n onDocument(fn) {\n documentFns.push(fn)\n if (opened) runOnDocument(fn, opened)\n },\n onAnnotationEdit(fn) {\n editFns.push(fn)\n if (opened) opened.detach.push(opts.history().react(fn))\n },\n layer(spec): PluginLayerHandle {\n return layers.add(withProps(spec, { plugin: plugin.id }))\n },\n scrollTo(page, rect, scrollOpts) {\n opts.viewport?.()?.scrollToRect(page, rect, scrollOpts)\n },\n }\n }\n\n for (const plugin of opts.plugins) {\n let cleanup: void | (() => void)\n try {\n cleanup = plugin.setup(contextFor(plugin))\n } catch (error) {\n // No host comes back to destroy, so undo the plugins already set up here.\n for (const done of setupCleanups.reverse()) guard(done)\n throw error\n }\n if (typeof cleanup === 'function') setupCleanups.push(cleanup)\n }\n\n const current = opts.document.get()\n if (current) open(current)\n const stopDocument = opts.document.subscribe((doc) => {\n close()\n if (doc) open(doc)\n })\n\n return {\n commands: registry.commands,\n command: (id) => registry.commands.get(id),\n tools,\n decorate(annotation) {\n const all = [opts.decorate?.(), ...decorators]\n let merged: AnnotationDecoration | undefined\n for (const fn of all) {\n const d = fn && guard(() => fn(annotation))\n if (!d) continue\n merged ??= {}\n if (d.data) merged = { ...merged, data: { ...d.data, ...merged.data } }\n if (d.classes)\n merged = { ...merged, classes: [...(merged.classes ?? []), ...d.classes] }\n if (merged.description === undefined && d.description !== undefined)\n merged = { ...merged, description: d.description }\n }\n return merged\n },\n layers: layers.layers,\n watchLayers: (listener) => layers.watchLayers(listener),\n watchRedecorate(listener) {\n // Wrapped, so the same listener added twice runs twice and each stop removes its own.\n const run = () => listener()\n redecorators.add(run)\n return () => {\n redecorators.delete(run)\n }\n },\n destroy() {\n if (destroyed) return\n destroyed = true\n stopDocument()\n close()\n for (const cleanup of setupCleanups.reverse()) guard(cleanup)\n },\n }\n}\n","import { createOverlay, type DecorateAnnotation, type Overlay } from './overlay'\nimport { createPageRenderer, type PageRenderer } from './page-renderer'\nimport { createTextLayer, type TextLayerHandle } from './text-layer'\n\nimport type { PluginLayers } from './plugins/layer'\nimport type { PageTransform } from './transform'\nimport type { AnnotationStore } from '../model/annotations/store'\nimport type { Annotation } from '../model/annotations/types'\nimport type { InkDocument } from '../model/document'\n\nexport interface PageMountOptions {\n document: InkDocument\n /** Zero-based page index. */\n page: number\n /** The page host (`div.ink-page`) from the viewport's `onMount`. */\n host: HTMLElement\n transform: PageTransform\n store: AnnotationStore\n onActivate?(id: string): void\n isCustom?(a: Annotation): boolean\n /** The app's data attributes and classes for each annotation element (see `OverlayOptions`). */\n decorate?: DecorateAnnotation\n /** Defaults to `window.devicePixelRatio`. */\n devicePixelRatio?: number\n /** Plugin layers, mounted above the overlay. The engine passes them for its pages only. */\n layers?: PluginLayers\n /**\n * Canvas and text layer failures, with the layer that failed (cancellations are not\n * reported).\n */\n onError?(error: unknown, layer: PageLayer): void\n /**\n * A layer finished without error: the canvas painted, or the text layer mounted or applied\n * an update. Pair it with `onError` to tell when a failed layer has recovered.\n */\n onRendered?(layer: PageLayer): void\n}\n\n/** The page layers that can fail and recover: the canvas and the text layer. */\nexport type PageLayer = 'canvas' | 'text'\n\nexport interface PageMount {\n readonly renderer: PageRenderer\n readonly textLayer: TextLayerHandle\n readonly overlay: Overlay\n update(transform: PageTransform): void\n destroy(): void\n}\n\n/**\n * Canvas, text layer, annotation overlay and any plugin layers for one page, stacked in that\n * order.\n */\nexport function createPageMount(opts: PageMountOptions): PageMount {\n const { document, page, host, transform } = opts\n const callbacks = (layer: PageLayer) => ({\n ...(opts.onError\n ? { onError: (error: unknown) => opts.onError?.(error, layer) }\n : {}),\n ...(opts.onRendered ? { onRendered: () => opts.onRendered?.(layer) } : {}),\n })\n const renderer = createPageRenderer({\n document,\n page,\n host,\n transform,\n ...(opts.devicePixelRatio === undefined\n ? {}\n : { devicePixelRatio: opts.devicePixelRatio }),\n ...callbacks('canvas'),\n })\n const textLayer = createTextLayer({\n document,\n page,\n host,\n transform,\n ...callbacks('text'),\n })\n const overlay = createOverlay({\n host,\n page,\n store: opts.store,\n transform,\n document,\n ...(opts.devicePixelRatio === undefined\n ? {}\n : { devicePixelRatio: opts.devicePixelRatio }),\n ...(opts.onActivate ? { onActivate: (id: string) => opts.onActivate?.(id) } : {}),\n ...(opts.isCustom\n ? { isCustom: (a: Annotation) => opts.isCustom?.(a) === true }\n : {}),\n ...(opts.decorate ? { decorate: opts.decorate } : {}),\n })\n const layers = opts.layers?.mount(page, host, transform)\n return {\n renderer,\n textLayer,\n overlay,\n update(next) {\n renderer.update(next)\n textLayer.update(next)\n overlay.update(next)\n layers?.update(next)\n },\n destroy() {\n layers?.destroy()\n overlay.destroy()\n textLayer.destroy()\n renderer.destroy()\n },\n }\n}\n","// Per-tool options (the shape kind, the highlight kind, the chosen signature…). They persist\n// per tool for the viewer's life: the engine keeps one registry across rebuilds, so reopening a\n// tool, or rebuilding the viewport, keeps its last options.\nimport { readonly, writable, type Readable, type Writable } from '../../model/readable'\n\nimport type { Tool, ToolId } from './controller'\n\nexport interface ToolOptions {\n /** The tool's current options. Throws a `RangeError` for an id no tool registered. */\n readable(id: ToolId): Readable<object>\n get(id: ToolId): object\n /** Merges `patch` into the tool's options. */\n merge(id: ToolId, patch: object): void\n /** Registers tools not seen yet, seeded from their `defaultOptions`; known ids keep theirs. */\n register(tools: readonly Tool[]): void\n}\n\nexport function createToolOptions(tools: readonly Tool[] = []): ToolOptions {\n const byId = new Map<ToolId, Writable<object>>()\n const views = new Map<ToolId, Readable<object>>()\n\n const entry = (id: ToolId): Writable<object> => {\n const w = byId.get(id)\n if (!w) throw new RangeError(`Unknown tool ${id}`)\n return w\n }\n\n function register(list: readonly Tool[]): void {\n for (const t of list) {\n if (byId.has(t.id)) continue\n const w = writable<object>({ ...(t.defaultOptions ?? {}) })\n byId.set(t.id, w)\n views.set(t.id, readonly(w))\n }\n }\n register(tools)\n\n return {\n readable(id) {\n entry(id)\n return views.get(id) as Readable<object>\n },\n get: (id) => entry(id).get(),\n merge(id, patch) {\n const w = entry(id)\n w.set({ ...w.get(), ...patch })\n },\n register,\n }\n}\n","// Move, resize and marquee for the two select tools.\n//\n// The marquee is `position:absolute; pointer-events:none` with left/top/width/height from the\n// drag. Moving annotations are shown with a temporary `transform: translate(...)` on their\n// overlay elements; a resizing one with `translate(...) scale(...)` from a `0 0` origin. A line\n// whose end is being dragged is hidden (`visibility`) and drawn into a temporary\n// `pointer-events:none` preview element beside it. All of these are geometry; their look comes\n// from the theme.\n//\n// Resize: a press on one of the overlay's corner handles (`[data-handle=nw|ne|sw|se]`, drawn\n// on a selected, unlocked annotation) drags that CSS corner while the opposite one stays put.\n// The new box is converted back to user space once, on release, and the annotation's rect and\n// points are scaled onto it in one `store.update`. Neither side goes below 1 pt. `Shift`, or\n// a type that always keeps its aspect (`keepsAspect`), keeps the box's aspect ratio. A free\n// text's corners are its text box's: the box takes the new size and `rect` and `fringe` are\n// refit around it (`resizedBox`). One with a fringe or a callout is shown resizing in a\n// preview element, as a line end is, since scaling its element would stretch the callout too.\n//\n// Line ends: a press on `[data-handle=start|end]` drags that end; the other stays put. A\n// callout's tip (`[data-handle=callout]`) drags the same way and moves `callout[0]` only, the\n// text box staying where it is (`movedTip`).\n//\n// Move: dragging a pressed annotation moves it, or, when it belongs to the selection, every\n// selected unlocked annotation, in one history step.\n//\n// Text boxes: a press inside one that can be edited (`canEditFreeText`) selects it and, on the\n// release, opens its editor with the caret where the press landed; it never moves the box. The\n// box moves by the band along its edge (`[data-ink-edge]`), or a speech bubble by its outline\n// and tail, as any annotation does. A locked or embedded box only selects.\n//\n// Under select-text, text markup is left to the overlay: a drag across it selects text, a\n// click selects it, and a press on empty space clears the annotation selection and starts a\n// text selection (Shift keeps it). Rectangle select (`marquee`) handles markup like any other\n// annotation and draws a marquee on empty space.\nimport { freeTextBox } from '../../model/annotations/callout'\nimport {\n MIN_SIZE,\n hasCallout,\n hasCornerHandles,\n hasRectGeometry,\n isTextMarkup,\n keepsAspect,\n movedEndpoint,\n movedTip,\n resizedBox,\n scaled,\n translated,\n} from '../../model/annotations/edit'\nimport { withoutReplies } from '../../model/annotations/threads'\nimport { rectFromPoints, rectsIntersect } from '../../model/geometry'\nimport { canEditFreeText, editFreeTextIn, editorFor } from '../freetext-editor'\nimport { annotationBox, handleBox, renderAnnotationContent } from '../overlay-render'\n\nimport { cssIn, type PageHit, type ToolContext } from './controller'\n\nimport type { Annotation } from '../../model/annotations/types'\nimport type { Point, Rect } from '../../model/geometry'\nimport type { CssRect, PageTransform } from '../transform'\n\ntype Corner = 'nw' | 'ne' | 'sw' | 'se'\ntype End = 'start' | 'end' | 'callout'\nconst CORNERS: readonly string[] = ['nw', 'ne', 'sw', 'se']\nconst ENDS: readonly string[] = ['start', 'end']\nconst CALLOUT = 'callout'\n\n/** Pointer travel, CSS px, before a press on an annotation becomes a move. */\nconst DRAG_THRESHOLD = 3\n\ntype Mode =\n | { kind: 'idle' }\n | {\n kind: 'press'\n id: string\n start: PageHit\n /** Pressed a member of a multi-selection: a click narrows the selection to it. */\n narrow: boolean\n }\n | { kind: 'move'; ids: string[]; start: PageHit; els: HTMLElement[] }\n | {\n kind: 'edit'\n id: string\n start: PageHit\n /** Where the press landed, for the caret. */\n caret: { clientX: number; clientY: number }\n }\n | { kind: 'marquee'; start: PageHit; el: HTMLElement; additive: boolean }\n | {\n kind: 'resize'\n id: string\n start: PageHit\n corner: Corner\n /** The annotation's CSS box when the press began. */\n box: CssRect\n el: HTMLElement | undefined\n /** Keeps its aspect ratio whatever the modifier keys. */\n locked: boolean\n /** Where the resized annotation is drawn instead of scaling `el`, for a free text. */\n preview: HTMLElement | undefined\n }\n | {\n kind: 'endpoint'\n id: string\n start: PageHit\n which: End\n /** Where the dragged end was when the press began, CSS px. */\n from: Point\n el: HTMLElement | undefined\n preview: HTMLElement\n }\n\nexport interface SelectionEdit {\n onPointerDown(e: PointerEvent, hit: PageHit | undefined, id?: string): boolean | void\n onPointerMove(e: PointerEvent, hit: PageHit | undefined): void\n onPointerUp(e: PointerEvent, hit: PageHit | undefined): void\n onPointerCancel(): void\n /** `Escape` clears the selection; `Delete` and `Backspace` remove the unlocked selected. */\n onKeyDown(e: KeyboardEvent): void\n /** Drops any gesture in progress without writing. */\n reset(): void\n}\n\nexport interface SelectionEditOptions {\n /** A press on empty space draws a marquee (rectangle select). Otherwise it is left alone. */\n marquee?: boolean\n}\n\nexport function createSelectionEdit(\n ctx: ToolContext,\n opts: SelectionEditOptions = {}\n): SelectionEdit {\n let mode: Mode = { kind: 'idle' }\n const batch = (fn: () => void): void => (ctx.history ? ctx.history.batch(fn) : fn())\n\n const reset = (): void => {\n if (mode.kind === 'marquee') mode.el.remove()\n if (mode.kind === 'move') {\n for (const el of mode.els) el.style.transform = ''\n ctx.root.removeAttribute('data-ink-dragging')\n }\n if (mode.kind === 'resize' && mode.el) {\n mode.el.style.transform = ''\n mode.el.style.transformOrigin = ''\n mode.el.style.visibility = ''\n }\n if (mode.kind === 'resize') mode.preview?.remove()\n if (mode.kind === 'endpoint') {\n mode.preview.remove()\n if (mode.el) mode.el.style.visibility = ''\n }\n mode = { kind: 'idle' }\n }\n\n const elementIn = (root: ParentNode, id: string): HTMLElement | undefined =>\n root.querySelector<HTMLElement>(`[data-annotation=\"${CSS.escape(id)}\"]`) ?? undefined\n\n const previewFor = (host: HTMLElement, a: Annotation): HTMLElement => {\n const preview = host.ownerDocument.createElement('div')\n preview.className = 'ink-annotation ink-edit-preview'\n preview.dataset.inkPreview = ''\n preview.dataset.type = a.type\n preview.style.cssText = 'position:absolute;pointer-events:none;'\n return preview\n }\n\n /** Shows `draft` in `preview` beside `el`, which is hidden meanwhile. */\n const showPreview = (\n preview: HTMLElement,\n el: HTMLElement | undefined,\n draft: Annotation,\n start: PageHit\n ): void => {\n drawPreview(preview, draft, start)\n if (el) el.style.visibility = 'hidden'\n // Beside the annotation in the overlay, so it paints where the annotation does.\n if (!preview.isConnected) (el?.parentElement ?? start.host).append(preview)\n }\n\n function startHandle(\n e: PointerEvent,\n hit: PageHit,\n a: Annotation,\n handle: string\n ): boolean {\n const el = elementIn(hit.host, a.id)\n if (CORNERS.includes(handle) && hasCornerHandles(a)) {\n const text = a.type === 'freetext'\n mode = {\n kind: 'resize',\n id: a.id,\n start: hit,\n corner: handle as Corner,\n box: text ? hit.transform.toCssRect(freeTextBox(a)) : handleBox(a, hit.transform),\n el,\n locked: keepsAspect(a),\n preview:\n text && (a.fringe !== undefined || hasCallout(a))\n ? previewFor(hit.host, a)\n : undefined,\n }\n } else if (\n (ENDS.includes(handle) && a.type === 'line') ||\n (handle === CALLOUT && hasCallout(a))\n ) {\n const preview = previewFor(hit.host, a)\n mode = {\n kind: 'endpoint',\n id: a.id,\n start: hit,\n which: handle as End,\n from: hit.transform.toCss(endOf(a, handle as End)!),\n el,\n preview,\n }\n } else {\n return false\n }\n // The annotation is already selected (it has handles): keep the overlay from\n // re-activating it.\n e.stopPropagation()\n e.preventDefault()\n return true\n }\n\n return {\n reset,\n onPointerDown(e, hit, annotationId) {\n if (!hit) return\n reset()\n if (annotationId !== undefined) {\n const a = ctx.store.get(annotationId)\n if (!a) return\n // Under select-text, text markup lets a drag through to text selection and the overlay\n // selects it on a click. Rectangle select treats it as any other annotation: it selects\n // on the press and a drag moves it, so it claims the press from the overlay.\n const markup = isTextMarkup(a)\n if (markup && !opts.marquee) return\n const handle = handleOf(e.target)\n if (handle !== undefined && !a.locked && startHandle(e, hit, a, handle))\n return true\n const selected = ctx.store.selection.get()\n if (e.shiftKey) {\n // Toggle membership ourselves; the overlay would replace the selection.\n e.stopPropagation()\n ctx.store.select(\n selected.includes(annotationId)\n ? selected.filter((s) => s !== annotationId)\n : [...selected, annotationId]\n )\n return\n }\n if (inText(e.target) && canEditFreeText(a, elementIn(hit.host, annotationId))) {\n // Selected here, not by the overlay, which would also take the press for a move.\n e.stopPropagation()\n ctx.store.select([annotationId])\n ctx.onActivate?.(annotationId)\n mode = {\n kind: 'edit',\n id: annotationId,\n start: hit,\n caret: { clientX: e.clientX, clientY: e.clientY },\n }\n e.preventDefault()\n return true\n }\n const narrow = selected.length > 1 && selected.includes(annotationId)\n // A press on a member of the selection keeps the selection, so it can move as one.\n // Otherwise the overlay selects and activates it once this capture-phase handler\n // returns, except markup, which the overlay would hold until the release.\n if (narrow) e.stopPropagation()\n else if (markup) {\n e.stopPropagation()\n ctx.store.select([annotationId])\n ctx.onActivate?.(annotationId)\n }\n mode = { kind: 'press', id: annotationId, start: hit, narrow }\n e.preventDefault()\n return true\n }\n if (!opts.marquee) {\n // Select text: an empty press drops the annotation selection and is left alone, so a\n // text selection starts as usual. Shift keeps the selection.\n if (!e.shiftKey) ctx.store.select([])\n return\n }\n const el = hit.host.ownerDocument.createElement('div')\n el.className = 'ink-marquee'\n el.dataset.inkMarquee = ''\n el.style.cssText = `position:absolute;pointer-events:none;left:${hit.css.x}px;top:${hit.css.y}px;width:0;height:0;`\n hit.host.append(el)\n mode = { kind: 'marquee', start: hit, el, additive: e.shiftKey }\n if (!e.shiftKey) ctx.store.select([])\n e.preventDefault()\n return true\n },\n onPointerMove(e) {\n if (mode.kind === 'idle') return\n // No button down: the release was missed, so drop the gesture. So does a start host\n // that scrolling has unmounted.\n if (e.buttons === 0 || !mode.start.host.isConnected) {\n reset()\n return\n }\n const { start } = mode\n if (mode.kind === 'edit') return\n if (mode.kind === 'resize') {\n const { box, el, preview } = mode\n const next = resizeCss(box, mode.corner, cornerAt(mode, e), minCss(start), {\n aspect: mode.locked || e.shiftKey,\n page: start.transform,\n })\n if (preview) {\n const a = ctx.store.get(mode.id)\n if (a?.type !== 'freetext') return\n const draft = { ...a, ...resizedBox(a, userBox(start.transform, next)) }\n showPreview(preview, el, draft, start)\n } else if (el) {\n // The drawn box's corner within the element, which may be padded past it.\n const ox = box.left - (parseFloat(el.style.left) || 0)\n const oy = box.top - (parseFloat(el.style.top) || 0)\n el.style.transformOrigin = `${ox}px ${oy}px`\n el.style.transform =\n `translate(${next.left - box.left}px, ${next.top - box.top}px) ` +\n `scale(${next.width / box.width}, ${next.height / box.height})`\n }\n return\n }\n if (mode.kind === 'endpoint') {\n const a = ctx.store.get(mode.id)\n if (!a) return\n const patch = endPatch(a, mode.which, endAt(mode, e))\n if (!patch) return\n showPreview(mode.preview, mode.el, { ...a, ...patch } as Annotation, start)\n return\n }\n const css = cssIn(start.host, e)\n const dx = css.x - start.css.x\n const dy = css.y - start.css.y\n if (mode.kind === 'press') {\n if (Math.hypot(dx, dy) < DRAG_THRESHOLD) return\n const a = ctx.store.get(mode.id)\n if (!a || a.locked) {\n mode = { kind: 'idle' }\n return\n }\n const selected = ctx.store.selection.get()\n // Text markup is anchored to its text, and may carry a comment: it moves only when it\n // is what the drag pressed, never along with the rest of a selection.\n const pressed = mode.id\n const ids = selected.includes(pressed)\n ? selected.filter((id) => {\n const m = ctx.store.get(id)\n return m !== undefined && !m.locked && (id === pressed || !isTextMarkup(m))\n })\n : [pressed]\n const els = ids\n .map((id) => elementIn(ctx.root, id))\n .filter((el): el is HTMLElement => el !== undefined)\n mode = { kind: 'move', ids, start, els }\n // The theme shows the move cursor everywhere until the release.\n ctx.root.setAttribute('data-ink-dragging', '')\n }\n if (mode.kind === 'move') {\n for (const el of mode.els) el.style.transform = `translate(${dx}px, ${dy}px)`\n return\n }\n mode.el.style.left = `${Math.min(start.css.x, css.x)}px`\n mode.el.style.top = `${Math.min(start.css.y, css.y)}px`\n mode.el.style.width = `${Math.abs(dx)}px`\n mode.el.style.height = `${Math.abs(dy)}px`\n },\n onPointerCancel() {\n reset()\n },\n onPointerUp(e) {\n const current = mode\n reset()\n if (current.kind !== 'idle' && !current.start.host.isConnected) return\n switch (current.kind) {\n case 'press':\n // A click on a member of a multi-selection: just that one, as the overlay would.\n if (current.narrow) {\n ctx.store.select([current.id])\n ctx.onActivate?.(current.id)\n }\n return\n case 'edit': {\n // Opened on the release, so the press's own focus change has already happened.\n const el = elementIn(current.start.host, current.id)\n const a = ctx.store.get(current.id)\n if (!el || !canEditFreeText(a, el) || editorFor(el)) return\n editFreeTextIn(ctx.store, el, a.id, ctx.viewport.transformFor(a.page), {\n caret: current.caret,\n })\n return\n }\n case 'move': {\n const { start } = current\n const end = start.transform.fromCss(cssIn(start.host, e))\n const dx = end.x - start.user.x\n const dy = end.y - start.user.y\n batch(() => {\n for (const id of current.ids) {\n const a = ctx.store.get(id)\n if (a && !a.locked) ctx.store.update(id, translated(a, dx, dy))\n }\n })\n return\n }\n case 'resize': {\n const { start, box } = current\n const next = resizeCss(\n box,\n current.corner,\n cornerAt(current, e),\n minCss(start),\n {\n aspect: current.locked || e.shiftKey,\n page: start.transform,\n }\n )\n if (\n next.left === box.left &&\n next.top === box.top &&\n next.width === box.width &&\n next.height === box.height\n )\n return\n const a = ctx.store.get(current.id)\n if (!a || a.locked) return\n const to = userBox(start.transform, next)\n if (a.type === 'freetext') {\n ctx.store.update(a.id, resizedBox(a, to))\n return\n }\n // A rect-shaped annotation's box is its rect; a point-based one's is its drawn box.\n const from = hasRectGeometry(a) ? a.rect : start.transform.fromCssRect(box)\n ctx.store.update(a.id, scaled(a, from, to))\n return\n }\n case 'endpoint': {\n const a = ctx.store.get(current.id)\n if (!a || a.locked) return\n const css = cssIn(current.start.host, e)\n if (css.x === current.start.css.x && css.y === current.start.css.y) return\n const patch = endPatch(a, current.which, endAt(current, e))\n if (patch) ctx.store.update(a.id, patch)\n return\n }\n case 'marquee': {\n const { start } = current\n const box = rectFromPoints(\n start.user,\n start.transform.fromCss(cssIn(start.host, e))\n )\n if (box.width === 0 && box.height === 0) return\n // Replies have no element on the page, so a marquee never picks them.\n const ids = withoutReplies(ctx.store.list.get())\n .filter((a) => a.page === start.page && rectsIntersect(a.rect, box))\n .map((a) => a.id)\n ctx.store.select(\n current.additive ? [...new Set([...ctx.store.selection.get(), ...ids])] : ids\n )\n return\n }\n default:\n }\n },\n onKeyDown(e) {\n if (e.key === 'Escape') {\n reset()\n ctx.store.select([])\n return\n }\n if (e.key !== 'Delete' && e.key !== 'Backspace') return\n // A focused annotation's overlay element owns the key (it removes that one annotation\n // and prevents the default); deleting the selection too would double-handle it.\n if (e.defaultPrevented) return\n const target = e.target instanceof Element ? e.target : null\n if (\n target?.closest(\n '[data-annotation], input, textarea, [contenteditable]:not([contenteditable=\"false\"])'\n )\n )\n return\n for (const id of ctx.store.selection.get()) {\n if (ctx.store.get(id)?.locked !== true) ctx.store.remove(id)\n }\n },\n }\n}\n\n/** The handle (`nw`, `start`, ...) a press landed on, if it landed on one. */\nfunction handleOf(target: EventTarget | null): string | undefined {\n if (!(target instanceof Element)) return undefined\n return target.closest('[data-handle]')?.getAttribute('data-handle') ?? undefined\n}\n\n/** True when a press landed inside a free text's drawn text box. */\nfunction inText(target: EventTarget | null): boolean {\n return target instanceof Element && target.closest('.ink-free-text') !== null\n}\n\n/** The point a line's end or a callout's tip handle sits on. */\nfunction endOf(a: Annotation, which: End): Point | undefined {\n if (which === 'callout') return hasCallout(a) ? a.callout[0] : undefined\n return a.type === 'line' ? a[which] : undefined\n}\n\n/** The patch that moves a line's end, or a callout's tip, to `to`; undefined for neither. */\nfunction endPatch(a: Annotation, which: End, to: Point): Partial<Annotation> | undefined {\n if (which === 'callout') return hasCallout(a) ? movedTip(a, to) : undefined\n return a.type === 'line' ? movedEndpoint(a, which, to) : undefined\n}\n\n/** A resized CSS box in user space, at least `MIN_SIZE` a side. */\nfunction userBox(t: PageTransform, css: CssRect): Rect {\n const r = t.fromCssRect(css)\n return {\n ...r,\n width: Math.max(MIN_SIZE, r.width),\n height: Math.max(MIN_SIZE, r.height),\n }\n}\n\n/** Draws `a` into the preview element at its own box. */\nfunction drawPreview(el: HTMLElement, a: Annotation, start: PageHit): void {\n const box = annotationBox(a, start.transform)\n el.style.left = `${box.left}px`\n el.style.top = `${box.top}px`\n el.style.width = `${box.width}px`\n el.style.height = `${box.height}px`\n renderAnnotationContent(el, a, start.transform)\n}\n\n/** Keeps a CSS point on the page. */\nfunction onPage(start: PageHit, x: number, y: number): Point {\n const { cssWidth, cssHeight } = start.transform\n return {\n x: Math.min(Math.max(x, 0), cssWidth),\n y: Math.min(Math.max(y, 0), cssHeight),\n }\n}\n\n/**\n * Where the dragged line end is now, in user space: where it started plus the pointer's\n * travel, kept on the page.\n */\nfunction endAt(\n mode: { start: PageHit; from: Point },\n e: { clientX: number; clientY: number }\n): Point {\n const { start, from } = mode\n const css = cssIn(start.host, e)\n return start.transform.fromCss(\n onPage(start, from.x + css.x - start.css.x, from.y + css.y - start.css.y)\n )\n}\n\n/**\n * Where the dragged corner is now: where it started plus the pointer's travel since the\n * press, kept on the page. Keeping the press's offset from the corner means a click on a\n * handle, with no drag, leaves the box as it was.\n */\nfunction cornerAt(\n mode: { start: PageHit; box: CssRect; corner: Corner },\n e: { clientX: number; clientY: number }\n): Point {\n const { start, box, corner } = mode\n const css = cssIn(start.host, e)\n const x = (corner[1] === 'w' ? box.left : box.left + box.width) + css.x - start.css.x\n const y = (corner[0] === 'n' ? box.top : box.top + box.height) + css.y - start.css.y\n return onPage(start, x, y)\n}\n\n/** `MIN_SIZE` points as CSS px on the press's page. */\nfunction minCss(start: PageHit): number {\n return start.transform.toCssLength(MIN_SIZE)\n}\n\n/**\n * `box` with its `corner` dragged to `p` and the opposite corner fixed, at least `min` a side.\n * With `aspect`, the box keeps its proportions: it scales by the larger of the two axes'\n * changes, kept on the page.\n */\nfunction resizeCss(\n box: CssRect,\n corner: Corner,\n p: Point,\n min: number,\n opts: { aspect: boolean; page: { cssWidth: number; cssHeight: number } }\n): CssRect {\n const west = corner[1] === 'w'\n const north = corner[0] === 'n'\n /** The fixed corner. */\n const fx = west ? box.left + box.width : box.left\n const fy = north ? box.top + box.height : box.top\n let width = Math.max(west ? fx - p.x : p.x - fx, min)\n let height = Math.max(north ? fy - p.y : p.y - fy, min)\n if (opts.aspect && box.width > 0 && box.height > 0) {\n // Room from the fixed corner to the page edge the dragged corner moves towards.\n const roomX = west ? fx : opts.page.cssWidth - fx\n const roomY = north ? fy : opts.page.cssHeight - fy\n const lo = min / Math.min(box.width, box.height)\n const hi = Math.min(roomX / box.width, roomY / box.height)\n const s = Math.min(\n Math.max(width / box.width, height / box.height, lo),\n Math.max(hi, lo)\n )\n width = box.width * s\n height = box.height * s\n }\n return {\n left: west ? fx - width : fx,\n top: north ? fy - height : fy,\n width,\n height,\n }\n}\n","// The controller writes two things to the root: `data-ink-tool=\"<id>\"` (a marker for themes\n// and tests; `data-tool` belongs to toolbar buttons) and `style.cursor` from the active tool.\n// Both are structural, and both are removed on destroy.\n//\n// `pointerdown` is listened for in the capture phase. The overlay stops propagation of presses\n// on annotation shapes other than text markup (so a creation tool never starts a drag from\n// one), but a capture listener on the root runs before that, so the controller can pass the\n// pressed annotation's id to the tool. Move, up and key events bubble normally.\n//\n// When a tool starts a gesture (its `onPointerDown` returns true) the controller captures the\n// pointer on the root, so the release still arrives when it happens outside. `pointercancel`\n// and `lostpointercapture` reach the tool as `onPointerCancel`. `touch-action` is left to the\n// theme or host: touch gestures are theirs to arbitrate.\n//\n// The controller tracks the pressed pointer. Switching tools mid-press cancels the old tool's\n// gesture and swallows that pointer's release, so the new tool never sees half a gesture.\n// `lostpointercapture` after a completed release is not a cancel. Only primary-button presses\n// and releases reach tools. The root's own inline cursor is restored on destroy.\n//\n// A one-shot tool (`kind: 'one-shot'`) is used once, then hands back to `select-text`. It is\n// ready until it reports what it made (`ctx.made`), then made, with `data-ink-made` on the\n// root. A press on empty page (a page or a gap between pages, not a scroll bar) while made, or\n// Escape, ends it (`ctx.done`), and the tool never sees that press. A press on another annotation switches to `select-text` and goes to it, so\n// the same press can drag: in either state, bar text markup, which switches only when made. Whether a press finds the tool\n// made is read before anything the press itself does: on the window when it is created, or on\n// the document once a free-text editor (which listens on the window) has committed. So a note\n// dropped by the press that closes its popover still counts as made. Removing everything it\n// made (Delete, undo, a controlled host refusing the add) returns the tool to ready; the\n// selection moving to something else switches to `select-text`.\n//\n// While made, a press on a made item or on its handles goes to the controller's own selection\n// editor (selection-edit.ts) instead of the tool, as under `select-text`: a drag moves it, a\n// handle resizes it, a press inside a made text box reopens its editor, and the tool stays on\n// and made. Escape in an editor on a made text box (opened that way, or by Enter or a\n// double-click) commits and ends the tool, as in a new box. Delete and\n// Backspace go to the selection editor too, so the made item can be removed without switching.\nimport { isTextMarkup } from '../../model/annotations/edit'\nimport {\n createToolStyle,\n type StyleGroup,\n type ToolStyle,\n} from '../../model/annotations/tool-style'\nimport { readonly, writable, type Readable } from '../../model/readable'\nimport { canEditFreeText, editFreeTextIn, editorFor } from '../freetext-editor'\n\nimport { createToolOptions, type ToolOptions } from './options'\nimport { createSelectionEdit, type SelectionEdit } from './selection-edit'\n\nimport type { AnnotationStore } from '../../model/annotations/store'\nimport type { Point } from '../../model/geometry'\nimport type { SignatureLibrary } from '../../model/signatures'\nimport type { SelectionQuads } from '../selection'\nimport type { Viewport, ViewportHit } from '../viewport'\nimport type { IconNode } from '@inkbar/icons'\n\nexport type BuiltinToolId =\n | 'select-text'\n | 'select'\n | 'highlight'\n | 'redact-area'\n | 'note'\n | 'shape'\n | 'freetext'\n | 'draw'\n | 'sketch'\n | 'signature'\n/** A built-in tool's id, or any id a host registers its own tool under. */\nexport type ToolId = BuiltinToolId | (string & {})\n\n/**\n * A one-shot tool switches back to `select-text` once it has made something and the user moves\n * on; a sticky tool stays on. A tool without a kind is sticky.\n */\nexport type ToolKind = 'one-shot' | 'sticky'\n\nexport interface PageHit extends ViewportHit {\n /** Pointer position in user space. */\n user: Point\n /** Pointer position relative to the page host's top-left, CSS px. */\n css: Point\n}\n\nexport interface ToolContext {\n store: AnnotationStore\n viewport: Viewport\n /** The element pointer and key events are listened on (the viewport container). */\n root: HTMLElement\n /** The live text selection as user-space quads, one entry per page. */\n selectionQuads(): SelectionQuads[]\n clearSelection(): void\n onActivate?(id: string): void\n /** The style each group creates with, shared with the style controls. */\n toolStyle: ToolStyle\n /** The active tool's current options. */\n options<O extends object>(): O\n /**\n * Groups a gesture's changes into one undo step (a group move). Without it each change is\n * its own step.\n */\n history?: { batch(fn: () => void): void }\n /** The signature templates the `signature` tool places. Without it, it places nothing. */\n signatures?: SignatureLibrary | undefined\n /**\n * A one-shot tool reports what it just made, already added and selected. Does nothing under\n * a sticky tool or with an empty list.\n */\n made(ids: readonly string[]): void\n /** Clears the selection and switches to `select-text`. */\n done(): void\n}\n\nexport interface Tool<O extends object = object> {\n id: ToolId\n /** The accessible name a toolbar button shows for a tool core has no label for. */\n label?: string\n /** The icon a toolbar button shows for a tool core has no icon for. */\n icon?: IconNode\n /** Default sticky. */\n kind?: ToolKind\n cursor: string\n /** Style group the tool creates into; select tools have none. */\n styleGroup?: StyleGroup\n /** Option defaults. Options persist per tool for the viewer's life. */\n defaultOptions?: O\n activate(ctx: ToolContext): void\n deactivate(): void\n /**\n * Runs in the capture phase, before the overlay sees the press. `annotationId` is set when\n * the press landed on an annotation; the overlay then selects and activates it (text markup\n * on a click, other types on the press), so tools other than the select tools should ignore\n * such presses. Calling `e.stopPropagation()` here keeps the overlay from handling it.\n * Return true when the press starts a gesture: the controller then captures the pointer\n * until it is released or cancelled.\n */\n onPointerDown?(\n e: PointerEvent,\n hit: PageHit | undefined,\n annotationId?: string\n ): boolean | void\n /**\n * A move with `e.buttons === 0` during a gesture means the release was missed (it happened\n * where no listener saw it): tools treat it as a cancel.\n */\n onPointerMove?(e: PointerEvent, hit: PageHit | undefined): void\n onPointerUp?(e: PointerEvent, hit: PageHit | undefined): void\n /** `pointercancel` or `lostpointercapture`: drop any gesture in progress without writing. */\n onPointerCancel?(e: PointerEvent): void\n onKeyDown?(e: KeyboardEvent): void\n}\n\nexport interface ToolController {\n readonly active: Readable<ToolId>\n /** Switches to the tool, first merging `options` into its options. */\n set(id: ToolId, options?: object): void\n /** Merges `patch` into a tool's options without switching to it. */\n setOptions(id: ToolId, patch: object): void\n options(id: ToolId): Readable<object>\n destroy(): void\n}\n\nexport interface ToolControllerOptions {\n /**\n * The controller adds `options`, `made` and `done`; `toolStyle` defaults to one of the\n * controller's own.\n */\n ctx: Omit<ToolContext, 'toolStyle' | 'options' | 'made' | 'done'> & {\n toolStyle?: ToolStyle\n }\n /** Default `'select-text'`. */\n initial?: ToolId\n tools: Tool[]\n /**\n * Where options live. Pass the same registry to each controller that replaces another (a\n * rebuild) so options persist; by default the controller keeps its own.\n */\n options?: ToolOptions\n}\n\n/** Host-relative CSS point for a client point. */\nexport function cssIn(host: HTMLElement, e: { clientX: number; clientY: number }): Point {\n const r = host.getBoundingClientRect()\n return { x: e.clientX - r.left, y: e.clientY - r.top }\n}\n\n/** Like `cssIn`, clamped to the host's box, so a drag past the page edge stops at the edge. */\nexport function clampedCssIn(\n host: HTMLElement,\n e: { clientX: number; clientY: number }\n): Point {\n const r = host.getBoundingClientRect()\n return {\n x: Math.min(Math.max(e.clientX - r.left, 0), r.width),\n y: Math.min(Math.max(e.clientY - r.top, 0), r.height),\n }\n}\n\n/** The mounted page under a client point, with the point in CSS px and user space. */\nexport function hitFor(\n ctx: ToolContext,\n e: { clientX: number; clientY: number }\n): PageHit | undefined {\n const hit = ctx.viewport.pageAtCss(e.clientX, e.clientY)\n if (!hit) return undefined\n const css = cssIn(hit.host, e)\n return { ...hit, css, user: hit.transform.fromCss(css) }\n}\n\nexport function createToolController(opts: ToolControllerOptions): ToolController {\n const byId = new Map(opts.tools.map((t) => [t.id, t]))\n const active = writable<ToolId>(opts.initial ?? 'select-text')\n let current: Tool | undefined\n const registry = opts.options ?? createToolOptions()\n registry.register(opts.tools)\n const ctx: ToolContext = {\n ...opts.ctx,\n // Read through, as a spread copies a getter's value once: the host's library may change.\n get signatures() {\n return opts.ctx.signatures\n },\n toolStyle:\n opts.ctx.toolStyle ??\n createToolStyle({\n store: opts.ctx.store,\n history: opts.ctx.history ?? { batch: (fn) => fn() },\n activeGroup: () => current?.styleGroup,\n active,\n }),\n // `current` is the activating tool already, so `activate` reads its own options.\n options: <O extends object>() => registry.get(current?.id ?? active.get()) as O,\n made(ids) {\n if (current?.kind !== 'one-shot' || ids.length === 0) return\n clearMade()\n made = [...ids]\n ctx.root.dataset.inkMade = ''\n stopMade = [\n ctx.store.list.subscribe(checkMade),\n ctx.store.selection.subscribe(checkMade),\n ]\n },\n done() {\n clearMade()\n ctx.store.select([])\n set('select-text')\n },\n }\n const originalCursor = ctx.root.style.cursor\n /** The pointer between a primary press and its release or cancel. */\n let pressed: number | undefined\n /** Pointers whose release belongs to a tool that is no longer active. */\n const swallow = new Set<number>()\n /** What the active one-shot tool made; undefined while it is ready. */\n let made: string[] | undefined\n let stopMade: (() => void)[] = []\n /** Whether the press now under way found the tool made (see the top of the file). */\n let pressFoundMade = false\n /** Moves and resizes what the active one-shot tool made. */\n let madeEdit: SelectionEdit | undefined\n /** The press now under way went to `madeEdit`, not the tool. */\n let editingMade = false\n\n function clearMade(): void {\n stopMade.forEach((stop) => stop())\n stopMade = []\n made = undefined\n delete ctx.root.dataset.inkMade\n }\n /** Leaves the made state when its items are gone, or switches when the selection moved on. */\n function checkMade(): void {\n if (!made) return\n const store = ctx.store\n if (!made.some((id) => (store.get(id) ?? store._getProposed(id)) !== undefined)) {\n clearMade()\n return\n }\n const selected = store.selection.get()\n if (!made.some((id) => selected.includes(id))) set('select-text')\n }\n\n /** True for events from a pointer other than the one whose press is live. */\n const foreign = (e: PointerEvent): boolean =>\n pressed !== undefined && pressed !== e.pointerId\n\n const readFirst = (): void => {\n pressFoundMade = made !== undefined\n }\n const readAfterEditor = (): void => {\n pressFoundMade ||= made !== undefined\n }\n const onDown = (e: PointerEvent): void => {\n if (!e.isPrimary || e.button !== 0 || inCustomContent(e.target)) return\n // One gesture at a time: a second pointer pressing mid-gesture is ignored.\n if (foreign(e)) return\n swallow.delete(e.pointerId)\n const target = e.target instanceof Element ? e.target : null\n const annotationId =\n target?.closest('[data-annotation]')?.getAttribute('data-annotation') ?? undefined\n if (current?.kind === 'one-shot') {\n // Empty page is a page or the gaps between pages, not the viewport's own scroll bars.\n if (pressFoundMade && annotationId === undefined && !onScrollBar(e, ctx.root)) {\n // No text selection starts. The press still bubbles, so a host's popover sees a\n // press outside it and closes.\n e.preventDefault()\n // The release belongs to no tool.\n swallow.add(e.pointerId)\n ctx.done()\n return\n }\n const a = annotationId === undefined ? undefined : ctx.store.get(annotationId)\n if (a && made?.includes(a.id) && madeEdit) {\n pressed = e.pointerId\n editingMade = true\n if (madeEdit.onPointerDown(e, hitFor(ctx, e), a.id) === true) capture(e.pointerId)\n return\n }\n // Text markup counts as another annotation once the tool has made something; while it\n // is ready the tool may claim the press (area redaction draws from it).\n if (a && (!isTextMarkup(a) || pressFoundMade)) set('select-text')\n }\n pressed = e.pointerId\n if (current?.onPointerDown?.(e, hitFor(ctx, e), annotationId) === true)\n capture(e.pointerId)\n }\n const onMove = (e: PointerEvent): void => {\n if (!e.isPrimary || foreign(e)) return\n // A buttonless move means the release was missed: the press is over (tools drop their\n // own gesture on the same signal), so another pointer may press again.\n const missed = pressed === e.pointerId && e.buttons === 0\n if (missed) pressed = undefined\n if (editingMade) {\n madeEdit?.onPointerMove(e, hitFor(ctx, e))\n if (missed) editingMade = false\n return\n }\n current?.onPointerMove?.(e, hitFor(ctx, e))\n }\n const onUp = (e: PointerEvent): void => {\n if (!e.isPrimary || e.button !== 0 || foreign(e)) return\n if (pressed === e.pointerId) pressed = undefined\n if (swallow.delete(e.pointerId)) {\n release(e.pointerId)\n return\n }\n if (editingMade) {\n editingMade = false\n madeEdit?.onPointerUp(e, hitFor(ctx, e))\n } else current?.onPointerUp?.(e, hitFor(ctx, e))\n release(e.pointerId)\n }\n const onCancel = (e: PointerEvent): void => {\n if (!e.isPrimary || foreign(e)) return\n // Capture is also lost when a completed release frees it: only a live press cancels.\n if (e.type === 'lostpointercapture' && pressed !== e.pointerId) return\n if (pressed === e.pointerId) pressed = undefined\n swallow.delete(e.pointerId)\n if (editingMade) {\n editingMade = false\n madeEdit?.onPointerCancel()\n } else current?.onPointerCancel?.(e)\n }\n const onKey = (e: KeyboardEvent): void => {\n if (inCustomContent(e.target)) return\n if (made && e.key === 'Escape' && !e.defaultPrevented) {\n e.preventDefault()\n ctx.done()\n return\n }\n if (made && (e.key === 'Delete' || e.key === 'Backspace')) {\n madeEdit?.onKeyDown(e)\n return\n }\n current?.onKeyDown?.(e)\n // Enter that no tool took edits the one selected text box, wherever focus is in the viewport.\n if (isViewportEnter(e, ctx.root)) editSelectedText(e)\n }\n /**\n * Escape in an editor on a made text box, however it was opened (a press inside, Enter, a\n * double-click): commits and ends the tool. Captured, as the editor keeps its keys to itself.\n */\n const onEditorEscape = (e: KeyboardEvent): void => {\n if (!made || e.key !== 'Escape' || e.isComposing || e.defaultPrevented) return\n const target = e.target instanceof Element ? e.target : null\n if (!target?.closest('[data-ink-editor]')) return\n const el = target.closest<HTMLElement>('[data-annotation]')\n const id = el?.getAttribute('data-annotation')\n if (!el || !id || !made.includes(id)) return\n e.preventDefault()\n e.stopPropagation()\n editorFor(el)?.close(true)\n ctx.done()\n }\n function editSelectedText(e: KeyboardEvent): void {\n const selected = ctx.store.selection.get()\n if (selected.length !== 1) return\n const id = selected[0]!\n const a = ctx.store.get(id)\n const el = ctx.root.querySelector<HTMLElement>(\n `[data-annotation=\"${CSS.escape(id)}\"]`\n )\n if (!canEditFreeText(a, el) || !el) return\n e.preventDefault()\n editFreeTextIn(ctx.store, el, id, ctx.viewport.transformFor(a.page))\n }\n\n // Capture is best effort: synthetic events may carry a pointer id the browser does not know.\n function capture(id: number): void {\n try {\n ctx.root.setPointerCapture?.(id)\n } catch {\n // Not an active pointer: the gesture still works while the pointer stays over the root.\n }\n }\n function release(id: number): void {\n try {\n if (ctx.root.hasPointerCapture?.(id)) ctx.root.releasePointerCapture(id)\n } catch {\n // Already released.\n }\n }\n const doc = ctx.root.ownerDocument\n doc.defaultView?.addEventListener('pointerdown', readFirst, { capture: true })\n doc.addEventListener('pointerdown', readAfterEditor, { capture: true })\n ctx.root.addEventListener('pointerdown', onDown, { capture: true })\n ctx.root.addEventListener('pointermove', onMove)\n ctx.root.addEventListener('pointerup', onUp)\n ctx.root.addEventListener('pointercancel', onCancel)\n ctx.root.addEventListener('lostpointercapture', onCancel)\n ctx.root.addEventListener('keydown', onKey)\n ctx.root.addEventListener('keydown', onEditorEscape, { capture: true })\n\n function set(id: ToolId, options?: object): void {\n const next = byId.get(id)\n if (!next) throw new RangeError(`Unknown tool ${id}`)\n if (options) registry.merge(id, options)\n if (pressed !== undefined) {\n // Mid-press: end the old tool's gesture here and keep its release from the new tool.\n if (editingMade) madeEdit?.onPointerCancel()\n else\n current?.onPointerCancel?.(\n new PointerEvent('pointercancel', { pointerId: pressed, isPrimary: true })\n )\n swallow.add(pressed)\n pressed = undefined\n }\n editingMade = false\n madeEdit?.reset()\n current?.deactivate()\n // After `deactivate`, which may commit an open edit and report it made.\n clearMade()\n current = next\n madeEdit = next.kind === 'one-shot' ? createSelectionEdit(ctx) : undefined\n next.activate(ctx)\n ctx.root.dataset.inkTool = id\n ctx.root.style.cursor = next.cursor\n active.set(id)\n }\n set(opts.initial ?? 'select-text')\n\n return {\n active: readonly(active),\n set,\n setOptions(id, patch) {\n if (!byId.has(id)) throw new RangeError(`Unknown tool ${id}`)\n registry.merge(id, patch)\n },\n options(id) {\n if (!byId.has(id)) throw new RangeError(`Unknown tool ${id}`)\n return registry.readable(id)\n },\n destroy() {\n madeEdit?.reset()\n madeEdit = undefined\n current?.deactivate()\n clearMade()\n current = undefined\n doc.defaultView?.removeEventListener('pointerdown', readFirst, { capture: true })\n doc.removeEventListener('pointerdown', readAfterEditor, { capture: true })\n ctx.root.removeEventListener('pointerdown', onDown, { capture: true })\n ctx.root.removeEventListener('pointermove', onMove)\n ctx.root.removeEventListener('pointerup', onUp)\n ctx.root.removeEventListener('pointercancel', onCancel)\n ctx.root.removeEventListener('lostpointercapture', onCancel)\n ctx.root.removeEventListener('keydown', onKey)\n ctx.root.removeEventListener('keydown', onEditorEscape, { capture: true })\n delete ctx.root.dataset.inkTool\n ctx.root.style.cursor = originalCursor\n },\n }\n}\n\n/**\n * True for an unmodified, unhandled Enter on the viewport's own elements: the scroll element\n * (`root`), a page host, or content of a page's text layer or canvas layer. Every other target\n * (annotations, custom slot content, any control a host puts in the page) keeps its Enter.\n * This is the keyboard trigger for the creation tools.\n */\nexport function isViewportEnter(e: KeyboardEvent, root: HTMLElement): boolean {\n if (e.key !== 'Enter' || e.defaultPrevented) return false\n if (e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || e.isComposing) return false\n const target = e.target\n if (target === root) return true\n if (!(target instanceof Element) || !root.contains(target)) return false\n if (target.matches('.ink-page[data-page]')) return true\n return target.closest('[data-ink-text-layer], [data-ink-canvas-layer]') !== null\n}\n\n/**\n * True for a press on `root` itself outside its client area: on a scroll bar (or its border).\n * Client coordinates only, so a synthetic press gives the same answer as a real one.\n */\nfunction onScrollBar(e: PointerEvent, root: HTMLElement): boolean {\n if (e.target !== root) return false\n const r = root.getBoundingClientRect()\n const x = e.clientX - r.left - root.clientLeft\n const y = e.clientY - r.top - root.clientTop\n return x < 0 || y < 0 || x >= root.clientWidth || y >= root.clientHeight\n}\n\n/**\n * True for a target inside a custom annotation element (`data-custom`) but not that element\n * itself: the host's buttons and inputs there own their presses and keys, as in the overlay.\n */\nfunction inCustomContent(target: EventTarget | null): boolean {\n if (!(target instanceof Element)) return false\n // A free-text editor's presses and keys are its own, too, and so are a plugin layer's\n // marks. The layer element itself lets presses through to the page underneath.\n if (target.closest('[data-ink-editor]')) return true\n const layer = target.closest('.ink-plugin-layer')\n if (layer && layer !== target) return true\n const el = target.closest('[data-annotation]')\n return (\n el !== null &&\n el !== target &&\n el.hasAttribute('data-custom') &&\n // Resize handles are the overlay's, not the host's content.\n target.closest('[data-handle]') === null\n )\n}\n","// Freehand stroke capture, shared by `draw` and `sketch`. A press-drag-release is one stroke:\n// samples come from coalesced pointer events where the browser has them, with pen and touch\n// pressure, and a live preview paints the stroke as the ink it will become. The tool decides\n// what a finished stroke writes.\nimport { outlinePath, strokeOutline } from '../ink-stroke'\n\nimport {\n clampedCssIn,\n type PageHit,\n type Tool,\n type ToolContext,\n type ToolId,\n} from './controller'\n\nimport type { AnnotationInput } from '../../model/annotations/types'\nimport type { Point } from '../../model/geometry'\n\nconst SVG_NS = 'http://www.w3.org/2000/svg'\n\n/** A finished stroke, in user space. */\nexport interface FreehandStroke {\n page: number\n points: Point[]\n /**\n * One value per point, 0 to 1, from a pen or touch that reports real pressure; undefined for\n * a mouse, or a device that only ever reports 0 or 0.5.\n */\n pressure: number[] | undefined\n /** When the press happened (`Date.now()`). */\n startedAt: number\n}\n\nexport interface FreehandOptions {\n id: ToolId\n /** Writes a finished stroke. */\n commit(ctx: ToolContext, stroke: FreehandStroke): void\n /** Escape, or the tool deactivating. */\n end?(): void\n /** The tool deactivating (a tool switch, or the controller's destroy). */\n deactivate?(): void\n}\n\n/** A stroke being drawn: its page, and each sample in CSS px (host-relative) and user space. */\ninterface Stroke {\n from: PageHit\n css: Point[]\n user: Point[]\n /** One value per sample for pen and touch, else undefined. */\n pressure: number[] | undefined\n startedAt: number\n}\n\n/** Pressure from a device that reports it, else undefined. Shared with the signature pad. */\nexport function pressureOf(e: PointerEvent): number | undefined {\n if (e.pointerType !== 'pen' && e.pointerType !== 'touch') return undefined\n // Two decimals: the device's float32 noise has no place in the saved file.\n return Math.round(Math.min(Math.max(e.pressure, 0), 1) * 100) / 100\n}\n\n/** True when the samples carry real pressure: not all 0 or 0.5, the values of a device with none. */\nexport function reportsPressure(samples: readonly number[]): boolean {\n return samples.some((p) => p !== 0 && p !== 0.5)\n}\n\n/**\n * A tool in the `ink` style group that captures freehand strokes and previews them in\n * `.ink-draft[data-ink-draft=<id>]`.\n */\nexport function freehandTool(opts: FreehandOptions): Tool {\n let ctx: ToolContext | undefined\n let stroke: Stroke | undefined\n let draft: HTMLElement | undefined\n\n const clear = (): void => {\n draft?.remove()\n draft = undefined\n stroke = undefined\n }\n\n /** Adds a sample. A release reports 0 pressure, so it repeats the last sample's instead. */\n const sample = (s: Stroke, e: PointerEvent, release = false): void => {\n const css = clampedCssIn(s.from.host, e)\n s.css.push(css)\n s.user.push(s.from.transform.fromCss(css))\n const p = release ? s.pressure?.[s.pressure.length - 1] : pressureOf(e)\n if (p !== undefined) (s.pressure ??= []).push(p)\n }\n\n const paint = (c: ToolContext, s: Stroke): void => {\n const host = s.from.host\n const doc = host.ownerDocument\n if (!draft) {\n draft = doc.createElement('div')\n draft.className = 'ink-draft'\n draft.dataset.inkDraft = opts.id\n draft.style.position = 'absolute'\n draft.style.pointerEvents = 'none'\n draft.style.left = '0'\n draft.style.top = '0'\n host.append(draft)\n }\n draft.style.width = `${host.clientWidth}px`\n draft.style.height = `${host.clientHeight}px`\n const blank: AnnotationInput & { type: 'ink' } = {\n type: 'ink',\n page: s.from.page,\n inklist: [[]],\n }\n const style = c.toolStyle.resolve('ink', blank)\n const path = doc.createElementNS(SVG_NS, 'path')\n path.setAttribute(\n 'd',\n outlinePath(\n strokeOutline(s.css, s.pressure, s.from.transform.toCssLength(style.width ?? 2))\n )\n )\n path.setAttribute('fill', style.color ?? '#000000')\n if (style.opacity !== undefined) path.setAttribute('opacity', String(style.opacity))\n const svg = doc.createElementNS(SVG_NS, 'svg')\n svg.setAttribute('width', String(host.clientWidth))\n svg.setAttribute('height', String(host.clientHeight))\n svg.style.overflow = 'visible'\n svg.append(path)\n draft.replaceChildren(svg)\n }\n\n return {\n id: opts.id,\n kind: 'sticky',\n cursor: 'crosshair',\n styleGroup: 'ink',\n activate(c) {\n ctx = c\n },\n deactivate() {\n clear()\n opts.end?.()\n opts.deactivate?.()\n ctx = undefined\n },\n onPointerDown(e, hit) {\n if (!hit) return\n stroke = {\n from: hit,\n css: [],\n user: [],\n pressure: undefined,\n startedAt: Date.now(),\n }\n sample(stroke, e)\n // Drawing over an annotation draws; it neither selects it nor starts a text selection.\n e.stopPropagation()\n e.preventDefault()\n return true\n },\n onPointerMove(e) {\n if (!ctx || !stroke) return\n // No button down: the release was missed, so drop the stroke. A host scrolled out of the\n // mounted range is gone with it.\n if (e.buttons === 0 || !stroke.from.host.isConnected) {\n clear()\n return\n }\n const coalesced = e.getCoalescedEvents?.() ?? []\n for (const ev of coalesced.length > 0 ? coalesced : [e]) sample(stroke, ev)\n paint(ctx, stroke)\n },\n onPointerCancel() {\n clear()\n },\n onPointerUp(e) {\n if (!ctx || !stroke) return\n const s = stroke\n if (!s.from.host.isConnected) {\n clear()\n return\n }\n const last = s.css[s.css.length - 1]!\n const end = clampedCssIn(s.from.host, e)\n if (end.x !== last.x || end.y !== last.y) sample(s, e, true)\n clear()\n opts.commit(ctx, {\n page: s.from.page,\n points: s.user,\n pressure: s.pressure && reportsPressure(s.pressure) ? s.pressure : undefined,\n startedAt: s.startedAt,\n })\n },\n onKeyDown(e) {\n if (e.key !== 'Escape') return\n // Drops a stroke in progress too, so the release that follows commits nothing.\n clear()\n opts.end?.()\n },\n }\n}\n","// Freehand ink. A press-drag-release is one stroke; strokes that start within JOIN_GAP_MS of\n// the last one join its annotation, so a handwritten word stays one object. Each stroke is its\n// own undo step: the first is an `add`, the rest are `update`s that append to `inklist`.\n// Switching tools or pressing Escape ends the annotation. Pen and touch report pressure;\n// a mouse, or a device that always reports 0 or 0.5, leaves it out.\nimport { deriveRect } from '../../model/annotations/store'\nimport { JOIN_GAP_MS } from '../ink-stroke'\n\nimport { freehandTool } from './freehand'\n\nimport type { Tool, ToolContext } from './controller'\nimport type { InkAnnotation } from '../../model/annotations/types'\nimport type { Point } from '../../model/geometry'\n\n/** The annotation later strokes join, until the gap passes or something ends it. */\ninterface Session {\n id: string\n page: number\n endedAt: number\n}\n\nexport function drawTool(): Tool {\n let session: Session | undefined\n\n const join = (\n c: ToolContext,\n ink: InkAnnotation,\n points: Point[],\n pressure: number[] | undefined\n ): void => {\n const inklist = [...ink.inklist, points]\n // A stroke without pressure takes 0.5 throughout, which draws as no pressure does.\n const even = (p: Point[]): number[] => p.map(() => 0.5)\n const next =\n ink.pressure || pressure\n ? [...(ink.pressure ?? ink.inklist.map(even)), pressure ?? even(points)]\n : undefined\n c.store.update(ink.id, {\n inklist,\n pressure: next,\n rect: deriveRect({ type: 'ink', page: ink.page, inklist, width: ink.width }),\n })\n }\n\n return freehandTool({\n id: 'draw',\n end() {\n session = undefined\n },\n /** Appends the stroke to the live session's annotation, else starts a new one. */\n commit(c, s) {\n // The gap runs from the last stroke's release to this one's press. Under a host that\n // applies changes later, the last stroke may be proposed but not yet applied.\n const joined = session\n const current =\n joined && joined.page === s.page && s.startedAt - joined.endedAt <= JOIN_GAP_MS\n ? (c.store._getProposed(joined.id) ?? c.store.get(joined.id))\n : undefined\n if (current?.type === 'ink' && !current.locked) {\n join(c, current, s.points, s.pressure)\n session = { id: current.id, page: current.page, endedAt: Date.now() }\n return\n }\n const added = c.store.add(\n c.toolStyle.resolve('ink', {\n type: 'ink',\n page: s.page,\n inklist: [s.points],\n ...(s.pressure ? { pressure: [s.pressure] } : {}),\n })\n )\n session = { id: added.id, page: added.page, endedAt: Date.now() }\n },\n })\n}\n","// A click places a text box with its top-left corner at the press, a drag sizes one, and Enter\n// on the viewport places one at the centre of the current page. Each new box opens straight\n// into the in-place editor, and joins the store, selected, once it has text. The live draft is\n// `.ink-draft[data-ink-draft='freetext']`, `position:absolute; pointer-events:none`: geometry\n// only, the look is the theme's.\nimport { closedEditor, editFreeText, type FreeTextEditor } from '../freetext-editor'\nimport { renderAnnotationContent } from '../overlay-render'\n\nimport {\n clampedCssIn,\n isViewportEnter,\n type PageHit,\n type Tool,\n type ToolContext,\n} from './controller'\n\nimport type { AnnotationInput } from '../../model/annotations/types'\nimport type { CssRect } from '../transform'\n\ntype FreeTextInput = Extract<AnnotationInput, { type: 'freetext' }>\n\n/** Width of a box placed with a click or Enter, user-space points. */\nexport const DEFAULT_FREETEXT_WIDTH = 144\n\n/** Line height as a multiple of the font size, as the theme sets it. */\nconst LINE_HEIGHT = 1.2\n\n/** Font size a box gets when neither the text group nor the input sets one, points. */\nconst FONT_SIZE = 12\n\n/** Smallest drag, in CSS px on each axis, that sizes a box rather than counting as a click. */\nconst MIN_CSS = 3\n\nexport function freetextTool(): Tool {\n let ctx: ToolContext | undefined\n let start: PageHit | undefined\n let draft: HTMLElement | undefined\n\n const clear = (): void => {\n draft?.remove()\n draft = undefined\n start = undefined\n }\n\n /** The new box being typed into: it joins the store on its first non-empty commit. */\n let pending: FreeTextEditor | undefined\n\n /**\n * Opens an editor on a new box on `page` over `css` (the page host's CSS px), or, without a\n * box, one line high and `DEFAULT_FREETEXT_WIDTH` wide with its top-left at `at` (or centred\n * on it). The box is a stand-in element until the first commit with text, which adds and\n * selects it: creating and typing are one change and one undo step, and an empty box never\n * reaches the store.\n */\n const place = (\n c: ToolContext,\n page: number,\n css: CssRect | { at: { x: number; y: number }; centred: boolean }\n ): void => {\n const host = c.viewport.hostFor(page)\n if (!host) return\n pending?.close(true)\n const t = c.viewport.transformFor(page)\n const blank: FreeTextInput = { type: 'freetext', page, contents: '' }\n const input = c.toolStyle.resolve('text', blank)\n let box: CssRect\n if ('at' in css) {\n const size = input.defaultStyle?.fontSize ?? FONT_SIZE\n const border = input.width ?? 0\n const width = t.toCssLength(DEFAULT_FREETEXT_WIDTH)\n const height = t.toCssLength(size * LINE_HEIGHT + border * 2)\n box = css.centred\n ? { left: css.at.x - width / 2, top: css.at.y - height / 2, width, height }\n : { left: css.at.x, top: css.at.y, width, height }\n } else {\n box = css\n }\n const draftBox = c.store.completeInput({ ...input, rect: t.fromCssRect(box) })\n if (draftBox.type !== 'freetext') return\n const doc = host.ownerDocument\n // Laid out as the overlay lays out an annotation, stacked above the overlay (the theme\n // gives it z-index 1) so existing annotations under the new box neither cover its editor\n // nor take its presses.\n const el = doc.createElement('div')\n el.className = 'ink-annotation'\n el.dataset.inkPending = ''\n el.dataset.type = 'freetext'\n el.tabIndex = -1\n el.style.cssText = `position:absolute;left:${box.left}px;top:${box.top}px;width:${box.width}px;height:${box.height}px;pointer-events:none;z-index:2;`\n host.append(el)\n renderAnnotationContent(el, draftBox, t)\n\n // A new zoom or rotation commits the box as it stands, as does its page unmounting.\n const view = [\n ...[c.viewport.scale, c.viewport.rotation].map((r) =>\n r.subscribe(() => editor.close(true))\n ),\n c.viewport.mounted.subscribe((pages) => {\n if (!pages.includes(page)) editor.close(true)\n }),\n ]\n const done = (): void => {\n view.forEach((stop) => stop())\n el.remove()\n if (pending === editor) pending = undefined\n }\n /** After the stand-in goes: focus the new box, else the viewport, never <body>. */\n const refocus = (id?: string): void => {\n // Focus that already moved on (a click on a control) stays there.\n const active = doc.activeElement\n if (active && active !== doc.body && active !== el) return\n const drawn =\n id === undefined\n ? null\n : c.root.querySelector<HTMLElement>(`[data-annotation=\"${CSS.escape(id)}\"]`)\n if (drawn) drawn.focus({ preventScroll: true })\n else {\n if (!c.root.hasAttribute('tabindex')) c.root.tabIndex = -1\n c.root.focus({ preventScroll: true })\n }\n }\n const editor = editFreeText(el, draftBox, {\n transform: t,\n commit(contents, rect, _grown, how) {\n done()\n // An empty box makes nothing: the tool stays ready.\n if (contents.trim() === '') return refocus()\n const created = c.store.add({ ...input, id: draftBox.id, contents, rect })\n c.store.select([created.id])\n c.made([created.id])\n refocus(created.id)\n if (how === 'escape') c.done()\n },\n cancel() {\n done()\n refocus()\n },\n })\n pending = editor\n }\n\n const paint = (from: PageHit, e: PointerEvent): void => {\n const css = clampedCssIn(from.host, e)\n if (!draft) {\n draft = from.host.ownerDocument.createElement('div')\n draft.className = 'ink-draft'\n draft.dataset.inkDraft = 'freetext'\n draft.style.position = 'absolute'\n draft.style.pointerEvents = 'none'\n from.host.append(draft)\n }\n draft.style.left = `${Math.min(from.css.x, css.x)}px`\n draft.style.top = `${Math.min(from.css.y, css.y)}px`\n draft.style.width = `${Math.abs(css.x - from.css.x)}px`\n draft.style.height = `${Math.abs(css.y - from.css.y)}px`\n }\n\n return {\n id: 'freetext',\n kind: 'one-shot',\n cursor: 'text',\n styleGroup: 'text',\n defaultOptions: {},\n activate(c) {\n ctx = c\n },\n deactivate() {\n clear()\n pending?.close(true)\n ctx = undefined\n },\n onPointerDown(e, hit, annotationId) {\n // A press that ended an edit only ends it.\n if (!hit || annotationId !== undefined || closedEditor(e)) return\n start = hit\n // Keeps the press from starting a text selection or taking focus from the editor to be.\n e.preventDefault()\n return true\n },\n onPointerMove(e) {\n if (!start) return\n if (e.buttons === 0 || !start.host.isConnected) {\n clear()\n return\n }\n paint(start, e)\n },\n onPointerCancel() {\n clear()\n },\n onPointerUp(e) {\n const from = start\n clear()\n if (!ctx || !from || !from.host.isConnected) return\n const css = clampedCssIn(from.host, e)\n const dx = Math.abs(css.x - from.css.x)\n const dy = Math.abs(css.y - from.css.y)\n if (dx >= MIN_CSS && dy >= MIN_CSS) {\n place(ctx, from.page, {\n left: Math.min(from.css.x, css.x),\n top: Math.min(from.css.y, css.y),\n width: dx,\n height: dy,\n })\n } else {\n place(ctx, from.page, { at: from.css, centred: false })\n }\n },\n onKeyDown(e) {\n if (!ctx || !isViewportEnter(e, ctx.root)) return\n e.preventDefault()\n const page = ctx.viewport.currentPage.get()\n const t = ctx.viewport.transformFor(page)\n const { box } = t.page\n const middle = t.toCss({ x: box.x + box.width / 2, y: box.y + box.height / 2 })\n place(ctx, page, { at: middle, centred: true })\n },\n }\n}\n","import { isViewportEnter, type Tool, type ToolContext } from './controller'\n\nimport type { TextMarkupAnnotation } from '../../model/annotations/types'\n\nexport type MarkupKind = TextMarkupAnnotation['type']\n\n/** The text markup kinds, in menu order. */\nexport const MARKUP_KINDS: readonly MarkupKind[] = [\n 'highlight',\n 'underline',\n 'strikeout',\n 'squiggly',\n]\n\nexport interface HighlightOptions {\n /** Which text markup the tool makes. */\n kind: MarkupKind\n}\n\nexport const DEFAULT_HIGHLIGHT_OPTIONS: Readonly<HighlightOptions> = { kind: 'highlight' }\n\n/**\n * Turns the text selection into one markup of the chosen kind per page when the pointer is\n * released, or on Enter in the viewport (a keyboard selection), and selects what it made.\n * Without a selection both do nothing. The markup's `contents` is left for a comment: hosts\n * read the marked text with `doc.text(page)`.\n */\nexport function highlightTool(): Tool<HighlightOptions> {\n let ctx: ToolContext | undefined\n const convert = (): boolean => {\n if (!ctx) return false\n const selections = ctx.selectionQuads()\n if (selections.length === 0) return false\n const { kind } = { ...DEFAULT_HIGHLIGHT_OPTIONS, ...ctx.options<HighlightOptions>() }\n const ids: string[] = []\n for (const s of selections) {\n const a = ctx.store.add(\n ctx.toolStyle.resolve('markup', { type: kind, page: s.page, quads: s.quads })\n )\n ids.push(a.id)\n }\n ctx.clearSelection()\n ctx.store.select(ids)\n return true\n }\n return {\n id: 'highlight',\n kind: 'sticky',\n cursor: 'text',\n styleGroup: 'markup',\n defaultOptions: { ...DEFAULT_HIGHLIGHT_OPTIONS },\n activate(c) {\n ctx = c\n },\n deactivate() {\n ctx = undefined\n },\n onPointerUp() {\n convert()\n },\n onKeyDown(e) {\n if (!!ctx && isViewportEnter(e, ctx.root) && convert()) e.preventDefault()\n },\n }\n}\n","import { isViewportEnter, type PageHit, type Tool, type ToolContext } from './controller'\n\nimport type { Point } from '../../model/geometry'\n\n/** Side of a new note's icon box, user-space points. */\nconst SIZE = 20\n\n/** Frames to wait for a controlled host to apply a new note before giving up on focusing it. */\nconst FOCUS_FRAMES = 10\n\n/**\n * Click places a note centred on the press. Enter in the viewport places one at the centre of\n * the current page and focuses it. Either way the note is selected and activated.\n */\nexport function noteTool(): Tool {\n let ctx: ToolContext | undefined\n let down: PageHit | undefined\n\n const place = (c: ToolContext, page: number, at: Point): string => {\n const a = c.store.add({\n type: 'text',\n icon: 'Comment',\n page,\n rect: { x: at.x - SIZE / 2, y: at.y - SIZE / 2, width: SIZE, height: SIZE },\n })\n c.store.select([a.id])\n c.made([a.id])\n return a.id\n }\n\n return {\n id: 'note',\n kind: 'one-shot',\n cursor: 'copy',\n activate(c) {\n ctx = c\n },\n deactivate() {\n ctx = undefined\n down = undefined\n },\n onPointerDown(_e, hit, annotationId) {\n down = annotationId === undefined ? hit : undefined\n return down !== undefined\n },\n onPointerCancel() {\n down = undefined\n },\n onPointerUp(_e, hit) {\n const pressed = down\n down = undefined\n if (!ctx || !pressed || !hit || hit.page !== pressed.page) return\n const id = place(ctx, hit.page, hit.user)\n ctx.onActivate?.(id)\n },\n onKeyDown(e) {\n if (!ctx || !isViewportEnter(e, ctx.root)) return\n e.preventDefault()\n const c = ctx\n const page = c.viewport.currentPage.get()\n const { box } = c.viewport.transformFor(page).page\n const id = place(c, page, { x: box.x + box.width / 2, y: box.y + box.height / 2 })\n focusWhenDrawn(c, id)\n c.onActivate?.(id)\n },\n }\n}\n\n/**\n * Focuses the note's overlay element. An uncontrolled store draws it synchronously; a\n * controlled host applies the change later, so wait a few frames, and give up if focus has\n * meanwhile moved off the viewport (a popover took it).\n */\nfunction focusWhenDrawn(ctx: ToolContext, id: string): void {\n const doc = ctx.root.ownerDocument\n const find = (): HTMLElement | null =>\n ctx.root.querySelector<HTMLElement>(`[data-annotation=\"${CSS.escape(id)}\"]`)\n const now = find()\n if (now) {\n now.focus({ preventScroll: true })\n return\n }\n let frames = 0\n const view = doc.defaultView\n const tick = (): void => {\n if (doc.activeElement !== ctx.root) return\n const el = find()\n if (el) el.focus({ preventScroll: true })\n else if (++frames < FOCUS_FRAMES) view?.requestAnimationFrame(tick)\n }\n view?.requestAnimationFrame(tick)\n}\n","// The live draft is `position:absolute; pointer-events:none` with left/top/width/height from\n// the drag: geometry only. Its look comes from the theme (`.ink-draft[data-ink-draft]`).\nimport { isTextMarkup } from '../../model/annotations/edit'\n\nimport {\n clampedCssIn,\n isViewportEnter,\n type PageHit,\n type Tool,\n type ToolContext,\n} from './controller'\n\n/** Smallest drag, in CSS px on each axis, that draws a box rather than counting as a click. */\nconst MIN_CSS = 3\n\nexport function redactAreaTool(): Tool {\n let ctx: ToolContext | undefined\n let start: PageHit | undefined\n let draft: HTMLElement | undefined\n\n /** Selects what the tool just added, together, and reports it made. */\n const made = (c: ToolContext, ids: string[]): void => {\n c.store.select(ids)\n c.made(ids)\n }\n\n /** Text redactions from the live selection, one per page. False when nothing is selected. */\n const fromSelection = (): boolean => {\n if (!ctx) return false\n const selections = ctx.selectionQuads()\n if (selections.length === 0) return false\n const c = ctx\n const ids = selections.map(\n (s) =>\n c.store.add(\n c.toolStyle.resolve('redact', { type: 'redact', page: s.page, quads: s.quads })\n ).id\n )\n c.clearSelection()\n made(c, ids)\n return true\n }\n\n const clear = (): void => {\n draft?.remove()\n draft = undefined\n start = undefined\n }\n\n return {\n id: 'redact-area',\n kind: 'one-shot',\n cursor: 'crosshair',\n styleGroup: 'redact',\n activate(c) {\n ctx = c\n },\n deactivate() {\n clear()\n ctx = undefined\n },\n onPointerDown(e, hit, annotationId) {\n if (!hit) return\n if (annotationId !== undefined) {\n // Text markup would let a drag through to text selection, which the next click here\n // turns into a text redaction. Claim the press instead, as rectangle select does: a\n // drag from markup draws an area, and a click redacts the live selection.\n const a = ctx?.store.get(annotationId)\n if (!a || !isTextMarkup(a)) return\n e.stopPropagation()\n }\n start = hit\n // Keeps the press from starting a text selection; an existing one survives for the\n // text-derived mode on pointerup.\n e.preventDefault()\n return true\n },\n onPointerMove(e) {\n if (!start) return\n // No button down: the release was missed, so drop the draft. A host scrolled out of\n // the mounted range is gone with it.\n if (e.buttons === 0 || !start.host.isConnected) {\n clear()\n return\n }\n const css = clampedCssIn(start.host, e)\n if (!draft) {\n draft = start.host.ownerDocument.createElement('div')\n draft.className = 'ink-draft'\n draft.dataset.inkDraft = 'redact'\n draft.style.position = 'absolute'\n draft.style.pointerEvents = 'none'\n start.host.append(draft)\n }\n draft.style.left = `${Math.min(start.css.x, css.x)}px`\n draft.style.top = `${Math.min(start.css.y, css.y)}px`\n draft.style.width = `${Math.abs(css.x - start.css.x)}px`\n draft.style.height = `${Math.abs(css.y - start.css.y)}px`\n },\n onPointerCancel() {\n clear()\n },\n onPointerUp(e) {\n if (!ctx || !start) return\n if (!start.host.isConnected) {\n clear()\n return\n }\n const css = clampedCssIn(start.host, e)\n const width = Math.abs(css.x - start.css.x)\n const height = Math.abs(css.y - start.css.y)\n if (width >= MIN_CSS && height >= MIN_CSS) {\n const rect = start.transform.fromCssRect({\n left: Math.min(start.css.x, css.x),\n top: Math.min(start.css.y, css.y),\n width,\n height,\n })\n const a = ctx.store.add(\n ctx.toolStyle.resolve('redact', { type: 'redact', page: start.page, rect })\n )\n made(ctx, [a.id])\n } else {\n fromSelection()\n }\n clear()\n },\n onKeyDown(e) {\n // The keyboard path for text marks: select text, then Enter.\n if (!!ctx && isViewportEnter(e, ctx.root) && fromSelection()) e.preventDefault()\n },\n }\n}\n","import { createSelectionEdit, type SelectionEdit } from './selection-edit'\n\nimport type { Tool } from './controller'\n\n/**\n * Rectangle select: a drag on empty space draws a marquee that selects the annotations it\n * touches (`Shift` adds to the selection). Presses on annotations select, move and resize them\n * as `select-text` does (selection-edit.ts).\n */\nexport function selectTool(): Tool {\n let edit: SelectionEdit | undefined\n return {\n id: 'select',\n cursor: 'default',\n activate(ctx) {\n edit = createSelectionEdit(ctx, { marquee: true })\n },\n deactivate() {\n edit?.reset()\n edit = undefined\n },\n onPointerDown: (e, hit, id) => edit?.onPointerDown(e, hit, id),\n onPointerMove: (e, hit) => edit?.onPointerMove(e, hit),\n onPointerUp: (e, hit) => edit?.onPointerUp(e, hit),\n onPointerCancel: () => edit?.onPointerCancel(),\n onKeyDown: (e) => edit?.onKeyDown(e),\n }\n}\n","import { createSelectionEdit, type SelectionEdit } from './selection-edit'\n\nimport type { Tool } from './controller'\n\n/**\n * The default tool. Text selection stays native: presses on text, and drags across text\n * markup, select text. Presses on other annotations select them, and drags move and resize\n * them (selection-edit.ts). There is no marquee.\n */\nexport function selectTextTool(): Tool {\n let edit: SelectionEdit | undefined\n return {\n id: 'select-text',\n cursor: 'auto',\n activate(ctx) {\n edit = createSelectionEdit(ctx)\n },\n deactivate() {\n edit?.reset()\n edit = undefined\n },\n onPointerDown: (e, hit, id) => edit?.onPointerDown(e, hit, id),\n onPointerMove: (e, hit) => edit?.onPointerMove(e, hit),\n onPointerUp: (e, hit) => edit?.onPointerUp(e, hit),\n onPointerCancel: () => edit?.onPointerCancel(),\n onKeyDown: (e) => edit?.onKeyDown(e),\n }\n}\n","// Drag draws a shape between the press and the release; a click, or Enter on the viewport,\n// places a default-size one. Enter places no loupe or mask: they are pointer-only. The live\n// draft is `position:absolute; pointer-events:none`, a box over the shape's bounds holding an\n// SVG preview: geometry only, the look comes from the theme\n// (`.ink-draft[data-ink-draft='shape']`).\nimport {\n calloutStroke,\n freeTextBox,\n withCalloutBounds,\n} from '../../model/annotations/callout'\nimport { isBubble } from '../../model/annotations/edit'\nimport {\n constrain,\n DEFAULT_SHAPE_OPTIONS,\n defaultEnds,\n isPointerOnlyKind,\n shapeInput,\n type ShapeOptions,\n} from '../../model/annotations/shape-geometry'\nimport { closedEditor, editFreeTextIn } from '../freetext-editor'\n\nimport {\n clampedCssIn,\n isViewportEnter,\n type PageHit,\n type Tool,\n type ToolContext,\n} from './controller'\n\nimport type {\n Annotation,\n AnnotationInput,\n FreeTextAnnotation,\n} from '../../model/annotations/types'\nimport type { Point } from '../../model/geometry'\n\nexport {\n DEFAULT_CORNER_RADIUS,\n DEFAULT_SHAPE_SIZE,\n SHAPE_KINDS,\n type ShapeKind,\n type ShapeOptions,\n} from '../../model/annotations/shape-geometry'\n\n/** Smallest drag, in CSS px on its longer axis, that draws a shape rather than counting as a click. */\nconst MIN_CSS = 3\n\nconst SVG_NS = 'http://www.w3.org/2000/svg'\n\nexport function shapeTool(): Tool<ShapeOptions> {\n let ctx: ToolContext | undefined\n let start: PageHit | undefined\n let draft: HTMLElement | undefined\n\n const clear = (): void => {\n draft?.remove()\n draft = undefined\n start = undefined\n }\n\n const options = (c: ToolContext): ShapeOptions => ({\n ...DEFAULT_SHAPE_OPTIONS,\n ...c.options<ShapeOptions>(),\n })\n\n /** The input for a drag from `a` to `b` (user space), with Shift's constraint applied. */\n const inputFor = (\n c: ToolContext,\n page: number,\n a: Point,\n b: Point,\n shift: boolean\n ): AnnotationInput | undefined => {\n const o = options(c)\n return shapeInput(o.kind, page, a, shift ? constrain(o.kind, a, b) : b, o)\n }\n\n /** The input with the shape group's style and, for a bubble, the text group's text style. */\n const styled = (c: ToolContext, input: AnnotationInput): AnnotationInput => {\n if (input.type === 'line') {\n // The line style menu's ends win; until it picks them an arrow has an open tail.\n const line = c.toolStyle.resolve('shape', input)\n const arrow = input.intent === 'LineArrow'\n return {\n ...line,\n head: line.head ?? 'None',\n tail: line.tail ?? (arrow ? 'OpenArrow' : 'None'),\n }\n }\n if (input.type !== 'freetext') return c.toolStyle.resolve('shape', input)\n // The group's width must not lose to the bubble's default one, so it is filled last.\n const shape = c.toolStyle.resolve('shape', { ...input, width: undefined })\n const blank: AnnotationInput & { type: 'freetext' } = {\n type: 'freetext',\n page: input.page,\n contents: '',\n }\n const text = c.toolStyle.resolve('text', blank)\n const out = {\n ...shape,\n width: shape.width ?? input.width,\n defaultStyle: { ...text.defaultStyle, ...input.defaultStyle },\n }\n if (!input.callout || !input.rect) return out\n // The bounds were fit to the bubble's default width: refit them to the group's.\n const box = freeTextBox({ rect: input.rect, fringe: input.fringe })\n const { width } = calloutStroke(out as FreeTextAnnotation)\n return { ...out, ...withCalloutBounds(box, input.callout, width, input.head) }\n }\n\n /** Stops waiting for a bubble the host has not applied yet. */\n let waiting: (() => void) | undefined\n\n const openEditor = (c: ToolContext, a: Annotation): boolean => {\n const el = c.root.querySelector<HTMLElement>(\n `[data-annotation=\"${CSS.escape(a.id)}\"]`\n )\n return (\n el !== null &&\n editFreeTextIn(c.store, el, a.id, c.viewport.transformFor(a.page), {\n // Escape ends the bubble's edit and the tool's use, unless the tool has gone already.\n onClose: (how) => {\n if (how === 'escape' && ctx === c) c.done()\n },\n }) !== undefined\n )\n }\n\n /**\n * Opens the in-place editor on a new bubble. When a controlled host has not applied it yet,\n * the editor opens once it does.\n */\n const edit = (c: ToolContext, a: Annotation): void => {\n waiting?.()\n waiting = undefined\n if (openEditor(c, a)) return\n const stop = c.store.list.subscribe(() => {\n if (!c.store.get(a.id)) return\n stop()\n if (waiting === stop) waiting = undefined\n openEditor(c, a)\n })\n waiting = stop\n }\n\n const add = (c: ToolContext, input: AnnotationInput | undefined): void => {\n if (!input) return\n const created = c.store.add(styled(c, input))\n c.store.select([created.id])\n c.made([created.id])\n if (isBubble(created)) edit(c, created)\n }\n\n const paint = (c: ToolContext, from: PageHit, e: PointerEvent): void => {\n const css = clampedCssIn(from.host, e)\n const user = from.transform.fromCss(css)\n const input = inputFor(c, from.page, from.user, user, e.shiftKey)\n if (!input) return\n const t = from.transform\n let box: { left: number; top: number; width: number; height: number }\n let points: Point[] | undefined\n let kind: 'rect' | 'ellipse' | 'path' = 'path'\n if (\n input.type === 'square' ||\n input.type === 'circle' ||\n input.type === 'freetext' ||\n input.type === 'loupe' ||\n input.type === 'mask'\n ) {\n if (!input.rect) return\n // A bubble previews its text box; its tail comes with the bubble itself.\n box = t.toCssRect(\n input.type === 'freetext'\n ? freeTextBox({ rect: input.rect, fringe: input.fringe })\n : input.rect\n )\n kind =\n input.type === 'circle' ||\n input.type === 'loupe' ||\n (input.type === 'mask' && input.shape === 'ellipse')\n ? 'ellipse'\n : 'rect'\n } else {\n if (input.type === 'line') points = [t.toCss(input.start), t.toCss(input.end)]\n else if (input.type === 'polygon') points = input.vertices.map((v) => t.toCss(v))\n else return\n const xs = points.map((p) => p.x)\n const ys = points.map((p) => p.y)\n const left = Math.min(...xs)\n const top = Math.min(...ys)\n box = {\n left,\n top,\n width: Math.max(...xs) - left,\n height: Math.max(...ys) - top,\n }\n }\n if (!draft) {\n draft = from.host.ownerDocument.createElement('div')\n draft.className = 'ink-draft'\n draft.dataset.inkDraft = 'shape'\n draft.style.position = 'absolute'\n draft.style.pointerEvents = 'none'\n from.host.append(draft)\n }\n draft.dataset.inkShape = options(c).kind\n draft.style.left = `${box.left}px`\n draft.style.top = `${box.top}px`\n draft.style.width = `${box.width}px`\n draft.style.height = `${box.height}px`\n const doc = from.host.ownerDocument\n const svg = doc.createElementNS(SVG_NS, 'svg')\n svg.setAttribute('width', String(box.width))\n svg.setAttribute('height', String(box.height))\n svg.style.overflow = 'visible'\n const node =\n kind === 'path'\n ? doc.createElementNS(SVG_NS, input.type === 'line' ? 'polyline' : 'polygon')\n : doc.createElementNS(SVG_NS, kind)\n if (kind === 'path') {\n node.setAttribute(\n 'points',\n (points ?? []).map((p) => `${p.x - box.left},${p.y - box.top}`).join(' ')\n )\n } else if (kind === 'ellipse') {\n node.setAttribute('cx', String(box.width / 2))\n node.setAttribute('cy', String(box.height / 2))\n node.setAttribute('rx', String(box.width / 2))\n node.setAttribute('ry', String(box.height / 2))\n } else {\n node.setAttribute('width', String(box.width))\n node.setAttribute('height', String(box.height))\n if ((input.type === 'square' || input.type === 'freetext') && input.cornerRadius)\n node.setAttribute('rx', String(t.toCssLength(input.cornerRadius)))\n }\n svg.append(node)\n draft.replaceChildren(svg)\n }\n\n return {\n id: 'shape',\n kind: 'one-shot',\n cursor: 'crosshair',\n styleGroup: 'shape',\n defaultOptions: { ...DEFAULT_SHAPE_OPTIONS },\n activate(c) {\n ctx = c\n },\n deactivate() {\n clear()\n waiting?.()\n waiting = undefined\n ctx = undefined\n },\n onPointerDown(e, hit, annotationId) {\n // A press that ended a bubble's edit only ends it.\n if (!hit || annotationId !== undefined || closedEditor(e)) return\n start = hit\n // Keeps the press from starting a text selection.\n e.preventDefault()\n return true\n },\n onPointerMove(e) {\n if (!ctx || !start) return\n // No button down: the release was missed, so drop the draft. A host scrolled out of the\n // mounted range is gone with it.\n if (e.buttons === 0 || !start.host.isConnected) {\n clear()\n return\n }\n paint(ctx, start, e)\n },\n onPointerCancel() {\n clear()\n },\n onPointerUp(e) {\n if (!ctx || !start) return\n const from = start\n if (!from.host.isConnected) {\n clear()\n return\n }\n const css = clampedCssIn(from.host, e)\n const long = Math.max(Math.abs(css.x - from.css.x), Math.abs(css.y - from.css.y))\n if (long >= MIN_CSS) {\n add(\n ctx,\n inputFor(ctx, from.page, from.user, from.transform.fromCss(css), e.shiftKey)\n )\n } else {\n const [a, b] = defaultEnds(\n options(ctx).kind,\n from.user,\n from.transform.page.rotate\n )\n add(ctx, inputFor(ctx, from.page, a, b, false))\n }\n clear()\n },\n onKeyDown(e) {\n if (!ctx || !isViewportEnter(e, ctx.root)) return\n // The loupe and the mask are pointer-only, like area redaction.\n if (isPointerOnlyKind(options(ctx).kind)) return\n e.preventDefault()\n const page = ctx.viewport.currentPage.get()\n const { box, rotate } = ctx.viewport.transformFor(page).page\n const [a, b] = defaultEnds(\n options(ctx).kind,\n { x: box.x + box.width / 2, y: box.y + box.height / 2 },\n rotate\n )\n add(ctx, inputFor(ctx, page, a, b, false))\n },\n }\n}\n","// Places the chosen signature template. A click puts it centred on the press, about 150 pt\n// wide; Enter in the viewport puts it at the centre of the current page. It is turned against\n// the page's own /Rotate, so it reads upright on the page as the file displays it; a view\n// rotation is the viewer's, and turns it with the page like any annotation. Ink takes the\n// `ink` group's colour at the template's own width; an image is placed as it is. Either way\n// the new annotation is selected and one undo step.\nimport {\n DEFAULT_SIGNATURE_WIDTH,\n placeSignature,\n type SignatureOptions,\n type SignatureTemplate,\n} from '../../model/signatures'\n\nimport { isViewportEnter, type PageHit, type Tool, type ToolContext } from './controller'\n\nimport type { Point } from '../../model/geometry'\nimport type { PageRotation } from '../../model/pages'\n\nexport type { SignatureOptions }\n\nexport function signatureTool(): Tool<SignatureOptions> {\n let ctx: ToolContext | undefined\n let down: PageHit | undefined\n /** Bumped on deactivate, so a load still pending from an earlier use places nothing. */\n let generation = 0\n\n const place = (\n c: ToolContext,\n t: SignatureTemplate,\n page: number,\n at: Point,\n rotation: PageRotation\n ): void => {\n const input = placeSignature(t, page, at, DEFAULT_SIGNATURE_WIDTH, rotation)\n const a = c.store.add(\n input.type === 'ink' ? c.toolStyle.resolve('ink', input) : input\n )\n c.store.select([a.id])\n c.made([a.id])\n }\n\n /**\n * Places the selected template, from the library at once, or after reloading it when the\n * template was saved since the last load. False when there is nothing to place.\n */\n const placeSelected = (\n c: ToolContext,\n page: number,\n at: Point,\n rotation: PageRotation\n ): boolean => {\n const id = c.options<SignatureOptions>().templateId\n const library = c.signatures\n if (id === undefined || !library) return false\n const t = library.get(id)\n if (t) {\n place(c, t, page, at, rotation)\n return true\n }\n const gen = generation\n void library.refresh().then(() => {\n // The tool may have been switched (even away and back), or the template removed.\n const later = library.get(id)\n if (\n later &&\n ctx === c &&\n gen === generation &&\n c.options<SignatureOptions>().templateId === id\n )\n place(c, later, page, at, rotation)\n })\n return true\n }\n\n return {\n id: 'signature',\n kind: 'one-shot',\n cursor: 'copy',\n defaultOptions: {},\n activate(c) {\n ctx = c\n },\n deactivate() {\n ctx = undefined\n down = undefined\n generation++\n },\n onPointerDown(_e, hit, annotationId) {\n down = annotationId === undefined ? hit : undefined\n return down !== undefined\n },\n onPointerMove(e) {\n // The release was missed: treat it as a cancel.\n if (e.buttons === 0) down = undefined\n },\n onPointerCancel() {\n down = undefined\n },\n onPointerUp(_e, hit) {\n const pressed = down\n down = undefined\n if (!ctx || !pressed || !hit || hit.page !== pressed.page) return\n placeSelected(ctx, hit.page, hit.user, hit.transform.page.rotate)\n },\n onKeyDown(e) {\n if (!ctx || !isViewportEnter(e, ctx.root)) return\n const page = ctx.viewport.currentPage.get()\n const t = ctx.viewport.transformFor(page)\n const { box } = t.page\n const centre = { x: box.x + box.width / 2, y: box.y + box.height / 2 }\n if (placeSelected(ctx, page, centre, t.page.rotate)) e.preventDefault()\n },\n }\n}\n","// Freehand ink that tidies itself. It captures and previews strokes as `draw` does, but each\n// stroke stands alone: sketch never joins strokes. On release the stroke is added as ink, then\n// `recogniseStroke` scores it; a fit at `RECOGNISE_THRESHOLD` or better replaces the ink with\n// the clean shape, styled from the `shape` group. Two undo steps: the ink, then the swap (one\n// `history.batch`), so one undo brings the stroke back and a second removes it.\n//\n// A controlled host applies the ink later, or never. The swap waits until the ink is in the\n// list, then a task more, so the host's own history records the ink as a step before the swap.\n// Deactivating the tool cancels a swap still waiting.\nimport { DEFAULT_SHAPE_OPTIONS, shapeInput } from '../../model/annotations/shape-geometry'\nimport {\n recogniseStroke,\n RECOGNISE_THRESHOLD,\n type Recognised,\n} from '../../model/recognise'\n\nimport { freehandTool } from './freehand'\n\nimport type { Tool, ToolContext } from './controller'\nimport type { AnnotationInput } from '../../model/annotations/types'\n\n/** How long the swap waits for a controlled host to apply the ink before giving up. */\nconst APPLY_WAIT_MS = 2000\n\n/**\n * The smallest stroke, in CSS px across its longer side, that can become a shape. A click or\n * its jitter stays a dot of ink, as with `draw`, rather than an invisible sliver of a line.\n */\nconst MIN_SHAPE_PX = 4\n\n/** The longer side of the box `points` span, in the units they are in. */\nfunction extent(points: readonly { x: number; y: number }[]): number {\n const xs = points.map((p) => p.x)\n const ys = points.map((p) => p.y)\n return Math.max(Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys))\n}\n\n/** The annotation a recognised stroke becomes. */\nfunction recognisedInput(shape: Recognised, page: number): AnnotationInput | undefined {\n switch (shape.kind) {\n case 'line':\n case 'arrow':\n return shapeInput(shape.kind, page, shape.start, shape.end, DEFAULT_SHAPE_OPTIONS)\n case 'rectangle':\n case 'ellipse': {\n const { x, y, width, height } = shape.rect\n return shapeInput(\n shape.kind,\n page,\n { x, y },\n { x: x + width, y: y + height },\n DEFAULT_SHAPE_OPTIONS\n )\n }\n // The recogniser already tidied the vertices: a polygon keeps the corners the stroke had,\n // a star is regular.\n case 'polygon':\n case 'star':\n return { type: 'polygon', page, vertices: shape.vertices }\n }\n}\n\n/**\n * Runs `fn` once the annotation `id` is in the list and the host has had a task to record it.\n * Gives up (calling `onGiveUp`) when the host has not applied it in `APPLY_WAIT_MS`. Returns a\n * cancel that drops whatever is still pending.\n */\nfunction whenApplied(\n c: ToolContext,\n id: string,\n fn: () => void,\n onGiveUp: () => void\n): () => void {\n if (c.store.get(id)) {\n fn()\n return () => undefined\n }\n let swap: ReturnType<typeof setTimeout> | undefined\n // Every timer and the subscription exist before anything can call `cancel`.\n const giveUp = setTimeout(() => {\n cancel()\n onGiveUp()\n }, APPLY_WAIT_MS)\n let stop: (() => void) | undefined = c.store.list.subscribe(() => {\n if (!c.store.get(id)) return\n cancel()\n swap = setTimeout(fn, 0)\n })\n function cancel(): void {\n stop?.()\n stop = undefined\n clearTimeout(giveUp)\n clearTimeout(swap)\n }\n return cancel\n}\n\nexport function sketchTool(): Tool {\n /** Cancels for swaps still waiting on a controlled host. */\n const pending = new Set<() => void>()\n return freehandTool({\n id: 'sketch',\n // Switching tools or tearing the viewer down drops any swap still waiting: the stroke\n // stays ink, and nothing fires against a store that may be gone.\n deactivate() {\n for (const cancel of pending) cancel()\n pending.clear()\n },\n commit(c, s) {\n const ink = c.store.add(\n c.toolStyle.resolve('ink', {\n type: 'ink',\n page: s.page,\n inklist: [s.points],\n ...(s.pressure ? { pressure: [s.pressure] } : {}),\n })\n )\n if (c.viewport.transformFor(s.page).toCssLength(extent(s.points)) < MIN_SHAPE_PX)\n return\n const fit = recogniseStroke(s.points)\n if (!fit || fit.score < RECOGNISE_THRESHOLD) return\n const input = recognisedInput(fit.shape, s.page)\n if (!input) return\n const shape = c.toolStyle.resolve('shape', input)\n const batch = (fn: () => void): void => (c.history ? c.history.batch(fn) : fn())\n // Uncontrolled, the swap runs straight away, before `whenApplied` returns.\n let ran = false\n let cancel = (): void => undefined\n cancel = whenApplied(\n c,\n ink.id,\n () => {\n ran = true\n pending.delete(cancel)\n // Undone, or changed, before the swap: leave the stroke as it is. A host may hand back\n // copies, so the check is by modification time, not identity.\n if (c.store.get(ink.id)?.modifiedAt !== ink.modifiedAt) return\n batch(() => {\n c.store.remove(ink.id)\n c.store.add(shape)\n })\n },\n () => pending.delete(cancel)\n )\n if (!ran) pending.add(cancel)\n },\n })\n}\n","import { createToolStyle, type ToolStyle } from '../../model/annotations/tool-style'\nimport { writable } from '../../model/readable'\n\nimport {\n createToolController as createWith,\n type Tool,\n type ToolControllerOptions,\n type ToolController,\n type ToolId,\n} from './controller'\nimport { drawTool } from './draw'\nimport { DEFAULT_FREETEXT_WIDTH, freetextTool } from './freetext'\nimport { highlightTool } from './highlight'\nimport { noteTool } from './note'\nimport { redactAreaTool } from './redact-area'\nimport { selectTool } from './select'\nimport { selectTextTool } from './select-text'\nimport { shapeTool } from './shape'\nimport { signatureTool } from './signature'\nimport { sketchTool } from './sketch'\n\nimport type { AnnotationStore } from '../../model/annotations/store'\n\nexport type {\n BuiltinToolId,\n PageHit,\n Tool,\n ToolContext,\n ToolController,\n ToolControllerOptions,\n ToolId,\n ToolKind,\n} from './controller'\nexport { hitFor } from './controller'\nexport { createToolOptions, type ToolOptions } from './options'\nexport {\n DEFAULT_FREETEXT_WIDTH,\n drawTool,\n freetextTool,\n highlightTool,\n noteTool,\n redactAreaTool,\n selectTextTool,\n selectTool,\n shapeTool,\n signatureTool,\n sketchTool,\n}\nexport type { SignatureOptions } from './signature'\nexport {\n DEFAULT_HIGHLIGHT_OPTIONS,\n MARKUP_KINDS,\n type HighlightOptions,\n type MarkupKind,\n} from './highlight'\nexport {\n DEFAULT_CORNER_RADIUS,\n DEFAULT_SHAPE_SIZE,\n SHAPE_KINDS,\n type ShapeKind,\n type ShapeOptions,\n} from './shape'\n\n/** Fresh instances of every built-in tool. */\nexport function builtinTools(): Tool[] {\n return [\n selectTextTool(),\n selectTool(),\n highlightTool(),\n redactAreaTool(),\n sketchTool(),\n drawTool(),\n noteTool(),\n shapeTool(),\n freetextTool(),\n signatureTool(),\n ]\n}\n\n/** The built-in tools with a host's tools added, a host tool replacing a built-in by id. */\nexport function withHostTools(host: readonly Tool[] = []): Tool[] {\n const byId = new Map(builtinTools().map((t) => [t.id, t]))\n for (const t of host) byId.set(t.id, t)\n return [...byId.values()]\n}\n\n/** Listens on `ctx.root` and routes pointer and key events to the active tool. */\nexport function createToolController(\n opts: Omit<ToolControllerOptions, 'tools'> & { tools?: Tool[] }\n): ToolController {\n return createWith({ ...opts, tools: opts.tools ?? builtinTools() })\n}\n\nexport interface ToolStyleTracker {\n readonly toolStyle: ToolStyle\n /** Call when the active tool changes: the style's active group follows it. */\n setTool(id: ToolId): void\n}\n\n/**\n * A `ToolStyle` whose active group is the style group of the active tool among `tools` (the\n * built-ins plus a host's). The engine makes one when it is not handed a style; a binding\n * makes its own per document, so its style controls work before the viewport mounts.\n */\nexport function trackToolStyle(opts: {\n store: AnnotationStore\n history: { batch(fn: () => void): void }\n /** Host tools, as passed to `mountViewer`. */\n tools?: readonly Tool[] | undefined\n tool?: ToolId | undefined\n}): ToolStyleTracker {\n const groups = new Map(withHostTools(opts.tools).map((t) => [t.id, t.styleGroup]))\n const active = writable<ToolId>(opts.tool ?? 'select-text')\n const toolStyle = createToolStyle({\n store: opts.store,\n history: opts.history,\n activeGroup: () => groups.get(active.get()),\n active,\n })\n return { toolStyle, setTool: (id) => active.set(id) }\n}\n","// The swatches the colour menus offer: a row of common colours, a row of greys, and a tonal\n// grid. Every value is upper-case #RRGGBB, so a style's colour compares to a swatch directly.\n\nexport interface Palette {\n /** 12 swatches, the top row. */\n readonly common: readonly string[]\n /** 12 greys, white to black. */\n readonly greys: readonly string[]\n /** 8 rows of 12 hue columns (red round to rose in 30 degree steps), dark to light. */\n readonly grid: readonly (readonly string[])[]\n}\n\nexport const PALETTE: Palette = {\n common: [\n '#FF3B30',\n '#FF9500',\n '#FFCC00',\n '#34C759',\n '#00C7BE',\n '#32ADE6',\n '#007AFF',\n '#5856D6',\n '#AF52DE',\n '#FF2D55',\n '#A2845E',\n '#8E8E93',\n ],\n greys: [\n '#FFFFFF',\n '#E8E8E8',\n '#D1D1D1',\n '#B9B9B9',\n '#A2A2A2',\n '#8B8B8B',\n '#747474',\n '#5D5D5D',\n '#464646',\n '#2E2E2E',\n '#171717',\n '#000000',\n ],\n grid: [\n [\n '#590D0D',\n '#59330D',\n '#59590D',\n '#33590D',\n '#0D590D',\n '#0D5933',\n '#0D5959',\n '#0D3359',\n '#0D0D59',\n '#330D59',\n '#590D59',\n '#590D33',\n ],\n [\n '#861313',\n '#864D13',\n '#868613',\n '#4D8613',\n '#138613',\n '#13864D',\n '#138686',\n '#134D86',\n '#131386',\n '#4D1386',\n '#861386',\n '#86134D',\n ],\n [\n '#B31919',\n '#B36619',\n '#B3B319',\n '#66B319',\n '#19B319',\n '#19B366',\n '#19B3B3',\n '#1966B3',\n '#1919B3',\n '#6619B3',\n '#B319B3',\n '#B31966',\n ],\n [\n '#DF2020',\n '#DF8020',\n '#DFDF20',\n '#80DF20',\n '#20DF20',\n '#20DF80',\n '#20DFDF',\n '#2080DF',\n '#2020DF',\n '#8020DF',\n '#DF20DF',\n '#DF2080',\n ],\n [\n '#E64C4C',\n '#E6994C',\n '#E6E64C',\n '#99E64C',\n '#4CE64C',\n '#4CE699',\n '#4CE6E6',\n '#4C99E6',\n '#4C4CE6',\n '#994CE6',\n '#E64CE6',\n '#E64C99',\n ],\n [\n '#EC7979',\n '#ECB379',\n '#ECEC79',\n '#B3EC79',\n '#79EC79',\n '#79ECB3',\n '#79ECEC',\n '#79B3EC',\n '#7979EC',\n '#B379EC',\n '#EC79EC',\n '#EC79B3',\n ],\n [\n '#F2A6A6',\n '#F2CCA6',\n '#F2F2A6',\n '#CCF2A6',\n '#A6F2A6',\n '#A6F2CC',\n '#A6F2F2',\n '#A6CCF2',\n '#A6A6F2',\n '#CCA6F2',\n '#F2A6F2',\n '#F2A6CC',\n ],\n [\n '#F9D2D2',\n '#F9E6D2',\n '#F9F9D2',\n '#E6F9D2',\n '#D2F9D2',\n '#D2F9E6',\n '#D2F9F9',\n '#D2E6F9',\n '#D2D2F9',\n '#E6D2F9',\n '#F9D2F9',\n '#F9D2E6',\n ],\n ],\n}\n","// Vocabulary the framework packages share: labels, zoom levels and the props they hand to\n// host-rendered content. Core owns these so Vue and React cannot drift apart.\nimport { isKnown, LINE_ENDINGS } from '../model/annotations/pdf-names'\n\nimport { PALETTE } from './palette'\n\nimport type {\n HighlightOptions,\n MarkupKind,\n ShapeKind,\n ShapeOptions,\n ToolId,\n} from './tools'\nimport type { CurrentStyle, StyleKey, StyleProps } from '../model/annotations/tool-style'\nimport type {\n Annotation,\n LineEnding,\n NoteAnnotation,\n TextMarkupAnnotation,\n} from '../model/annotations/types'\nimport type { SignatureOptions, SignatureTemplate } from '../model/signatures'\n\n/**\n * Accessible names of the built-in tools, as the toolbar buttons announce them. A host tool has\n * no entry: its button takes the host's `label`, else the tool id.\n */\nexport const TOOL_LABELS: Readonly<Partial<Record<ToolId, string>>> = {\n 'select-text': 'Select text',\n select: 'Rectangle select',\n highlight: 'Highlight',\n 'redact-area': 'Mark for redaction',\n sketch: 'Sketch',\n draw: 'Draw',\n note: 'Add note',\n shape: 'Shape',\n freetext: 'Text',\n signature: 'Sign',\n}\n\n/**\n * The font families a text box offers by default: the PDF standard families, which a PDF\n * writer can use without embedding a font. Hosts pass their own list as `fonts`.\n */\nexport const FONT_FAMILIES: readonly string[] = ['Helvetica', 'Times', 'Courier']\n\n/**\n * The fonts a typed signature offers by default: the browser's own handwriting family. Hosts\n * load handwriting fonts and pass them as `signatureFonts`.\n */\nexport const SIGNATURE_FONTS: readonly string[] = ['cursive']\n\n/** Zoom levels the zoom select offers, as scale factors. */\nexport const ZOOM_LEVELS: readonly number[] = [0.5, 0.75, 1, 1.25, 1.5, 2, 3, 4]\n\n/** Stroke weights the line style menu offers, in points. */\nexport const LINE_WEIGHTS: readonly number[] = [0.5, 1, 2, 3, 4, 6, 8]\n\n/** The dash pattern the menu's dashed choice writes, in points. */\nexport const DASH_PATTERN: readonly number[] = [3, 3]\n\n/** The ending the menu's arrowhead choices draw. */\nexport const ARROWHEAD_ENDING: LineEnding = 'OpenArrow'\n\nexport type ArrowheadChoice = 'none' | 'start' | 'end' | 'both'\n\n/** The arrowhead choices in menu order, with the style each one writes (`head` is the start). */\nexport const ARROWHEAD_CHOICES: readonly {\n value: ArrowheadChoice\n label: string\n patch: Pick<StyleProps, 'head' | 'tail'>\n}[] = [\n { value: 'none', label: 'No arrowheads', patch: { head: 'None', tail: 'None' } },\n {\n value: 'start',\n label: 'Arrowhead at start',\n patch: { head: ARROWHEAD_ENDING, tail: 'None' },\n },\n {\n value: 'end',\n label: 'Arrowhead at end',\n patch: { head: 'None', tail: ARROWHEAD_ENDING },\n },\n {\n value: 'both',\n label: 'Arrowheads at both ends',\n patch: { head: ARROWHEAD_ENDING, tail: ARROWHEAD_ENDING },\n },\n]\n\n/**\n * Which arrowhead choice a style shows, `'mixed'` when the selection disagrees, else `undefined`.\n * Only an ending Inkbar draws counts: one it does not know draws as `None`.\n */\nexport function arrowheadChoice(\n head: LineEnding | 'mixed' | undefined,\n tail: LineEnding | 'mixed' | undefined\n): ArrowheadChoice | 'mixed' | undefined {\n if (head === undefined && tail === undefined) return undefined\n if (head === 'mixed' || tail === 'mixed') return 'mixed'\n const drawn = (e: LineEnding | undefined) =>\n e !== undefined && e !== 'None' && isKnown(LINE_ENDINGS, e)\n const start = drawn(head)\n const end = drawn(tail)\n return start ? (end ? 'both' : 'start') : end ? 'end' : 'none'\n}\n\nexport interface LineStyleMenuItem {\n key: string\n label: string\n checked: boolean\n /** What choosing the item writes through the tool style. */\n patch: StyleProps\n}\n\nexport interface LineStyleMenuSection {\n label: string\n /** The selection or active tool supports none of the section's props. */\n disabled: boolean\n items: LineStyleMenuItem[]\n}\n\nexport interface LineStyleMenuModel {\n /** False when nothing supports weight, pattern or endings: the trigger disables. */\n enabled: boolean\n /** The selection disagrees on weight, pattern or endings. */\n mixed: boolean\n sections: LineStyleMenuSection[]\n}\n\n/**\n * What the line style menu shows for a style: sections of checkable items, each section\n * disabled when `supported` lacks its props. A section whose value is mixed checks nothing.\n * Shared by the bindings and the vanilla menu so they cannot drift apart.\n */\nexport function lineStyleMenuModel(\n current: CurrentStyle,\n supported: ReadonlySet<StyleKey>\n): LineStyleMenuModel {\n const canWeight = supported.has('width')\n const canDash = supported.has('dashes')\n const canEnds = supported.has('head') || supported.has('tail')\n const dashed = Array.isArray(current.dashes) && current.dashes.length > 0\n const ends = arrowheadChoice(current.head, current.tail)\n return {\n enabled: canWeight || canDash || canEnds,\n mixed: (['width', 'dashes', 'head', 'tail'] as const).some(\n (k) => current[k] === 'mixed'\n ),\n sections: [\n {\n label: 'Weight',\n disabled: !canWeight,\n items: LINE_WEIGHTS.map((w) => ({\n key: String(w),\n label: `${w} pt`,\n checked: current.width === w,\n patch: { width: w },\n })),\n },\n {\n label: 'Pattern',\n disabled: !canDash,\n items: [\n {\n key: 'solid',\n label: 'Solid',\n checked: current.dashes === null,\n patch: { dashes: null },\n },\n {\n key: 'dashed',\n label: 'Dashed',\n checked: dashed,\n patch: { dashes: [...DASH_PATTERN] },\n },\n ],\n },\n {\n label: 'Arrowheads',\n disabled: !canEnds,\n items: ARROWHEAD_CHOICES.map((c) => ({\n key: c.value,\n label: c.label,\n checked: ends === c.value,\n patch: c.patch,\n })),\n },\n ],\n }\n}\n\n/** The colour props a colour menu can set. */\nexport type ColorProperty = 'border' | 'fill' | 'textColor'\n\n/** Accessible names of the colour menus, by property. */\nexport const COLOR_LABELS: Readonly<Record<ColorProperty, string>> = {\n border: 'Border colour',\n fill: 'Fill colour',\n textColor: 'Text colour',\n}\n\n/** Columns of the swatch grid: the arrow keys move by this much between rows. */\nexport const COLOR_COLUMNS = 12\n\nexport interface ColorMenuSwatch {\n /** Unique within the menu. */\n key: string\n /** The swatch's accessible name: its hex value. */\n label: string\n color: string\n checked: boolean\n patch: StyleProps\n}\n\n/** What the trigger's swatch shows. */\nexport type ColorTrigger =\n | { kind: 'color'; color: string }\n /** No fill. */\n | { kind: 'none' }\n /** The selection disagrees. */\n | { kind: 'mixed' }\n /** Nothing to show: the menu is disabled or the style has no value. */\n | { kind: 'empty' }\n\nexport interface ColorMenuModel {\n label: string\n /** False when nothing supports the property: the trigger disables. */\n enabled: boolean\n mixed: boolean\n trigger: ColorTrigger\n /** Common colours, greys, then the tonal grid, `COLOR_COLUMNS` to a row. */\n swatches: ColorMenuSwatch[]\n /** The \"No fill\" choice, for `fill` only. */\n noFill: { checked: boolean; patch: StyleProps } | null\n /** The colour the custom picker starts on. */\n customValue: string\n /** What picking `hex` in the custom picker writes. */\n custom(hex: string): StyleProps\n}\n\n/**\n * What a colour menu shows for a style: the palette with the matching swatch checked, \"No fill\"\n * for `fill`, and the trigger's swatch. Shared by the bindings and the vanilla menu. `fallback`\n * is the colour new annotations get while the style leaves it unset: the trigger shows it\n * rather than an empty swatch.\n */\nexport function colorMenuModel(\n property: ColorProperty,\n current: CurrentStyle,\n supported: ReadonlySet<StyleKey>,\n fallback?: string\n): ColorMenuModel {\n const value = current[property]\n const enabled = supported.has(property)\n const color =\n typeof value === 'string' && value !== 'mixed' ? value.toUpperCase() : undefined\n const flat = [\n ...PALETTE.common.map((c, i) => [`common-${i}`, c] as const),\n ...PALETTE.greys.map((c, i) => [`grey-${i}`, c] as const),\n ...PALETTE.grid.flatMap((row, r) =>\n row.map((c, i) => [`grid-${r}-${i}`, c] as const)\n ),\n ]\n const patchFor = (c: string): StyleProps => ({ [property]: c })\n const trigger: ColorTrigger = !enabled\n ? { kind: 'empty' }\n : value === 'mixed'\n ? { kind: 'mixed' }\n : value === null\n ? { kind: 'none' }\n : typeof value === 'string'\n ? { kind: 'color', color: value }\n : fallback !== undefined\n ? { kind: 'color', color: fallback }\n : { kind: 'empty' }\n return {\n label: COLOR_LABELS[property],\n enabled,\n mixed: value === 'mixed',\n trigger,\n swatches: flat.map(([key, c]) => ({\n key,\n label: c,\n color: c,\n checked: color === c,\n patch: patchFor(c),\n })),\n noFill:\n property === 'fill' ? { checked: value === null, patch: { fill: null } } : null,\n customValue: color ?? fallback?.toUpperCase() ?? '#000000',\n custom: (hex) => patchFor(hex.toUpperCase()),\n }\n}\n\n/** The smallest, largest and default text size in points, and what one step changes. */\nexport const FONT_SIZE_MIN = 1\nexport const FONT_SIZE_MAX = 144\nexport const FONT_SIZE_DEFAULT = 12\nexport const FONT_SIZE_STEP = 1\n\n/** A typed size as the menu stores it: a whole number of points within the range. */\nexport function clampFontSize(size: number): number {\n return Math.min(FONT_SIZE_MAX, Math.max(FONT_SIZE_MIN, Math.round(size)))\n}\n\nexport type TextToggleKey = 'bold' | 'italic' | 'underline'\nexport type TextAlignKey = 'left' | 'center' | 'right' | 'justify'\n\nexport interface TextStyleToggle {\n key: TextToggleKey\n label: string\n /** `'mixed'` when the selection disagrees. */\n pressed: boolean | 'mixed'\n /** What pressing writes: the opposite of `pressed`, and on for a mix. */\n patch: StyleProps\n}\n\nexport interface TextAlignChoice {\n key: TextAlignKey\n label: string\n checked: boolean\n /** The one radio in the Tab order: the checked one, else the first. */\n tabStop: boolean\n patch: StyleProps\n}\n\nexport interface TextStyleMenuModel {\n label: string\n /** False when nothing supports text style: the trigger disables. */\n enabled: boolean\n mixed: boolean\n font: {\n label: string\n /** The family, or `''` when the selection disagrees. */\n value: string\n /** The families on offer, each once; a current family outside the list is added. */\n options: string[]\n patch(family: string): StyleProps\n }\n size: {\n label: string\n /** The size, the default when the style sets none, or `null` when the selection disagrees. */\n value: number | null\n min: number\n max: number\n step: number\n /** What committing a typed size writes, or `null` when it changes nothing. */\n commit(raw: number): StyleProps | null\n /** What a stepper press writes, or `null` at the end of the range. */\n nudge(direction: 1 | -1): StyleProps | null\n }\n toggles: TextStyleToggle[]\n align: { label: string; choices: TextAlignChoice[] }\n}\n\nconst TEXT_KEYS: readonly StyleKey[] = [\n 'fontFamily',\n 'fontSize',\n 'fontWeight',\n 'fontStyle',\n 'textDecoration',\n 'textAlign',\n]\n\nconst ALIGN_KEYS: readonly TextAlignKey[] = ['left', 'center', 'right', 'justify']\n\nconst ALIGN_LABELS: Readonly<Record<TextAlignKey, string>> = {\n left: 'Align left',\n center: 'Align centre',\n right: 'Align right',\n justify: 'Justify',\n}\n\n/**\n * What the text style menu shows for a style: the font, size, bold/italic/underline and\n * alignment, each with the patch choosing it. `fonts` is the list the host offers.\n */\nexport function textStyleMenuModel(\n current: CurrentStyle,\n supported: ReadonlySet<StyleKey>,\n fonts: readonly string[]\n): TextStyleMenuModel {\n const family = current.fontFamily\n const size = current.fontSize\n // A style with no size yet (a fresh group) shows the size a new box gets.\n const value =\n size === 'mixed' ? null : typeof size === 'number' ? size : FONT_SIZE_DEFAULT\n const toggle = (\n key: TextToggleKey,\n label: string,\n prop: 'fontWeight' | 'fontStyle' | 'textDecoration',\n on: string,\n off: string\n ): TextStyleToggle => {\n const now = current[prop]\n const pressed = now === 'mixed' ? 'mixed' : now === on\n return { key, label, pressed, patch: { [prop]: pressed === true ? off : on } }\n }\n const nudge = (direction: 1 | -1): StyleProps | null => {\n const next = clampFontSize((value ?? FONT_SIZE_DEFAULT) + direction * FONT_SIZE_STEP)\n return next === value ? null : { fontSize: next }\n }\n return {\n label: 'Text style',\n enabled: TEXT_KEYS.some((k) => supported.has(k)),\n // The panel holds the text colour too, so a mix of colours shows on the trigger.\n mixed: [...TEXT_KEYS, 'textColor' as const].some((k) => current[k] === 'mixed'),\n font: {\n label: 'Font',\n value: typeof family === 'string' && family !== 'mixed' ? family : '',\n options: [\n ...new Set(\n typeof family === 'string' && family !== 'mixed' ? [...fonts, family] : fonts\n ),\n ],\n patch: (f) => ({ fontFamily: f }),\n },\n size: {\n label: 'Font size',\n value,\n min: FONT_SIZE_MIN,\n max: FONT_SIZE_MAX,\n step: FONT_SIZE_STEP,\n commit: (raw) => {\n if (!Number.isFinite(raw)) return null\n const next = clampFontSize(raw)\n return next === value ? null : { fontSize: next }\n },\n nudge,\n },\n toggles: [\n toggle('bold', 'Bold', 'fontWeight', 'bold', 'normal'),\n toggle('italic', 'Italic', 'fontStyle', 'italic', 'normal'),\n toggle('underline', 'Underline', 'textDecoration', 'underline', 'none'),\n ],\n align: {\n label: 'Alignment',\n choices: ALIGN_KEYS.map((key, i) => ({\n key,\n label: ALIGN_LABELS[key],\n checked: current.textAlign === key,\n tabStop:\n current.textAlign === key ||\n (i === 0 && !ALIGN_KEYS.includes(current.textAlign as TextAlignKey)),\n patch: { textAlign: key },\n })),\n },\n }\n}\n\n/** Accessible names of the shape kinds, as the shape menu announces them. */\nexport const SHAPE_LABELS: Readonly<Record<ShapeKind, string>> = {\n line: 'Line',\n arrow: 'Arrow',\n rectangle: 'Rectangle',\n roundedRectangle: 'Rounded rectangle',\n ellipse: 'Ellipse',\n bubble: 'Speech bubble',\n star: 'Star',\n polygon: 'Polygon',\n loupe: 'Loupe',\n mask: 'Mask',\n ovalMask: 'Oval mask',\n}\n\n/** Accessible names of the text markup kinds, as the highlight menu announces them. */\nexport const MARKUP_LABELS: Readonly<Record<MarkupKind, string>> = {\n highlight: 'Highlight',\n underline: 'Underline',\n strikeout: 'Strikethrough',\n squiggly: 'Squiggly underline',\n}\n\nexport interface HighlightMenuItem {\n kind: MarkupKind\n label: string\n checked: boolean\n}\n\nexport interface HighlightMenuModel {\n /** The kind the main button makes. */\n kind: MarkupKind\n /** The main button's accessible name. */\n label: string\n /** The kinds on offer, in menu order, with the current one checked. */\n items: HighlightMenuItem[]\n}\n\n/** What the highlight menu shows for the highlight tool's options. */\nexport function highlightMenuModel(\n options: Partial<HighlightOptions>,\n kinds: readonly MarkupKind[]\n): HighlightMenuModel {\n const kind =\n options.kind !== undefined && kinds.includes(options.kind)\n ? options.kind\n : (kinds[0] ?? 'highlight')\n return {\n kind,\n label: MARKUP_LABELS[kind],\n items: kinds.map((k) => ({ kind: k, label: MARKUP_LABELS[k], checked: k === kind })),\n }\n}\n\n/** Columns of the shape grid: the arrow keys move by this much between rows. */\nexport const SHAPE_COLUMNS = 2\n\nexport interface ShapeMenuItem {\n kind: ShapeKind\n label: string\n checked: boolean\n}\n\nexport interface ShapeMenuModel {\n /** The kind the main button draws. */\n kind: ShapeKind\n /** The main button's accessible name. */\n label: string\n /** The kinds on offer, in menu order, with the current one checked. */\n items: ShapeMenuItem[]\n}\n\n/**\n * What the shape menu shows for the shape tool's options, over the kinds in `kinds`\n * (`SHAPE_KINDS`). A kind that is not on offer falls back to `rectangle` when that is offered,\n * else to the first.\n */\nexport function shapeMenuModel(\n options: Partial<ShapeOptions>,\n kinds: readonly ShapeKind[]\n): ShapeMenuModel {\n const kind =\n options.kind !== undefined && kinds.includes(options.kind)\n ? options.kind\n : (kinds.find((k) => k === 'rectangle') ?? kinds[0] ?? 'rectangle')\n return {\n kind,\n label: `Shape: ${SHAPE_LABELS[kind]}`,\n items: kinds.map((k) => ({ kind: k, label: SHAPE_LABELS[k], checked: k === kind })),\n }\n}\n\n/** The overlay's per-annotation state, as on its `data-state` attribute. */\nexport type AnnotationState = 'idle' | 'hover' | 'selected'\n\n/**\n * What a host-rendered annotation receives: Vue's `annotation` slot and React's\n * `renderAnnotation`.\n */\nexport interface AnnotationSlotProps {\n annotation: Annotation\n state: AnnotationState\n locked: boolean\n select: () => void\n remove: () => void\n}\n\n/** The thread popover's accessible name: \"Note thread\" for a note, \"Comment thread\" for markup. */\nexport function threadPopoverLabel(root: Pick<Annotation, 'type'>): string {\n return root.type === 'text' ? 'Note thread' : 'Comment thread'\n}\n\n/**\n * The thread popover's delete button. It removes the root and its replies, so on text markup\n * it says it deletes the highlight, not only the comment.\n */\nexport function threadDeleteLabel(root: Pick<Annotation, 'type'>): string {\n return root.type === 'text' ? 'Delete' : 'Delete highlight'\n}\n\n/** What a host-rendered comment thread receives: a note's, or text markup's. */\nexport interface ThreadPopoverSlotProps {\n root: NoteAnnotation | TextMarkupAnnotation\n replies: Annotation[]\n reply: (text: string) => void\n update: (contents: string) => void\n remove: () => void\n close: () => void\n}\n\n/** The signature controls' words, shared so every binding announces the same names. */\nexport const SIGNATURE_LABELS = {\n /** The menu's group and main button. */\n sign: 'Sign',\n trigger: 'Choose signature',\n menu: 'Signatures',\n saved: 'Saved signatures',\n create: 'Create signature',\n /** The dialog's title. */\n dialog: 'Create signature',\n tabs: 'Signature source',\n draw: 'Draw',\n type: 'Type',\n image: 'Image',\n pad: 'Signature pad',\n clear: 'Clear',\n name: 'Name',\n namePlaceholder: 'Your name',\n fonts: 'Font',\n file: 'Image file',\n cancel: 'Cancel',\n save: 'Save',\n} as const\n\n/** The dialog's tabs, in order. */\nexport const SIGNATURE_TABS = ['draw', 'type', 'image'] as const\nexport type SignatureTab = (typeof SIGNATURE_TABS)[number]\n\nexport interface SignatureMenuItem {\n id: string\n /** `Signature 1`, `Signature 2`… in saved order. */\n label: string\n /** The remove button's accessible name. */\n removeLabel: string\n checked: boolean\n template: SignatureTemplate\n}\n\nexport interface SignatureMenuModel {\n /** The template the tool places, when it is still saved. */\n selected: SignatureTemplate | undefined\n items: SignatureMenuItem[]\n}\n\n/** What the signature menu shows for the saved templates and the signature tool's options. */\nexport function signatureMenuModel(\n templates: readonly SignatureTemplate[],\n options: SignatureOptions\n): SignatureMenuModel {\n const items = templates.map((template, i) => ({\n id: template.id,\n label: `Signature ${i + 1}`,\n removeLabel: `Remove signature ${i + 1}`,\n checked: template.id === options.templateId,\n template,\n }))\n return { selected: items.find((i) => i.checked)?.template, items }\n}\n","// Keyboard support the style menus share across the bindings and the vanilla factories. Items\n// are `[role=\"menuitemradio\"]` (or `menuitem`) buttons that are not focus stops themselves\n// (`tabindex=\"-1\"`): the menu moves focus between them, and Tab leaves the menu.\n//\n// An element with `data-ink-menu-columns=\"N\"` lays its items out as a grid N wide: ArrowLeft\n// and ArrowRight move within a row, ArrowUp and ArrowDown between rows, and past the first or\n// last row they carry on to the items before or after the grid.\n\nconst ITEMS =\n ':is([role=\"menuitemradio\"], [role=\"menuitem\"]):not(:disabled):not([aria-disabled=\"true\"])'\n\n/** The menu's enabled items in document order. */\nexport function menuItems(root: ParentNode): HTMLElement[] {\n return [...root.querySelectorAll<HTMLElement>(ITEMS)]\n}\n\n/** Focuses the first checked item, else the first enabled one. */\nexport function focusInitialMenuItem(root: ParentNode): void {\n const items = menuItems(root)\n const target =\n items.find((el) => el.getAttribute('aria-checked') === 'true') ?? items[0]\n target?.focus({ preventScroll: true })\n}\n\n/** The index to focus for a key, or -1 when the key means nothing here. */\nfunction nextIndex(key: string, items: HTMLElement[], i: number): number {\n const last = items.length - 1\n if (key === 'Home') return 0\n if (key === 'End') return last\n const grid = items[i]?.closest<HTMLElement>('[data-ink-menu-columns]')\n const cols = Number(grid?.dataset.inkMenuColumns)\n if (grid && cols > 0) {\n const cells = items.filter((el) => grid.contains(el))\n const first = items.indexOf(cells[0]!)\n const end = first + cells.length - 1\n const at = i - first\n if (key === 'ArrowRight')\n return at % cols === cols - 1 || at === cells.length - 1 ? i : i + 1\n if (key === 'ArrowLeft') return at % cols === 0 ? i : i - 1\n if (key === 'ArrowDown')\n return at + cols < cells.length ? i + cols : end === last ? 0 : end + 1\n if (key === 'ArrowUp')\n return at - cols >= 0 ? i - cols : first === 0 ? last : first - 1\n return -1\n }\n if (key === 'ArrowDown') return i < 0 || i === last ? 0 : i + 1\n if (key === 'ArrowUp') return i <= 0 ? last : i - 1\n return -1\n}\n\n/**\n * ArrowDown and ArrowUp move between enabled items and wrap; Home and End go to the ends.\n * Inside a grid the arrow keys move in both directions.\n */\nexport function handleMenuKeys(e: KeyboardEvent, root: ParentNode): void {\n if (e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey) return\n const items = menuItems(root)\n if (items.length === 0) return\n const next = nextIndex(\n e.key,\n items,\n items.indexOf(document.activeElement as HTMLElement)\n )\n if (next < 0) return\n e.preventDefault()\n items[next]!.focus({ preventScroll: true })\n}\n\n/**\n * Arrow keys inside a `role=\"radiogroup\"`: the next (or previous) enabled `role=\"radio\"`\n * takes focus and is chosen, wrapping at the ends, as a native radio group does.\n */\nexport function handleRadioKeys(e: KeyboardEvent, group: ParentNode): void {\n if (e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return\n const forward = e.key === 'ArrowRight' || e.key === 'ArrowDown'\n if (!forward && e.key !== 'ArrowLeft' && e.key !== 'ArrowUp') return\n const radios = [...group.querySelectorAll<HTMLElement>('[role=\"radio\"]:not(:disabled)')]\n const at = radios.indexOf(document.activeElement as HTMLElement)\n if (at < 0) return\n e.preventDefault()\n const next = radios[(at + (forward ? 1 : -1) + radios.length) % radios.length]!\n next.focus({ preventScroll: true })\n next.click()\n}\n\n/**\n * Arrow keys, Home and End inside a `role=\"tablist\"`: the next (or previous) enabled\n * `role=\"tab\"` takes focus and is chosen, wrapping at the ends.\n */\nexport function handleTabKeys(e: KeyboardEvent, tablist: ParentNode): void {\n if (e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return\n const tabs = [\n ...tablist.querySelectorAll<HTMLElement>(\n '[role=\"tab\"]:not(:disabled):not([aria-disabled=\"true\"])'\n ),\n ]\n const at = tabs.indexOf(document.activeElement as HTMLElement)\n if (at < 0) return\n const last = tabs.length - 1\n const next =\n e.key === 'ArrowRight' || e.key === 'ArrowDown'\n ? at === last\n ? 0\n : at + 1\n : e.key === 'ArrowLeft' || e.key === 'ArrowUp'\n ? at === 0\n ? last\n : at - 1\n : e.key === 'Home'\n ? 0\n : e.key === 'End'\n ? last\n : -1\n if (next < 0) return\n e.preventDefault()\n tabs[next]!.focus({ preventScroll: true })\n tabs[next]!.click()\n}\n\nconst TABBABLE = [\n 'a[href]',\n 'button:not(:disabled)',\n 'input:not(:disabled):not([type=\"hidden\"])',\n 'select:not(:disabled)',\n 'textarea:not(:disabled)',\n '[tabindex]',\n]\n .map((s) => `${s}:not([tabindex=\"-1\"])`)\n .join(', ')\n\n/**\n * Keeps Tab inside `container`, a modal: Tab from its last stop goes to its first, and\n * Shift+Tab from the first to the last.\n */\nexport function trapTab(e: KeyboardEvent, container: HTMLElement): void {\n if (e.key !== 'Tab' || e.defaultPrevented) return\n const stops = [...container.querySelectorAll<HTMLElement>(TABBABLE)].filter(\n (el) => !el.matches(':disabled') && el.getClientRects().length > 0\n )\n if (stops.length === 0) {\n e.preventDefault()\n return\n }\n const first = stops[0]!\n const last = stops[stops.length - 1]!\n const active = document.activeElement\n if (e.shiftKey && (active === first || !container.contains(active))) {\n e.preventDefault()\n last.focus()\n } else if (!e.shiftKey && (active === last || !container.contains(active))) {\n e.preventDefault()\n first.focus()\n }\n}\n","/*\n * The wiring every viewer needs: a viewport over the scroll element, page layers in each page\n * host it creates, page-error tracking, the tool controller and keyboard shortcuts. Framework\n * bindings and `createViewer` sit on top: they render their own chrome and get pages and\n * errors back through the callbacks.\n */\nimport { InkError, isInkError } from '../model/errors'\nimport {\n createMemorySignatureStore,\n createSignatureLibrary,\n type SignatureLibrary,\n type SignatureStore,\n} from '../model/signatures'\n\nimport { createPageMount, type PageLayer, type PageMount } from './page-mount'\nimport { createPluginLayers } from './plugins/layer'\nimport { getSelectionQuads } from './selection'\nimport {\n createToolController,\n createToolOptions,\n trackToolStyle,\n withHostTools,\n type Tool,\n type ToolController,\n type ToolId,\n type ToolOptions,\n} from './tools'\nimport { FONT_FAMILIES, SIGNATURE_FONTS } from './ui'\nimport { createViewport, type Viewport, type ZoomValue } from './viewport'\nimport { attachViewportKeys } from './viewport-keys'\n\nimport type { LayoutMode } from './layout'\nimport type { DecorateAnnotation } from './overlay'\nimport type { PluginHost } from './plugins/host'\nimport type { PageTransform, ViewRotation } from './transform'\nimport type { ToolStyle } from '../model/annotations/tool-style'\nimport type { InkDocument } from '../model/document'\nimport type { Point } from '../model/geometry'\n\n/** A user-space point on a page, used to put the scroll position back after a rebuild. */\ninterface ScrollAnchor {\n page: number\n user: Point\n /** Whether the vertical position is restored too, not only the horizontal one. */\n vertical: boolean\n}\n\nexport interface MountViewerOptions {\n container: HTMLElement\n document: InkDocument\n zoom?: ZoomValue\n page?: number\n mode?: LayoutMode\n rotation?: ViewRotation\n gap?: number\n buffer?: number\n tool?: ToolId\n /**\n * Host tools, added to the built-ins. A host tool with a built-in's id replaces it. The same\n * instances are reused when the engine rebuilds.\n */\n tools?: Tool[]\n /**\n * The tools' options (the shape kind, the highlight kind…). A binding or `createViewer` passes\n * one it keeps for its own life, so options persist across documents, as for the life of the\n * viewer. By default the engine makes one, which lasts as long as the engine.\n */\n toolOptions?: ToolOptions\n /**\n * The style the tools create with. A binding passes its own, made with `trackToolStyle` and\n * its own history (and keeps its active group in step with the tool). By default the engine\n * makes one over the document's history.\n */\n toolStyle?: ToolStyle\n /**\n * The history the tools group a gesture's changes with (a group move, a sketch's swap to its\n * shape). A binding passes its own, so a controlled host's undo steps match the gesture. By\n * default the document's history.\n */\n toolHistory?: { batch(fn: () => void): void }\n /**\n * The font families text boxes offer, replacing the default `FONT_FAMILIES` (the PDF\n * standard families). Fonts beyond those are the PDF writer's to embed.\n */\n fonts?: string[]\n /**\n * Where signature templates live. Default: memory, gone on reload\n * (`createMemorySignatureStore`). `createLocalSignatureStore` keeps them in the browser.\n */\n signatures?: SignatureStore\n /**\n * The templates the `signature` tool and the signature controls share. A binding or\n * `createViewer` passes its own, so they outlive one document; it wins over `signatures`.\n * A function is read each time the library is needed, so a host that swaps its library\n * after mount reaches the tool too.\n */\n signatureLibrary?: SignatureLibrary | (() => SignatureLibrary)\n /**\n * The handwriting fonts a typed signature offers. The host loads them (`@font-face`).\n * Default `SIGNATURE_FONTS`.\n */\n signatureFonts?: string[]\n /** Annotation content is rendered by the host (custom slots). Changing it needs `rebuild`. */\n customAnnotations?: boolean\n /**\n * The app's own data attributes, classes and description for each annotation element, to\n * style or find its marks: `{ data: { 'my-flag': 'on' } }` writes `data-my-flag=\"on\"`.\n * Decorations re-apply whenever the annotations change; when the function's output changes\n * for another reason (app state it reads), call `redecorate()`. Core's attributes and `ink-`\n * classes cannot be overridden.\n */\n decorateAnnotation?: DecorateAnnotation\n /**\n * The viewer's plugins. Their tools join `tools`, their layers are drawn on every page the\n * engine mounts, and the host's `decorate` replaces `decorateAnnotation`: build the host with\n * the app's decoration (its `decorate` option) so the two compose.\n */\n plugins?: PluginHost\n onActivate?(id: string): void\n /**\n * After every (re)build: subscribe to the new viewport and controller here. It fires inside\n * `mountViewer` before it returns, and after the build's `onPageMount` calls.\n */\n onBuild?(viewport: Viewport, tools: ToolController): void\n /**\n * The viewport mounts pages synchronously, so a build's `onPageMount` calls fire before its\n * `onBuild` (on the first build, before `mountViewer` returns). Do not read `engine.viewport`\n * or `engine.tools` here: during a rebuild they still point at the destroyed objects. Use\n * the arguments, or wait for `onBuild`.\n */\n onPageMount?(page: number, mount: PageMount, host: HTMLElement): void\n /** Same ordering rule as `onPageMount`: do not read `engine.viewport` or `engine.tools`. */\n onPageUnmount?(page: number): void\n /**\n * `error` when a page's canvas or text layer fails; `null` once every failed layer recovers.\n * Unmounting a failed page does not emit `null`: hosts that track errors by page must clear\n * them in `onPageUnmount`. Same ordering rule as `onPageMount`: do not read `engine.viewport`\n * or `engine.tools`.\n */\n onPageError?(page: number, error: InkError | null): void\n}\n\nexport interface ViewerEngine {\n readonly viewport: Viewport\n readonly tools: ToolController\n /**\n * The style each group creates with, shared by the tools and the style controls. It lives as\n * long as the engine, across rebuilds.\n */\n readonly toolStyle: ToolStyle\n /** The font families text boxes offer: the `fonts` option, else `FONT_FAMILIES`. */\n readonly fonts: readonly string[]\n /** The signature templates: the host's current library, or the engine's own. */\n readonly signatures: SignatureLibrary\n /** The fonts a typed signature offers: the `signatureFonts` option, else `SIGNATURE_FONTS`. */\n readonly signatureFonts: readonly string[]\n readonly pages: ReadonlyMap<number, PageMount>\n /**\n * Recreates the viewport for construction-only options, keeping zoom, page, mode, rotation\n * and tool. The scroll position is kept too: the user-space point at the top-left of the\n * visible area stays there. When that corner is in a gap rather than on a page, the page below\n * the gap lands where `scrollToPage` puts it, with the new gap above it.\n */\n rebuild(opts: { gap?: number; buffer?: number; customAnnotations?: boolean }): void\n /**\n * Runs `decorateAnnotation` (or the plugins' `decorate`) again for every mounted annotation\n * element, without re-rendering anything else. Call it when the decorations would change but\n * no annotation did.\n */\n redecorate(): void\n destroy(): void\n}\n\nexport function mountViewer(opts: MountViewerOptions): ViewerEngine {\n const { container: el, document: doc } = opts\n const pages = new Map<number, PageMount>()\n let gap = opts.gap\n let buffer = opts.buffer\n let custom = opts.customAnnotations ?? false\n let viewport: Viewport\n let tools: ToolController\n let stopKeys: () => void = () => undefined\n let stopActive: () => void = () => undefined\n let destroyed = false\n const plugins = opts.plugins\n const hostTools = [...(opts.tools ?? []), ...(plugins?.tools ?? [])]\n /** Plugin layers follow the host for the engine's life, across rebuilds. */\n const layers = plugins && createPluginLayers(plugins)\n const decorate: DecorateAnnotation = plugins\n ? (a) => plugins.decorate(a)\n : (a) => opts.decorateAnnotation?.(a)\n /** A plugin's `ctx.redecorate()` reaches every page this engine has mounted. */\n const stopRedecorate = plugins?.watchRedecorate(() => {\n for (const mount of pages.values()) mount.overlay.redecorate()\n })\n /** Option values outlive rebuilds: every controller shares this registry. */\n const toolOptions = opts.toolOptions ?? createToolOptions()\n /** Without a host style, the engine's own follows the active tool across rebuilds. */\n const tracker = opts.toolStyle\n ? undefined\n : trackToolStyle({\n store: doc.annotations,\n history: opts.toolHistory ?? doc.history,\n tools: hostTools,\n tool: opts.tool,\n })\n const toolStyle = opts.toolStyle ?? (tracker as NonNullable<typeof tracker>).toolStyle\n const host = opts.signatureLibrary\n const own = host\n ? undefined\n : createSignatureLibrary(opts.signatures ?? createMemorySignatureStore())\n /** The library now: a host getter is read each time, so a swapped library takes effect. */\n const signatures = (): SignatureLibrary =>\n typeof host === 'function' ? host() : (host ?? (own as SignatureLibrary))\n void signatures().refresh()\n\n function mountPage(page: number, host: HTMLElement, transform: PageTransform): void {\n /** Layers that failed and have not rendered since; the error clears when this empties. */\n const failed = new Set<PageLayer>()\n let error: InkError | null = null\n const isCustom = custom\n const mount = createPageMount({\n document: doc,\n page,\n host,\n transform,\n store: doc.annotations,\n onActivate: (id) => opts.onActivate?.(id),\n isCustom: () => isCustom,\n decorate,\n ...(layers ? { layers } : {}),\n onError: (cause, layer) => {\n failed.add(layer)\n // The first failure wins: a canvas and a text layer failing together report once.\n if (error) return\n error = isInkError(cause)\n ? cause\n : new InkError(\n 'InvalidPdf',\n cause instanceof Error ? cause.message : String(cause),\n { page },\n cause\n )\n host.setAttribute('data-state', 'error')\n opts.onPageError?.(page, error)\n },\n onRendered: (layer) => {\n failed.delete(layer)\n if (!error || failed.size > 0) return\n error = null\n host.removeAttribute('data-state')\n opts.onPageError?.(page, null)\n },\n })\n pages.set(page, mount)\n opts.onPageMount?.(page, mount, host)\n }\n\n function unmountPage(page: number): void {\n const mount = pages.get(page)\n if (!mount) return\n pages.delete(page)\n opts.onPageUnmount?.(page)\n mount.destroy()\n }\n\n /** The client point at the top-left of the container's visible content area. */\n function viewTopLeft(): Point {\n const r = el.getBoundingClientRect()\n return { x: r.left + el.clientLeft, y: r.top + el.clientTop }\n }\n\n /** The client point of the pages element's top-left: the origin of the layout's page boxes. */\n function layoutOrigin(): Point | undefined {\n const pagesEl = el.querySelector<HTMLElement>(':scope > [data-ink-pages]')\n if (!pagesEl) return undefined\n const r = pagesEl.getBoundingClientRect()\n return { x: r.left, y: r.top }\n }\n\n /**\n * Where the view sits before a rebuild: the user-space point under the top-left of the\n * visible area, on the page whose box contains it. When the top of the view is in a gap or a\n * margin, only the horizontal position is kept, and the page lands where `scrollToPage` puts\n * it, the new gap above it (a view resting at a page boundary stays at that boundary).\n */\n function scrollAnchor(vp: Viewport): ScrollAnchor | undefined {\n const o = layoutOrigin()\n if (!o) return undefined\n const corner = viewTopLeft()\n const x = corner.x - o.x\n const y = corner.y - o.y\n const boxes = vp.layout.get().boxes\n const inside = boxes.find((b) => y >= b.top && y < b.top + b.height)\n // In a gap or margin: the page just below it, which the view reaches first. Past the\n // last page there is none, so the current page stands in.\n const box =\n inside ??\n boxes.find((b) => b.top > y) ??\n boxes.find((b) => b.index === vp.currentPage.get())\n if (!box) return undefined\n // Transforms are affine, so a point left or right of the page maps back exactly too.\n const user = vp.transformFor(box.index).fromCss({ x: x - box.left, y: y - box.top })\n return { page: box.index, user, vertical: inside !== undefined }\n }\n\n /** Scrolls so the anchor's point sits under the top-left of the visible area again. */\n function restoreScroll(vp: Viewport, anchor: ScrollAnchor): void {\n const o = layoutOrigin()\n const box = vp.layout.get().boxes.find((b) => b.index === anchor.page)\n if (!o || !box) return\n const css = vp.transformFor(anchor.page).toCss(anchor.user)\n const corner = viewTopLeft()\n el.scrollLeft += o.x + box.left + css.x - corner.x\n if (anchor.vertical) el.scrollTop += o.y + box.top + css.y - corner.y\n }\n\n function build(state: {\n zoom: ZoomValue\n page: number | undefined\n mode: LayoutMode | undefined\n rotation: ViewRotation | undefined\n tool: ToolId | undefined\n anchor?: ScrollAnchor | undefined\n }): void {\n const vp = createViewport({\n container: el,\n document: doc,\n zoom: state.zoom,\n ...(state.mode === undefined ? {} : { mode: state.mode }),\n ...(state.rotation === undefined ? {} : { rotation: state.rotation }),\n ...(gap === undefined ? {} : { gap }),\n ...(buffer === undefined ? {} : { buffer }),\n onMount: mountPage,\n onUpdate: (page, _host, transform) => pages.get(page)?.update(transform),\n onUnmount: unmountPage,\n })\n const list = withHostTools(hostTools)\n const tc = createToolController({\n ...(state.tool === undefined ? {} : { initial: state.tool }),\n tools: list,\n options: toolOptions,\n ctx: {\n toolStyle,\n store: doc.annotations,\n viewport: vp,\n root: el,\n selectionQuads: () =>\n getSelectionQuads(el, (host) => {\n const page = Number(host.dataset.page)\n return { page, transform: vp.transformFor(page) }\n }),\n clearSelection: () =>\n el.ownerDocument.defaultView?.getSelection()?.removeAllRanges(),\n onActivate: (id) => opts.onActivate?.(id),\n history: opts.toolHistory ?? doc.history,\n get signatures() {\n return signatures()\n },\n },\n })\n viewport = vp\n tools = tc\n if (tracker) {\n tracker.setTool(tc.active.get())\n stopActive = tc.active.subscribe((id) => tracker.setTool(id))\n }\n stopKeys = attachViewportKeys(el, { viewport: vp, pageCount: () => doc.pages.length })\n // A view resting in a gap lands on the page below it, not on the most visible page.\n // The scroll position resets on teardown, so the guard below must not skip a gap anchor.\n if (state.anchor && !state.anchor.vertical) vp.scrollToPage(state.anchor.page)\n else if (state.page !== undefined && state.page !== vp.currentPage.get())\n vp.scrollToPage(state.page)\n if (state.anchor) restoreScroll(vp, state.anchor)\n opts.onBuild?.(vp, tc)\n }\n\n function teardown(): void {\n stopKeys()\n stopActive()\n tools.destroy()\n // The viewport unmounts every page it mounted, which destroys the page mounts.\n viewport.destroy()\n for (const page of [...pages.keys()]) unmountPage(page)\n }\n\n build({\n zoom: opts.zoom ?? 'fit-width',\n page: opts.page,\n mode: opts.mode,\n rotation: opts.rotation,\n tool: opts.tool,\n })\n\n return {\n get viewport() {\n return viewport\n },\n get tools() {\n return tools\n },\n toolStyle,\n fonts: opts.fonts ? [...opts.fonts] : FONT_FAMILIES,\n get signatures() {\n return signatures()\n },\n signatureFonts: opts.signatureFonts ? [...opts.signatureFonts] : SIGNATURE_FONTS,\n pages,\n rebuild(next) {\n if (destroyed) return\n const state = {\n zoom: viewport.zoom.get(),\n page: viewport.currentPage.get(),\n mode: viewport.mode.get(),\n rotation: viewport.rotation.get(),\n tool: tools.active.get(),\n anchor: scrollAnchor(viewport),\n }\n teardown()\n if (next.gap !== undefined) gap = next.gap\n if (next.buffer !== undefined) buffer = next.buffer\n if (next.customAnnotations !== undefined) custom = next.customAnnotations\n build(state)\n },\n redecorate() {\n if (destroyed) return\n for (const mount of pages.values()) mount.overlay.redecorate()\n },\n destroy() {\n if (destroyed) return\n destroyed = true\n teardown()\n layers?.destroy()\n stopRedecorate?.()\n },\n }\n}\n","/*\n * The thread for the activated note or text markup, anchored to the root's overlay element.\n * Activating a reply opens the whole thread from its root. Closing (Close, Escape, a press\n * outside) clears the activation.\n *\n * A new note, or a highlight, has no text. While its root is empty (and unlocked) the form\n * writes the root's own `contents`, labelled \"Comment\", and the thread list stays hidden until\n * there is something in it; after that the form adds replies. A note closed, or left for\n * another annotation, while still empty and without replies is removed; markup stays, since\n * the mark is the point. The thread list re-renders on every store change; the form, and the\n * draft in it, stays until the popover moves to another thread or the root is gone.\n */\nimport {\n isAbandonedNote,\n isThreadRoot,\n threadOf,\n threadRoot,\n type ThreadRoot,\n} from '../../model/annotations/threads'\nimport { threadDeleteLabel, threadPopoverLabel } from '../ui'\n\nimport { button, h } from './dom'\nimport { createPopover } from './popover'\n\nimport type { AnnotationStore } from '../../model/annotations/store'\nimport type { Annotation } from '../../model/annotations/types'\nimport type { Writable } from '../../model/readable'\nimport type { FocusReturn } from '../popover-focus'\n\nexport interface ThreadPopoverOptions {\n root: HTMLElement\n store: AnnotationStore\n activated: Writable<string | null>\n focusReturn: FocusReturn\n}\n\nexport function createThreadPopover(opts: ThreadPopoverOptions): { destroy(): void } {\n const { root, store, activated, focusReturn } = opts\n const popover = createPopover({\n root,\n attrs: {\n class: 'ink-thread-popover',\n 'data-ink-thread-popover': '',\n 'aria-label': 'Note thread',\n },\n focusReturn,\n onDismiss: close,\n })\n const thread = h('ol', { class: 'ink-thread', 'data-ink-thread': '' })\n let form: ThreadForm | null = null\n /** The thread root shown now. */\n let current: string | null = null\n /** Roots given text or a reply here: never dropped as abandoned. */\n const written = new Set<string>()\n /** Notes already removed from here, so they are not removed twice. */\n const dropped = new Set<string>()\n\n function shown(): ThreadRoot | null {\n const a = current ? store.get(current) : undefined\n return a && isThreadRoot(a) ? a : null\n }\n\n function target(): ThreadRoot | null {\n const list = store.list.get()\n const id = activated.get()\n const a = id === null ? undefined : list.find((x) => x.id === id)\n return a ? threadRoot(list, a) : null\n }\n\n const editingRoot = (n: ThreadRoot): boolean => !n.locked && !n.contents?.trim()\n\n /** A note that closing now would remove. */\n function isEmptyRoot(n: ThreadRoot): boolean {\n return !written.has(n.id) && isAbandonedNote(n, store.list.get())\n }\n\n function dropIfEmpty(id: string): void {\n const list = store.list.get()\n const a = list.find((x) => x.id === id)\n if (!a || dropped.has(id) || written.has(id) || !isAbandonedNote(a, list)) return\n dropped.add(id)\n store.remove(id)\n }\n\n function renderThread(n: ThreadRoot): void {\n const items = threadOf(store.list.get(), n)\n if (editingRoot(n) && items.length === 1) {\n thread.remove()\n return\n }\n thread.replaceChildren(...items.map(threadItem))\n if (!thread.isConnected) popover.panel.prepend(thread)\n }\n\n function update(): void {\n const n = target()\n const id = n?.id ?? null\n if (id === current) {\n if (n && form) {\n renderThread(n)\n form.sync(n)\n }\n return\n }\n const previous = current\n current = id\n if (n) {\n const hadFocus = popover.panel.contains(document.activeElement)\n const opening = popover.panel.hidden\n form = createThreadForm(n, { submit, remove: removeThread, close })\n popover.panel.replaceChildren(form.element)\n popover.panel.setAttribute('aria-label', threadPopoverLabel(n))\n renderThread(n)\n popover.show(n.id)\n if ((opening || hadFocus) && !popover.panel.hidden) form.textarea.focus()\n } else {\n form = null\n popover.hide()\n }\n // Activation moved on from a note that never got any text: drop it. This can re-enter\n // `update`, which finds `current` already settled.\n if (previous !== null) dropIfEmpty(previous)\n }\n\n function submit(text: string): void {\n const n = shown()\n if (!n) return\n written.add(n.id)\n if (editingRoot(n)) store.update(n.id, { contents: text })\n else\n store.add({\n type: 'text',\n page: n.page,\n rect: n.rect,\n contents: text,\n inReplyTo: n.id,\n })\n }\n\n /** Locked roots cannot be removed: Delete is not offered for them. */\n function removeThread(): void {\n const n = shown()\n if (!n || n.locked) return\n focusReturn.beforeRemove(popover.anchor)\n dropped.add(n.id)\n store.remove(n.id)\n activated.set(null)\n }\n\n function close(): void {\n const n = shown()\n if (n && isEmptyRoot(n)) focusReturn.beforeRemove(popover.anchor)\n // `update` hides the popover and drops the note if it is still empty.\n activated.set(null)\n }\n\n const stops = [store.list.subscribe(update), activated.subscribe(update)]\n update()\n\n return {\n destroy() {\n for (const stop of stops) stop()\n popover.destroy()\n },\n }\n}\n\nfunction threadItem(a: Annotation): HTMLLIElement {\n return h(\n 'li',\n {\n class: 'ink-thread-item',\n 'data-ink-thread-item': '',\n ...(a.inReplyTo ? { 'data-reply': '' } : {}),\n },\n h('span', { class: 'ink-thread-author' }, a.author ?? 'Anonymous'),\n h(\n 'time',\n { class: 'ink-thread-time', datetime: a.createdAt },\n new Date(a.createdAt).toLocaleString()\n ),\n h('p', { class: 'ink-thread-text' }, a.contents ?? '')\n )\n}\n\ninterface ThreadForm {\n readonly element: HTMLFormElement\n readonly textarea: HTMLTextAreaElement\n /** Follows the root's state: \"Comment\" while its own text is empty, \"Reply\" after. */\n sync(n: ThreadRoot): void\n}\n\nfunction createThreadForm(\n n: ThreadRoot,\n actions: { submit: (text: string) => void; remove: () => void; close: () => void }\n): ThreadForm {\n const textarea = h('textarea', { rows: '2' })\n const send = h('button', { type: 'submit' })\n const remove = button(threadDeleteLabel(n), actions.remove)\n const actionRow = h(\n 'div',\n { class: 'ink-thread-actions' },\n send,\n remove,\n button('Close', actions.close)\n )\n const element = h(\n 'form',\n { class: 'ink-thread-reply', 'data-ink-thread-reply': '' },\n textarea,\n actionRow\n )\n const syncSend = (): void => {\n send.disabled = !textarea.value.trim()\n }\n textarea.addEventListener('input', syncSend)\n element.addEventListener('submit', (e) => {\n e.preventDefault()\n const text = textarea.value.trim()\n if (!text) return\n // Cleared first: the store change re-renders the thread straight away.\n textarea.value = ''\n syncSend()\n actions.submit(text)\n })\n\n function sync(root: ThreadRoot): void {\n const label = !root.locked && !root.contents?.trim() ? 'Comment' : 'Reply'\n textarea.setAttribute('aria-label', label)\n textarea.placeholder = label\n send.textContent = label\n if (root.locked) remove.remove()\n else if (!remove.isConnected) send.after(remove)\n }\n sync(n)\n syncSend()\n return { element, textarea, sync }\n}\n","/*\n * A viewer without a framework: opens a document, mounts the engine and renders the note\n * thread popover, with the bindings' markup so `@inkbar/theme` styles it unchanged.\n * Toolbars are the host's, built from the controls in ./controls.\n */\nimport {\n cssVariableDefaults,\n type AnnotationDefaults,\n} from '../../model/annotations/defaults'\nimport {\n openDocument,\n type InkDocument,\n type InkStatus,\n type OpenOptions,\n} from '../../model/document'\nimport { InkError, isInkError } from '../../model/errors'\nimport { readonly, writable, type Readable } from '../../model/readable'\nimport {\n createMemorySignatureStore,\n createSignatureLibrary,\n} from '../../model/signatures'\nimport { createPluginHost, type PluginHost } from '../plugins/host'\nimport { createFocusReturn } from '../popover-focus'\nimport { createToolOptions } from '../tools'\nimport { mountViewer, type MountViewerOptions, type ViewerEngine } from '../viewer-engine'\n\nimport { h } from './dom'\nimport { createThreadPopover } from './thread-popover'\n\nimport type { PluginHistory } from '../../model/annotations/history'\nimport type { DocumentSource } from '../../model/source'\nimport type { PdfAssets } from '../../pdfjs/types'\nimport type { Command, InkPlugin } from '../plugins/define'\nimport type { Tool, ToolController } from '../tools'\nimport type { Viewport } from '../viewport'\n\n/**\n * The engine options, less what the viewer owns: the container, the document, the tool style\n * (bound to one document's store, so each engine makes its own), and the tool options and\n * signature library (one for the viewer's life).\n */\nexport interface CreateViewerOptions extends Omit<\n MountViewerOptions,\n | 'container'\n | 'document'\n | 'toolStyle'\n | 'toolHistory'\n | 'toolOptions'\n | 'signatureLibrary'\n | 'plugins'\n> {\n source: DocumentSource\n assets: PdfAssets\n /** User password for encrypted files. `open` can pass its own for one load. */\n password?: string\n /** Default: read from the theme's CSS variables on the viewer root. */\n defaults?: AnnotationDefaults\n history?: OpenOptions['history']\n /**\n * Plugins, set up once for the viewer's life. Their tools join the viewer's tools, their\n * decoration and page layers apply to every document, and their commands are placed with\n * `createCommandButton`.\n */\n plugins?: readonly InkPlugin[]\n /** The thread popover for notes and text markup. Default true. */\n threads?: boolean\n onReady?(this: void, doc: InkDocument): void\n onError?(this: void, error: InkError): void\n}\n\nexport interface Viewer {\n /** The root element (`[data-ink-root]`) the viewer rendered into the host element. */\n readonly element: HTMLElement\n readonly status: Readable<InkStatus>\n readonly document: Readable<InkDocument | null>\n /** Set while a document is ready; `null` otherwise. */\n readonly engine: Readable<ViewerEngine | null>\n /**\n * The current viewport and tool controller; `null` while no document is ready. Both change\n * when the engine rebuilds, so read them here rather than holding on to `engine.viewport`.\n */\n readonly viewport: Readable<Viewport | null>\n readonly tools: Readable<ToolController | null>\n /**\n * The activated annotation's id: the one last clicked, or activated with Enter or Space.\n * The note thread opens from it, and an app can anchor its own popover (`createPopover`) to\n * it. `null` when none is, and again once that annotation is removed or the document closes.\n */\n readonly activated: Readable<string | null>\n /**\n * Activates annotation `id`, or clears the activation with `null` (closing the thread\n * popover). Unlike a click, it does not select the annotation or call `onActivate`. An id\n * not in the open document's annotations is ignored.\n */\n setActivated(id: string | null): void\n /** The plugins' commands by namespaced id (`sandbox.suggest`); place one with `createCommandButton`. */\n readonly commands: { get(id: string): Command | undefined }\n /**\n * Opens another document in place; the previous one is destroyed. Latest call wins.\n * `password` is used for this load only; without it, the constructor's `password` applies.\n */\n open(source: DocumentSource, opts?: { password?: string }): void\n destroy(): void\n}\n\nconst noop = () => undefined\nconst passThrough: PluginHistory = {\n batch: (fn) => fn(),\n track: () => noop,\n react: () => noop,\n}\n\nexport function createViewer(el: HTMLElement, opts: CreateViewerOptions): Viewer {\n const {\n source: initial,\n assets,\n password,\n defaults,\n history,\n plugins,\n threads: withThreads = true,\n onReady,\n onError,\n onActivate,\n onBuild,\n onPageMount,\n onPageUnmount,\n onPageError,\n // Not options (see the type), but a caller without types could still pass them.\n toolStyle: _toolStyle,\n toolOptions: _toolOptions,\n signatureLibrary: _signatureLibrary,\n signatures: signatureStore,\n ...view\n } = opts as CreateViewerOptions &\n Pick<MountViewerOptions, 'toolStyle' | 'toolOptions' | 'signatureLibrary'>\n /** One library for the viewer's life, so templates and the menu outlive each document. */\n const signatures = createSignatureLibrary(\n signatureStore ?? createMemorySignatureStore()\n )\n /** Tool options persist for the viewer's life; the tool style is per document. */\n const toolOptions = createToolOptions()\n const status = writable<InkStatus>({ state: 'idle' })\n const current = writable<InkDocument | null>(null)\n const engine = writable<ViewerEngine | null>(null)\n const viewport = writable<Viewport | null>(null)\n const tools = writable<ToolController | null>(null)\n /** The activated annotation: the note thread opens from it. */\n const activated = writable<string | null>(null)\n\n const rootEl = writable<HTMLElement | null>(null)\n const root = h('div', { 'data-ink-root': '', 'data-state': 'idle' })\n const scroll = h('div', {\n class: 'ink-scroll',\n 'data-ink-scroll': '',\n tabindex: '0',\n role: 'document',\n 'aria-label': 'Document',\n })\n const viewportRoot = h(\n 'div',\n { class: 'ink-viewport-root', 'data-ink-viewport-root': '', 'data-state': 'idle' },\n scroll\n )\n root.append(viewportRoot)\n el.append(root)\n rootEl.set(scroll)\n\n /**\n * One host for the viewer's life. It reads the history when a document opens, and `current`\n * is set before it notifies, so that is the new document's. With no document open, a\n * command's `batch` just runs its function.\n */\n const host: PluginHost = createPluginHost({\n plugins: plugins ?? [],\n document: readonly(current),\n history: () => current.get()?.history ?? passThrough,\n activated: readonly(activated),\n setActivated: (id) => {\n if (id === null || current.get()?.annotations.get(id)) activated.set(id)\n },\n root: readonly(rootEl),\n decorate: () => view.decorateAnnotation,\n viewport: () => viewport.get(),\n })\n\n const focusReturn = createFocusReturn({\n root: () => root,\n activated: () => activated.get(),\n })\n\n let statusEl: HTMLElement | null = null\n function renderStatus(s: InkStatus): void {\n root.dataset.state = s.state\n viewportRoot.dataset.state = s.state\n statusEl?.remove()\n statusEl = null\n if (s.state === 'loading') {\n statusEl = h(\n 'div',\n { class: 'ink-status', role: 'status', 'aria-live': 'polite' },\n 'Loading document…'\n )\n } else if (s.state === 'error') {\n // The engine's message is not written for readers: it stays on the code's tooltip.\n statusEl = h(\n 'div',\n { class: 'ink-status ink-error', role: 'alert' },\n h('p', { class: 'ink-error-title' }, 'This document could not be opened.'),\n h(\n 'p',\n {},\n h('code', { class: 'ink-error-code', title: s.error.message }, s.error.code)\n )\n )\n }\n if (statusEl) viewportRoot.prepend(statusEl)\n }\n function setStatus(s: InkStatus): void {\n renderStatus(s)\n status.set(s)\n }\n\n /** Mounts the engine and the thread popover for a ready document; returns their teardown. */\n function start(doc: InkDocument): () => void {\n const store = doc.annotations\n const threads = withThreads\n ? createThreadPopover({ root, store, activated, focusReturn })\n : null\n // An activated annotation that has gone (removed, undone) is no longer activated, so it\n // does not reopen its popover if it comes back.\n const stopList = store.list.subscribe(() => {\n const id = activated.get()\n if (id !== null && !store.get(id)) activated.set(null)\n })\n const hosts = new Map<number, HTMLElement>()\n const errors = new Map<number, HTMLElement>()\n const clearError = (page: number): void => {\n errors.get(page)?.remove()\n errors.delete(page)\n }\n const mounted = mountViewer({\n ...view,\n plugins: host,\n container: scroll,\n document: doc,\n toolOptions,\n signatureLibrary: signatures,\n onActivate: (id) => {\n activated.set(id)\n onActivate?.(id)\n },\n onBuild: (vp, tc) => {\n // Tools first: a viewport subscriber may read the tools.\n tools.set(tc)\n viewport.set(vp)\n onBuild?.(vp, tc)\n },\n onPageMount: (page, mount, host) => {\n hosts.set(page, host)\n onPageMount?.(page, mount, host)\n },\n // A failed page that unmounts reports no recovery: its error goes with it.\n onPageUnmount: (page) => {\n hosts.delete(page)\n clearError(page)\n onPageUnmount?.(page)\n },\n onPageError: (page, error) => {\n clearError(page)\n const host = hosts.get(page)\n if (error && host) {\n const shown = h(\n 'div',\n { class: 'ink-page-error', 'data-ink-page-error': '', role: 'alert' },\n h('p', {}, `Page ${page + 1} could not be shown.`),\n h('code', { class: 'ink-error-code' }, error.code)\n )\n host.append(shown)\n errors.set(page, shown)\n }\n onPageError?.(page, error)\n },\n })\n engine.set(mounted)\n return () => {\n stopList()\n threads?.destroy()\n activated.set(null)\n engine.set(null)\n mounted.destroy()\n viewport.set(null)\n tools.set(null)\n }\n }\n\n let loads = 0\n let destroyed = false\n let stop: () => void = () => undefined\n\n /** Tears down the open document, if any, and destroys it. */\n function close(): void {\n stop()\n stop = () => undefined\n const doc = current.get()\n current.set(null)\n doc?.destroy()\n }\n\n function open(source: DocumentSource, openOpts?: { password?: string }): void {\n if (destroyed) return\n const load = ++loads\n close()\n setStatus({ state: 'loading' })\n // The theme's colour variables are read from the root, which is in the page by now.\n openDocument(source, {\n assets,\n password: openOpts?.password ?? password,\n defaults: defaults ?? cssVariableDefaults(root),\n history,\n }).then(\n (doc) => {\n // A later `open` or `destroy` superseded this load.\n if (load !== loads) {\n doc.destroy()\n return\n }\n current.set(doc)\n const s = doc.status.get()\n if (s.state === 'error') {\n setStatus(s)\n onError?.(s.error)\n return\n }\n // The status leaves the layout before the engine measures the scroll element, and the\n // engine is set before anyone hears `ready`.\n renderStatus({ state: 'ready' })\n stop = start(doc)\n status.set({ state: 'ready' })\n // A status subscriber may have opened another document already.\n if (load === loads) onReady?.(doc)\n },\n (cause: unknown) => {\n // Only a programmer error (missing assets) rejects; it gets the error state too.\n if (load !== loads) return\n const error = isInkError(cause)\n ? cause\n : new InkError(\n 'InvalidPdf',\n cause instanceof Error ? cause.message : String(cause),\n {},\n cause\n )\n setStatus({ state: 'error', error })\n onError?.(error)\n }\n )\n }\n\n open(initial)\n\n const viewer: Viewer = {\n element: root,\n status: readonly(status),\n document: readonly(current),\n engine: readonly(engine),\n viewport: readonly(viewport),\n tools: readonly(tools),\n activated: readonly(activated),\n setActivated: (id) => {\n if (id === null || current.get()?.annotations.get(id)) activated.set(id)\n },\n commands: { get: (id) => host.command(id) },\n open,\n destroy() {\n if (destroyed) return\n destroyed = true\n loads++\n close()\n host.destroy()\n root.remove()\n },\n }\n toolsByViewer.set(viewer, [...(view.tools ?? []), ...host.tools])\n commandIdsByViewer.set(viewer, () => [...host.commands.keys()])\n return viewer\n}\n\nconst toolsByViewer = new WeakMap<Viewer, readonly Tool[]>()\n\n/** The host tools a viewer was given (its own and its plugins'), for the controls' labels and icons. */\nexport function hostToolsOf(viewer: Viewer): readonly Tool[] {\n return toolsByViewer.get(viewer) ?? []\n}\n\nconst commandIdsByViewer = new WeakMap<Viewer, () => string[]>()\n\n/** The ids of the commands a viewer's plugins registered, for the error on an unknown one. */\nexport function hostCommandIdsOf(viewer: Viewer): string[] {\n return commandIdsByViewer.get(viewer)?.() ?? []\n}\n","/*\n * Toolbar controls for createViewer, with the classes and data attributes of the bindings'\n * components so `@inkbar/theme` styles them. Each control follows a viewer: it is disabled\n * while no document is ready and picks up the new viewport after every engine rebuild. A\n * control lives as long as its viewer.\n *\n * Buttons show an icon from `@inkbar/icons`; replace their children with your own and the\n * accessible name stays. Put controls in a `createToolbar()` bar, and put the bar where it\n * belongs: `viewer.element.prepend(bar)` above the document, `append` below it.\n */\nimport {\n ChevronLeft,\n ChevronRight,\n Highlighter,\n ICON_ATTRIBUTES,\n MessageSquare,\n PenLine,\n PenTool,\n Signature,\n Redo2,\n Square,\n SquareDashedMousePointer,\n TextCursor,\n Type,\n Undo2,\n ZoomIn,\n ZoomOut,\n type IconNode,\n} from '@inkbar/icons'\n\nimport { unknownCommand } from '../plugins/commands'\nimport { TOOL_LABELS, ZOOM_LEVELS } from '../ui'\n\nimport { hostCommandIdsOf, hostToolsOf } from './create-viewer'\nimport { h } from './dom'\n\nimport type { InkDocument } from '../../model/document'\nimport type { Readable } from '../../model/readable'\nimport type { ToolController, ToolId } from '../tools'\nimport type { Viewport } from '../viewport'\nimport type { Viewer } from './create-viewer'\n\ntype Control = HTMLButtonElement | HTMLSelectElement | HTMLInputElement\n\n/**\n * Runs `connect` for every value `source` takes while it is set, undoing the previous run's\n * subscriptions first, and disables `control` while it is `null`.\n */\nfunction follow<T>(\n source: Readable<T | null>,\n control: Control,\n connect: (value: T, watch: <V>(r: Readable<V>, fn: (value: V) => void) => void) => void,\n reset?: () => void\n): void {\n let stops: (() => void)[] = []\n const watch = <V>(r: Readable<V>, fn: (value: V) => void): void => {\n fn(r.get())\n stops.push(r.subscribe(fn))\n }\n const run = (value: T | null): void => {\n for (const s of stops) s()\n stops = []\n control.disabled = value === null\n if (value === null) reset?.()\n else connect(value, watch)\n }\n run(source.get())\n source.subscribe(run)\n}\n\nconst SVG = 'http://www.w3.org/2000/svg'\n\nconst TOOL_ICONS: Readonly<Partial<Record<ToolId, IconNode>>> = {\n 'select-text': TextCursor,\n select: SquareDashedMousePointer,\n highlight: Highlighter,\n 'redact-area': Square,\n sketch: PenTool,\n draw: PenLine,\n note: MessageSquare,\n freetext: Type,\n signature: Signature,\n}\n\n/**\n * An `<svg>` drawing `icon` from `@inkbar/icons`, hidden from assistive technology: the\n * control it sits in carries the name. The theme sizes it with `--ink-icon-size`.\n */\nexport function createIcon(icon: IconNode): SVGSVGElement {\n const svg = document.createElementNS(SVG, 'svg')\n const attrs = {\n ...ICON_ATTRIBUTES,\n width: '18',\n height: '18',\n class: 'ink-icon',\n 'aria-hidden': 'true',\n }\n for (const [k, v] of Object.entries(attrs)) svg.setAttribute(k, v)\n for (const [tag, shape] of icon) {\n const child = document.createElementNS(SVG, tag)\n for (const [k, v] of Object.entries(shape)) child.setAttribute(k, v)\n svg.append(child)\n }\n return svg\n}\n\nfunction button(\n label: string,\n attrs: Record<string, string>,\n icon: IconNode | undefined\n): HTMLButtonElement {\n const b = h('button', { type: 'button', ...attrs, 'aria-label': label, title: label })\n if (icon) b.append(createIcon(icon))\n return b\n}\n\n/**\n * A toolbar following the WAI-ARIA toolbar pattern: its buttons share one Tab stop, with\n * arrow keys, Home and End to move between them. Fields and selects are Tab stops of their\n * own and keep their keys. Buttons added later join in.\n */\nexport function createToolbar(opts: { label?: string } = {}): HTMLElement {\n const bar = h('div', {\n class: 'ink-toolbar',\n 'data-ink-toolbar': '',\n role: 'toolbar',\n 'aria-label': opts.label ?? 'Document tools',\n 'aria-orientation': 'horizontal',\n })\n rovingTabindex(bar)\n return bar\n}\n\n/** A divider between groups of controls in a horizontal toolbar. Not focusable. */\nexport function createToolbarSeparator(): HTMLDivElement {\n return h('div', {\n role: 'separator',\n 'aria-orientation': 'vertical',\n class: 'ink-toolbar-separator',\n 'data-ink-toolbar-separator': '',\n })\n}\n\n/** Undoes the last change to the document's annotations; disabled when there is none. */\nexport function createUndo(viewer: Viewer): HTMLButtonElement {\n return historyButton(viewer, 'undo')\n}\n\n/** Redoes the last undone change; disabled when there is none. */\nexport function createRedo(viewer: Viewer): HTMLButtonElement {\n return historyButton(viewer, 'redo')\n}\n\nfunction historyButton(viewer: Viewer, action: 'undo' | 'redo'): HTMLButtonElement {\n const label = action === 'undo' ? 'Undo' : 'Redo'\n const b = button(\n label,\n { class: `ink-${action}`, [`data-ink-${action}`]: '' },\n action === 'undo' ? Undo2 : Redo2\n )\n b.addEventListener('click', () => viewer.document.get()?.history[action]())\n follow<InkDocument>(viewer.document, b, (doc, watch) =>\n watch(action === 'undo' ? doc.history.canUndo : doc.history.canRedo, (can) => {\n b.disabled = !can\n })\n )\n return b\n}\n\n/**\n * Sets the tool; pressed while it is the active one. A host or plugin tool's button takes the\n * tool's own `label` and `icon`; `opts.label` wins, and without either it is named by the tool id.\n */\nexport function createToolButton(\n viewer: Viewer,\n tool: ToolId,\n opts: { label?: string } = {}\n): HTMLButtonElement {\n const own = hostToolsOf(viewer).find((t) => t.id === tool)\n const label = opts.label ?? TOOL_LABELS[tool] ?? own?.label ?? tool\n const b = button(\n label,\n { class: 'ink-tool-button', 'data-ink-tool-button': '', 'data-tool': tool },\n TOOL_ICONS[tool] ?? own?.icon\n )\n const show = (active: ToolId | null): void => {\n const on = active === tool\n b.dataset.state = on ? 'on' : 'off'\n b.setAttribute('aria-pressed', String(on))\n }\n b.addEventListener('click', () => viewer.tools.get()?.set(tool))\n follow<ToolController>(\n viewer.tools,\n b,\n (tools, watch) => watch(tools.active, show),\n () => show(null)\n )\n return b\n}\n\n/**\n * A plugin command as a button with its status text beside it. The button is named by the\n * command's label and disabled while the command is, except while it runs: then it keeps focus,\n * with `aria-busy` and `aria-disabled`, and a press does nothing. The status is a live region. A command without an icon shows its label as the button's text. For an id no\n * plugin registered it logs `InkError('UnknownCommand')` to the console and returns the same\n * markup disabled, `aria-hidden` and unnamed.\n */\nexport function createCommandButton(viewer: Viewer, id: string): HTMLElement {\n const command = viewer.commands.get(id)\n const status = h('span', { class: 'ink-command-status', role: 'status' })\n if (!command) {\n console.error(unknownCommand(id, hostCommandIdsOf(viewer)))\n const pending = h('button', {\n type: 'button',\n 'data-command': id,\n 'aria-hidden': 'true',\n })\n pending.disabled = true\n return h('div', { class: 'ink-command' }, pending, status)\n }\n const b = button(command.label, { 'data-command': id }, command.icon)\n if (!command.icon) b.textContent = command.label\n b.addEventListener('click', () => void command.run())\n // Enabled follows the command (a ready document by default). A busy command is disabled too,\n // but its button stays enabled so focus stays on it; `run` does nothing meanwhile.\n const sync = () => {\n const busy = command.busy.get()\n b.disabled = !command.enabled.get() && !busy\n b.setAttribute('aria-busy', String(busy))\n if (busy) b.setAttribute('aria-disabled', 'true')\n else b.removeAttribute('aria-disabled')\n }\n command.enabled.subscribe(sync)\n command.busy.subscribe(sync)\n sync()\n command.status.subscribe((text) => {\n status.textContent = text\n })\n status.textContent = command.status.get()\n return h('div', { class: 'ink-command' }, b, status)\n}\n\nexport function createZoomIn(viewer: Viewer): HTMLButtonElement {\n const b = button('Zoom in', { class: 'ink-zoom-in', 'data-ink-zoom-in': '' }, ZoomIn)\n b.addEventListener('click', () => viewer.viewport.get()?.zoomBy(1.25))\n follow(viewer.viewport, b, () => undefined)\n return b\n}\n\nexport function createZoomOut(viewer: Viewer): HTMLButtonElement {\n const b = button(\n 'Zoom out',\n { class: 'ink-zoom-out', 'data-ink-zoom-out': '' },\n ZoomOut\n )\n b.addEventListener('click', () => viewer.viewport.get()?.zoomBy(0.8))\n follow(viewer.viewport, b, () => undefined)\n return b\n}\n\n/** Fit width, fit page and the zoom levels; a zoom between levels gets an option of its own. */\nexport function createZoomSelect(viewer: Viewer): HTMLSelectElement {\n const custom = h('option', { value: 'custom' })\n const select = h(\n 'select',\n { class: 'ink-zoom-select', 'data-ink-zoom-select': '', 'aria-label': 'Zoom' },\n h('option', { value: 'fit-width' }, 'Fit width'),\n h('option', { value: 'fit-page' }, 'Fit page'),\n ...ZOOM_LEVELS.map((l) =>\n h('option', { value: String(l) }, `${Math.round(l * 100)}%`)\n )\n )\n select.addEventListener('change', () => {\n const v = select.value\n const viewport = viewer.viewport.get()\n if (v === 'fit-width' || v === 'fit-page') viewport?.setZoom(v)\n else if (v !== 'custom') viewport?.setZoom(Number(v))\n })\n follow<Viewport>(\n viewer.viewport,\n select,\n (viewport, watch) =>\n watch(viewport.zoom, (z) => {\n const level =\n typeof z === 'number'\n ? ZOOM_LEVELS.find((l) => Math.abs(l - z) < 0.001)\n : undefined\n if (typeof z === 'number' && level === undefined) {\n custom.textContent = `${Math.round(z * 100)}%`\n // In order among the levels.\n const after = [...select.options].find(\n (o) => o !== custom && Number(o.value) > z\n )\n select.insertBefore(custom, after ?? null)\n select.value = 'custom'\n } else {\n custom.remove()\n select.value = typeof z === 'number' ? String(level) : z\n }\n }),\n () => {\n custom.remove()\n select.value = 'fit-width'\n }\n )\n return select\n}\n\n/**\n * The current page, 1-based. Enter or leaving the field goes to the page typed; a number out\n * of range puts the current page back.\n */\nexport function createPageInput(viewer: Viewer): HTMLInputElement {\n const input = h('input', {\n class: 'ink-page-input',\n 'data-ink-page-input': '',\n type: 'number',\n inputmode: 'numeric',\n 'aria-label': 'Page',\n min: '1',\n })\n const commit = (): void => {\n const viewport = viewer.viewport.get()\n const doc = viewer.document.get()\n if (!viewport || !doc) return\n const n = Number(input.value)\n const current = viewport.currentPage.get()\n if (Number.isInteger(n) && n >= 1 && n <= doc.pages.length) {\n if (n - 1 !== current) viewport.scrollToPage(n - 1)\n } else input.value = String(current + 1)\n }\n // `change` fires on blur after typing and on each arrow-key or spinner step.\n input.addEventListener('change', commit)\n input.addEventListener('keydown', (e) => {\n if (e.key !== 'Enter' || e.defaultPrevented) return\n e.preventDefault()\n commit()\n })\n follow<Viewport>(\n viewer.viewport,\n input,\n (viewport, watch) => {\n input.max = String(viewer.document.get()?.pages.length ?? 1)\n watch(viewport.currentPage, (p) => (input.value = String(p + 1)))\n },\n () => (input.value = '')\n )\n return input\n}\n\n/** \"of 12\": the page count, announced when it changes. */\nexport function createPageCount(viewer: Viewer): HTMLSpanElement {\n const span = h('span', {\n class: 'ink-page-count',\n 'data-ink-page-count': '',\n 'aria-live': 'polite',\n })\n const show = (): void => {\n const doc = viewer.document.get()\n span.textContent = doc && viewer.viewport.get() ? `of ${doc.pages.length}` : ''\n }\n show()\n viewer.viewport.subscribe(show)\n return span\n}\n\n/** Disabled on the first page. */\nexport function createPrevPage(viewer: Viewer): HTMLButtonElement {\n return pageButton(viewer, -1)\n}\n\n/** Disabled on the last page. */\nexport function createNextPage(viewer: Viewer): HTMLButtonElement {\n return pageButton(viewer, 1)\n}\n\nfunction pageButton(viewer: Viewer, step: -1 | 1): HTMLButtonElement {\n const b =\n step < 0\n ? button(\n 'Previous page',\n { class: 'ink-prev-page', 'data-ink-prev-page': '' },\n ChevronLeft\n )\n : button(\n 'Next page',\n { class: 'ink-next-page', 'data-ink-next-page': '' },\n ChevronRight\n )\n b.addEventListener('click', () => {\n const viewport = viewer.viewport.get()\n viewport?.scrollToPage(viewport.currentPage.get() + step)\n })\n follow<Viewport>(viewer.viewport, b, (viewport, watch) => {\n const last = (viewer.document.get()?.pages.length ?? 1) - 1\n watch(viewport.currentPage, (p) => {\n b.disabled = step < 0 ? p <= 0 : p >= last\n })\n })\n return b\n}\n\n/** Roving items, as in the bindings' Radix toolbar: buttons only. */\nconst ITEMS = 'button'\n\n/**\n * One Tab stop across the enabled buttons in `bar`: the current one has `tabindex=\"0\"`, the\n * rest `-1`. ArrowLeft and ArrowRight move between them and wrap, Home and End go to the ends.\n * Inputs, selects and textareas, built in or added by the host, keep their own tabindex (a\n * Tab stop of their own by default) and their own arrow, Home and End keys.\n */\nfunction rovingTabindex(bar: HTMLElement): { sync(): void; destroy(): void } {\n let current: HTMLElement | null = null\n const items = (): HTMLElement[] =>\n [...bar.querySelectorAll<HTMLButtonElement>(ITEMS)].filter(\n (el) => !el.disabled && !el.closest('[hidden]')\n )\n const sync = (): void => {\n const list = items()\n if (!current || !list.includes(current)) current = list[0] ?? null\n for (const el of bar.querySelectorAll<HTMLElement>(ITEMS))\n el.tabIndex = el === current ? 0 : -1\n // Fields are left alone: they are Tab stops by default, and a host's tabindex on one stays.\n }\n const onFocusIn = (e: FocusEvent): void => {\n const target = e.target as HTMLElement\n if (!items().includes(target)) return\n current = target\n sync()\n }\n const onKeyDown = (e: KeyboardEvent): void => {\n if (e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey) return\n const list = items()\n const i = list.indexOf(e.target as HTMLElement)\n if (i < 0) return\n const last = list.length - 1\n const next =\n e.key === 'ArrowRight'\n ? i === last\n ? 0\n : i + 1\n : e.key === 'ArrowLeft'\n ? i === 0\n ? last\n : i - 1\n : e.key === 'Home'\n ? 0\n : e.key === 'End'\n ? last\n : -1\n if (next < 0) return\n e.preventDefault()\n list[next]!.focus()\n }\n // Host-added buttons, and buttons a host enables or disables, join the rotation.\n const observer = new MutationObserver(sync)\n observer.observe(bar, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['disabled', 'hidden'],\n })\n bar.addEventListener('focusin', onFocusIn)\n bar.addEventListener('keydown', onKeyDown)\n sync()\n return {\n sync,\n destroy() {\n observer.disconnect()\n bar.removeEventListener('focusin', onFocusIn)\n bar.removeEventListener('keydown', onKeyDown)\n },\n }\n}\n","/*\n * A menu anchored to a trigger button, shared by the vanilla style controls. The shell owns\n * the panel (`role=\"menu\"`, created on open and removed on close), its placement (the\n * popover's), and dismissal: an outside press, focus leaving, or Escape (which returns focus\n * to the trigger). ArrowDown on the trigger opens it with the first enabled item focused.\n * It closes when the trigger becomes disabled. Items are `[role=\"menuitemradio\"]` buttons;\n * ArrowUp, ArrowDown, Home and End move between them.\n */\nimport { focusInitialMenuItem, handleMenuKeys, menuItems } from '../menu-keys'\n\nimport { h } from './dom'\nimport { placePanel } from './popover'\n\nexport interface MenuOptions {\n label: string\n /** Extra attributes for the panel. */\n attrs?: Record<string, string>\n /**\n * The panel's role. `menu` (the default) is a list of items with arrow-key movement; `dialog`\n * is for a panel of mixed widgets, which take Tab and their own keys, and opens on the first\n * focusable one.\n */\n role?: 'menu' | 'dialog'\n /** The element the panel lines up under. Default `trigger`; a split button passes itself. */\n anchor?: HTMLElement\n /**\n * Whether `target` belongs to a menu nested in this one (its panel sits outside this panel\n * in the DOM). Presses, focus and Escape inside it neither dismiss this menu nor close it.\n */\n owns?(target: Node): boolean\n /** Builds the items on first call and updates them in place after; called on open and `refresh`. */\n render(menu: HTMLElement): void\n}\n\nexport interface Menu {\n readonly isOpen: boolean\n /** Re-renders an open menu, and closes it if the trigger has become disabled. */\n refresh(): void\n close(restoreFocus?: boolean): void\n}\n\nconst FOCUSABLE =\n 'select:not(:disabled), input:not(:disabled), button:not(:disabled):not([tabindex=\"-1\"])'\n\nexport function createMenu(trigger: HTMLButtonElement, opts: MenuOptions): Menu {\n const role = opts.role ?? 'menu'\n let panel: HTMLElement | null = null\n let teardown: (() => void) | null = null\n\n const place = (): void => {\n if (panel) placePanel(panel, (opts.anchor ?? trigger).getBoundingClientRect())\n }\n\n function close(restoreFocus = false): void {\n if (!panel) return\n teardown?.()\n teardown = null\n panel.remove()\n panel = null\n trigger.setAttribute('aria-expanded', 'false')\n trigger.dataset.state = 'closed'\n if (restoreFocus) trigger.focus()\n }\n\n function open(focus: 'initial' | 'first'): void {\n if (panel || trigger.disabled) return\n const el = h('div', {\n role,\n 'aria-label': opts.label,\n class: 'ink-select-content ink-menu-content',\n 'data-ink-select-content': '',\n ...opts.attrs,\n })\n panel = el\n el.style.visibility = 'hidden'\n document.body.append(el)\n opts.render(el)\n place()\n el.style.visibility = ''\n trigger.setAttribute('aria-expanded', 'true')\n trigger.dataset.state = 'open'\n if (role === 'dialog')\n el.querySelector<HTMLElement>(FOCUSABLE)?.focus({ preventScroll: true })\n else if (focus === 'first') menuItems(el)[0]?.focus({ preventScroll: true })\n else focusInitialMenuItem(el)\n\n const onKey = (e: KeyboardEvent): void => {\n const nested = opts.owns?.(e.target as Node) === true\n if (e.key === 'Escape') {\n // The nested menu closes itself; this one stays.\n if (nested) return\n e.preventDefault()\n close(true)\n } else if (role === 'menu' && el.contains(e.target as Node)) handleMenuKeys(e, el)\n }\n const outside = (t: Node): boolean =>\n !el.contains(t) && !trigger.contains(t) && opts.owns?.(t) !== true\n const onPress = (e: PointerEvent): void => {\n if (outside(e.target as Node)) close()\n }\n const onFocus = (e: FocusEvent): void => {\n if (outside(e.target as Node)) close()\n }\n document.addEventListener('keydown', onKey, true)\n document.addEventListener('pointerdown', onPress, true)\n document.addEventListener('focusin', onFocus)\n window.addEventListener('resize', place)\n document.addEventListener('scroll', place, true)\n teardown = () => {\n document.removeEventListener('keydown', onKey, true)\n document.removeEventListener('pointerdown', onPress, true)\n document.removeEventListener('focusin', onFocus)\n window.removeEventListener('resize', place)\n document.removeEventListener('scroll', place, true)\n }\n }\n\n trigger.addEventListener('click', () => (panel ? close(true) : open('initial')))\n trigger.addEventListener('keydown', (e) => {\n // An enclosing menu that already moved focus on this key keeps it.\n if (e.key !== 'ArrowDown' || e.defaultPrevented || panel || trigger.disabled) return\n e.preventDefault()\n open('first')\n })\n\n return {\n get isOpen() {\n return panel !== null\n },\n refresh() {\n if (!panel) return\n if (trigger.disabled) close()\n else {\n opts.render(panel)\n place()\n }\n },\n close,\n }\n}\n","/*\n * The line style menu for createViewer: the same markup, classes and data attributes as the\n * bindings' `InkLineStyleMenu`, so `@inkbar/theme` styles both. The trigger follows the\n * viewer's tool style (disabled while nothing supports line style, `data-mixed` when the\n * selection disagrees); the panel is created on open and removed on close.\n */\nimport { Check, Minus } from '@inkbar/icons'\n\nimport { lineStyleMenuModel, type LineStyleMenuModel } from '../ui'\n\nimport { createIcon } from './controls'\nimport { h } from './dom'\nimport { createMenu } from './menu'\n\nimport type { Viewer } from './create-viewer'\nimport type { ToolStyle } from '../../model/annotations/tool-style'\n\n/** A button that opens the line style menu: weight, solid or dashed, and arrowheads. */\nexport function createLineStyleMenu(viewer: Viewer): HTMLButtonElement {\n const trigger = h('button', {\n type: 'button',\n class: 'ink-menu-trigger ink-line-style-menu',\n 'data-ink-line-style-menu': '',\n 'data-state': 'closed',\n 'aria-label': 'Line style',\n title: 'Line style',\n 'aria-haspopup': 'menu',\n 'aria-expanded': 'false',\n })\n trigger.append(createIcon(Minus))\n trigger.disabled = true\n\n let style: ToolStyle | null = null\n let stops: (() => void)[] = []\n\n const model = (): LineStyleMenuModel =>\n lineStyleMenuModel(style?.current.get() ?? {}, style?.supported.get() ?? new Set())\n\n function refresh(): void {\n const m = model()\n trigger.disabled = !m.enabled\n if (m.mixed) trigger.setAttribute('data-mixed', '')\n else trigger.removeAttribute('data-mixed')\n menu.refresh()\n }\n\n /** Builds the panel's sections on the first call; later calls update them in place. */\n function paint(root: HTMLElement, m: LineStyleMenuModel): void {\n const menu = root\n if (menu.childElementCount === 0) {\n for (const section of m.sections) {\n const group = h(\n 'div',\n { role: 'group', class: 'ink-menu-group', 'aria-label': section.label },\n h('div', { class: 'ink-menu-label', 'aria-hidden': 'true' }, section.label)\n )\n for (const item of section.items) {\n const b = h(\n 'button',\n {\n type: 'button',\n role: 'menuitemradio',\n class: 'ink-select-item ink-menu-item',\n 'data-ink-select-item': '',\n tabindex: '-1',\n 'data-key': item.key,\n },\n item.label\n )\n b.addEventListener('click', () => {\n const found = model()\n .sections.flatMap((s) => s.items)\n .find((i) => i.key === item.key && i.label === item.label)\n if (found) style?.set(found.patch)\n })\n group.append(b)\n }\n menu.append(group)\n }\n }\n m.sections.forEach((section, i) => {\n const group = menu.children[i] as HTMLElement\n group.toggleAttribute('data-disabled', section.disabled)\n if (section.disabled) group.setAttribute('aria-disabled', 'true')\n else group.removeAttribute('aria-disabled')\n section.items.forEach((item, j) => {\n const b = group.children[j + 1] as HTMLButtonElement\n b.disabled = section.disabled\n b.setAttribute('aria-checked', String(item.checked))\n b.dataset.state = item.checked ? 'checked' : 'unchecked'\n const mark = b.querySelector('.ink-select-indicator')\n if (item.checked && !mark) {\n const span = h('span', { class: 'ink-select-indicator' })\n span.append(createIcon(Check))\n b.append(span)\n } else if (!item.checked) mark?.remove()\n })\n })\n }\n\n const menu = createMenu(trigger, {\n label: 'Line style',\n attrs: { 'data-ink-menu': 'line-style' },\n render: (root) => paint(root, model()),\n })\n\n const follow = (engine: { toolStyle: ToolStyle } | null): void => {\n for (const stop of stops) stop()\n stops = []\n style = engine?.toolStyle ?? null\n if (style)\n stops = [style.current.subscribe(refresh), style.supported.subscribe(refresh)]\n // The panel's old style is gone with the old document.\n if (!style) menu.close()\n refresh()\n }\n follow(viewer.engine.get())\n viewer.engine.subscribe(follow)\n return trigger\n}\n","/*\n * The colour menus for createViewer: the same markup, classes and data attributes as the\n * bindings' `InkColorMenu`, so `@inkbar/theme` styles both. The trigger shows the current\n * colour as a swatch and follows the viewer's tool style (disabled while nothing supports the\n * property); the panel is created on open and removed on close.\n */\nimport { Check } from '@inkbar/icons'\n\nimport {\n COLOR_COLUMNS,\n colorMenuModel,\n type ColorMenuModel,\n type ColorProperty,\n} from '../ui'\n\nimport { createIcon } from './controls'\nimport { h } from './dom'\nimport { createMenu } from './menu'\n\nimport type { Viewer } from './create-viewer'\nimport type {\n CurrentStyle,\n StyleGroup,\n StyleKey,\n StyleProps,\n ToolStyle,\n} from '../../model/annotations/tool-style'\nimport type { Readable } from '../../model/readable'\n\nexport interface ColorMenuOptions {\n property: ColorProperty\n /** Accessible name; defaults to \"Border colour\", \"Fill colour\" or \"Text colour\". */\n label?: string\n /**\n * Scopes the menu to one style group (`ToolStyle.scoped`): it shows and sets that group's\n * colour whatever tool is active, and recolours the selection only when it is all in the group.\n */\n group?: StyleGroup\n /** The colour new annotations get while the style leaves it unset; the trigger shows it. */\n fallback?: Readable<string | undefined>\n}\n\n/** Sets a swatch element's kind and colour from the model's trigger. */\nfunction paintSwatch(swatch: HTMLElement, model: ColorMenuModel): void {\n const t = model.trigger\n swatch.dataset.kind = t.kind\n if (t.kind === 'color') {\n swatch.dataset.color = t.color\n swatch.style.setProperty('--ink-swatch', t.color)\n } else {\n delete swatch.dataset.color\n swatch.style.removeProperty('--ink-swatch')\n }\n}\n\nfunction checkmark(): HTMLElement {\n const span = h('span', { class: 'ink-select-indicator' })\n span.append(createIcon(Check))\n return span\n}\n\n/** A button that opens a colour menu for one colour property of the selection or tool. */\nexport function createColorMenu(\n viewer: Viewer,\n opts: ColorMenuOptions\n): HTMLButtonElement {\n const { property } = opts\n const name = opts.label ?? colorMenuModel(property, {}, new Set()).label\n const trigger = h('button', {\n type: 'button',\n class: 'ink-menu-trigger ink-color-menu',\n 'data-ink-color-menu': property,\n 'data-state': 'closed',\n 'aria-label': name,\n title: name,\n 'aria-haspopup': 'menu',\n 'aria-expanded': 'false',\n })\n const swatch = h('span', {\n class: 'ink-swatch',\n 'data-ink-swatch': '',\n 'data-property': property,\n 'aria-hidden': 'true',\n })\n trigger.append(swatch)\n trigger.disabled = true\n\n /** What the menu reads and writes: the whole tool style, or one group's view of it. */\n let style: {\n current: Readable<CurrentStyle>\n supported: Readable<ReadonlySet<StyleKey>>\n set(patch: StyleProps): void\n } | null = null\n let stops: (() => void)[] = []\n\n const model = (): ColorMenuModel =>\n colorMenuModel(\n property,\n style?.current.get() ?? {},\n style?.supported.get() ?? new Set(),\n opts.fallback?.get()\n )\n\n function refresh(): void {\n const m = model()\n trigger.disabled = !m.enabled\n if (m.mixed) trigger.setAttribute('data-mixed', '')\n else trigger.removeAttribute('data-mixed')\n paintSwatch(swatch, m)\n if (picker && !trigger.isConnected) picker.remove()\n menu.refresh()\n }\n\n /**\n * The native colour input lives beside the trigger, not in the panel: the panel is removed\n * when the menu closes, and a pick that arrives after that must still land. Created on\n * first use and reused.\n */\n let picker: HTMLInputElement | null = null\n function pickerInput(): HTMLInputElement {\n if (!picker) {\n picker = h('input', {\n type: 'color',\n class: 'ink-color-input',\n 'aria-label': 'Custom colour',\n 'data-ink-color-input': property,\n tabindex: '-1',\n })\n picker.addEventListener('change', () => style?.set(model().custom(picker!.value)))\n }\n picker.value = model().customValue.toLowerCase()\n if (picker.parentNode !== trigger.parentNode || !picker.isConnected)\n if (trigger.parentNode) trigger.after(picker)\n else document.body.append(picker)\n return picker\n }\n\n function paint(root: HTMLElement, m: ColorMenuModel): void {\n if (root.childElementCount === 0) {\n if (m.noFill) {\n const b = h(\n 'button',\n {\n type: 'button',\n role: 'menuitemradio',\n class: 'ink-select-item ink-menu-item',\n 'data-ink-select-item': '',\n 'data-key': 'no-fill',\n tabindex: '-1',\n },\n 'No fill'\n )\n b.addEventListener('click', () => {\n const found = model().noFill\n if (found) style?.set(found.patch)\n })\n root.append(b)\n }\n const grid = h('div', {\n role: 'group',\n 'aria-label': 'Colours',\n class: 'ink-color-grid',\n 'data-ink-menu-columns': String(COLOR_COLUMNS),\n })\n for (const sw of m.swatches) {\n const b = h('button', {\n type: 'button',\n role: 'menuitemradio',\n class: 'ink-swatch-item',\n 'aria-label': sw.label,\n 'data-key': sw.key,\n tabindex: '-1',\n })\n b.style.setProperty('--ink-swatch', sw.color)\n b.addEventListener('click', () => {\n const found = model().swatches.find((s) => s.key === sw.key)\n if (found) style?.set(found.patch)\n })\n grid.append(b)\n }\n root.append(grid)\n const custom = h(\n 'button',\n {\n type: 'button',\n role: 'menuitem',\n class: 'ink-select-item ink-menu-item',\n 'data-ink-select-item': '',\n 'data-key': 'custom',\n tabindex: '-1',\n },\n 'Custom…'\n )\n custom.addEventListener('click', () => pickerInput().click())\n root.append(custom)\n }\n const noFill = root.querySelector<HTMLElement>('[data-key=\"no-fill\"]')\n if (noFill && m.noFill) mark(noFill, m.noFill.checked, true)\n const cells = root.querySelectorAll<HTMLElement>('.ink-swatch-item')\n m.swatches.forEach((sw, i) => mark(cells[i]!, sw.checked, false))\n if (picker) picker.value = m.customValue.toLowerCase()\n }\n\n /** Reflects checked state on an item; `withMark` adds the check icon (labelled items). */\n function mark(el: HTMLElement, checked: boolean, withMark: boolean): void {\n el.setAttribute('aria-checked', String(checked))\n el.dataset.state = checked ? 'checked' : 'unchecked'\n if (!withMark) return\n const existing = el.querySelector('.ink-select-indicator')\n if (checked && !existing) el.append(checkmark())\n else if (!checked) existing?.remove()\n }\n\n const menu = createMenu(trigger, {\n label: opts.label ?? model().label,\n attrs: { 'data-ink-menu': `color-${property}` },\n render: (root) => paint(root, model()),\n })\n\n const follow = (engine: { toolStyle: ToolStyle } | null): void => {\n for (const stop of stops) stop()\n stops = []\n const tool = engine?.toolStyle ?? null\n style = tool && opts.group ? tool.scoped(opts.group) : tool\n if (style)\n stops = [style.current.subscribe(refresh), style.supported.subscribe(refresh)]\n if (!style) menu.close()\n refresh()\n }\n follow(viewer.engine.get())\n viewer.engine.subscribe(follow)\n opts.fallback?.subscribe(refresh)\n return trigger\n}\n","/*\n * The text style menu for createViewer: the same markup, classes and data attributes as the\n * bindings' `InkTextStyleMenu`, so `@inkbar/theme` styles both. The trigger follows the\n * viewer's tool style (disabled while nothing supports text style, `data-mixed` when the\n * selection disagrees); the panel is created on open and removed on close. It holds a font\n * select, the text colour menu, a size input with a stepper, bold/italic/underline toggles\n * and an alignment radio group.\n */\nimport {\n ALargeSmall,\n AlignCenter,\n AlignJustify,\n AlignLeft,\n AlignRight,\n Bold,\n Italic,\n Minus,\n Plus,\n Underline,\n} from '@inkbar/icons'\n\nimport { handleRadioKeys } from '../menu-keys'\nimport { FONT_FAMILIES, textStyleMenuModel, type TextStyleMenuModel } from '../ui'\n\nimport { createColorMenu } from './color-menu'\nimport { createIcon } from './controls'\nimport { h } from './dom'\nimport { createMenu } from './menu'\n\nimport type { Viewer } from './create-viewer'\nimport type { ToolStyle } from '../../model/annotations/tool-style'\n\nconst TOGGLE_ICONS = { bold: Bold, italic: Italic, underline: Underline }\nconst ALIGN_ICONS = {\n left: AlignLeft,\n center: AlignCenter,\n right: AlignRight,\n justify: AlignJustify,\n}\n\nfunction iconButton(label: string, icon: Parameters<typeof createIcon>[0]) {\n const b = h('button', {\n type: 'button',\n class: 'ink-text-style-button',\n 'aria-label': label,\n title: label,\n })\n const svg = createIcon(icon)\n svg.setAttribute('width', '16')\n svg.setAttribute('height', '16')\n b.append(svg)\n return b\n}\n\n/** A button that opens the text style menu: font, size, colour, emphasis and alignment. */\nexport function createTextStyleMenu(viewer: Viewer): HTMLButtonElement {\n const trigger = h('button', {\n type: 'button',\n class: 'ink-menu-trigger ink-text-style-menu',\n 'data-ink-text-style-menu': '',\n 'data-state': 'closed',\n 'aria-label': 'Text style',\n title: 'Text style',\n 'aria-haspopup': 'dialog',\n 'aria-expanded': 'false',\n })\n trigger.append(createIcon(ALargeSmall))\n trigger.disabled = true\n\n let style: ToolStyle | null = null\n let stops: (() => void)[] = []\n\n const model = (): TextStyleMenuModel =>\n textStyleMenuModel(\n style?.current.get() ?? {},\n style?.supported.get() ?? new Set(),\n viewer.engine.get()?.fonts ?? FONT_FAMILIES\n )\n\n // One text colour menu for the life of the control; each panel adopts its trigger.\n const colour = createColorMenu(viewer, { property: 'textColor' })\n\n let select: HTMLSelectElement | null = null\n let input: HTMLInputElement | null = null\n /** True while the size holds text the user has typed and not yet committed. */\n let drafting = false\n\n function commitSize(): void {\n if (!drafting || !input) return\n drafting = false\n if (input.value.trim() !== '') {\n const patch = model().size.commit(Number(input.value))\n if (patch) style?.set(patch)\n }\n input.value = model().size.value === null ? '' : String(model().size.value)\n }\n function nudge(direction: 1 | -1): void {\n drafting = false\n const patch = model().size.nudge(direction)\n if (patch) style?.set(patch)\n }\n\n function build(root: HTMLElement, m: TextStyleMenuModel): void {\n select = h('select', { class: 'ink-text-style-font', 'aria-label': m.font.label })\n select.addEventListener('change', () => style?.set(model().font.patch(select!.value)))\n\n input = h('input', {\n type: 'number',\n class: 'ink-text-style-input',\n 'aria-label': m.size.label,\n min: String(m.size.min),\n max: String(m.size.max),\n step: String(m.size.step),\n })\n input.addEventListener('input', () => (drafting = true))\n input.addEventListener('blur', commitSize)\n input.addEventListener('keydown', (e) => {\n if (e.key !== 'Enter') return\n e.preventDefault()\n commitSize()\n })\n const less = iconButton('Decrease font size', Minus)\n const more = iconButton('Increase font size', Plus)\n less.addEventListener('click', () => nudge(-1))\n more.addEventListener('click', () => nudge(1))\n const size = h(\n 'div',\n { class: 'ink-text-style-size', role: 'group', 'aria-label': 'Size' },\n less,\n input,\n more\n )\n\n const emphasis = h('div', {\n class: 'ink-text-style-row',\n role: 'group',\n 'aria-label': 'Emphasis',\n })\n for (const t of m.toggles) {\n const b = iconButton(t.label, TOGGLE_ICONS[t.key])\n b.dataset.key = t.key\n b.addEventListener('click', () => {\n const found = model().toggles.find((x) => x.key === t.key)\n if (found) style?.set(found.patch)\n })\n emphasis.append(b)\n }\n\n const align = h('div', {\n class: 'ink-text-style-row',\n role: 'radiogroup',\n 'aria-label': m.align.label,\n })\n align.addEventListener('keydown', (e) => handleRadioKeys(e, align))\n for (const c of m.align.choices) {\n const b = iconButton(c.label, ALIGN_ICONS[c.key])\n b.setAttribute('role', 'radio')\n b.dataset.key = c.key\n b.addEventListener('click', () => {\n const found = model().align.choices.find((x) => x.key === c.key)\n if (found) style?.set(found.patch)\n })\n align.append(b)\n }\n\n root.append(\n select,\n h('div', { class: 'ink-text-style-row' }, colour, size),\n emphasis,\n align\n )\n }\n\n function paint(root: HTMLElement, m: TextStyleMenuModel): void {\n if (root.childElementCount === 0) build(root, m)\n const sel = select!\n const options = m.font.value === '' ? ['', ...m.font.options] : m.font.options\n if (\n sel.options.length !== options.length ||\n options.some((o, i) => sel.options[i]!.value !== o)\n ) {\n sel.replaceChildren(\n ...options.map((o) => {\n const opt = h('option', { value: o }, o === '' ? 'Mixed' : o)\n if (o === '') {\n opt.disabled = true\n opt.hidden = true\n }\n return opt\n })\n )\n }\n sel.value = m.font.value\n if (!drafting) input!.value = m.size.value === null ? '' : String(m.size.value)\n root\n .querySelectorAll<HTMLElement>('[role=\"group\"][aria-label=\"Emphasis\"] button')\n .forEach((b) => {\n const t = m.toggles.find((x) => x.key === b.dataset.key)!\n b.setAttribute('aria-pressed', String(t.pressed))\n b.dataset.state = t.pressed === true ? 'on' : 'off'\n if (t.pressed === 'mixed') b.setAttribute('data-mixed', '')\n else b.removeAttribute('data-mixed')\n })\n root.querySelectorAll<HTMLElement>('[role=\"radio\"]').forEach((b) => {\n const c = m.align.choices.find((x) => x.key === b.dataset.key)!\n b.setAttribute('aria-checked', String(c.checked))\n b.dataset.state = c.checked ? 'on' : 'off'\n b.tabIndex = c.tabStop ? 0 : -1\n })\n }\n\n function refresh(): void {\n const m = model()\n trigger.disabled = !m.enabled\n if (m.mixed) trigger.setAttribute('data-mixed', '')\n else trigger.removeAttribute('data-mixed')\n menu.refresh()\n }\n\n const menu = createMenu(trigger, {\n label: 'Text style',\n role: 'dialog',\n attrs: {\n 'data-ink-menu': 'text-style',\n class: 'ink-select-content ink-menu-content ink-text-style-content',\n },\n owns: (t) =>\n t instanceof Element && t.closest('[data-ink-menu=\"color-textColor\"]') !== null,\n render: (root) => paint(root, model()),\n })\n\n const follow = (engine: { toolStyle: ToolStyle } | null): void => {\n for (const stop of stops) stop()\n stops = []\n style = engine?.toolStyle ?? null\n if (style)\n stops = [style.current.subscribe(refresh), style.supported.subscribe(refresh)]\n // The panel's old style is gone with the old document.\n if (!style) menu.close()\n refresh()\n }\n follow(viewer.engine.get())\n viewer.engine.subscribe(follow)\n return trigger\n}\n","// The icon each shape kind draws in the shape menu, shared by the vanilla menu and the\n// framework bindings so a kind has one icon everywhere.\nimport {\n Circle,\n CircleDashed,\n Hexagon,\n MessageCircle,\n MoveUpRight,\n RectangleHorizontal,\n Search,\n Slash,\n Square,\n SquareDashed,\n Star,\n type IconNode,\n} from '@inkbar/icons'\n\nimport type { ShapeKind } from './tools'\n\nexport const SHAPE_ICONS: Readonly<Record<ShapeKind, IconNode>> = {\n line: Slash,\n arrow: MoveUpRight,\n rectangle: Square,\n roundedRectangle: RectangleHorizontal,\n ellipse: Circle,\n bubble: MessageCircle,\n star: Star,\n polygon: Hexagon,\n loupe: Search,\n mask: SquareDashed,\n ovalMask: CircleDashed,\n}\n","/*\n * The shape menu for createViewer: a split button with the same markup, classes and data\n * attributes as the bindings' `InkShapeMenu`, so `@inkbar/theme` styles both. The main button\n * activates the shape tool with the current kind and draws that kind's icon; the chevron\n * opens a two-column grid of kinds. Choosing one switches to the shape tool with that kind.\n */\nimport { ChevronDown } from '@inkbar/icons'\n\nimport { SHAPE_ICONS } from '../shape-icons'\nimport { SHAPE_KINDS, type ShapeKind, type ToolController } from '../tools'\nimport { SHAPE_COLUMNS, shapeMenuModel, type ShapeMenuModel } from '../ui'\n\nimport { createIcon } from './controls'\nimport { h } from './dom'\nimport { createMenu } from './menu'\n\nimport type { Viewer } from './create-viewer'\n\n/** A split button: the main part draws with the current shape kind, the chevron picks the kind. */\nexport function createShapeMenu(viewer: Viewer): HTMLElement {\n const main = h('button', {\n type: 'button',\n class: 'ink-tool-button ink-shape-button',\n 'data-ink-tool-button': '',\n 'data-ink-shape-button': '',\n 'data-tool': 'shape',\n 'data-state': 'off',\n 'aria-pressed': 'false',\n })\n const trigger = h('button', {\n type: 'button',\n class: 'ink-menu-trigger ink-shape-menu-trigger',\n 'data-ink-shape-menu-trigger': '',\n 'data-state': 'closed',\n 'aria-label': 'Choose shape',\n title: 'Choose shape',\n 'aria-haspopup': 'menu',\n 'aria-expanded': 'false',\n })\n trigger.append(createIcon(ChevronDown))\n const root = h(\n 'div',\n {\n class: 'ink-split-button ink-shape-menu',\n 'data-ink-shape-menu': '',\n role: 'group',\n 'aria-label': 'Shape',\n },\n main,\n trigger\n )\n main.disabled = true\n trigger.disabled = true\n\n let tools: ToolController | null = null\n let stops: (() => void)[] = []\n let shownKind: ShapeKind | null = null\n\n const model = (): ShapeMenuModel =>\n shapeMenuModel(tools?.options('shape').get() ?? {}, SHAPE_KINDS)\n\n function refresh(): void {\n const m = model()\n main.disabled = trigger.disabled = tools === null\n main.setAttribute('aria-label', m.label)\n main.title = m.label\n main.dataset.kind = m.kind\n if (shownKind !== m.kind) {\n main.replaceChildren(createIcon(SHAPE_ICONS[m.kind]))\n shownKind = m.kind\n }\n const on = tools?.active.get() === 'shape'\n main.dataset.state = on ? 'on' : 'off'\n main.setAttribute('aria-pressed', String(on))\n menu.refresh()\n }\n\n function paint(panel: HTMLElement, m: ShapeMenuModel): void {\n if (panel.childElementCount === 0) {\n const grid = h('div', {\n role: 'group',\n 'aria-label': 'Shapes',\n class: 'ink-shape-grid',\n 'data-ink-menu-columns': String(SHAPE_COLUMNS),\n })\n for (const item of m.items) {\n const b = h(\n 'button',\n {\n type: 'button',\n role: 'menuitemradio',\n class: 'ink-select-item ink-menu-item ink-shape-item',\n 'data-ink-select-item': '',\n 'data-key': item.kind,\n tabindex: '-1',\n },\n item.label\n )\n b.prepend(createIcon(SHAPE_ICONS[item.kind]))\n b.addEventListener('click', () => {\n tools?.set('shape', { kind: item.kind })\n menu.close(true)\n })\n grid.append(b)\n }\n panel.append(grid)\n }\n const cells = panel.querySelectorAll<HTMLElement>('.ink-shape-item')\n m.items.forEach((item, i) => {\n cells[i]!.setAttribute('aria-checked', String(item.checked))\n cells[i]!.dataset.state = item.checked ? 'checked' : 'unchecked'\n })\n }\n\n const menu = createMenu(trigger, {\n label: 'Shapes',\n anchor: root,\n attrs: { 'data-ink-menu': 'shape' },\n render: (panel) => paint(panel, model()),\n })\n\n main.addEventListener('click', () => tools?.set('shape'))\n\n const follow = (next: ToolController | null): void => {\n for (const stop of stops) stop()\n stops = []\n tools = next\n if (tools)\n stops = [tools.active.subscribe(refresh), tools.options('shape').subscribe(refresh)]\n if (!tools) menu.close()\n refresh()\n }\n follow(viewer.tools.get())\n viewer.tools.subscribe(follow)\n return root\n}\n","// The icon each text markup kind draws in the highlight menu, shared by the vanilla menu and\n// the framework bindings so a kind has one icon everywhere.\nimport {\n Highlighter,\n SpellCheck2,\n Strikethrough,\n Underline,\n type IconNode,\n} from '@inkbar/icons'\n\nimport type { MarkupKind } from './tools'\n\nexport const MARKUP_ICONS: Readonly<Record<MarkupKind, IconNode>> = {\n highlight: Highlighter,\n underline: Underline,\n strikeout: Strikethrough,\n squiggly: SpellCheck2,\n}\n","/*\n * The highlight menu for createViewer: a split button with the same markup, classes and data\n * attributes as the bindings' `InkHighlightMenu`, so `@inkbar/theme` styles both. The main\n * button activates the highlight tool with the current markup kind and draws that kind's icon;\n * the chevron opens a menu of kinds plus the markup colour. Choosing a kind switches to the\n * highlight tool with that kind. The colour is a nested colour menu scoped to the `markup`\n * style group, so it works whatever tool is active.\n */\nimport { ChevronDown } from '@inkbar/icons'\n\nimport { writable } from '../../model/readable'\nimport { MARKUP_ICONS } from '../markup-icons'\nimport { MARKUP_KINDS, type MarkupKind, type ToolController } from '../tools'\nimport { highlightMenuModel, type HighlightMenuModel } from '../ui'\n\nimport { createColorMenu } from './color-menu'\nimport { createIcon } from './controls'\nimport { h } from './dom'\nimport { createMenu } from './menu'\n\nimport type { Viewer } from './create-viewer'\n\n/** The nested colour menu's accessible name. */\nconst COLOUR_LABEL = 'Highlight colour'\n\n/** A split button: the main part marks text with the current kind, the chevron picks it. */\nexport function createHighlightMenu(viewer: Viewer): HTMLElement {\n const main = h('button', {\n type: 'button',\n class: 'ink-tool-button ink-highlight-button',\n 'data-ink-tool-button': '',\n 'data-ink-highlight-button': '',\n 'data-tool': 'highlight',\n 'data-state': 'off',\n 'aria-pressed': 'false',\n })\n const trigger = h('button', {\n type: 'button',\n class: 'ink-menu-trigger ink-highlight-menu-trigger',\n 'data-ink-highlight-menu-trigger': '',\n 'data-state': 'closed',\n 'aria-label': 'Choose highlight',\n title: 'Choose highlight',\n 'aria-haspopup': 'menu',\n 'aria-expanded': 'false',\n })\n trigger.append(createIcon(ChevronDown))\n const root = h(\n 'div',\n {\n class: 'ink-split-button ink-highlight-menu',\n 'data-ink-highlight-menu': '',\n role: 'group',\n 'aria-label': 'Highlight',\n },\n main,\n trigger\n )\n main.disabled = true\n trigger.disabled = true\n\n /** The colour the chosen kind gets while the markup style leaves it unset. */\n const defaultColour = writable<string | undefined>(undefined)\n // One colour menu for the life of the control; each panel adopts its trigger.\n const colour = createColorMenu(viewer, {\n property: 'border',\n group: 'markup',\n label: COLOUR_LABEL,\n fallback: defaultColour,\n })\n colour.setAttribute('role', 'menuitem')\n colour.tabIndex = -1\n\n let tools: ToolController | null = null\n let stops: (() => void)[] = []\n let shownKind: MarkupKind | null = null\n\n const model = (): HighlightMenuModel =>\n highlightMenuModel(tools?.options('highlight').get() ?? {}, MARKUP_KINDS)\n\n function refresh(): void {\n const m = model()\n main.disabled = trigger.disabled = tools === null\n main.setAttribute('aria-label', m.label)\n main.title = m.label\n main.dataset.kind = m.kind\n if (shownKind !== m.kind) {\n main.replaceChildren(createIcon(MARKUP_ICONS[m.kind]))\n shownKind = m.kind\n }\n const on = tools?.active.get() === 'highlight'\n main.dataset.state = on ? 'on' : 'off'\n main.setAttribute('aria-pressed', String(on))\n defaultColour.set(viewer.document.get()?.annotations.defaults.color(m.kind))\n menu.refresh()\n }\n\n function paint(panel: HTMLElement, m: HighlightMenuModel): void {\n if (panel.childElementCount === 0) {\n const kinds = h('div', {\n role: 'group',\n 'aria-label': 'Kinds',\n class: 'ink-highlight-kinds',\n })\n for (const item of m.items) {\n const b = h(\n 'button',\n {\n type: 'button',\n role: 'menuitemradio',\n class: 'ink-select-item ink-menu-item ink-highlight-item',\n 'data-ink-select-item': '',\n 'data-key': item.kind,\n tabindex: '-1',\n },\n item.label\n )\n b.prepend(createIcon(MARKUP_ICONS[item.kind]))\n b.addEventListener('click', () => {\n tools?.set('highlight', { kind: item.kind })\n menu.close(true)\n })\n kinds.append(b)\n }\n const colourRow = h(\n 'div',\n { role: 'group', 'aria-label': 'Colour', class: 'ink-highlight-colour' },\n h(\n 'span',\n { class: 'ink-highlight-colour-label', 'aria-hidden': 'true' },\n 'Colour'\n ),\n colour\n )\n panel.append(\n kinds,\n h('div', { role: 'separator', class: 'ink-select-separator' }),\n colourRow\n )\n }\n const cells = panel.querySelectorAll<HTMLElement>('.ink-highlight-item')\n m.items.forEach((item, i) => {\n cells[i]!.setAttribute('aria-checked', String(item.checked))\n cells[i]!.dataset.state = item.checked ? 'checked' : 'unchecked'\n })\n }\n\n const menu = createMenu(trigger, {\n label: 'Highlights',\n anchor: root,\n attrs: { 'data-ink-menu': 'highlight' },\n owns: (t) =>\n t instanceof Element && t.closest('[data-ink-menu=\"color-border\"]') !== null,\n render: (panel) => paint(panel, model()),\n })\n\n main.addEventListener('click', () => tools?.set('highlight'))\n\n const follow = (next: ToolController | null): void => {\n for (const stop of stops) stop()\n stops = []\n tools = next\n if (tools)\n stops = [\n tools.active.subscribe(refresh),\n tools.options('highlight').subscribe(refresh),\n viewer.document.subscribe(refresh),\n ]\n if (!tools) menu.close()\n refresh()\n }\n follow(viewer.tools.get())\n viewer.tools.subscribe(follow)\n return root\n}\n","// Making signature templates in the browser: a pad to draw one, a name typed in a handwriting\n// font, or an image file. The pad samples like the `draw` tool (coalesced events, pen and touch\n// pressure) and paints with its renderer, so a drawn signature looks the same placed.\nimport { readonly, writable, type Readable } from '../model/readable'\nimport {\n createImageTemplate,\n createInkTemplate,\n type SignatureTemplate,\n} from '../model/signatures'\n\nimport { outlinePath, strokeOutline } from './ink-stroke'\nimport { pressureOf, reportsPressure } from './tools/freehand'\n\nimport type { Point } from '../model/geometry'\n\nconst SVG_NS = 'http://www.w3.org/2000/svg'\n\n/** The pad's stroke width, CSS px. */\nconst PAD_STROKE = 3\n\nexport interface SignaturePad {\n /** The drawing surface, `svg.ink-signature-pad`, filling the host. */\n readonly element: SVGSVGElement\n /** True while nothing is drawn. */\n readonly empty: Readable<boolean>\n clear(): void\n /** The drawing as an ink template with a new id; undefined while the pad is empty. */\n toTemplate(): SignatureTemplate | undefined\n destroy(): void\n}\n\ninterface PadStroke {\n points: Point[]\n pressure: number[]\n path: SVGPathElement\n}\n\n/**\n * A drawing pad in `host`. Each press-drag-release is a stroke; the theme colours it through\n * `path.ink-stroke` (`fill: currentColor` by default).\n */\nexport function createSignaturePad(host: HTMLElement): SignaturePad {\n const doc = host.ownerDocument\n const svg = doc.createElementNS(SVG_NS, 'svg')\n svg.classList.add('ink-signature-pad')\n svg.dataset.inkSignaturePad = ''\n svg.setAttribute('width', '100%')\n svg.setAttribute('height', '100%')\n svg.setAttribute('aria-hidden', 'true')\n // Structural: the pad owns its touches, so a finger draws instead of scrolling.\n svg.style.touchAction = 'none'\n svg.style.display = 'block'\n host.append(svg)\n\n const strokes: PadStroke[] = []\n const empty = writable(true)\n let live: { id: number; stroke: PadStroke } | undefined\n\n const at = (e: PointerEvent): Point => {\n const r = svg.getBoundingClientRect()\n return { x: e.clientX - r.left, y: e.clientY - r.top }\n }\n const paint = (s: PadStroke): void => {\n const pressure = reportsPressure(s.pressure) ? s.pressure : undefined\n s.path.setAttribute('d', outlinePath(strokeOutline(s.points, pressure, PAD_STROKE)))\n }\n const sample = (s: PadStroke, e: PointerEvent): void => {\n s.points.push(at(e))\n s.pressure.push(pressureOf(e) ?? 0.5)\n }\n\n const onDown = (e: PointerEvent): void => {\n if (!e.isPrimary || e.button !== 0 || live) return\n e.preventDefault()\n const path = doc.createElementNS(SVG_NS, 'path')\n path.classList.add('ink-stroke')\n svg.append(path)\n const stroke: PadStroke = { points: [], pressure: [], path }\n sample(stroke, e)\n paint(stroke)\n live = { id: e.pointerId, stroke }\n try {\n svg.setPointerCapture(e.pointerId)\n } catch {\n // A synthetic pointer: the stroke still works while it stays over the pad.\n }\n }\n const onMove = (e: PointerEvent): void => {\n if (!live || e.pointerId !== live.id) return\n if (e.buttons === 0) {\n finish()\n return\n }\n const coalesced = e.getCoalescedEvents?.() ?? []\n for (const ev of coalesced.length > 0 ? coalesced : [e]) sample(live.stroke, ev)\n paint(live.stroke)\n }\n const finish = (e?: PointerEvent): void => {\n if (!live) return\n const s = live.stroke\n live = undefined\n const last = s.points[s.points.length - 1]!\n const end = e ? at(e) : last\n // A release reports no pressure: it repeats the last sample's.\n if (end.x !== last.x || end.y !== last.y) {\n s.points.push(end)\n s.pressure.push(s.pressure[s.pressure.length - 1]!)\n }\n paint(s)\n strokes.push(s)\n empty.set(false)\n }\n const onUp = (e: PointerEvent): void => {\n if (live && e.pointerId === live.id) finish(e)\n }\n const onCancel = (e: PointerEvent): void => {\n if (!live || e.pointerId !== live.id) return\n live.stroke.path.remove()\n live = undefined\n }\n /** Capture gone mid-stroke: keep what was drawn, as a touch sends no move to end it. */\n const onLostCapture = (e: PointerEvent): void => {\n if (live && e.pointerId === live.id) finish()\n }\n svg.addEventListener('pointerdown', onDown)\n svg.addEventListener('pointermove', onMove)\n svg.addEventListener('pointerup', onUp)\n svg.addEventListener('pointercancel', onCancel)\n svg.addEventListener('lostpointercapture', onLostCapture)\n\n return {\n element: svg,\n empty: readonly(empty),\n clear() {\n live?.stroke.path.remove()\n live = undefined\n for (const s of strokes.splice(0)) s.path.remove()\n empty.set(true)\n },\n toTemplate() {\n if (strokes.length === 0) return undefined\n // CSS y grows downwards; a template's grows upwards.\n const inklist = strokes.map((s) => s.points.map((p) => ({ x: p.x, y: -p.y })))\n const pressured = strokes.some((s) => reportsPressure(s.pressure))\n return createInkTemplate(\n inklist,\n pressured ? strokes.map((s) => [...s.pressure]) : undefined\n )\n },\n destroy() {\n svg.removeEventListener('pointerdown', onDown)\n svg.removeEventListener('pointermove', onMove)\n svg.removeEventListener('pointerup', onUp)\n svg.removeEventListener('pointercancel', onCancel)\n svg.removeEventListener('lostpointercapture', onLostCapture)\n svg.remove()\n },\n }\n}\n\n/** CSS generic families, which a font shorthand must not quote. */\nconst GENERIC_FAMILIES = new Set([\n 'serif',\n 'sans-serif',\n 'monospace',\n 'cursive',\n 'fantasy',\n 'system-ui',\n 'ui-serif',\n 'ui-sans-serif',\n 'ui-monospace',\n 'ui-rounded',\n 'math',\n 'emoji',\n 'fangsong',\n])\n\n/** `font` as a CSS font-family value: quoted unless it is a generic family. */\nexport function fontFamilyValue(font: string): string {\n return GENERIC_FAMILIES.has(font) ? font : `\"${font.replace(/[\"\\\\]/g, '\\\\$&')}\"`\n}\n\nexport interface TypedSignatureOptions {\n /** The image's height in pixels. Default 96. */\n height?: number\n /** The ink colour. Default `#151820`, the theme's ink. */\n color?: string\n}\n\ninterface Rendered {\n url: string\n width: number\n height: number\n}\n\nasync function drawTyped(\n name: string,\n font: string,\n opts: TypedSignatureOptions = {}\n): Promise<Rendered> {\n const text = name.trim()\n if (text === '') throw new RangeError('A typed signature needs a name')\n const height = opts.height ?? 96\n const size = height * 0.625\n const margin = height / 8\n const shorthand = `${size}px ${fontFamilyValue(font)}`\n try {\n // Draws in the fallback font if the face never arrives.\n await document.fonts.load(shorthand, text)\n } catch {\n // Unavailable: the canvas uses the fallback.\n }\n const canvas = document.createElement('canvas')\n const measure = canvas.getContext('2d')\n if (!measure) throw new Error('Canvas 2D is unavailable')\n measure.font = shorthand\n const m = measure.measureText(text)\n const left = m.actualBoundingBoxLeft\n const width = Math.ceil(left + m.actualBoundingBoxRight + margin * 2)\n canvas.width = width\n canvas.height = height\n // Resizing a canvas resets its state.\n const ctx = canvas.getContext('2d')!\n ctx.font = shorthand\n ctx.fillStyle = opts.color ?? '#151820'\n ctx.textBaseline = 'middle'\n ctx.fillText(text, margin + left, height / 2)\n return { url: canvas.toDataURL('image/png'), width, height }\n}\n\n/**\n * `name` drawn in `font` on a transparent canvas, as a PNG data URL. Waits for the font to load\n * (`document.fonts.load`) first. Rejects with a RangeError for an empty name.\n */\nexport async function renderTypedSignature(\n name: string,\n font: string,\n opts?: TypedSignatureOptions\n): Promise<string> {\n return (await drawTyped(name, font, opts)).url\n}\n\n/** A typed signature as an image template, with a new id. */\nexport async function createTypedSignature(\n name: string,\n font: string,\n opts?: TypedSignatureOptions\n): Promise<SignatureTemplate> {\n const r = await drawTyped(name, font, opts)\n return createImageTemplate(r.url, r.width / r.height)\n}\n\n/** The image types a signature image may be. */\nexport const SIGNATURE_IMAGE_TYPES: readonly string[] = ['image/png', 'image/jpeg']\n\n/** The longest side, in pixels, an image signature is stored at. */\nexport const SIGNATURE_IMAGE_MAX_SIDE = 1000\n\n/**\n * The longest data URL, in characters, an image signature may be once scaled. Templates live\n * in host storage (`localStorage` holds about 5 MB) and are copied into every placed stamp.\n */\nexport const SIGNATURE_IMAGE_MAX_LENGTH = 3_000_000\n\n/**\n * An image file (a scan of a signature) as an image template. The image is drawn again at no\n * more than `SIGNATURE_IMAGE_MAX_SIDE` pixels on its long side, as a PNG (a JPEG stays a JPEG,\n * as photos compress far better that way), so a phone photo does not fill the store. Rejects\n * with a TypeError for anything but a PNG or JPEG, and a RangeError when the result is still\n * longer than `SIGNATURE_IMAGE_MAX_LENGTH`.\n */\nexport async function createImageSignature(file: Blob): Promise<SignatureTemplate> {\n if (!SIGNATURE_IMAGE_TYPES.includes(file.type))\n throw new TypeError('A signature image must be a PNG or JPEG')\n const source = URL.createObjectURL(file)\n try {\n const img = new Image()\n img.src = source\n try {\n await img.decode()\n } catch {\n throw new TypeError('The image could not be read')\n }\n const { naturalWidth: w, naturalHeight: h } = img\n if (w === 0 || h === 0) throw new TypeError('The image is empty')\n const scale = Math.min(1, SIGNATURE_IMAGE_MAX_SIDE / Math.max(w, h))\n const canvas = document.createElement('canvas')\n canvas.width = Math.max(1, Math.round(w * scale))\n canvas.height = Math.max(1, Math.round(h * scale))\n const ctx = canvas.getContext('2d')\n if (!ctx) throw new Error('Canvas 2D is unavailable')\n ctx.imageSmoothingQuality = 'high'\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height)\n const url =\n file.type === 'image/jpeg'\n ? canvas.toDataURL('image/jpeg', 0.9)\n : canvas.toDataURL('image/png')\n if (url.length > SIGNATURE_IMAGE_MAX_LENGTH)\n throw new RangeError('The signature image is too large')\n return createImageTemplate(url, canvas.width / canvas.height)\n } finally {\n URL.revokeObjectURL(source)\n }\n}\n\n/** The preview's height in its own units; the width follows the template's aspect. */\nconst PREVIEW_HEIGHT = 100\nconst PREVIEW_STROKE = 4\n\n/**\n * An ink template drawn for a menu: one filled outline per stroke (the `draw` renderer) in a\n * `viewBox` of the template's aspect, with room for the stroke. Paint `paths` with\n * `fill: currentColor`.\n */\nexport function signaturePreview(t: SignatureTemplate & { kind: 'ink' }): {\n viewBox: string\n paths: string[]\n} {\n const h = PREVIEW_HEIGHT\n const w = h * t.aspect\n const pad = PREVIEW_STROKE\n const paths = t.inklist.map((stroke, i) =>\n outlinePath(\n strokeOutline(\n stroke.map((p) => ({ x: p.x * w, y: (1 - p.y) * h })),\n t.pressure?.[i],\n PREVIEW_STROKE\n )\n )\n )\n const r = (n: number): number => Math.round(n * 100) / 100\n return { viewBox: `${-pad} ${-pad} ${r(w + pad * 2)} ${r(h + pad * 2)}`, paths }\n}\n","// The state behind the \"Create signature\" dialog, shared by every binding and the vanilla\n// dialog: which tab is open, the pad, the typed name and font, the chosen image, and whether\n// Save can go. The bindings render it; nothing here touches their markup.\nimport { readonly, writable, type Readable } from '../model/readable'\n\nimport {\n createImageSignature,\n createSignaturePad,\n createTypedSignature,\n type SignaturePad,\n} from './signature-pad'\nimport { SIGNATURE_FONTS, type SignatureTab } from './ui'\n\nimport type { SignatureLibrary, SignatureTemplate } from '../model/signatures'\n\nexport interface SignatureDraftState {\n tab: SignatureTab\n /** True while the pad has nothing on it. */\n padEmpty: boolean\n name: string\n font: string\n /** The chosen image, read and checked. */\n image: SignatureTemplate | undefined\n /** Why the chosen file was refused, for the Image tab to show. */\n imageError: string | undefined\n /** Why the last save failed (the store refused it, full or offline), for the dialog to show. */\n saveError: string | undefined\n /** True when the open tab has something to save. */\n canSave: boolean\n saving: boolean\n}\n\nexport interface SignatureDraft {\n readonly state: Readable<SignatureDraftState>\n readonly fonts: readonly string[]\n setTab(tab: SignatureTab): void\n setName(name: string): void\n setFont(font: string): void\n /** Mounts the pad in `host`; returns its teardown. One pad at a time. */\n attachPad(host: HTMLElement): () => void\n clearPad(): void\n /** Reads an image file for the Image tab. */\n chooseFile(file: Blob | undefined): Promise<void>\n /**\n * Builds the open tab's template and saves it to `library`. Resolves with it, or undefined\n * when there is nothing to save, the save failed (setting `saveError`), or the draft was\n * destroyed before the save finished.\n */\n save(library: SignatureLibrary): Promise<SignatureTemplate | undefined>\n /** Back to an empty Draw tab. */\n reset(): void\n destroy(): void\n}\n\nexport function createSignatureDraft(\n opts: { fonts?: readonly string[] } = {}\n): SignatureDraft {\n const fonts = opts.fonts && opts.fonts.length > 0 ? [...opts.fonts] : SIGNATURE_FONTS\n const initial = (): SignatureDraftState => ({\n tab: 'draw',\n padEmpty: true,\n name: '',\n font: fonts[0]!,\n image: undefined,\n imageError: undefined,\n saveError: undefined,\n canSave: false,\n saving: false,\n })\n const state = writable<SignatureDraftState>(initial())\n let pad: SignaturePad | undefined\n let stopPad: (() => void) | undefined\n /** Only the latest file read lands. */\n let reads = 0\n /** Set by `destroy`: a save that finishes later selects nothing. */\n let destroyed = false\n\n const ready = (s: SignatureDraftState): boolean =>\n s.tab === 'draw'\n ? !s.padEmpty\n : s.tab === 'type'\n ? s.name.trim() !== ''\n : s.image !== undefined\n const patch = (p: Partial<SignatureDraftState>): void => {\n const next = { ...state.get(), ...p }\n state.set({ ...next, canSave: !next.saving && ready(next) })\n }\n\n const detachPad = (): void => {\n stopPad?.()\n stopPad = undefined\n pad?.destroy()\n pad = undefined\n }\n\n return {\n state: readonly(state),\n fonts,\n setTab: (tab) => patch({ tab }),\n setName: (name) => patch({ name }),\n setFont: (font) => patch({ font }),\n attachPad(host) {\n // Mounting again revives a destroyed draft, as React's StrictMode remounts do.\n destroyed = false\n detachPad()\n const p = createSignaturePad(host)\n pad = p\n stopPad = p.empty.subscribe((padEmpty) => patch({ padEmpty }))\n patch({ padEmpty: p.empty.get() })\n return () => {\n if (pad === p) detachPad()\n }\n },\n clearPad() {\n pad?.clear()\n },\n async chooseFile(file) {\n const n = ++reads\n if (!file) {\n patch({ image: undefined, imageError: undefined })\n return\n }\n // The old image goes at once, so Save waits for the new one.\n patch({ image: undefined, imageError: undefined })\n try {\n const image = await createImageSignature(file)\n if (n === reads) patch({ image, imageError: undefined })\n } catch (e) {\n if (n === reads)\n patch({\n image: undefined,\n imageError:\n e instanceof RangeError\n ? 'This image is too large. Choose a smaller one.'\n : 'Choose a PNG or JPEG image.',\n })\n }\n },\n async save(library) {\n const s = state.get()\n if (!s.canSave) return undefined\n patch({ saving: true, saveError: undefined })\n try {\n const t =\n s.tab === 'draw'\n ? pad?.toTemplate()\n : s.tab === 'type'\n ? await createTypedSignature(s.name, s.font)\n : s.image\n if (!t) return undefined\n await library.save(t)\n // Closed while saving: the template stays in the library, but nothing acts on it.\n return destroyed ? undefined : t\n } catch {\n patch({\n saveError: 'The signature could not be saved. Try again, or try a smaller one.',\n })\n return undefined\n } finally {\n patch({ saving: false })\n }\n },\n reset() {\n reads++\n pad?.clear()\n state.set({ ...initial(), padEmpty: pad ? pad.empty.get() : true })\n },\n destroy() {\n destroyed = true\n reads++\n detachPad()\n },\n }\n}\n","/*\n * The \"Create signature\" dialog for createViewer, with the same markup, classes and data\n * attributes as the bindings' `InkSignatureDialog`, so `@inkbar/theme` styles both. A modal:\n * Tab stays inside it, Escape or a press on the overlay closes it, and focus goes back where it\n * came from. Draw, Type and Image tabs each make a template; Save stores it in the viewer's\n * signature library and selects it for the `signature` tool.\n */\nimport { handleRadioKeys, handleTabKeys, trapTab } from '../menu-keys'\nimport { createSignatureDraft, type SignatureDraftState } from '../signature-draft'\nimport { fontFamilyValue } from '../signature-pad'\nimport {\n SIGNATURE_FONTS,\n SIGNATURE_LABELS,\n SIGNATURE_TABS,\n type SignatureTab,\n} from '../ui'\n\nimport { h } from './dom'\n\nimport type { Viewer } from './create-viewer'\n\nexport interface SignatureDialogOptions {\n /** The fonts the Type tab offers. Default: the viewer's `signatureFonts`. */\n fonts?: string[]\n}\n\nexport interface SignatureDialog {\n readonly isOpen: boolean\n /** Opens the dialog. On close, focus goes to `returnFocus`, else to what had it before. */\n open(opts?: { returnFocus?: HTMLElement | null }): void\n close(): void\n destroy(): void\n}\n\nlet dialogs = 0\n\nexport function createSignatureDialog(\n viewer: Viewer,\n opts: SignatureDialogOptions = {}\n): SignatureDialog {\n const uid = `ink-signature-dialog-${++dialogs}`\n let teardown: (() => void) | null = null\n\n function close(): void {\n teardown?.()\n teardown = null\n }\n\n function open(o: { returnFocus?: HTMLElement | null } = {}): void {\n if (teardown) return\n const returnTo =\n o.returnFocus ??\n (document.activeElement instanceof HTMLElement ? document.activeElement : null)\n const draft = createSignatureDraft({\n fonts: opts.fonts ?? viewer.engine.get()?.signatureFonts ?? SIGNATURE_FONTS,\n })\n\n const tabs = new Map<SignatureTab, HTMLButtonElement>()\n const panels = new Map<SignatureTab, HTMLElement>()\n const tablist = h('div', {\n role: 'tablist',\n 'aria-label': SIGNATURE_LABELS.tabs,\n class: 'ink-tabs',\n })\n for (const tab of SIGNATURE_TABS) {\n const b = h(\n 'button',\n {\n type: 'button',\n role: 'tab',\n id: `${uid}-tab-${tab}`,\n 'aria-controls': `${uid}-panel-${tab}`,\n class: 'ink-tab',\n 'data-key': tab,\n },\n SIGNATURE_LABELS[tab]\n )\n b.addEventListener('click', () => draft.setTab(tab))\n tabs.set(tab, b)\n tablist.append(b)\n panels.set(\n tab,\n h('div', {\n role: 'tabpanel',\n id: `${uid}-panel-${tab}`,\n 'aria-labelledby': `${uid}-tab-${tab}`,\n class: 'ink-tab-panel',\n 'data-key': tab,\n })\n )\n }\n tablist.addEventListener('keydown', (e) => handleTabKeys(e, tablist))\n\n // Draw\n const padHost = h('div', {\n class: 'ink-signature-pad-host',\n 'data-ink-signature-pad-host': '',\n role: 'img',\n 'aria-label': SIGNATURE_LABELS.pad,\n })\n const clear = h(\n 'button',\n { type: 'button', class: 'ink-button', 'data-ink-signature-clear': '' },\n SIGNATURE_LABELS.clear\n )\n clear.addEventListener('click', () => draft.clearPad())\n panels.get('draw')!.append(padHost, h('div', { class: 'ink-dialog-row' }, clear))\n const detachPad = draft.attachPad(padHost)\n\n // Type\n const name = h('input', {\n type: 'text',\n class: 'ink-input',\n 'data-ink-signature-name': '',\n autocomplete: 'name',\n placeholder: SIGNATURE_LABELS.namePlaceholder,\n })\n name.addEventListener('input', () => draft.setName(name.value))\n const fontGroup = h('div', {\n role: 'radiogroup',\n 'aria-label': SIGNATURE_LABELS.fonts,\n class: 'ink-signature-fonts',\n })\n const fontSamples = draft.fonts.map((font) => {\n const b = h('button', {\n type: 'button',\n role: 'radio',\n class: 'ink-signature-font',\n 'data-key': font,\n 'aria-label': font,\n })\n const sample = h('span', { class: 'ink-signature-font-sample' })\n // The font is the option itself, so it is set on the element, not left to the theme.\n sample.style.fontFamily = fontFamilyValue(font)\n b.append(sample)\n b.addEventListener('click', () => draft.setFont(font))\n fontGroup.append(b)\n return sample\n })\n fontGroup.addEventListener('keydown', (e) => handleRadioKeys(e, fontGroup))\n panels\n .get('type')!\n .append(\n h('label', { class: 'ink-field' }, h('span', {}, SIGNATURE_LABELS.name), name),\n fontGroup\n )\n\n // Image\n const file = h('input', {\n type: 'file',\n accept: 'image/png,image/jpeg',\n class: 'ink-input',\n 'data-ink-signature-file': '',\n })\n file.addEventListener('change', () => void draft.chooseFile(file.files?.[0]))\n const preview = h('img', { class: 'ink-signature-image', alt: '' })\n const imageError = h('p', { class: 'ink-field-error', role: 'alert' })\n panels\n .get('image')!\n .append(\n h('label', { class: 'ink-field' }, h('span', {}, SIGNATURE_LABELS.file), file),\n preview,\n imageError\n )\n\n // Actions\n const saveError = h('p', {\n class: 'ink-field-error',\n role: 'alert',\n 'data-ink-signature-save-error': '',\n })\n const cancel = h(\n 'button',\n { type: 'button', class: 'ink-button', 'data-ink-signature-cancel': '' },\n SIGNATURE_LABELS.cancel\n )\n cancel.addEventListener('click', () => close())\n const save = h(\n 'button',\n {\n type: 'button',\n class: 'ink-button',\n 'data-variant': 'primary',\n 'data-ink-signature-save': '',\n },\n SIGNATURE_LABELS.save\n )\n save.addEventListener('click', () => {\n const library = viewer.engine.get()?.signatures\n if (!library) return\n draft.save(library).then(\n (t) => {\n if (!t) return\n viewer.tools.get()?.set('signature', { templateId: t.id })\n close()\n },\n () => {\n // The host's store refused it: the dialog stays open to try again.\n }\n )\n })\n\n const title = h(\n 'h2',\n { id: `${uid}-title`, class: 'ink-dialog-title' },\n SIGNATURE_LABELS.dialog\n )\n const content = h(\n 'div',\n {\n role: 'dialog',\n 'aria-modal': 'true',\n 'aria-labelledby': `${uid}-title`,\n class: 'ink-dialog ink-signature-dialog',\n 'data-ink-signature-dialog': '',\n 'data-state': 'open',\n tabindex: '-1',\n },\n title,\n tablist,\n ...panels.values(),\n saveError,\n h('div', { class: 'ink-dialog-actions' }, cancel, save)\n )\n const overlay = h('div', {\n class: 'ink-dialog-overlay',\n 'data-ink-dialog-overlay': '',\n 'data-state': 'open',\n })\n overlay.addEventListener('pointerdown', () => close())\n\n const paint = (s: SignatureDraftState): void => {\n for (const [tab, b] of tabs) {\n const on = tab === s.tab\n b.setAttribute('aria-selected', String(on))\n b.dataset.state = on ? 'active' : 'inactive'\n b.tabIndex = on ? 0 : -1\n panels.get(tab)!.hidden = !on\n }\n clear.disabled = s.padEmpty\n draft.fonts.forEach((font, i) => {\n const sample = fontSamples[i]!\n const b = sample.parentElement!\n const on = font === s.font\n b.setAttribute('aria-checked', String(on))\n b.dataset.state = on ? 'checked' : 'unchecked'\n b.tabIndex = on ? 0 : -1\n sample.textContent = s.name.trim() || SIGNATURE_LABELS.namePlaceholder\n })\n if (s.image?.kind === 'image') {\n preview.src = s.image.imagedata\n preview.hidden = false\n } else {\n preview.removeAttribute('src')\n preview.hidden = true\n }\n imageError.textContent = s.imageError ?? ''\n imageError.hidden = s.imageError === undefined\n saveError.textContent = s.saveError ?? ''\n saveError.hidden = s.saveError === undefined\n save.disabled = !s.canSave || !viewer.engine.get()\n }\n const stopState = draft.state.subscribe(paint)\n paint(draft.state.get())\n\n const onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n close()\n return\n }\n trapTab(e, content)\n }\n // Focus that escapes (a click on the page behind) comes back in.\n const onFocus = (e: FocusEvent): void => {\n if (!content.contains(e.target as Node)) tabs.get(draft.state.get().tab)?.focus()\n }\n document.addEventListener('keydown', onKey, true)\n document.addEventListener('focusin', onFocus)\n document.body.append(overlay, content)\n tabs.get('draw')!.focus({ preventScroll: true })\n\n teardown = () => {\n document.removeEventListener('keydown', onKey, true)\n document.removeEventListener('focusin', onFocus)\n stopState()\n detachPad()\n draft.destroy()\n overlay.remove()\n content.remove()\n if (returnTo?.isConnected) returnTo.focus({ preventScroll: true })\n }\n }\n\n return {\n get isOpen() {\n return teardown !== null\n },\n open,\n close,\n destroy: close,\n }\n}\n","/*\n * The signature menu for createViewer: a split button with the same markup, classes and data\n * attributes as the bindings' `InkSignatureMenu`, so `@inkbar/theme` styles both. The main\n * button activates the signature tool with the chosen template (or opens the menu when none is\n * chosen); the chevron opens the saved signatures, each with a remove button, and \"Create\n * signature\", which opens the signature dialog.\n */\nimport { ChevronDown, Plus, Signature, Trash2 } from '@inkbar/icons'\n\nimport { signaturePreview } from '../signature-pad'\nimport { SIGNATURE_LABELS, signatureMenuModel, type SignatureMenuModel } from '../ui'\n\nimport { createIcon } from './controls'\nimport { h } from './dom'\nimport { createMenu } from './menu'\nimport { createSignatureDialog, type SignatureDialogOptions } from './signature-dialog'\n\nimport type { Viewer } from './create-viewer'\nimport type { SignatureLibrary, SignatureTemplate } from '../../model/signatures'\nimport type { ToolController } from '../tools'\nimport type { ViewerEngine } from '../viewer-engine'\n\nconst SVG_NS = 'http://www.w3.org/2000/svg'\n\n/** A template drawn small: ink as an SVG of filled outlines, an image as an `<img>`. */\nexport function createSignaturePreview(t: SignatureTemplate): HTMLElement {\n const box = h('span', { class: 'ink-signature-preview', 'data-kind': t.kind })\n if (t.kind === 'image') {\n box.append(h('img', { src: t.imagedata, alt: '', draggable: 'false' }))\n return box\n }\n const { viewBox, paths } = signaturePreview(t)\n const svg = document.createElementNS(SVG_NS, 'svg')\n svg.setAttribute('viewBox', viewBox)\n svg.setAttribute('aria-hidden', 'true')\n for (const d of paths) {\n const path = document.createElementNS(SVG_NS, 'path')\n path.setAttribute('d', d)\n path.setAttribute('fill', 'currentColor')\n svg.append(path)\n }\n box.append(svg)\n return box\n}\n\nexport function createSignatureMenu(\n viewer: Viewer,\n opts: SignatureDialogOptions = {}\n): HTMLElement {\n const main = h('button', {\n type: 'button',\n class: 'ink-tool-button ink-signature-button',\n 'data-ink-tool-button': '',\n 'data-ink-signature-button': '',\n 'data-tool': 'signature',\n 'data-state': 'off',\n 'aria-pressed': 'false',\n 'aria-label': SIGNATURE_LABELS.sign,\n title: SIGNATURE_LABELS.sign,\n })\n main.append(createIcon(Signature))\n const trigger = h('button', {\n type: 'button',\n class: 'ink-menu-trigger ink-signature-menu-trigger',\n 'data-ink-signature-menu-trigger': '',\n 'data-state': 'closed',\n 'aria-label': SIGNATURE_LABELS.trigger,\n title: SIGNATURE_LABELS.trigger,\n 'aria-haspopup': 'menu',\n 'aria-expanded': 'false',\n })\n trigger.append(createIcon(ChevronDown))\n const root = h(\n 'div',\n {\n class: 'ink-split-button ink-signature-menu',\n 'data-ink-signature-menu': '',\n role: 'group',\n 'aria-label': SIGNATURE_LABELS.sign,\n },\n main,\n trigger\n )\n main.disabled = true\n trigger.disabled = true\n\n const dialog = createSignatureDialog(viewer, opts)\n let tools: ToolController | null = null\n let library: SignatureLibrary | null = null\n let stops: (() => void)[] = []\n /** The ids the open panel shows, to rebuild it only when the list changes. */\n let shown = ''\n\n const model = (): SignatureMenuModel =>\n signatureMenuModel(\n library?.templates.get() ?? [],\n tools?.options('signature').get() ?? {}\n )\n\n function refresh(): void {\n main.disabled = trigger.disabled = tools === null\n const on = tools?.active.get() === 'signature'\n main.dataset.state = on ? 'on' : 'off'\n main.setAttribute('aria-pressed', String(on))\n menu.refresh()\n }\n\n /** Removes a template; focus moves to the signature now in its row, else \"Create signature\". */\n function remove(panel: HTMLElement, id: string): void {\n const row = model().items.findIndex((i) => i.id === id)\n library?.remove(id).then(\n () => {\n if (!menu.isOpen) return\n const rows = panel.querySelectorAll<HTMLElement>('.ink-signature-item')\n const next =\n rows[Math.min(row, rows.length - 1)] ??\n panel.querySelector<HTMLElement>('[data-ink-signature-create]')\n next?.focus({ preventScroll: true })\n },\n () => {\n // The store refused: the row stays, and `removeError` shows in the menu.\n }\n )\n }\n\n function paint(panel: HTMLElement, m: SignatureMenuModel): void {\n const ids = m.items.map((i) => i.id).join(' ')\n // A fresh panel is a fresh opening: an old removal error is not news any more.\n if (panel.childElementCount === 0) library?.clearRemoveError()\n if (panel.childElementCount === 0 || ids !== shown) {\n shown = ids\n const list = h('div', {\n role: 'group',\n 'aria-label': SIGNATURE_LABELS.saved,\n class: 'ink-signature-list',\n 'data-ink-menu-columns': '2',\n })\n for (const item of m.items) {\n const choose = h('button', {\n type: 'button',\n role: 'menuitemradio',\n class: 'ink-select-item ink-menu-item ink-signature-item',\n 'data-ink-select-item': '',\n 'data-key': item.id,\n 'aria-label': item.label,\n tabindex: '-1',\n })\n choose.append(createSignaturePreview(item.template))\n choose.addEventListener('click', () => {\n tools?.set('signature', { templateId: item.id })\n menu.close(true)\n })\n const drop = h('button', {\n type: 'button',\n role: 'menuitem',\n class: 'ink-menu-item ink-signature-remove',\n 'data-ink-signature-remove': '',\n 'data-key': item.id,\n 'aria-label': item.removeLabel,\n title: item.removeLabel,\n tabindex: '-1',\n })\n drop.append(createIcon(Trash2))\n drop.addEventListener('click', () => remove(panel, item.id))\n list.append(choose, drop)\n }\n const create = h(\n 'button',\n {\n type: 'button',\n role: 'menuitem',\n class: 'ink-select-item ink-menu-item ink-signature-create',\n 'data-ink-select-item': '',\n 'data-ink-signature-create': '',\n tabindex: '-1',\n },\n SIGNATURE_LABELS.create\n )\n create.prepend(createIcon(Plus))\n create.addEventListener('click', () => {\n menu.close()\n dialog.open({ returnFocus: main })\n })\n panel.replaceChildren(\n ...(m.items.length > 0\n ? [list, h('div', { role: 'separator', class: 'ink-select-separator' })]\n : []),\n create,\n h('p', {\n class: 'ink-field-error ink-signature-remove-error',\n role: 'alert',\n 'data-ink-signature-remove-error': '',\n })\n )\n }\n const error = panel.querySelector<HTMLElement>('[data-ink-signature-remove-error]')!\n const message = library?.removeError.get()\n error.textContent = message ?? ''\n error.hidden = message === undefined\n for (const item of m.items) {\n const el = panel.querySelector<HTMLElement>(\n `.ink-signature-item[data-key=\"${CSS.escape(item.id)}\"]`\n )\n el?.setAttribute('aria-checked', String(item.checked))\n if (el) el.dataset.state = item.checked ? 'checked' : 'unchecked'\n }\n }\n\n const menu = createMenu(trigger, {\n label: SIGNATURE_LABELS.menu,\n anchor: root,\n attrs: { 'data-ink-menu': 'signature' },\n render: (panel) => paint(panel, model()),\n })\n\n main.addEventListener('click', () => {\n if (!tools) return\n if (model().selected) tools.set('signature')\n else trigger.click()\n })\n\n const follow = (next: ToolController | null): void => {\n for (const stop of stops) stop()\n stops = []\n tools = next\n if (tools)\n stops = [\n tools.active.subscribe(refresh),\n tools.options('signature').subscribe(refresh),\n ]\n if (!tools) {\n menu.close()\n dialog.close()\n }\n refresh()\n }\n // The library lives as long as the viewer, but reaches the menu with the first engine.\n let stopLibrary: () => void = () => undefined\n const followLibrary = (engine: ViewerEngine | null): void => {\n const next = engine?.signatures ?? null\n if (next === library) return\n stopLibrary()\n library = next\n const stops = library\n ? [library.templates.subscribe(refresh), library.removeError.subscribe(refresh)]\n : []\n stopLibrary = () => stops.forEach((stop) => stop())\n refresh()\n }\n follow(viewer.tools.get())\n viewer.tools.subscribe(follow)\n followLibrary(viewer.engine.get())\n viewer.engine.subscribe(followLibrary)\n return root\n}\n"],"mappings":"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"}
|