@inkbar/core 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dom.mjs.map CHANGED
@@ -1 +1 @@
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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"}
1
+ {"version":3,"file":"dom.mjs","names":["isCancellation","isCancellation","SVG","CORNERS","fmt","isCancellation","release","SVG","readingOrder","button","TABBABLE","EMPTY","guard","createToolController","SVG_NS","SVG_NS","LINE_FACTOR","MIN_CSS","MIN_CSS","SVG_NS","createWith","ITEMS","FOCUSABLE","button"],"sources":["../src/dom/transform.ts","../src/dom/layout.ts","../src/dom/viewport.ts","../src/dom/viewport-keys.ts","../src/dom/history-keys.ts","../src/pdfjs/widget-appearance.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/form-appearance.ts","../src/dom/form-button.ts","../src/dom/tools/options.ts","../src/dom/tools/selection-edit.ts","../src/dom/tools/controller.ts","../src/dom/tools/freehand.ts","../src/dom/signature-pad.ts","../src/dom/form-text.ts","../src/dom/form-choice.ts","../src/dom/form-order.ts","../src/dom/palette.ts","../src/dom/ui.ts","../src/dom/form-signature.ts","../src/dom/form-layer.ts","../src/dom/page-mount.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/menu-keys.ts","../src/dom/search/highlights.ts","../src/dom/viewer-engine.ts","../src/dom/search/controller.ts","../src/dom/search/find-key.ts","../src/dom/viewer/form-alert.ts","../src/dom/viewer/menu.ts","../src/dom/signature-draft.ts","../src/dom/viewer/signature-dialog.ts","../src/dom/viewer/signature-menu.ts","../src/dom/viewer/thread-popover.ts","../src/dom/viewer/create-viewer.ts","../src/dom/viewer/controls.ts","../src/dom/search/find-text.ts","../src/dom/search/find-bar.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"],"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","/** A flag as a plain value, or as a readable such as core's `History.canUndo`. */\ntype Flag = boolean | { get(): boolean }\n\n/**\n * What the keys drive: core's `History`, or a framework binding's history, whose flags are\n * plain values.\n */\nexport interface HistoryKeysTarget {\n readonly canUndo: Flag\n readonly canRedo: Flag\n undo(): void\n redo(): void\n}\n\n/** Keys typed here keep the element's own undo (a text field's typing). */\nconst EDITABLE =\n 'input, textarea, select, [contenteditable]:not([contenteditable=\"false\"])'\n\nconst on = (f: Flag): boolean => (typeof f === 'boolean' ? f : f.get())\n\n/** `'undo'`, `'redo'` or nothing for a keydown. */\nfunction historyAction(e: KeyboardEvent): 'undo' | 'redo' | undefined {\n if (e.altKey || !(e.ctrlKey || e.metaKey)) return undefined\n const k = e.key.toLowerCase()\n if (k === 'z') return e.shiftKey ? 'redo' : 'undo'\n if (k === 'y' && e.ctrlKey && !e.metaKey && !e.shiftKey) return 'redo'\n return undefined\n}\n\n/**\n * Undo and redo from the keyboard: Ctrl or Cmd+Z undoes, Ctrl or Cmd+Shift+Z and Ctrl+Y redo,\n * for keys pressed anywhere inside `el`. They do what the Undo and Redo buttons do: `history`\n * is read on every key, and a key acts only while its button would be enabled (`canUndo`,\n * `canRedo`). Then it is prevented; otherwise it is left to the browser. Events from inputs,\n * text areas, selects and editable content are left alone, so a field keeps its native text\n * undo, as are events already handled. Returns a function that removes the listener.\n */\nexport function attachHistoryKeys(\n el: HTMLElement,\n history: () => HistoryKeysTarget | null | undefined\n): () => void {\n const onKeydown = (e: KeyboardEvent): void => {\n // A held chord repeats, stepping through the history as native apps do. Each repeat reads\n // the flags again, so the last step stops it.\n if (e.defaultPrevented || e.isComposing) return\n const action = historyAction(e)\n if (!action) return\n // The innermost target: inside a shadow root, `e.target` is retargeted to its host.\n const target = e.composedPath()[0] ?? e.target\n if (target instanceof Element && target.closest(EDITABLE)) return\n const h = history()\n if (!h || !on(action === 'undo' ? h.canUndo : h.canRedo)) return\n e.preventDefault()\n h[action]()\n }\n el.addEventListener('keydown', onKeydown)\n return () => el.removeEventListener('keydown', onKeydown)\n}\n\n/**\n * Keeps focus in the viewer when a focused Undo or Redo button inside `el` turns disabled\n * (it undid or redid the last step), which would otherwise drop focus to `<body>`, out of\n * reach of the undo and redo keys. Focus moves to `scroll()`, the viewer's scroll element,\n * without scrolling. Returns a function that removes the listeners.\n *\n * Chrome and Firefox blur the button as it is disabled: its `focusout` comes while the\n * `disabled` change is still queued for the observer below, and only that `focusout` counts.\n * WebKit can leave focus on the disabled button instead. The observer then moves it, and a later\n * `focusout` (a click on content that takes no focus) is left alone.\n */\nexport function keepHistoryFocus(\n el: HTMLElement,\n scroll: () => HTMLElement | null | undefined\n): () => void {\n const isHistoryButton = (node: unknown): node is HTMLButtonElement =>\n node instanceof HTMLButtonElement &&\n node.disabled &&\n node.matches('[data-ink-undo], [data-ink-redo]')\n const toScroll = (): void => {\n const target = scroll()\n if (!target?.isConnected) return\n // A container the host did not make focusable still takes focus from script.\n if (!target.hasAttribute('tabindex')) target.tabIndex = -1\n target.focus({ preventScroll: true })\n }\n /** Buttons disabled since the observer last ran that still hold focus (WebKit). */\n const stillFocused = (records: MutationRecord[]): void => {\n for (const r of records)\n if (\n isHistoryButton(r.target) &&\n r.target.ownerDocument.activeElement === r.target\n ) {\n toScroll()\n return\n }\n }\n const observer = new MutationObserver(stillFocused)\n observer.observe(el, { subtree: true, attributes: true, attributeFilter: ['disabled'] })\n const onFocusout = (e: FocusEvent): void => {\n const button = e.target\n if (!isHistoryButton(button) || e.relatedTarget !== null) return\n // Only the blur the disable itself caused: its change has not reached the observer yet.\n const records = observer.takeRecords()\n if (records.some((r) => r.target === button)) toScroll()\n else stillFocused(records)\n }\n el.addEventListener('focusout', onFocusout)\n return () => {\n observer.disconnect()\n el.removeEventListener('focusout', onFocusout)\n }\n}\n","// Draws annotation appearances apart from the page: the page canvas of a form page leaves its\n// widgets out, and the form layer draws the widgets' own appearances apart from it, so a toggle\n// or an edit shows or hides a widget's canvas instead of painting the page again.\n//\n// Both rely on how PDF.js lays out a page's operator list: each annotation's appearance runs\n// from a `beginAnnotation` operation, whose first argument is the annotation id, to the next\n// `endAnnotation`. With `AnnotationMode.ENABLE_FORMS`, a checkbox or radio has two such runs,\n// its on and off appearances, named by the sixth argument (`'checked'`, `'unchecked'`).\n// widget-appearance.browser.test.ts pins that layout.\nimport type { PdfjsPage } from './types'\nimport type { InkDocument } from '../model/document'\n\ntype RenderParameters = Parameters<PdfjsPage['render']>[0]\ntype OperationsFilter = NonNullable<RenderParameters['operationsFilter']>\ntype OperatorList = Parameters<OperationsFilter>[1]\ntype Ops = InkDocument['_pdfjs']['module']['OPS']\n\n/** Which appearance a pass draws: each widget's own, or one of a toggle's two. */\nexport type AppearanceLook = 'own' | 'checked' | 'unchecked'\n\nconst isCancellation = (error: unknown): boolean =>\n (error as { name?: unknown } | null)?.name === 'RenderingCancelledException'\n\n/**\n * Which annotation run each operation of one operator list (one page in one annotation mode)\n * belongs to. Built once per list as it streams in, and shared by every filter over it.\n */\ninterface RunIndex {\n /** Operations indexed so far. */\n scanned: number\n /** By operation: the annotation id of the run it is in, its begin and end included. */\n ids: (string | undefined)[]\n /** By operation: the run's look name, for a toggle's two runs under ENABLE_FORMS. */\n looks: (string | undefined)[]\n /** The id of the run open at `scanned`. */\n open: string | undefined\n openLook: string | undefined\n /** The list is not laid out as this module expects. */\n broken: boolean\n}\n\nconst indexes = new WeakMap<OperatorList, RunIndex>()\n\nfunction runIndex(OPS: Ops, list: OperatorList): RunIndex {\n let index = indexes.get(list)\n if (!index) {\n index = {\n scanned: 0,\n ids: [],\n looks: [],\n open: undefined,\n openLook: undefined,\n broken: false,\n }\n indexes.set(list, index)\n }\n const { fnArray, argsArray } = list\n for (let i = index.scanned; i < fnArray.length; i++) {\n const fn = fnArray[i]\n if (fn === OPS.beginAnnotation) {\n const args = argsArray[i] as unknown[] | null\n const id = args?.[0]\n const look = args?.[5]\n if (index.open !== undefined || typeof id !== 'string') index.broken = true\n index.open = typeof id === 'string' ? id : undefined\n index.openLook = typeof look === 'string' ? look : undefined\n }\n index.ids[i] = index.open\n index.looks[i] = index.openLook\n if (fn === OPS.endAnnotation) {\n if (index.open === undefined) index.broken = true\n index.open = undefined\n index.openLook = undefined\n }\n }\n index.scanned = fnArray.length\n return index\n}\n\n/**\n * A filter for a page render that leaves out the appearances of the annotations in `ids` and\n * keeps everything else.\n *\n * @internal\n */\nexport function omitAppearances(\n doc: InkDocument,\n ids: ReadonlySet<string>\n): OperationsFilter {\n const { OPS } = doc._pdfjs.module\n return (i, list) => {\n const index = runIndex(OPS, list)\n const id = index.ids[i]\n // Dependencies only load fonts and images; one a later operation needs must still load.\n return id === undefined || !ids.has(id) || list.fnArray[i] === OPS.dependency\n }\n}\n\n/** One pass of appearances, drawn alone into one canvas over part of the page. */\nexport interface AppearancePass {\n /** Zero-based page index. */\n page: number\n look: AppearanceLook\n /** Annotation ids whose appearances (of `look`) the pass draws. */\n ids: ReadonlySet<string>\n /** Sized by the caller; drawn transparent except for the appearances. */\n canvas: HTMLCanvasElement\n /** The page canvas's zoom and total rotation, so the appearances land on its pixel grid. */\n zoom: number\n rotation: number\n /** Device pixels per CSS px. */\n devicePixelRatio: number\n /** The canvas's top-left corner on the page canvas, in device pixels. */\n x: number\n y: number\n}\n\n/** The operator list does not hold annotation runs as PDF.js 6.4 lays them out. */\nexport class AppearanceLayoutError extends Error {\n override name = 'AppearanceLayoutError'\n}\n\n/**\n * Draws the appearances of `ids` (their `look`), as the page canvas would draw them at the same\n * zoom, rotation and pixel ratio, into `canvas`, whose top-left corner sits at device pixel\n * (`x`, `y`) of the page. Nothing else on the page is drawn: the canvas stays transparent\n * around the appearances. The widgets' own appearances come from the ENABLE operator list the\n * page canvas and the loupe use; a toggle's two come from the ENABLE_FORMS list, which PDF.js\n * builds and keeps apart, parsing the page a second time for it.\n *\n * Resolves with the ids it found a run for. Rejects with `signal.reason` once `signal` aborts,\n * and with an `AppearanceLayoutError` when the list's runs are not laid out as expected.\n *\n * @internal\n */\nexport async function renderAppearances(\n doc: InkDocument,\n pass: AppearancePass,\n signal?: AbortSignal\n): Promise<Set<string>> {\n signal?.throwIfAborted()\n const pdfPage = await doc._pdfjs.getPage(pass.page)\n signal?.throwIfAborted()\n const { AnnotationMode, OPS } = doc._pdfjs.module\n const dpr = pass.devicePixelRatio\n const found = new Set<string>()\n let broken = false\n const { ids, look } = pass\n const filter: OperationsFilter = (i, list) => {\n const index = runIndex(OPS, list)\n if (index.broken) broken = true\n const id = index.ids[i]\n if (id !== undefined && ids.has(id) && (look === 'own' || index.looks[i] === look)) {\n found.add(id)\n return true\n }\n // Marked content brackets an appearance in its optional content group, and nests evenly\n // in the page's own content, so it runs everywhere.\n const fn = list.fnArray[i]\n return (\n fn === OPS.dependency ||\n (id === undefined &&\n (fn === OPS.beginMarkedContent ||\n fn === OPS.beginMarkedContentProps ||\n fn === OPS.endMarkedContent))\n )\n }\n // PDF.js would open the canvas without an alpha channel, as for a page; this one stays\n // see-through around the appearances.\n const context = pass.canvas.getContext('2d')\n if (!context) throw new Error('No 2D context for widget appearances')\n const task = pdfPage.render({\n canvas: pass.canvas,\n canvasContext: context,\n viewport: pdfPage.getViewport({ scale: pass.zoom, rotation: pass.rotation }),\n background: 'rgba(0,0,0,0)',\n annotationMode: look === 'own' ? AnnotationMode.ENABLE : AnnotationMode.ENABLE_FORMS,\n transform: [dpr, 0, 0, dpr, -pass.x, -pass.y],\n operationsFilter: filter,\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 signal?.throwIfAborted()\n if (broken)\n throw new AppearanceLayoutError(\n `Page ${pass.page + 1}'s operator list does not hold annotation appearances as expected`\n )\n return found\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 { omitAppearances } from '../pdfjs/widget-appearance'\n\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 /**\n * Whether form widgets are drawn into the canvas as the PDF draws them. By default they are\n * drawn only when the document has no form fields; a document with fields leaves the\n * widgets of its fields on the page out, and the form layer draws each one's appearance.\n */\n drawWidgets?: boolean\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 fields = doc.form.fields.get()\n const drawWidgets = opts.drawWidgets ?? fields.length === 0\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 // The same operator list the form layer draws widget appearances from, and the loupe\n // draws regions from.\n annotationMode: AnnotationMode.ENABLE,\n ...(drawWidgets\n ? {}\n : {\n operationsFilter: omitAppearances(\n doc,\n new Set(\n fields.flatMap((f) =>\n f.widgets.flatMap((w) => (w.page === page ? [w.id] : []))\n )\n )\n ),\n }),\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, form widgets included. Like the\n * annotations made in the session, field values filled in the session are not magnified: the\n * region shows each widget as the file draws it.\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]`, none on a pinned annotation) 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 // A pinned annotation (a signature filling its field) is selected to be deleted, never\n // moved or resized.\n syncHandles(\n node,\n a && !a.locked && !store._isPinned(id) && 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 setFlag(node, 'inkPinned', store._isPinned(a.id))\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 || store._isPinned(id)) 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 // A form field keeps its keys (Delete edits its text), so a press on an annotation over\n // the fields takes focus from it: Delete then removes the annotation, a signature\n // filling its field included.\n if (doc.activeElement?.closest('[data-ink-form-layer]'))\n node.focus({ preventScroll: true })\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 const offPinned = store._pinned.subscribe(() => {\n if (destroyed) return\n for (const [id, node] of elements) {\n setFlag(node, 'inkPinned', store._isPinned(id))\n applyState(node, id)\n }\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 offPinned()\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\n/**\n * Calls `onDetach` once when `el` leaves its document for any reason: its page unmounted, its\n * layer rebuilt, or an ancestor removed, inside a shadow root too. Already detached, it calls\n * on the next microtask. Returns the stop function.\n */\nexport function watchDetached(el: Element, onDetach: () => void): () => void {\n let done = false\n const fire = (): void => {\n if (done || el.isConnected) return\n done = true\n observer?.disconnect()\n onDetach()\n }\n const doc = el.ownerDocument\n const Observer = doc.defaultView?.MutationObserver\n const observer = Observer ? new Observer(fire) : undefined\n if (observer) {\n // A document's observer never sees inside a shadow tree, so each shadow root the element\n // sits in is watched as well.\n const opts = { childList: true, subtree: true }\n observer.observe(doc, opts)\n for (let root = el.getRootNode(); root instanceof doc.defaultView!.ShadowRoot;) {\n observer.observe(root, opts)\n root = root.host.getRootNode()\n }\n }\n if (!el.isConnected) queueMicrotask(fire)\n return () => {\n done = true\n observer?.disconnect()\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 { ViewerSearch } from '../search/controller'\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 * The viewer's search state and actions, shared with the find bar. Inert (always closed, no\n * hits) when the host has no search.\n */\n readonly search: ViewerSearch\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 { SearchState, ViewerSearch } from '../search/controller'\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 /** The viewer's search; without one, `ctx.search` is inert. */\n search?: ViewerSearch\n}\n\nconst inertState = readonly(\n writable<SearchState>({\n open: false,\n query: '',\n matchCase: false,\n hits: [],\n current: -1,\n scanning: false,\n })\n)\n\n/** What `ctx.search` is when the host has no search: closed, and every action does nothing. */\nconst inertSearch: ViewerSearch = {\n state: inertState,\n open() {},\n setQuery() {},\n setMatchCase() {},\n next() {},\n previous() {},\n close() {},\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 search: opts.search ?? inertSearch,\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","// The PDF's own appearance of each form widget on a page, each shown in a small canvas of its\n// own.\n//\n// The page canvas leaves form widgets out, and this layer draws their appearances apart from\n// it, on the page canvas's pixel grid, so together they look as PDF.js draws the whole page.\n// The widgets are drawn in batched passes: one render per look (the widgets' own appearances, a\n// toggle's checked ones, its unchecked ones) into a scratch canvas over their rects, which is\n// then cut into one canvas per widget. Widgets whose rects overlap go in a pass of their own,\n// so none picks up another's pixels; touching ones share a pass, as PDF.js clips each\n// appearance to its rect. Each widget's canvas has the parts of its neighbours' rects that its\n// padding reaches cleared, except the one pixel row or column that two touching rects share:\n// that row holds both widgets' edges, so it stays in both canvases, drawn twice, and a sliver\n// of a hidden neighbour's edge stays in it. A pass's scratch canvas stays under a pixel budget,\n// and a page runs its passes one at a time, so one scratch canvas at most is alive per page.\n// A checkbox or radio has both looks drawn, the one it does not show when the browser is idle,\n// and shows the one for its state. Showing, hiding or swapping an appearance paints nothing;\n// only a new zoom, rotation or pixel ratio draws the shown widgets again.\n//\n// Inline styles are structural or geometric: the layer is `position:absolute; inset:0;\n// overflow:hidden` over the page, and each canvas is placed at its widget's rect.\nimport { renderAppearances, type AppearanceLook } from '../pdfjs/widget-appearance'\n\nimport { watchDevicePixelRatio } from './dpr-watch'\n\nimport type { PageTransform } from './transform'\nimport type { InkDocument } from '../model/document'\nimport type { Rect } from '../model/geometry'\n\n/** Which appearance a widget shows: its own, one of a toggle's two, or none. */\nexport type WidgetLook = AppearanceLook | null\n\nexport interface AppearanceWidget {\n /** Widget (annotation) id. */\n id: string\n /** In user space. */\n rect: Rect\n /** A checkbox or radio, with an on and an off appearance. */\n toggle: boolean\n /**\n * The looks PDF.js should have a run for, by the file's appearance states: shown in the file\n * and with an appearance stream for the look. A pass that finds none of the widgets that\n * expect its look reports an error.\n */\n expects: ReadonlySet<AppearanceLook>\n}\n\nexport interface WidgetAppearancesOptions {\n /** The page host; the layer is created in its document but not attached. */\n host: HTMLElement\n document: InkDocument\n /** Zero-based page index. */\n page: number\n transform: PageTransform\n /** In paint order: a later widget's appearance lies over an earlier one's. */\n widgets: readonly AppearanceWidget[]\n /** Fixed device pixel ratio; `window.devicePixelRatio`, watched, when omitted. */\n devicePixelRatio?: number\n /**\n * A pass of appearances failed to render, and failed again when retried (cancellations are\n * not reported). A look that keeps failing is reported once per geometry.\n */\n onError?(error: unknown): void\n /** Every look shown has painted, with no failure since the last such call. */\n onRendered?(): void\n}\n\nexport interface WidgetAppearances {\n readonly element: HTMLElement\n /**\n * Resolves once the looks shown so far have painted, failed or been superseded. A toggle's\n * look it does not show is drawn later, when the browser is idle. Never rejects.\n */\n readonly rendered: Promise<void>\n /** Shows the widget's `look`, drawing it first if it is not drawn at the current geometry. */\n show(id: string, look: WidgetLook): void\n /** Draws the shown appearances again at a new zoom or rotation. */\n update(transform: PageTransform): void\n destroy(): void\n}\n\n/** Device px an appearance canvas reaches past its widget's rect, for its anti-aliased edge. */\nconst PAD = 1\n\n/** Device px a pass's scratch canvas may cover, unless one widget alone needs more. */\nexport const SCRATCH_BUDGET = 4_000_000\n\n/** Failed draws of one look at one geometry before the layer stops retrying it. */\nconst ATTEMPTS = 2\n\ntype Look = AppearanceLook\n\ninterface Geometry {\n x: number\n y: number\n width: number\n height: number\n}\n\ninterface Member {\n item: Item\n /** The widget's canvas, padded. */\n g: Geometry\n}\n\ninterface Pass {\n key: string\n look: Look\n members: Member[]\n abort: AbortController\n /** Slots still waiting on this pass; at none it is aborted. */\n users: number\n /** Draws a look a widget shows: `rendered` waits for it. */\n shown: boolean\n}\n\ninterface Slot {\n /** The painted canvas, for the geometry `key` at `rotation`. */\n canvas: HTMLCanvasElement | undefined\n key: string | undefined\n rotation: number | undefined\n /** Queued for, or being drawn by, a pass at the geometry `key`. */\n queued: string | undefined\n pending: Pass | undefined\n /** Failed draws at the geometry `failedKey`. */\n failedKey: string | undefined\n failures: number\n}\n\ninterface Item {\n widget: AppearanceWidget\n /** Holds the widget's canvases, so they keep the widgets' paint order. */\n box: HTMLElement\n slots: Map<Look, Slot>\n shown: WidgetLook\n}\n\nconst isAbort = (error: unknown): boolean =>\n (error as { name?: unknown } | null)?.name === 'AbortError'\n\n/** Drops a canvas for good, freeing its bitmap now rather than at garbage collection. */\nfunction release(canvas: HTMLCanvasElement): void {\n canvas.width = 0\n canvas.height = 0\n canvas.remove()\n}\n\n/**\n * Whether two padded canvases' widget rects (the pads left off) overlap by more than the one\n * device pixel that rects meeting edge to edge between pixels both cover.\n */\nconst overlaps = (a: Geometry, b: Geometry) =>\n a.x + PAD + 1 < b.x + b.width - PAD &&\n b.x + PAD + 1 < a.x + a.width - PAD &&\n a.y + PAD + 1 < b.y + b.height - PAD &&\n b.y + PAD + 1 < a.y + a.height - PAD\n\n/** A padded canvas's widget rect, the pads left off, as edges in device px. */\nconst inner = (g: Geometry) => ({\n x0: g.x + PAD,\n x1: g.x + g.width - PAD,\n y0: g.y + PAD,\n y1: g.y + g.height - PAD,\n})\n\n/**\n * The part of `of`'s padded canvas that a neighbour in its pass draws and `of` does not: the\n * neighbour's rect, less the pixel row or column the two rects share where they touch.\n */\nfunction neighbourStrip(of: Geometry, near: Geometry): Geometry | undefined {\n const a = inner(of)\n const b = inner(near)\n let { x0, x1, y0, y1 } = b\n // Along an axis where the rects meet (sharing at most a pixel), keep what `of` covers.\n if (Math.min(a.x1, b.x1) - Math.max(a.x0, b.x0) <= 1) {\n if (b.x0 >= a.x0) x0 = Math.max(x0, a.x1)\n else x1 = Math.min(x1, a.x0)\n }\n if (Math.min(a.y1, b.y1) - Math.max(a.y0, b.y0) <= 1) {\n if (b.y0 >= a.y0) y0 = Math.max(y0, a.y1)\n else y1 = Math.min(y1, a.y0)\n }\n x0 = Math.max(x0, of.x)\n y0 = Math.max(y0, of.y)\n x1 = Math.min(x1, of.x + of.width)\n y1 = Math.min(y1, of.y + of.height)\n return x1 > x0 && y1 > y0\n ? { x: x0, y: y0, width: x1 - x0, height: y1 - y0 }\n : undefined\n}\n\nconst union = (members: readonly Member[]): Geometry => {\n const x = Math.min(...members.map((m) => m.g.x))\n const y = Math.min(...members.map((m) => m.g.y))\n const right = Math.max(...members.map((m) => m.g.x + m.g.width))\n const bottom = Math.max(...members.map((m) => m.g.y + m.g.height))\n return { x, y, width: right - x, height: bottom - y }\n}\n\n/** Splits members, top to bottom, into runs whose union stays within the scratch budget. */\nfunction chunks(members: Member[]): Member[][] {\n const sorted = [...members].sort((a, b) => a.g.y - b.g.y || a.g.x - b.g.x)\n const out: Member[][] = []\n let run: Member[] = []\n for (const m of sorted) {\n const next = [...run, m]\n const u = union(next)\n if (run.length > 0 && u.width * u.height > SCRATCH_BUDGET) {\n out.push(run)\n run = [m]\n } else run = next\n }\n if (run.length > 0) out.push(run)\n return out\n}\n\n/** The widget appearances of one page. */\nexport function createWidgetAppearances(\n opts: WidgetAppearancesOptions\n): WidgetAppearances {\n const { document: doc, page } = opts\n const ownerDoc = opts.host.ownerDocument\n const view = ownerDoc.defaultView\n const currentDpr = (): number =>\n opts.devicePixelRatio ??\n (view && view.devicePixelRatio > 0 ? view.devicePixelRatio : 1)\n\n const element = ownerDoc.createElement('div')\n element.className = 'ink-form-appearance'\n element.dataset.inkFormAppearance = ''\n element.style.cssText = 'position:absolute;inset:0;overflow:hidden;pointer-events:none;'\n\n let transform = opts.transform\n let dpr = currentDpr()\n let destroyed = false\n const keyOf = () => `${transform.zoom}:${transform.totalRotation}:${dpr}`\n let key = keyOf()\n\n const items = new Map<string, Item>()\n for (const widget of opts.widgets) {\n const box = ownerDoc.createElement('div')\n box.dataset.inkAppearance = widget.id\n element.append(box)\n items.set(widget.id, { widget, box, slots: new Map(), shown: null })\n }\n\n // Work on shown looks: `rendered` and `onRendered` wait for it, not for idle work.\n let busy = 0\n let failed = false\n let resolveBusy: (() => void) | undefined\n let rendered: Promise<void> = Promise.resolve()\n const begin = () => {\n if (busy++ === 0) rendered = new Promise((resolve) => (resolveBusy = resolve))\n }\n const end = () => {\n if (--busy > 0) return\n const ok = !failed\n failed = false\n resolveBusy?.()\n resolveBusy = undefined\n if (ok && !destroyed) opts.onRendered?.()\n }\n\n /** The widget's canvas rect now, in device pixels of the page canvas. */\n const geometry = (w: AppearanceWidget): Geometry => {\n const r = transform.toCssRect(w.rect)\n const x = Math.floor(r.left * dpr) - PAD\n const y = Math.floor(r.top * dpr) - PAD\n const width = Math.max(1, Math.ceil((r.left + r.width) * dpr) + PAD - x)\n const height = Math.max(1, Math.ceil((r.top + r.height) * dpr) + PAD - y)\n return { x, y, width, height }\n }\n\n const place = (canvas: HTMLCanvasElement, g: Geometry) => {\n const s = canvas.style\n s.left = `${g.x / dpr}px`\n s.top = `${g.y / dpr}px`\n s.width = `${g.width / dpr}px`\n s.height = `${g.height / dpr}px`\n }\n\n const slotOf = (item: Item, look: Look): Slot => {\n let slot = item.slots.get(look)\n if (!slot) {\n slot = {\n canvas: undefined,\n key: undefined,\n rotation: undefined,\n queued: undefined,\n pending: undefined,\n failedKey: undefined,\n failures: 0,\n }\n item.slots.set(look, slot)\n }\n return slot\n }\n\n /** The looks the widget needs drawn: the one it shows, and a toggle's other one. */\n const wantedOf = (item: Item): Look[] =>\n item.shown === null\n ? []\n : item.widget.toggle\n ? [item.shown, item.shown === 'checked' ? 'unchecked' : 'checked']\n : [item.shown]\n\n /**\n * Shows the canvas of the look the widget shows. A bitmap drawn at another rotation stays\n * hidden until its new one lands, as it would show turned the wrong way.\n */\n const applyShown = (item: Item) => {\n for (const [look, slot] of item.slots)\n if (slot.canvas)\n slot.canvas.style.display =\n item.shown === look && slot.rotation === transform.totalRotation ? '' : 'none'\n }\n\n /** Stops waiting on the slot's pass, aborting the pass once nothing waits on it. */\n const drop = (slot: Slot) => {\n const pass = slot.pending\n slot.pending = undefined\n slot.queued = undefined\n if (pass && --pass.users === 0) pass.abort.abort()\n }\n\n // Widgets waiting for a pass, by look: drawn soon, or when the browser is idle.\n const soon = new Map<Look, Set<Item>>()\n const later = new Map<Look, Set<Item>>()\n let soonScheduled = false\n let idleHandle: (() => void) | undefined\n\n const idle = (fn: () => void): (() => void) => {\n if (view?.requestIdleCallback) {\n const handle = view.requestIdleCallback(fn, { timeout: 500 })\n return () => view.cancelIdleCallback(handle)\n }\n const handle = setTimeout(fn, 50)\n return () => clearTimeout(handle)\n }\n\n // Passes waiting to run, and the one running: one scratch canvas at a time.\n const jobs: Pass[] = []\n let running = false\n\n /**\n * An idle pass now draws a look a widget shows: `rendered` waits for it, and a queued one\n * goes before the idle work.\n */\n const promote = (pass: Pass) => {\n if (pass.shown) return\n pass.shown = true\n begin()\n const at = jobs.indexOf(pass)\n if (at < 0) return\n jobs.splice(at, 1)\n const first = jobs.findIndex((j) => !j.shown)\n jobs.splice(first < 0 ? jobs.length : first, 0, pass)\n }\n\n const request = (item: Item, look: Look, urgent: boolean) => {\n const slot = slotOf(item, look)\n if (slot.key === key && slot.canvas) return\n if (slot.pending?.key === key) {\n if (urgent) promote(slot.pending)\n return\n }\n if (slot.failedKey === key && slot.failures >= ATTEMPTS) return\n if (slot.queued === key && (!urgent || soon.get(look)?.has(item))) return\n if (slot.pending) drop(slot)\n slot.queued = key\n later.get(look)?.delete(item)\n const queue = urgent ? soon : later\n let set = queue.get(look)\n if (!set) queue.set(look, (set = new Set()))\n set.add(item)\n if (urgent && !soonScheduled) {\n soonScheduled = true\n begin()\n queueMicrotask(() => {\n soonScheduled = false\n flush(soon)\n end()\n })\n } else if (!urgent && !idleHandle) {\n idleHandle = idle(() => {\n idleHandle = undefined\n flush(later)\n })\n }\n }\n\n const ensure = (item: Item) => {\n wantedOf(item).forEach((look, i) => request(item, look, i === 0))\n }\n\n /** Queues a pass per look, per group of widgets that do not overlap, for `queue`. */\n const flush = (queue: Map<Look, Set<Item>>) => {\n if (destroyed) return\n for (const [look, set] of queue) {\n // A pass that runs now takes the same look's idle widgets along: they cost it little.\n const idleToo = queue === later ? undefined : later.get(look)\n const ready = [...set, ...(idleToo ?? [])].filter(\n (item) => item.slots.get(look)?.queued === key\n )\n set.clear()\n idleToo?.clear()\n const groups: Member[][] = []\n for (const item of ready) {\n const g = geometry(item.widget)\n const group = groups.find((members) => members.every((m) => !overlaps(m.g, g)))\n if (group) group.push({ item, g })\n else groups.push([{ item, g }])\n }\n for (const group of groups)\n for (const members of chunks(group)) {\n const pass: Pass = {\n key,\n look,\n members,\n abort: new AbortController(),\n users: members.length,\n shown: members.some((m) => m.item.shown === look),\n }\n for (const { item } of members) slotOf(item, look).pending = pass\n if (pass.shown) {\n begin()\n // Shown looks go before idle work already waiting.\n const at = jobs.findIndex((j) => !j.shown)\n jobs.splice(at < 0 ? jobs.length : at, 0, pass)\n } else jobs.push(pass)\n }\n }\n queue.clear()\n pump()\n }\n\n const pump = () => {\n if (running || destroyed) return\n const pass = jobs.shift()\n if (!pass) return\n running = true\n void run(pass).finally(() => {\n running = false\n if (pass.shown) end()\n pump()\n })\n }\n\n const fail = (pass: Pass, error: unknown) => {\n for (const { item } of pass.members) {\n const slot = slotOf(item, pass.look)\n if (slot.failedKey !== pass.key) slot.failures = 0\n slot.failedKey = pass.key\n slot.failures++\n }\n if (pass.shown) failed = true\n // Try once more; a look that keeps failing waits for a new geometry. Only a failure that\n // gets no retry is reported, so a look fails aloud once per geometry.\n for (const { item } of pass.members)\n if (wantedOf(item).includes(pass.look)) request(item, pass.look, false)\n const retrying = pass.members.some(\n ({ item }) => slotOf(item, pass.look).queued === pass.key\n )\n if (!retrying) opts.onError?.(error)\n }\n\n const run = async (pass: Pass): Promise<void> => {\n const { look, members } = pass\n if (pass.abort.signal.aborted || pass.key !== key) {\n for (const { item } of members) {\n const slot = slotOf(item, look)\n if (slot.pending === pass) drop(slot)\n }\n // Dropped for a new geometry: the widgets that still want the look ask again.\n for (const { item } of members) ensure(item)\n return\n }\n const u = union(members)\n const scratch = ownerDoc.createElement('canvas')\n scratch.width = u.width\n scratch.height = u.height\n const rotation = transform.totalRotation\n try {\n const found = await renderAppearances(\n doc,\n {\n page,\n look,\n ids: new Set(members.map((m) => m.item.widget.id)),\n canvas: scratch,\n zoom: transform.zoom,\n rotation,\n devicePixelRatio: dpr,\n x: u.x,\n y: u.y,\n },\n pass.abort.signal\n )\n if (destroyed) return\n for (const { item, g } of members) {\n const slot = slotOf(item, look)\n // Superseded, no longer wanted, or drawn for a geometry that has since changed.\n if (slot.pending !== pass) continue\n slot.pending = undefined\n slot.queued = undefined\n if (pass.key !== key) {\n ensure(item)\n continue\n }\n const canvas = ownerDoc.createElement('canvas')\n canvas.setAttribute('aria-hidden', 'true')\n canvas.dataset.inkLook = look\n canvas.width = g.width\n canvas.height = g.height\n canvas.style.cssText = 'position:absolute;'\n place(canvas, g)\n const ctx = canvas.getContext('2d')\n ctx?.drawImage(\n scratch,\n g.x - u.x,\n g.y - u.y,\n g.width,\n g.height,\n 0,\n 0,\n g.width,\n g.height\n )\n // A touching neighbour's rect is its own canvas's to show: clear what this one's\n // padding reaches of it, bar the pixel row or column the two rects share.\n for (const other of members) {\n if (other.item === item) continue\n const strip = neighbourStrip(g, other.g)\n if (strip)\n ctx?.clearRect(strip.x - g.x, strip.y - g.y, strip.width, strip.height)\n }\n if (slot.canvas) release(slot.canvas)\n slot.canvas = canvas\n slot.key = pass.key\n slot.rotation = rotation\n slot.failures = 0\n item.box.append(canvas)\n applyShown(item)\n }\n const expecting = members.filter((m) => m.item.widget.expects.has(look))\n if (expecting.length > 0 && expecting.every((m) => !found.has(m.item.widget.id)))\n fail(\n pass,\n new Error(\n `Page ${page + 1}: no form widget appearances found in the page's operator list`\n )\n )\n } catch (error) {\n for (const { item } of members) {\n const slot = slotOf(item, look)\n if (slot.pending === pass) {\n slot.pending = undefined\n slot.queued = undefined\n }\n }\n if (destroyed) return\n if (pass.abort.signal.aborted && isAbort(error)) {\n for (const { item } of members) ensure(item)\n return\n }\n fail(pass, error)\n } finally {\n release(scratch)\n }\n }\n\n // Draw again when the device pixel ratio changes, unless the caller fixed it.\n const dprWatch =\n opts.devicePixelRatio === undefined\n ? watchDevicePixelRatio(view, currentDpr, () => api.update(transform))\n : undefined\n dprWatch?.watch(dpr)\n\n const api: WidgetAppearances = {\n element,\n get rendered() {\n return rendered\n },\n show(id, look) {\n const item = items.get(id)\n if (destroyed || !item) return\n if (item.shown !== look) {\n item.shown = look\n const wanted = new Set(wantedOf(item))\n for (const [l, slot] of item.slots) if (!wanted.has(l)) drop(slot)\n applyShown(item)\n }\n // Also after a pass failed or was dropped: a look drawn or on its way asks for nothing.\n ensure(item)\n },\n update(next) {\n if (destroyed) return\n transform = next\n dpr = currentDpr()\n dprWatch?.watch(dpr)\n const before = key\n key = keyOf()\n if (key === before) return\n for (const item of items.values()) {\n const wanted = new Set(wantedOf(item))\n for (const [look, slot] of item.slots) {\n // Waiting on a pass for the old geometry: its result would land in the wrong place.\n if (slot.pending || slot.queued) drop(slot)\n if (!slot.canvas) continue\n // A shown appearance stays, stretched to the new rect, until its new one lands; a\n // hidden one is dropped and drawn again when it shows.\n if (wanted.has(look)) place(slot.canvas, geometry(item.widget))\n else {\n release(slot.canvas)\n slot.canvas = undefined\n slot.key = undefined\n slot.rotation = undefined\n }\n }\n applyShown(item)\n ensure(item)\n }\n },\n destroy() {\n if (destroyed) return\n destroyed = true\n dprWatch?.destroy()\n idleHandle?.()\n idleHandle = undefined\n for (const pass of jobs.splice(0)) if (pass.shown) end()\n for (const item of items.values())\n for (const slot of item.slots.values()) {\n slot.pending?.abort.abort()\n if (slot.canvas) release(slot.canvas)\n }\n items.clear()\n element.remove()\n },\n }\n return api\n}\n","// A push button widget: a native `<button>`, clear over the PDF's own appearance, so its\n// caption and look are the file's. Activating it (a click, Enter or Space) runs its Mouse Up\n// script and then its action through the form: a JavaScript action in the sandbox, and a reset,\n// submit, link, named or go-to action as the form runs them. Inkbar never sends, opens or\n// prints itself; the host is told.\nimport type { WidgetState, WidgetView, WidgetViewContext } from './form-layer'\n\nexport function createButtonWidget(ctx: WidgetViewContext): WidgetView {\n const { form, field, widget } = ctx\n const el = ctx.box.ownerDocument.createElement('button')\n el.type = 'button'\n el.className = 'ink-form-control'\n // The caption names the button unless the file gives it a tooltip.\n el.setAttribute(\n 'aria-label',\n field.tooltip?.trim() ? ctx.label : widget.appearance.caption?.trim() || ctx.label\n )\n el.style.cssText =\n 'position:absolute;box-sizing:border-box;margin:0;padding:0;border:none;' +\n 'background:transparent;transform-origin:center;'\n ctx.box.append(el)\n\n let state: WidgetState | undefined\n el.addEventListener('click', () => {\n if (!state || state.readOnly) return\n // One undo step: the Mouse Up's and the Action's scripts and the reset it may run.\n form._step(() => {\n if (widget.hasScripts) form._dispatch({ widget: widget.id, name: 'Mouse Up' })\n form._dispatch({ widget: widget.id, name: 'Action' })\n })\n })\n el.addEventListener('focus', () => form._dispatch({ widget: widget.id, name: 'Focus' }))\n el.addEventListener('blur', () => form._dispatch({ widget: widget.id, name: 'Blur' }))\n\n return {\n control: el,\n activates: true,\n drawn: false,\n sync(next) {\n state = next\n },\n layout() {},\n destroy() {\n el.remove()\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. A pinned one (a signature in its field)\n// only selects, like a locked one, but it can be deleted.\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 /** Locked, or pinned to what it fills (a signature in its field): it only selects. */\n const fixed = (a: Annotation): boolean => a.locked === true || ctx.store._isPinned(a.id)\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 && !fixed(a) && 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 || fixed(a)) {\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 && !fixed(m) && (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 && !fixed(a)) 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 || fixed(a)) 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 || fixed(a)) 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 * A form field's control, a free-text editor and a plugin layer's marks own theirs too.\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 // A form field takes its own presses and keys while it takes input at all.\n if (target.closest('[data-ink-form-layer] [data-ink-widget]')) 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","// 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","// A text field's widget: a native `<input>` (single-line, password, comb) or `<textarea>`\n// (multiline), so keyboard, IME and screen readers work as anywhere else on the page.\n//\n// Every keystroke goes through `form._keystroke`, so keystroke scripts can refuse or change it;\n// the value commits through `form.set` on blur and on Enter in a single-line field, and Escape\n// puts back the committed text. While the control is focused it shows the raw value; otherwise\n// the formatted one. The text it draws\n// takes the field's `/DA` font, size and colour, `/Q` alignment and `/MK` border and\n// background, or a script's colours and size over them. A field that does not scroll refuses\n// a keystroke that would take its text past the box.\n//\n// An editable combo box is the same control with a `<datalist>` of its options: a person picks\n// one or types their own text. It shows each option's label and stores its export value.\nimport { fontFamilyValue } from './signature-pad'\n\nimport type {\n WidgetFrame,\n WidgetState,\n WidgetView,\n WidgetViewContext,\n} from './form-layer'\nimport type { FieldOption } from '../model/form/types'\n\n/** Line height as a multiple of the font size, as PDF.js lays out field text. */\nconst LINE_FACTOR = 1.35\n/** Points between the border and the text, as Acrobat leaves. */\nconst PADDING = 2\n/** Auto size (`/DA` size 0) in a multiline field starts here, in points, and shrinks to fit. */\nconst MULTILINE_AUTO = 12\n/** The smallest auto size, in points. */\nconst AUTO_MIN = 4\n\n/** A font family from `/DA` as a CSS font-family list, closest standard fallbacks after it. */\nexport function familyList(family: string | undefined): string {\n if (!family) return 'Helvetica, Arial, sans-serif'\n if (/^times/i.test(family))\n return `${fontFamilyValue(family)}, 'Times New Roman', serif`\n if (/^courier/i.test(family))\n return `${fontFamilyValue(family)}, 'Courier New', monospace`\n return `${fontFamilyValue(family)}, Helvetica, Arial, sans-serif`\n}\n\nexport const BORDER_STYLES = {\n solid: 'solid',\n dashed: 'dashed',\n beveled: 'outset',\n inset: 'inset',\n underline: 'solid',\n} as const\n\ntype Control = HTMLInputElement | HTMLTextAreaElement\n\ninterface Snapshot {\n value: string\n start: number\n end: number\n}\n\n/** The edit that turned `before` into `after`: what replaced which range of `before`. */\nfunction editOf(\n before: Snapshot,\n after: string\n): { start: number; end: number; change: string } {\n const { value, start, end } = before\n const tail = value.length - end\n // The selection explains it: its text was replaced (typing, pasting, deleting a selection).\n if (\n after.length >= start + tail &&\n after.startsWith(value.slice(0, start)) &&\n after.endsWith(value.slice(end))\n )\n return { start, end, change: after.slice(start, after.length - tail) }\n // Otherwise (a backspace beside a collapsed caret, a word deleted): the differing middle.\n let p = 0\n while (p < value.length && p < after.length && value[p] === after[p]) p++\n let s = 0\n while (\n s < value.length - p &&\n s < after.length - p &&\n value[value.length - 1 - s] === after[after.length - 1 - s]\n )\n s++\n return { start: p, end: value.length - s, change: after.slice(p, after.length - s) }\n}\n\nlet lists = 0\n\n/**\n * A text field's control, or with `choices` an editable combo box's: the options are offered\n * by label, and a label typed or picked is stored as its export value.\n */\nexport function createTextWidget(\n ctx: WidgetViewContext,\n choices?: readonly FieldOption[]\n): WidgetView {\n const { form, field, widget } = ctx\n const ownerDoc = ctx.box.ownerDocument\n const multiline = !choices && field.flags.multiline\n const el: Control = ownerDoc.createElement(multiline ? 'textarea' : 'input')\n if (el instanceof HTMLInputElement) el.type = field.flags.password ? 'password' : 'text'\n el.className = 'ink-form-control'\n el.autocomplete = 'off'\n el.spellcheck = !field.flags.doNotSpellCheck\n if (field.maxLength !== undefined && field.maxLength > 0) el.maxLength = field.maxLength\n el.setAttribute('aria-label', ctx.label)\n el.style.cssText =\n 'position:absolute;box-sizing:border-box;margin:0;resize:none;overflow:hidden;' +\n 'transform-origin:center;white-space:pre-wrap;'\n if (!multiline) el.style.whiteSpace = 'pre'\n const comb =\n field.flags.comb &&\n !multiline &&\n !field.flags.password &&\n field.maxLength !== undefined &&\n field.maxLength > 0\n ? field.maxLength\n : 0\n if (comb) ctx.box.dataset.inkComb = String(comb)\n ctx.box.append(el)\n let datalist: HTMLDataListElement | undefined\n if (choices) {\n datalist = ownerDoc.createElement('datalist')\n datalist.id = `ink-form-list-${++lists}`\n for (const o of choices) {\n const option = ownerDoc.createElement('option')\n option.value = o.label\n datalist.append(option)\n }\n ctx.box.append(datalist)\n el.setAttribute('list', datalist.id)\n }\n /** The text shown for a stored value: an option's label, else the value itself. */\n const label = (value: string) => choices?.find((o) => o.value === value)?.label ?? value\n /** The value stored for text: the export value of the option it labels, else the text. */\n const valueOf = (text: string) => choices?.find((o) => o.label === text)?.value ?? text\n\n const appearance = widget.appearance\n const initial = typeof field.value === 'string' ? field.value : ''\n let state: WidgetState = {\n value: field.value,\n formatted: undefined,\n override: {},\n readOnly: false,\n required: false,\n }\n let frame: WidgetFrame | undefined\n let focused = false\n /** Text was typed since focus or the last commit. */\n let typed = false\n /** Text the form refused on Enter and still holds as typed; not committed again on blur. */\n let refused: string | undefined\n /**\n * Focus is in a form script's alert (`[data-ink-form-alert]`), which a refusing validator\n * often shows. The field has not been left: its text stays, and focus comes back after.\n */\n let paused = false\n let composing = false\n let before: Snapshot = { value: '', start: 0, end: 0 }\n\n const raw = (): string => (typeof state.value === 'string' ? state.value : '')\n const changed = () => raw() !== initial\n /** Script state the PDF's appearance does not show. */\n const restyled = () => {\n const o = state.override\n return (\n o.textColor !== undefined ||\n o.fillColor !== undefined ||\n o.strokeColor !== undefined ||\n o.textSize !== undefined ||\n // A widget the PDF hides has no appearance to show.\n (o.hidden === false && (widget.hidden || widget.printOnly))\n )\n }\n const drawn = () => focused || changed() || restyled()\n\n const snap = (): Snapshot => ({\n value: el.value,\n start: el.selectionStart ?? el.value.length,\n end: el.selectionEnd ?? el.value.length,\n })\n\n let measurer: CanvasRenderingContext2D | null | undefined\n const fontAt = (px: number) =>\n `${appearance.font?.fontStyle ?? 'normal'} ${appearance.font?.fontWeight ?? 'normal'} ${px}px ${familyList(appearance.font?.family)}`\n const textWidth = (text: string, px: number): number => {\n measurer ??= ownerDoc.createElement('canvas').getContext('2d')\n if (!measurer) return 0\n measurer.font = fontAt(px)\n return measurer.measureText(text).width\n }\n\n /** The border width in CSS px. */\n const borderPx = () =>\n appearance.border && frame ? appearance.border.width * frame.scale : 0\n\n /** The font size in CSS px: the script's or `/DA`'s, or fitted to the box for auto size. */\n const fontPx = (): number => {\n if (!frame) return 0\n const size = state.override.textSize ?? appearance.fontSize\n if (size > 0) return size * frame.scale\n const inner = frame.width - 2 * (borderPx() + PADDING * frame.scale)\n const min = AUTO_MIN * frame.scale\n if (multiline) return Math.max(min, MULTILINE_AUTO * frame.scale)\n const start = Math.max(min, (frame.height - 2 * borderPx()) / LINE_FACTOR)\n const shown = field.flags.password ? '•'.repeat(el.value.length) : el.value\n const width = textWidth(shown, start)\n return width > inner && width > 0 ? Math.max(min, (start * inner) / width) : start\n }\n\n /** A multiline auto-size field shrinks until its text fits the box. */\n const fitLines = () => {\n if (!frame || !multiline) return\n if ((state.override.textSize ?? appearance.fontSize) > 0) return\n let px = fontPx()\n const min = AUTO_MIN * frame.scale\n el.style.fontSize = `${px}px`\n while (px > min && el.scrollHeight > el.clientHeight + 1) {\n px = Math.max(min, px * 0.9)\n el.style.fontSize = `${px}px`\n }\n }\n\n const style = () => {\n if (!frame) return\n const s = el.style\n const o = state.override\n const px = fontPx()\n const color = o.textColor ?? appearance.color ?? '#000000'\n s.fontFamily = familyList(appearance.font?.family)\n s.fontWeight = appearance.font?.fontWeight ?? 'normal'\n s.fontStyle = appearance.font?.fontStyle ?? 'normal'\n s.fontSize = `${px}px`\n s.lineHeight = multiline ? `${LINE_FACTOR}` : 'normal'\n s.color = color\n s.caretColor = color === 'transparent' ? '#000000' : color\n s.textAlign = comb ? 'left' : appearance.align\n const bw = borderPx()\n const pad = PADDING * frame.scale\n const shows = drawn()\n // Clear while the PDF's own appearance shows underneath.\n s.setProperty('-webkit-text-fill-color', shows ? color : 'transparent')\n const border = appearance.border\n const stroke = o.strokeColor ?? border?.color\n if (shows && border && bw > 0 && stroke && stroke !== 'transparent') {\n s.borderStyle = 'none'\n s.borderWidth = `${bw}px`\n s.borderColor = stroke\n if (border.style === 'underline') s.borderBottomStyle = 'solid'\n else s.borderStyle = BORDER_STYLES[border.style]\n } else {\n s.borderStyle = 'solid'\n s.borderWidth = `${bw}px`\n s.borderColor = 'transparent'\n }\n s.backgroundColor = shows\n ? (o.fillColor ?? appearance.background ?? 'transparent')\n : 'transparent'\n if (comb) {\n const cell = (frame.width - 2 * bw) / comb\n const glyph = textWidth('0', px)\n s.letterSpacing = `${Math.max(0, cell - glyph)}px`\n s.paddingLeft = `${Math.max(0, (cell - glyph) / 2)}px`\n s.paddingRight = '0px'\n s.backgroundImage =\n shows && border && bw > 0 && stroke && stroke !== 'transparent'\n ? `repeating-linear-gradient(to right, transparent 0 ${cell - bw}px, ${stroke} ${cell - bw}px ${cell}px)`\n : ''\n } else {\n s.letterSpacing = ''\n s.paddingLeft = `${pad}px`\n s.paddingRight = `${pad}px`\n }\n s.paddingTop = multiline ? `${pad / 2}px` : '0px'\n s.paddingBottom = multiline ? `${pad / 2}px` : '0px'\n fitLines()\n }\n\n /** Shows the raw value while focused and the formatted one otherwise. */\n const show = () => {\n const text = focused ? label(raw()) : (state.formatted ?? label(raw()))\n if (el.value !== text) el.value = text\n }\n\n /**\n * Commits the typed text. Refused on Enter (`leaving` false), the text stays, as the form\n * keeps it, to be corrected, and the field is marked. Leaving the field drops it: the caller\n * dispatches Blur, shows the stored value and clears the mark, so a text already refused is\n * not validated a second time.\n */\n const commit = (leaving: boolean) => {\n if (!typed) return\n typed = false\n const text = valueOf(el.value)\n if (leaving && text === refused) return\n refused = undefined\n if (text === raw()) {\n show()\n return\n }\n const result = form.set({ [field.name]: text })\n const rejected = result.rejected.length > 0\n ctx.setInvalid(rejected)\n if (rejected && !leaving) {\n refused = text\n typed = true\n style()\n return\n }\n show()\n style()\n }\n\n /** The text no longer fits the box, at the smallest size for auto size. */\n const overflows = (): boolean => {\n if (!frame) return false\n style()\n if (multiline) return el.scrollHeight > el.clientHeight + 1\n const inner = frame.width - 2 * (borderPx() + PADDING * frame.scale)\n const shown = field.flags.password ? '•'.repeat(el.value.length) : el.value\n return textWidth(shown, fontPx()) > inner + 1\n }\n\n const keystroke = () => {\n const prev = before\n const next = el.value\n if (next === prev.value) return\n const refuse = () => {\n el.value = prev.value\n el.setSelectionRange(prev.start, prev.end)\n }\n const { start, end, change } = editOf(prev, next)\n // A field that does not scroll (`/Ff` DoNotScroll) takes no more text than it shows: any\n // edit that puts text in (typing, typing over a selection, a paste, autocorrect) is refused\n // when the result overflows. Deleting alone is always allowed, even from text the file\n // overfilled. This measures the text as typed, before keystroke scripts run: a script\n // that changes the text afterwards is not measured, as the sandbox has already taken the\n // keystroke and the draft cannot be rolled back.\n if (field.flags.doNotScroll && !comb && change !== '' && overflows()) {\n refuse()\n style()\n return\n }\n const result = form._keystroke(widget.id, change, start, end)\n if (!result.accepted) {\n refuse()\n return\n }\n typed = true\n if (result.value !== el.value) {\n el.value = result.value\n el.setSelectionRange(result.selStart, result.selEnd)\n }\n before = snap()\n style()\n }\n\n const on = <K extends keyof HTMLElementEventMap>(\n type: K,\n fn: (ev: HTMLElementEventMap[K]) => void\n ) => el.addEventListener(type, fn as EventListener)\n\n /** Focus is going into a form script's alert. */\n const toAlert = (target: EventTarget | null) =>\n target instanceof Element && target.closest('[data-ink-form-alert]') !== null\n\n /** Leaves the field: commits, drops what is left uncommitted, and shows the stored value. */\n const leave = () => {\n commit(true)\n // Leaving shows the stored value, which no script refused: a refused text's mark goes\n // with the text.\n ctx.setInvalid(false)\n focused = false\n composing = false\n typed = false\n refused = undefined\n form._dispatch({ widget: widget.id, name: 'Blur' })\n show()\n style()\n ctx.redraw()\n }\n\n /** While paused: focus that moves on from the alert to anywhere but the field leaves it. */\n const onFocusIn = (e: FocusEvent) => {\n if (e.target === el || toAlert(e.target)) return\n resume()\n leave()\n }\n const resume = () => {\n paused = false\n el.ownerDocument.removeEventListener('focusin', onFocusIn, true)\n }\n\n on('focus', () => {\n if (paused) {\n // Back from the alert: the field was never left, so nothing starts over.\n resume()\n return\n }\n focused = true\n typed = false\n show()\n before = snap()\n style()\n ctx.redraw()\n form._dispatch({ widget: widget.id, name: 'Focus' })\n })\n on('blur', (e) => {\n if (toAlert(e.relatedTarget)) {\n paused = true\n el.ownerDocument.addEventListener('focusin', onFocusIn, true)\n return\n }\n leave()\n })\n on('beforeinput', () => {\n if (!composing) before = snap()\n })\n on('compositionstart', () => {\n composing = true\n })\n on('compositionend', () => {\n composing = false\n keystroke()\n })\n on('input', (e) => {\n if (composing || e.isComposing) return\n keystroke()\n })\n /**\n * Puts back the committed text, dropping what was typed and a refused value with its mark.\n * Focus stays, and typing goes on from the committed text.\n */\n const revert = () => {\n typed = false\n refused = undefined\n form._revert(widget.id)\n ctx.setInvalid(false)\n show()\n el.setSelectionRange(el.value.length, el.value.length)\n before = snap()\n style()\n }\n\n on('keydown', (e) => {\n if (e.isComposing) return\n if (e.key === 'Escape') {\n if (!typed && refused === undefined) return\n e.preventDefault()\n revert()\n return\n }\n if (e.key !== 'Enter' || multiline) return\n e.preventDefault()\n commit(false)\n before = snap()\n })\n\n return {\n control: el,\n get drawn() {\n return drawn()\n },\n sync(next) {\n const was = raw()\n state = next\n el.readOnly = next.readOnly\n if (!focused) show()\n else if (raw() !== was) {\n // A new stored value while focused (a commit, a script) replaces the text, as the form\n // dropped what was typed before it.\n typed = false\n show()\n before = snap()\n }\n style()\n },\n layout(next) {\n frame = next\n style()\n },\n destroy() {\n resume()\n el.remove()\n datalist?.remove()\n },\n }\n}\n","// Checkbox, radio, combo box and list box widgets.\n//\n// Checkboxes and radios are `<button role=\"checkbox|radio\">`, clear over the PDF's own\n// appearance. The form layer shows the widget's own on or off appearance under it, as its state\n// says. A widget whose file has no on appearance draws itself while on, with its `/MK /CA`\n// character in ZapfDingbats style, and so does one a script gives colours or a size. A click,\n// or Space, commits the new state and then runs the widget's Mouse Up and Action; arrow keys\n// move through a radio group's shown, editable widgets on the page and pick as they go.\n//\n// A combo box is a native `<select>` (an editable one is a text input with a `<datalist>`, in\n// form-text.ts), and a list box a `<select>` with a `size`, or `multiple` for a multi-select.\n// They show option labels and store export values, and every change commits. Like a text\n// field, a choice control is clear over the PDF's appearance until it is focused or its value\n// changes.\nimport { sameValue } from '../model/form/values'\n\nimport { BORDER_STYLES, createTextWidget, familyList } from './form-text'\n\nimport type {\n WidgetFrame,\n WidgetState,\n WidgetView,\n WidgetViewContext,\n} from './form-layer'\nimport type { FieldValue } from '../model/form/types'\n\n/** ZapfDingbats characters `/MK /CA` names, as the Unicode signs that look like them. */\nconst DINGBATS: Readonly<Record<string, string>> = {\n '3': '✓',\n '4': '✔',\n '7': '✗',\n '8': '✘',\n H: '★',\n l: '●',\n n: '■',\n u: '◆',\n}\n\n/** The share of the box's shorter side the check character fills, as PDF.js draws it. */\nconst GLYPH_RATIO = 0.8\n/** Line height as a multiple of the font size, as PDF.js lays out field text. */\nconst LINE_FACTOR = 1.35\n/** Auto size (`/DA` size 0) in a list box, in points. */\nconst LIST_AUTO = 12\n\n/** Keys a `<select>` opens its list or moves its choice on. */\nconst SELECT_KEYS = new Set([\n 'ArrowUp',\n 'ArrowDown',\n 'ArrowLeft',\n 'ArrowRight',\n 'Home',\n 'End',\n 'PageUp',\n 'PageDown',\n ' ',\n 'Enter',\n 'F4',\n])\n\n/**\n * Whether the key opens a select or changes its choice: the keys above (Alt+Down and Alt+Up\n * included), and a key that types a character (one code point, astral ones too), which picks\n * the option it starts. Ctrl or Cmd makes a key a shortcut, and so does Alt on a letter or\n * digit key that still types that letter or digit; Alt that types another character (Option\n * on macOS) still picks.\n */\nfunction opensOrPicks(e: KeyboardEvent): boolean {\n if (e.ctrlKey || e.metaKey) return false\n if (SELECT_KEYS.has(e.key)) return true\n if ([...e.key].length !== 1) return false\n const plain = /^(?:Key|Digit)(.)$/.exec(e.code)?.[1]\n return !(e.altKey && plain !== undefined && e.key.toUpperCase() === plain)\n}\n\n/** Focus and Blur reach the widget's scripts. */\nfunction sendFocus(ctx: WidgetViewContext, el: HTMLElement, onChange: () => void) {\n el.addEventListener('focus', () => {\n onChange()\n ctx.form._dispatch({ widget: ctx.widget.id, name: 'Focus' })\n })\n el.addEventListener('blur', () => {\n ctx.form._dispatch({ widget: ctx.widget.id, name: 'Blur' })\n onChange()\n })\n}\n\n/** A checkbox or radio widget. */\nexport function createToggleWidget(ctx: WidgetViewContext): WidgetView {\n const { form, field, widget } = ctx\n const ownerDoc = ctx.box.ownerDocument\n const radio = field.type === 'radio'\n const onState = widget.onState\n const appearance = widget.appearance\n const el = ownerDoc.createElement('button')\n el.type = 'button'\n el.className = 'ink-form-control'\n el.setAttribute('role', radio ? 'radio' : 'checkbox')\n el.setAttribute('aria-label', ctx.label)\n el.style.cssText =\n 'position:absolute;box-sizing:border-box;margin:0;padding:0;border:none;' +\n 'background:transparent;display:flex;align-items:center;justify-content:center;' +\n 'line-height:1;overflow:hidden;transform-origin:center;'\n ctx.box.append(el)\n\n let state: WidgetState | undefined\n let frame: WidgetFrame | undefined\n const on = () => onState !== undefined && state?.value === onState\n /** Script state the PDF's appearance does not show. */\n const restyled = () => {\n const o = state?.override ?? {}\n return (\n o.textColor !== undefined ||\n o.fillColor !== undefined ||\n o.strokeColor !== undefined ||\n o.textSize !== undefined ||\n (o.hidden === false && (widget.hidden || widget.printOnly))\n )\n }\n /**\n * The widget draws itself while a script restyles it, and while it is on without an on\n * appearance of its own.\n */\n const drawn = () => restyled() || (appearance.onAppearance === false && on())\n const glyph = () =>\n DINGBATS[appearance.checkStyle ?? ''] ?? (radio ? DINGBATS.l! : DINGBATS['4']!)\n\n /** Colours, border and check size: the `/MK` and `/DA` ones, or a script's over them. */\n const style = () => {\n const s = el.style\n const o = state?.override ?? {}\n const shows = drawn()\n s.color = o.textColor ?? appearance.color ?? '#000000'\n s.backgroundColor = shows\n ? (o.fillColor ?? appearance.background ?? 'transparent')\n : 'transparent'\n const border = appearance.border\n const stroke = o.strokeColor ?? border?.color\n const bw = border && frame ? border.width * frame.scale : 0\n if (shows && border && bw > 0 && stroke && stroke !== 'transparent') {\n s.borderWidth = `${bw}px`\n s.borderColor = stroke\n s.borderStyle = 'none'\n if (border.style === 'underline') s.borderBottomStyle = 'solid'\n else s.borderStyle = BORDER_STYLES[border.style]\n } else s.border = 'none'\n // A radio draws round, as PDF radios are, unless its `/MK /CA` asks for a square check.\n s.borderRadius = radio && appearance.checkStyle !== 'n' ? '50%' : ''\n if (!frame) return\n const size = o.textSize ?? appearance.fontSize\n s.fontSize =\n size > 0\n ? `${size * frame.scale}px`\n : `${Math.min(frame.width, frame.height) * GLYPH_RATIO}px`\n }\n\n const show = () => {\n el.setAttribute('aria-checked', on() ? 'true' : 'false')\n const text = drawn() && on() ? glyph() : ''\n if (el.textContent !== text) el.textContent = text\n style()\n }\n\n const activate = () => {\n if (!state || state.readOnly || onState === undefined) return\n const next = radio ? onState : on() ? 'Off' : onState\n // One undo step: the new state and the scripts its Mouse Up and Action run.\n form._step(() => {\n if (next !== state?.value) {\n const result = form.set({ [field.name]: next })\n ctx.setInvalid(result.rejected.length > 0)\n }\n if (widget.hasScripts) form._dispatch({ widget: widget.id, name: 'Mouse Up' })\n form._dispatch({ widget: widget.id, name: 'Action' })\n })\n }\n\n el.addEventListener('click', activate)\n el.addEventListener('keydown', (e) => {\n // Space toggles, as the button's own click; Enter does not, as for any checkbox.\n if (e.key === 'Enter') {\n e.preventDefault()\n return\n }\n if (!radio) return\n const step =\n e.key === 'ArrowDown' || e.key === 'ArrowRight'\n ? 1\n : e.key === 'ArrowUp' || e.key === 'ArrowLeft'\n ? -1\n : 0\n if (step === 0) return\n e.preventDefault()\n // Hidden and read-only radios are passed over, and none is picked while this one is\n // read-only.\n if (state?.readOnly) return\n const group = ctx.siblings()\n const at = group.indexOf(el)\n if (at < 0 || group.length < 2) return\n const next = group[(at + step + group.length) % group.length]!\n next.focus()\n next.click()\n })\n sendFocus(ctx, el, () => undefined)\n\n return {\n control: el,\n activates: true,\n get drawn() {\n return drawn()\n },\n sync(next) {\n state = next\n show()\n },\n layout(next) {\n frame = next\n style()\n },\n destroy() {\n el.remove()\n },\n }\n}\n\n/** A combo box (editable or not) or list box widget. */\nexport function createChoiceWidget(ctx: WidgetViewContext): WidgetView {\n const { field } = ctx\n if (field.type === 'combo' && field.flags.editable)\n return createTextWidget(ctx, field.options)\n return createSelectWidget(ctx)\n}\n\nfunction createSelectWidget(ctx: WidgetViewContext): WidgetView {\n const { form, field, widget } = ctx\n const ownerDoc = ctx.box.ownerDocument\n const list = field.type === 'list'\n const multi = list && field.flags.multiSelect\n const appearance = widget.appearance\n const el = ownerDoc.createElement('select')\n el.className = 'ink-form-control'\n el.setAttribute('aria-label', ctx.label)\n if (multi) el.multiple = true\n else if (list) el.size = Math.max(2, field.options.length)\n el.style.cssText =\n 'position:absolute;box-sizing:border-box;margin:0;appearance:none;' +\n '-webkit-appearance:none;transform-origin:center;' +\n (list ? 'overflow-y:auto;' : 'overflow:hidden;')\n const options = field.options.map((o) => {\n const option = ownerDoc.createElement('option')\n option.value = o.value\n option.textContent = o.label\n el.append(option)\n return option\n })\n ctx.box.append(el)\n\n let state: WidgetState = {\n value: field.value,\n formatted: undefined,\n override: {},\n readOnly: false,\n required: false,\n }\n let frame: WidgetFrame | undefined\n let focused = false\n\n const chosen = (): string[] => {\n const v = state.value\n if (Array.isArray(v)) return [...(v as readonly string[])]\n return typeof v === 'string' ? [v] : []\n }\n const restyled = () => {\n const o = state.override\n return (\n o.textColor !== undefined ||\n o.fillColor !== undefined ||\n o.strokeColor !== undefined ||\n o.textSize !== undefined ||\n (o.hidden === false && (widget.hidden || widget.printOnly))\n )\n }\n const drawn = () => focused || !sameValue(state.value, field.value) || restyled()\n\n const show = () => {\n const picked = new Set(chosen())\n for (const option of options) option.selected = picked.has(option.value)\n if (!multi && !options.some((o) => o.selected)) el.selectedIndex = -1\n }\n\n const style = () => {\n if (!frame) return\n const s = el.style\n const o = state.override\n const shows = drawn()\n const bw = appearance.border ? appearance.border.width * frame.scale : 0\n const size = o.textSize ?? appearance.fontSize\n const px =\n size > 0\n ? size * frame.scale\n : list\n ? LIST_AUTO * frame.scale\n : Math.max(1, (frame.height - 2 * bw) / LINE_FACTOR)\n const color = o.textColor ?? appearance.color ?? '#000000'\n s.fontFamily = familyList(appearance.font?.family)\n s.fontWeight = appearance.font?.fontWeight ?? 'normal'\n s.fontStyle = appearance.font?.fontStyle ?? 'normal'\n s.fontSize = `${px}px`\n s.padding = `0 ${2 * frame.scale}px`\n s.color = shows ? color : 'transparent'\n s.backgroundColor = shows\n ? (o.fillColor ?? appearance.background ?? 'transparent')\n : 'transparent'\n const border = appearance.border\n const stroke = o.strokeColor ?? border?.color\n s.borderWidth = `${bw}px`\n if (shows && border && bw > 0 && stroke && stroke !== 'transparent') {\n s.borderStyle = BORDER_STYLES[border.style]\n s.borderColor = stroke\n } else {\n s.borderStyle = 'solid'\n s.borderColor = 'transparent'\n }\n // A list box's chosen options keep the browser's highlight only while it draws itself.\n for (const option of options) {\n option.style.color = shows ? '' : 'transparent'\n option.style.backgroundColor = shows ? '' : 'transparent'\n }\n }\n\n const commit = () => {\n // A select has no read-only state of its own: a change that got past the guards above is\n // put back.\n if (state.readOnly) {\n show()\n return\n }\n const value: FieldValue = multi\n ? options.filter((o) => o.selected).map((o) => o.value)\n : el.value\n if (sameValue(value, state.value)) return\n const result = form.set({ [field.name]: value })\n ctx.setInvalid(result.rejected.length > 0)\n // A refused change leaves the stored value, which nothing re-sends: show it again.\n show()\n style()\n }\n\n // A read-only select does not open or move its choice. It still takes focus, from a press\n // too, so a screen reader can land on it, and other keys and shortcuts pass through.\n el.addEventListener('mousedown', (e) => {\n if (!state.readOnly) return\n e.preventDefault()\n el.focus()\n })\n el.addEventListener('keydown', (e) => {\n if (state.readOnly && opensOrPicks(e)) e.preventDefault()\n })\n el.addEventListener('change', commit)\n sendFocus(ctx, el, () => {\n focused = ownerDoc.activeElement === el\n style()\n ctx.redraw()\n })\n\n return {\n control: el,\n get drawn() {\n return drawn()\n },\n sync(next) {\n state = next\n show()\n style()\n },\n layout(next) {\n frame = next\n style()\n },\n destroy() {\n el.remove()\n },\n }\n}\n","// The order Tab visits form widgets in: page by page, and on each page by its `/Tabs`.\n//\n// Rows and columns are read off the page as it displays, so a page with `/Rotate` reads in the\n// rows its reader sees. A widget joins the row (or column) under way when its centre falls\n// inside the first widget of that row, so a tall list box and the short field beside it share\n// a row even though their tops differ.\nimport { createPageTransform, type CssRect } from './transform'\n\nimport type { FormField, FormWidget, TabsOrder } from '../model/form/types'\nimport type { PageInfo } from '../model/pages'\n\nexport type { TabsOrder }\n\nconst unturned = (index: number): PageInfo => ({\n index,\n box: { x: 0, y: 0, width: 0, height: 0 },\n rotate: 0,\n userUnit: 1,\n width: 0,\n height: 0,\n})\n\ninterface Placed {\n id: string\n /** Position in `/Annots` order on its page. */\n index: number\n box: CssRect\n}\n\n/** Groups `items` into bands along one axis, then orders each band along the other. */\nfunction banded(\n items: readonly Placed[],\n start: (b: CssRect) => number,\n size: (b: CssRect) => number,\n across: (b: CssRect) => number\n): Placed[] {\n const sorted = [...items].sort(\n (a, b) =>\n start(a.box) - start(b.box) || across(a.box) - across(b.box) || a.index - b.index\n )\n const bands: Placed[][] = []\n let first: CssRect | undefined\n for (const item of sorted) {\n const mid = start(item.box) + size(item.box) / 2\n const band = bands.at(-1)\n if (band && first && mid >= start(first) && mid <= start(first) + size(first))\n band.push(item)\n else {\n bands.push([item])\n first = item.box\n }\n }\n return bands.flatMap((band) =>\n band.sort(\n (a, b) =>\n across(a.box) - across(b.box) || start(a.box) - start(b.box) || a.index - b.index\n )\n )\n}\n\n/**\n * A page's widgets in paint order: their `/Annots` order (`FormWidget.order`), else the order\n * they are listed in.\n */\nexport function annotsOrder<T>(\n items: readonly T[],\n widget: (item: T) => Pick<FormWidget, 'order'>\n): T[] {\n return items\n .map((item, i) => ({ item, i, at: widget(item).order ?? i }))\n .sort((a, b) => a.at - b.at || a.i - b.i)\n .map(({ item }) => item)\n}\n\n/**\n * One page's widget ids in Tab order: `R` reads rows top to bottom and each row left to right,\n * `C` reads columns left to right and each column top to bottom, and `S` follows `structure`\n * (the page's annotation ids in structure-tree order), with widgets the tree leaves out after\n * the rest in `/Annots` order. `W`, `A` or no `/Tabs` keep `/Annots` order. Positions are taken\n * as the page displays, after its `/Rotate`; without `info` the page is read unturned.\n */\nexport function pageTabOrder(\n widgets: readonly Pick<FormWidget, 'id' | 'rect' | 'order'>[],\n order: TabsOrder | undefined,\n info: PageInfo | undefined,\n page = 0,\n structure: readonly string[] = []\n): string[] {\n const listed = annotsOrder(widgets, (w) => w)\n if (order === 'S') {\n const at = new Map(structure.map((id, i) => [id, i]))\n return listed\n .map((w, i) => ({ id: w.id, i, at: at.get(w.id) ?? Infinity }))\n .sort((a, b) => a.at - b.at || a.i - b.i)\n .map((w) => w.id)\n }\n if (order !== 'R' && order !== 'C') return listed.map((w) => w.id)\n // Only the order matters, so a page without `info` is read through an unturned stand-in of\n // no size.\n const transform = createPageTransform(info ?? unturned(page), 1)\n const placed = listed.map((w, index): Placed => ({\n id: w.id,\n index,\n box: transform.toCssRect(w.rect),\n }))\n const sorted =\n order === 'R'\n ? banded(\n placed,\n (b) => b.top,\n (b) => b.height,\n (b) => b.left\n )\n : banded(\n placed,\n (b) => b.left,\n (b) => b.width,\n (b) => b.top\n )\n return sorted.map((p) => p.id)\n}\n\n/**\n * Widget ids in Tab order: pages in order, each by its `/Tabs` (`pageTabOrder`), with\n * `structure` the structure order of each `S` page. A page missing from `pages` is read\n * unturned.\n */\nexport function tabOrder(\n fields: readonly FormField[],\n tabs: ReadonlyMap<number, TabsOrder>,\n pages: readonly PageInfo[] = [],\n structure: ReadonlyMap<number, readonly string[]> = new Map()\n): string[] {\n const byPage = new Map<number, FormWidget[]>()\n for (const field of fields)\n for (const w of field.widgets) {\n const list = byPage.get(w.page) ?? []\n list.push(w)\n byPage.set(w.page, list)\n }\n return [...byPage.keys()]\n .sort((a, b) => a - b)\n .flatMap((page) =>\n pageTabOrder(\n byPage.get(page)!,\n tabs.get(page),\n pages[page],\n page,\n structure.get(page)\n )\n )\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\n/**\n * Words the form layer and the form dialogs add to the page's form fields, shared so every\n * binding says the same. A field is named by its own tooltip (`/TU`), else the last part of its\n * name; `unnamed` stands in when it has neither.\n */\nexport const FORM_LABELS = {\n unnamed: 'Form field',\n /** An empty signature field's affordance. */\n sign: 'Sign',\n /** Its tooltip, and the start of its accessible name. */\n signField: 'Sign this field',\n /** The title of the dialog a form's script message shows in. */\n alert: 'Message',\n ok: 'OK',\n} as const\n","// A signature field widget: a native `<button>` over the PDF's own appearance of the box. While\n// the field is empty it shows \"Sign\", and activating it (a click, Enter or Space) asks the host\n// to sign it through `onSignField`, anchored to the widget's box; the viewer opens the\n// signature menu there. Once signed it shows nothing of its own: the signature is an annotation,\n// drawn by the overlay above the field, and selecting and deleting it clears the field. A signed\n// field is not signed again until it is cleared: its button is disabled for assistive\n// technology and left out of the Tab order.\n//\n// The button's font size follows the box at each zoom (geometry); its look is the theme's.\nimport { FORM_LABELS } from './ui'\n\nimport type { WidgetState, WidgetView, WidgetViewContext } from './form-layer'\n\n/** Points the \"Sign\" text is set in at 100%, unless the box is too short for it. */\nconst LABEL_SIZE = 12\n\nexport function createSignatureWidget(ctx: WidgetViewContext): WidgetView {\n const { form, field, widget } = ctx\n const el = ctx.box.ownerDocument.createElement('button')\n el.type = 'button'\n el.className = 'ink-form-control ink-form-sign'\n el.dataset.inkSignField = ''\n el.style.cssText =\n 'position:absolute;box-sizing:border-box;margin:0;padding:0;border:none;' +\n 'background:transparent;transform-origin:center;white-space:nowrap;overflow:hidden;'\n ctx.box.append(el)\n\n let state: WidgetState | undefined\n const signed = () => typeof state?.value === 'object' && !Array.isArray(state.value)\n const signable = () => state !== undefined && !state.readOnly && !signed()\n\n el.addEventListener('click', () => {\n if (!signable()) return\n ctx.onSignField?.({\n field: field.name,\n widget: widget.id,\n page: ctx.page,\n rect: widget.rect,\n anchor: ctx.box,\n })\n })\n el.addEventListener('focus', () => form._dispatch({ widget: widget.id, name: 'Focus' }))\n el.addEventListener('blur', () => form._dispatch({ widget: widget.id, name: 'Blur' }))\n\n return {\n control: el,\n drawn: false,\n get tabbable() {\n return !signed()\n },\n sync(next) {\n state = next\n const isSigned = signed()\n if (isSigned) {\n el.dataset.inkSigned = ''\n el.setAttribute('aria-disabled', 'true')\n // No menu is open on a signed field: a host's signature menu leaves no state behind.\n el.removeAttribute('aria-expanded')\n delete el.dataset.state\n } else {\n delete el.dataset.inkSigned\n el.removeAttribute('aria-disabled')\n }\n // Text only: the label is ours, the name is the file's.\n el.textContent = signable() ? FORM_LABELS.sign : ''\n if (signable()) {\n el.setAttribute('aria-label', `${FORM_LABELS.signField}: ${ctx.label}`)\n el.title = FORM_LABELS.signField\n } else {\n el.setAttribute('aria-label', ctx.label)\n el.removeAttribute('title')\n }\n },\n layout(frame) {\n el.style.fontSize = `${Math.min(LABEL_SIZE * frame.scale, frame.height * 0.6)}px`\n },\n destroy() {\n el.remove()\n },\n }\n}\n","// The page's form fields, as native controls over the canvas.\n//\n// Inline styles here are structural or geometric: the layer is `position:absolute; inset:0;\n// pointer-events:none` over the page, each widget box is `position:absolute` at its rect from\n// the transform, and its control is placed and turned inside the box (`/MK /R` and the page's\n// turn). What a control looks like when it draws itself (font, size, colour, alignment, border,\n// background) is the field's own appearance from the PDF or a script, as an annotation's colours\n// are its own. The tint, focus ring and invalid mark are the theme's.\n//\n// Untouched widgets look exactly as the PDF draws them: the page canvas leaves the widgets out,\n// and the layer draws each widget's own appearance into a small canvas over its rect\n// (form-appearance.ts). Those canvases sit in the page's stack right above the page canvas,\n// under the text layer and the annotations, so annotations over a field stay visible. The layer\n// itself sits above the text layer and under the annotations: a press on an annotation's shape\n// selects the annotation, and a press anywhere else in a field's box is the field's. A widget's\n// control is clear until it is focused or shows something the PDF's appearance does not (a\n// changed value, a script's colour or size); then its appearance hides and the control draws.\n//\n// A signature field is a button: \"Sign\" while it is empty, which asks the host to sign it\n// (`onSignField`), and clear once signed, when the signature annotation shows over it.\n//\n// A checkbox or radio has both its on and off appearances drawn, and shows the one for its\n// state: a toggle, like an edit, paints nothing.\n//\n// The widget boxes are in the page's Tab order (its `/Tabs`: rows, columns or the structure\n// tree, else `/Annots` order), so Tab within a page is the browser's own. A radio group is one\n// stop: its chosen radio, else its first. The engine moves Tab on from a page's last stop to\n// the next page's first. The appearances, and the boxes over them, stack in `/Annots` order,\n// as the file paints its widgets; a focused or marked box rises above the rest.\nimport { sameValue } from '../model/form/values'\n\nimport { createWidgetAppearances, type WidgetAppearances } from './form-appearance'\nimport { createButtonWidget } from './form-button'\nimport { createChoiceWidget, createToggleWidget } from './form-choice'\nimport { annotsOrder, pageTabOrder } from './form-order'\nimport { createSignatureWidget } from './form-signature'\nimport { createTextWidget } from './form-text'\nimport { normalizeRotation, type PageTransform, type ViewRotation } from './transform'\nimport { FORM_LABELS } from './ui'\n\nimport type { InkDocument } from '../model/document'\nimport type { FormController } from '../model/form/controller'\nimport type {\n FieldValue,\n FormField,\n FormFieldType,\n FormWidget,\n WidgetOverride,\n} from '../model/form/types'\nimport type { Rect } from '../model/geometry'\nimport type { AppearanceLook } from '../pdfjs/widget-appearance'\n\n/** A signature field asked to be signed, anchored to its widget's box. */\nexport interface SignFieldRequest {\n /** Full field name. */\n field: string\n /** Widget id. */\n widget: string\n /** Zero-based page index. */\n page: number\n /** The widget's rect, in user space. */\n rect: Rect\n /** The widget's box, to anchor the signature menu to. */\n anchor: HTMLElement\n}\n\nexport interface FormLayerOptions {\n /** The page host (`div.ink-page`); the layer appends itself to it. */\n host: HTMLElement\n /** Zero-based page index. */\n page: number\n transform: PageTransform\n document: InkDocument\n /** Tints fillable fields. Off sets `data-ink-form-highlight=\"off\"` on the layer. */\n highlight: boolean\n onSignField?(req: SignFieldRequest): void\n /**\n * Whether fields take input now: while the default pointer tool is active. Read on\n * `refresh()` and when the layer is built.\n */\n isActive(): boolean\n /** Device pixel ratio for the widget appearances; `window.devicePixelRatio` when omitted. */\n devicePixelRatio?: number\n /** A widget's appearance failed to render (cancellations are not reported). */\n onError?(error: unknown): void\n /** The widget appearances shown painted. */\n onRendered?(): void\n}\n\nexport interface FormLayer {\n readonly element: HTMLElement\n /**\n * Resolves once the widget appearances shown now have painted (or failed). Never rejects.\n */\n readonly rendered: Promise<void>\n /** Places every widget for a new zoom or rotation, in place: focus, caret and typed text stay. */\n update(t: PageTransform): void\n /** Focuses the widget's control. False when the widget is not on this page or is hidden. */\n focusWidget(id: string): boolean\n /** The controls Tab stops at, in Tab order: none while fields take no input. */\n tabStops(): HTMLElement[]\n /** Reads `isActive()` again, after the active tool changed. */\n refresh(): void\n /** Tints the fields or stops, in place, as `highlight` does at creation. */\n setHighlight(on: boolean): void\n destroy(): void\n}\n\n/** What a widget shows: the field's value, its formatted text and any script state. */\nexport interface WidgetState {\n value: FieldValue | undefined\n /** Formatted text from a format script, shown while the widget is not focused. */\n formatted: string | undefined\n override: WidgetOverride\n readOnly: boolean\n required: boolean\n}\n\n/** The control's own frame in its box: unturned size, its turn on screen, and the zoom. */\nexport interface WidgetFrame {\n /** CSS px, before `rotation`. */\n width: number\n height: number\n /** Clockwise turn on screen: the page's total rotation less `/MK /R`. */\n rotation: ViewRotation\n /** CSS px per user-space unit. */\n scale: number\n}\n\n/** What the layer gives a widget renderer. */\nexport interface WidgetViewContext {\n readonly document: InkDocument\n readonly form: FormController\n readonly field: FormField\n readonly widget: FormWidget\n readonly page: number\n /** The widget's box (`[data-ink-widget]`), placed by the layer. The view adds its control. */\n readonly box: HTMLElement\n /** The control's accessible name: `/TU`, else the last part of the field name. */\n readonly label: string\n /** The view's `drawn` may have changed. */\n redraw(): void\n /**\n * The controls of this field's widgets on the page a person can pick (shown and not\n * read-only), in Tab order, this one included.\n */\n siblings(): HTMLElement[]\n /** Marks the widget invalid (a rejected commit) or valid again. */\n setInvalid(invalid: boolean): void\n onSignField?(req: SignFieldRequest): void\n}\n\n/** One widget's control, for one field type. */\nexport interface WidgetView {\n /** The element that takes focus; the layer places and turns it in the box. */\n readonly control: HTMLElement\n /**\n * True while the view draws the widget itself. False shows the PDF's own appearance under a\n * clear control.\n */\n readonly drawn: boolean\n /**\n * The view runs the widget's Mouse Up itself when activated (after any change of value), so\n * the layer does not send one on pointer up.\n */\n readonly activates?: boolean\n /** False keeps the control out of the Tab order (a signed signature field). */\n readonly tabbable?: boolean\n sync(state: WidgetState): void\n /** The control was placed in a new frame (zoom or rotation). */\n layout(frame: WidgetFrame): void\n destroy(): void\n}\n\nexport type WidgetRenderer = (ctx: WidgetViewContext) => WidgetView\n\n/** The field types the layer draws controls for. Widgets of other types keep their appearance. */\nconst RENDERERS: Partial<Record<FormFieldType, WidgetRenderer>> = {\n text: (ctx) => createTextWidget(ctx),\n checkbox: createToggleWidget,\n radio: createToggleWidget,\n combo: createChoiceWidget,\n list: createChoiceWidget,\n button: createButtonWidget,\n signature: createSignatureWidget,\n}\n\n/** Whether the layer gives the field a control: its type has one and nothing locks it. */\nexport function hasControl(field: FormField): boolean {\n return !field.locked && RENDERERS[field.type] !== undefined\n}\n\nconst isToggle = (field: FormField) => field.type === 'checkbox' || field.type === 'radio'\n\n/**\n * The appearances PDF.js has for a widget, by the file's appearance states: none for a widget\n * the file hides; a toggle's on and off looks where `/AP /N` holds them; any other widget's own\n * where the file has an `/AP`.\n */\nfunction expectedLooks(\n field: FormField,\n widget: FormWidget\n): ReadonlySet<AppearanceLook> {\n const looks = new Set<AppearanceLook>()\n if (\n widget.hidden ||\n widget.printOnly ||\n widget.rect.width <= 0 ||\n widget.rect.height <= 0\n )\n return looks\n const a = widget.appearance\n if (isToggle(field)) {\n if (a.onAppearance) looks.add('checked')\n if (a.offAppearance) looks.add('unchecked')\n } else if (a.fileAppearance) looks.add('own')\n return looks\n}\n\ninterface Entry {\n field: FormField\n widget: FormWidget\n box: HTMLElement\n view: WidgetView | undefined\n /** The field's value when last synced, to clear a refused commit's mark once it changes. */\n value: FieldValue | undefined\n}\n\n/** A field's accessible name: its tooltip, else the last part of its name. */\nfunction labelOf(field: FormField): string {\n const tip = field.tooltip?.trim()\n if (tip) return tip\n return field.name.split('.').at(-1)?.trim() || FORM_LABELS.unnamed\n}\n\nconst toggle = (el: Element, attr: string, on: boolean) => {\n if (on) el.setAttribute(attr, '')\n else el.removeAttribute(attr)\n}\n\n/** The form fields of one page: a control over each widget of a type the layer fills in. */\nexport function createFormLayer(opts: FormLayerOptions): FormLayer {\n const { host, page, document: doc } = opts\n const form = doc.form\n const ownerDoc = host.ownerDocument\n let transform = opts.transform\n let destroyed = false\n\n const element = ownerDoc.createElement('div')\n element.className = 'ink-form-layer'\n element.dataset.inkFormLayer = ''\n element.dataset.inkFormHighlight = opts.highlight ? 'on' : 'off'\n // Isolated, so the boxes' z-index orders them among themselves only.\n element.style.cssText =\n 'position:absolute;inset:0;pointer-events:none;isolation:isolate;'\n host.append(element)\n\n const fields = form.fields.get()\n const entries: Entry[] = []\n for (const field of fields)\n for (const widget of field.widgets) {\n if (widget.page !== page) continue\n const box = ownerDoc.createElement('div')\n box.className = 'ink-form-widget'\n box.dataset.inkWidget = widget.id\n box.dataset.inkField = field.name\n box.dataset.inkType = field.type\n box.style.cssText = 'position:absolute;pointer-events:none;'\n entries.push({\n field,\n widget,\n box,\n view: undefined,\n value: form.values.get()[field.name],\n })\n }\n // The page's Tab order, worked out once: the boxes go in it, so Tab is the browser's own.\n const order = new Map(\n pageTabOrder(\n entries.map((e) => e.widget),\n form._tabs.get(page),\n doc.pages[page],\n page,\n form._structure.get(page)\n ).map((id, i) => [id, i])\n )\n // The appearances paint in `/Annots` order, as the file stacks its widgets.\n const painted = annotsOrder(entries, (e) => e.widget)\n // The boxes stack in that order too, whatever their Tab order, so where widgets overlap a\n // press goes to the one whose appearance shows on top.\n const stackAt = new Map(painted.map((e, i) => [e, i]))\n /**\n * Stacks the box at its `/Annots` place, or above every other box while it is focused or\n * marked invalid, so no neighbour covers its focus ring or mark.\n */\n const restack = (e: Entry) => {\n const raised =\n e.box.hasAttribute('data-ink-focused') || e.box.hasAttribute('data-ink-invalid')\n e.box.style.zIndex = String((raised ? painted.length : 0) + (stackAt.get(e) ?? 0))\n }\n for (const e of painted) restack(e)\n entries.sort((a, b) => (order.get(a.widget.id) ?? 0) - (order.get(b.widget.id) ?? 0))\n for (const e of entries) element.append(e.box)\n /** Each radio group's entries on the page, in Tab order. */\n const radios = new Map<FormField, Entry[]>()\n for (const e of entries)\n if (e.field.type === 'radio') {\n const group = radios.get(e.field)\n if (group) group.push(e)\n else radios.set(e.field, [e])\n }\n\n // The PDF's own widget appearances: right above the page canvas, under the text layer and\n // the annotations.\n let appearances: WidgetAppearances | undefined\n if (entries.length > 0) {\n appearances = createWidgetAppearances({\n host,\n document: doc,\n page,\n transform,\n widgets: painted.map((e) => ({\n id: e.widget.id,\n rect: e.widget.rect,\n toggle: isToggle(e.field),\n expects: expectedLooks(e.field, e.widget),\n })),\n ...(opts.devicePixelRatio === undefined\n ? {}\n : { devicePixelRatio: opts.devicePixelRatio }),\n ...(opts.onError ? { onError: (error: unknown) => opts.onError?.(error) } : {}),\n ...(opts.onRendered ? { onRendered: () => opts.onRendered?.() } : {}),\n })\n const canvasLayer = host.querySelector(':scope > [data-ink-canvas-layer]')\n if (canvasLayer) canvasLayer.after(appearances.element)\n else host.prepend(appearances.element)\n }\n\n const setInvalid = (e: Entry, invalid: boolean) => {\n toggle(e.box, 'data-ink-invalid', invalid)\n restack(e)\n if (invalid) e.view?.control.setAttribute('aria-invalid', 'true')\n else e.view?.control.removeAttribute('aria-invalid')\n }\n\n const stateOf = (e: Entry): WidgetState => {\n const override = form.widgetState.get()[e.widget.id] ?? {}\n return {\n value: form.values.get()[e.field.name],\n formatted: form.formatted.get()[e.field.name],\n override,\n readOnly: e.field.locked || (override.readOnly ?? e.field.flags.readOnly),\n required: override.required ?? e.field.flags.required,\n }\n }\n\n const hiddenOf = (e: Entry): boolean =>\n form.widgetState.get()[e.widget.id]?.hidden ?? (e.widget.hidden || e.widget.printOnly)\n\n /** Shows the widget's own appearance, unless the layer draws it or it is hidden. */\n const showAppearance = (e: Entry) => {\n if (!appearances) return\n const look =\n e.view?.drawn || hiddenOf(e)\n ? null\n : isToggle(e.field)\n ? e.widget.onState !== undefined &&\n form.values.get()[e.field.name] === e.widget.onState\n ? 'checked'\n : 'unchecked'\n : 'own'\n appearances.show(e.widget.id, look)\n }\n\n const place = (e: Entry) => {\n const r = transform.toCssRect(e.widget.rect)\n const s = e.box.style\n s.left = `${r.left}px`\n s.top = `${r.top}px`\n s.width = `${r.width}px`\n s.height = `${r.height}px`\n const view = e.view\n if (!view) return\n const rotation = normalizeRotation(transform.totalRotation - e.widget.rotation)\n const across = rotation === 90 || rotation === 270\n const width = across ? r.height : r.width\n const height = across ? r.width : r.height\n const c = view.control.style\n c.position = 'absolute'\n c.left = `${(r.width - width) / 2}px`\n c.top = `${(r.height - height) / 2}px`\n c.width = `${width}px`\n c.height = `${height}px`\n c.transform = rotation === 0 ? '' : `rotate(${rotation}deg)`\n view.layout({ width, height, rotation, scale: transform.scale })\n }\n\n const syncEntry = (e: Entry) => {\n const state = stateOf(e)\n // A new value (a commit, a reset, a host's push, a script) clears a refused commit's mark;\n // so does a set or reset of the value it holds (`_onPut`).\n if (!sameValue(state.value, e.value)) {\n e.value = state.value\n setInvalid(e, false)\n }\n e.box.style.display = hiddenOf(e) ? 'none' : ''\n toggle(e.box, 'data-ink-readonly', state.readOnly)\n toggle(e.box, 'data-ink-required', state.required)\n const control = e.view?.control\n if (control) {\n if (state.readOnly) control.setAttribute('aria-readonly', 'true')\n else control.removeAttribute('aria-readonly')\n if (state.required) control.setAttribute('aria-required', 'true')\n else control.removeAttribute('aria-required')\n }\n e.view?.sync(state)\n toggle(e.box, 'data-ink-drawn', e.view?.drawn === true)\n }\n\n /** A radio group's widgets on the page a person can see and pick, in Tab order. */\n const shownOf = (group: readonly Entry[]) => group.filter((g) => g.view && !hiddenOf(g))\n\n /** Numbers each radio group's shown widgets on the page for assistive technology. */\n const numberRadios = () => {\n for (const group of radios.values()) {\n const shown = shownOf(group)\n for (const e of group) {\n const control = e.view?.control\n if (!control) continue\n const at = shown.indexOf(e)\n if (at < 0) {\n control.removeAttribute('aria-posinset')\n control.removeAttribute('aria-setsize')\n } else {\n control.setAttribute('aria-posinset', String(at + 1))\n control.setAttribute('aria-setsize', String(shown.length))\n }\n }\n }\n }\n\n const setActive = () => {\n const active = opts.isActive()\n // A radio group is one Tab stop on the page: its chosen radio, else its first.\n const values = form.values.get()\n const stops = new Set<Entry>()\n for (const group of radios.values()) {\n const shown = shownOf(group)\n const value = values[group[0]!.field.name]\n const stop = shown.find((g) => g.widget.onState === value) ?? shown[0]\n if (stop) stops.add(stop)\n }\n for (const e of entries) {\n if (!e.view) continue\n const stop = e.view.tabbable !== false && (e.field.type !== 'radio' || stops.has(e))\n e.box.style.pointerEvents = active ? 'auto' : 'none'\n e.view.control.tabIndex = active && stop ? 0 : -1\n }\n }\n\n /** The field values, formatted text and widget state the widgets were last synced with. */\n let synced = {\n values: form.values.get(),\n formatted: form.formatted.get(),\n state: form.widgetState.get(),\n }\n\n /** Syncs `list`, then the page's Tab stops and radio numbering, which span widgets. */\n const syncEntries = (list: readonly Entry[]) => {\n for (const e of list) {\n syncEntry(e)\n showAppearance(e)\n }\n numberRadios()\n setActive()\n }\n\n /** Syncs the widgets whose field's value or formatted text, or own state, changed. */\n const syncChanged = () => {\n if (destroyed) return\n const was = synced\n synced = {\n values: form.values.get(),\n formatted: form.formatted.get(),\n state: form.widgetState.get(),\n }\n const now = synced\n const dirty = entries.filter(\n (e) =>\n now.values[e.field.name] !== was.values[e.field.name] ||\n now.formatted[e.field.name] !== was.formatted[e.field.name] ||\n now.state[e.widget.id] !== was.state[e.widget.id]\n )\n if (dirty.length > 0) syncEntries(dirty)\n }\n\n const listeners: (() => void)[] = []\n const listen = <K extends keyof HTMLElementEventMap>(\n el: HTMLElement,\n type: K,\n fn: (ev: HTMLElementEventMap[K]) => void\n ) => {\n el.addEventListener(type, fn)\n listeners.push(() => el.removeEventListener(type, fn))\n }\n\n for (const e of entries) {\n const box = e.box\n const render = e.field.locked ? undefined : RENDERERS[e.field.type]\n if (render) {\n e.view = render({\n document: doc,\n form,\n field: e.field,\n widget: e.widget,\n page,\n box,\n label: labelOf(e.field),\n redraw: () => {\n if (destroyed) return\n toggle(box, 'data-ink-drawn', e.view?.drawn === true)\n showAppearance(e)\n },\n setInvalid: (invalid) => setInvalid(e, invalid),\n siblings: () =>\n entries.flatMap((x) =>\n x.field === e.field &&\n x.view &&\n (x === e || (!hiddenOf(x) && !stateOf(x).readOnly))\n ? [x.view.control]\n : []\n ),\n ...(opts.onSignField ? { onSignField: (req) => opts.onSignField?.(req) } : {}),\n })\n listen(box, 'focusin', () => {\n toggle(box, 'data-ink-focused', true)\n restack(e)\n })\n listen(box, 'focusout', () => {\n toggle(box, 'data-ink-focused', false)\n restack(e)\n })\n if (e.widget.hasScripts) {\n const mouse =\n (name: 'Mouse Enter' | 'Mouse Exit' | 'Mouse Down' | 'Mouse Up') => () => {\n if (opts.isActive()) form._dispatch({ widget: e.widget.id, name })\n }\n listen(box, 'pointerenter', mouse('Mouse Enter'))\n listen(box, 'pointerleave', mouse('Mouse Exit'))\n listen(box, 'pointerdown', mouse('Mouse Down'))\n if (!e.view.activates) listen(box, 'pointerup', mouse('Mouse Up'))\n }\n }\n place(e)\n }\n syncEntries(entries)\n\n const stops = [\n form.values.subscribe(syncChanged),\n form.formatted.subscribe(syncChanged),\n form.widgetState.subscribe(syncChanged),\n // A set or a reset clears a refused commit's mark, even when it puts back the value the\n // field held.\n form._onPut((names) => {\n if (destroyed) return\n const put = new Set(names)\n for (const e of entries) if (put.has(e.field.name)) setInvalid(e, false)\n }),\n form.on('focus', (id) => {\n layer.focusWidget(id)\n }),\n ]\n\n const layer: FormLayer = {\n element,\n get rendered() {\n return appearances?.rendered ?? Promise.resolve()\n },\n update(next) {\n if (destroyed) return\n transform = next\n appearances?.update(next)\n for (const e of entries) place(e)\n },\n focusWidget(id) {\n const e = entries.find((x) => x.widget.id === id)\n if (destroyed || !e?.view || hiddenOf(e)) return false\n e.view.control.focus()\n return ownerDoc.activeElement === e.view.control\n },\n tabStops() {\n if (destroyed) return []\n return entries.flatMap((e) =>\n e.view && !hiddenOf(e) && e.view.control.tabIndex >= 0 ? [e.view.control] : []\n )\n },\n refresh() {\n if (!destroyed) setActive()\n },\n setHighlight(on) {\n element.dataset.inkFormHighlight = on ? 'on' : 'off'\n },\n destroy() {\n if (destroyed) return\n destroyed = true\n stops.forEach((stop) => stop())\n listeners.forEach((stop) => stop())\n for (const e of entries) e.view?.destroy()\n appearances?.destroy()\n element.remove()\n },\n }\n return layer\n}\n","import { createFormLayer, type FormLayer, type SignFieldRequest } from './form-layer'\nimport { 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 { SearchHighlights } from './search/highlights'\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 /** Tints fillable form fields. Default true. */\n formHighlight?: boolean\n /**\n * Whether form fields take input now. Default: always. The engine passes \"the default\n * pointer tool is active\".\n */\n formActive?(): boolean\n /** A signature field asked to be signed. */\n onSignField?(req: SignFieldRequest): void\n /** Plugin layers, mounted above the overlay. The engine passes them for its pages only. */\n layers?: PluginLayers\n /** Search match highlights, mounted below the overlay. */\n highlights?: SearchHighlights\n /**\n * Canvas, text layer and form appearance failures, with the layer that failed (cancellations\n * are not reported).\n */\n onError?(error: unknown, layer: PageLayer): void\n /**\n * A layer finished without error: the canvas or the form appearances painted, or the text\n * layer mounted or applied an update. Pair it with `onError` to tell when a failed layer has\n * recovered.\n */\n onRendered?(layer: PageLayer): void\n}\n\n/**\n * The page layers that can fail and recover: the canvas, the text layer and the form layer's\n * canvas of widget appearances.\n */\nexport type PageLayer = 'canvas' | 'text' | 'form'\n\nexport interface PageMount {\n readonly renderer: PageRenderer\n readonly textLayer: TextLayerHandle\n readonly overlay: Overlay\n /** The page's form fields; undefined when the document has none. */\n readonly form: FormLayer | undefined\n update(transform: PageTransform): void\n destroy(): void\n}\n\n/**\n * Canvas, text layer, form layer, annotation overlay and any plugin layers for one page, stacked\n * in that 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 marks = opts.highlights?.mount(page, host, transform)\n // The fields sit under the annotations: a press on an annotation's shape is the\n // annotation's (to select or delete a signature that fills a field), and a press anywhere\n // else in a field's box is the field's.\n const form =\n document.form.fields.get().length > 0\n ? createFormLayer({\n host,\n page,\n transform,\n document,\n highlight: opts.formHighlight ?? true,\n isActive: () => opts.formActive?.() ?? true,\n ...(opts.onSignField\n ? { onSignField: (req: SignFieldRequest) => opts.onSignField?.(req) }\n : {}),\n ...(opts.devicePixelRatio === undefined\n ? {}\n : { devicePixelRatio: opts.devicePixelRatio }),\n ...callbacks('form'),\n })\n : undefined\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 form,\n update(next) {\n renderer.update(next)\n textLayer.update(next)\n overlay.update(next)\n form?.update(next)\n layers?.update(next)\n marks?.update(next)\n },\n destroy() {\n layers?.destroy()\n form?.destroy()\n overlay.destroy()\n marks?.destroy()\n textLayer.destroy()\n renderer.destroy()\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","// 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 * Search match highlights. Each mounted page gets one layer, `div.ink-search-layer`, inserted\n * before the annotation overlay so annotations and plugin marks draw over it, with one\n * `div[data-search-hit]` per quad of every hit on that page (`data-current` on the current\n * hit's). It is `pointer-events: none`: presses go to the overlay and the tools underneath.\n *\n * A page redraws when it mounts, when its transform changes, and when the hits on it or the\n * current hit change; a scan that finds hits on other pages leaves it alone.\n */\nimport type { SearchController } from './controller'\nimport type { Quad } from '../../model/geometry'\nimport type { SearchHit } from '../../model/search'\nimport type { PageLayers } from '../plugins/layer'\nimport type { PageTransform } from '../transform'\n\n/** The highlights of one viewer's pages; see `createSearchHighlights`. */\nexport interface SearchHighlights {\n mount(page: number, host: HTMLElement, transform: PageTransform): PageLayers\n /** Stops following the controller. Pages still mounted keep their highlights until they unmount. */\n destroy(): void\n}\n\ninterface MountedPage {\n el: HTMLElement\n transform: PageTransform\n /** What the layer shows now, to skip a redraw when nothing on this page changed. */\n hits: readonly SearchHit[]\n current: SearchHit | undefined\n}\n\nconst NO_HITS: readonly SearchHit[] = []\n\n/** One box over the quad: its CSS bounding box, clipped to the quad when it is not upright. */\nfunction hitBox(doc: Document, t: PageTransform, quad: Quad): HTMLElement {\n const { p1, p2, p3, p4 } = t.toCssQuad(quad)\n const xs = [p1.x, p2.x, p3.x, p4.x]\n const ys = [p1.y, p2.y, p3.y, p4.y]\n const left = Math.min(...xs)\n const top = Math.min(...ys)\n const width = Math.max(...xs) - left\n const height = Math.max(...ys) - top\n const el = doc.createElement('div')\n el.dataset.searchHit = ''\n let css = `position:absolute;left:${left}px;top:${top}px;width:${width}px;height:${height}px;`\n const upright =\n (Math.abs(p1.y - p2.y) < 0.01 && Math.abs(p3.y - p4.y) < 0.01) ||\n (Math.abs(p1.x - p2.x) < 0.01 && Math.abs(p3.x - p4.x) < 0.01)\n if (!upright && width > 0 && height > 0) {\n const pt = (p: { x: number; y: number }) =>\n `${(((p.x - left) / width) * 100).toFixed(3)}% ${(((p.y - top) / height) * 100).toFixed(3)}%`\n css += `clip-path:polygon(${[p1, p2, p4, p3].map(pt).join(',')});`\n }\n el.style.cssText = css\n return el\n}\n\nexport function createSearchHighlights(\n search: Pick<SearchController, 'state'>\n): SearchHighlights {\n const pages = new Map<number, MountedPage>()\n\n const sameHits = (a: readonly SearchHit[], b: readonly SearchHit[]): boolean =>\n a.length === b.length && a.every((hit, i) => hit === b[i])\n\n const draw = (page: MountedPage, force: boolean, hits: readonly SearchHit[]) => {\n const { current: index, hits: all } = search.state.get()\n const current = all[index]\n const shown = current && hits.includes(current) ? current : undefined\n if (!force && sameHits(page.hits, hits) && page.current === shown) return\n page.hits = hits\n page.current = shown\n const doc = page.el.ownerDocument\n page.el.replaceChildren(\n ...hits.flatMap((hit) =>\n hit.quads.map((quad) => {\n const box = hitBox(doc, page.transform, quad)\n if (hit === shown) box.dataset.current = ''\n return box\n })\n )\n )\n }\n\n /** The hits on `page`: a run of the state's hits, which are in `(page, start)` order. */\n const hitsOn = (all: readonly SearchHit[], page: number): readonly SearchHit[] => {\n const first = (p: number) => {\n let low = 0\n let high = all.length\n while (low < high) {\n const mid = (low + high) >>> 1\n if ((all[mid] as SearchHit).page < p) low = mid + 1\n else high = mid\n }\n return low\n }\n const from = first(page)\n const to = first(page + 1)\n return to > from ? all.slice(from, to) : NO_HITS\n }\n\n const stop = search.state.subscribe(({ hits }) => {\n for (const [index, page] of pages) draw(page, false, hitsOn(hits, index))\n })\n\n return {\n mount(index, host, transform) {\n const el = host.ownerDocument.createElement('div')\n el.className = 'ink-search-layer'\n el.dataset.inkSearchLayer = ''\n el.setAttribute('aria-hidden', 'true')\n el.style.cssText = 'position:absolute;inset:0;pointer-events:none;'\n const overlay = host.querySelector(':scope > .ink-overlay')\n host.insertBefore(el, overlay)\n const page: MountedPage = { el, transform, hits: NO_HITS, current: undefined }\n pages.set(index, page)\n draw(page, true, hitsOn(search.state.get().hits, index))\n return {\n update(next) {\n page.transform = next\n draw(page, true, page.hits)\n },\n destroy() {\n if (pages.get(index) === page) pages.delete(index)\n el.remove()\n },\n }\n },\n destroy: stop,\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 { hasControl, type SignFieldRequest } from './form-layer'\nimport { tabOrder } from './form-order'\nimport { createPageMount, type PageLayer, type PageMount } from './page-mount'\nimport { createPluginLayers } from './plugins/layer'\nimport { createSearchHighlights } from './search/highlights'\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 { SearchController } from './search/controller'\nimport type { PageTransform, ViewRotation } from './transform'\nimport type { ToolStyle } from '../model/annotations/tool-style'\nimport type { InkDocument } from '../model/document'\nimport type { FormAction, FormWidget } from '../model/form/types'\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 /**\n * Tints fillable form fields, as other PDF viewers do. Default true. False sets\n * `data-ink-form-highlight=\"off\"` on the container and each page's form layer.\n */\n formHighlight?: boolean\n /**\n * An empty signature field was activated: sign it, for instance by offering the saved\n * signatures anchored to `req.anchor` and calling `signField` with the one picked.\n * `createViewer` opens its signature menu here. Without it the field does nothing.\n */\n onSignField?(req: SignFieldRequest): void\n /**\n * The form asked the host to submit, open a link, send mail, print or prompt. Inkbar itself\n * never does any of these.\n */\n onFormAction?(action: FormAction): void\n /** A form script called `app.alert`: show `message` (text, not markup) without blocking. */\n onFormAlert?(message: string): void\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 /**\n * The viewer's search controller. Its matches are highlighted on every page the engine\n * mounts, below the annotations.\n */\n search?: SearchController\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 /**\n * Turns the form field tint on or off for the mounted pages and those mounted later, in\n * place: no page renders again and no field loses focus or typed text.\n */\n setFormHighlight(on: boolean): void\n destroy(): void\n}\n\nconst FOCUSABLE = [\n 'a[href]',\n 'area[href]',\n 'button',\n 'input',\n 'select',\n 'textarea',\n 'iframe',\n 'summary',\n '[tabindex]',\n '[contenteditable]',\n].join(', ')\n\n/** Whether `c` takes focus from Tab: enabled, rendered, visible and not inert. */\nfunction tabbable(c: HTMLElement): boolean {\n if (c.matches(':disabled') || c.closest('[inert]') || c.getClientRects().length === 0)\n return false\n return c.ownerDocument.defaultView?.getComputedStyle(c).visibility === 'visible'\n}\n\n/**\n * The element the browser's Tab moves to from `from` (`back`: Shift+Tab), skipping `from`'s\n * own descendants (`from` may be the viewer). Forward, that is the next element in document\n * order with tabindex 0: from a tabindex-0 control the browser never moves to a positive one.\n * Back, it is the previous tabindex-0 element, else the last of the positive tabindex ones,\n * which the browser visits first. Inside a shadow root it looks only within that root.\n */\nfunction nextFocusable(from: Element, back: boolean): HTMLElement | undefined {\n // The tree the viewer lives in: a shadow root that hosts it, else the document.\n const root = from.getRootNode()\n const scope: ParentNode = root instanceof ShadowRoot ? root : from.ownerDocument\n const all = [...scope.querySelectorAll<HTMLElement>(FOCUSABLE)].filter(\n (c) => c.tabIndex >= 0 && !from.contains(c) && tabbable(c)\n )\n const after = (c: Element) =>\n (from.compareDocumentPosition(c) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0\n const zero = all.filter((c) => c.tabIndex === 0)\n if (!back) return zero.find(after)\n const before = zero.filter((c) => !after(c)).at(-1)\n if (before) return before\n // Positive tabindex elements go first, by tabindex and then document order.\n return all\n .filter((c) => c.tabIndex > 0)\n .sort((a, b) => a.tabIndex - b.tabIndex)\n .at(-1)\n}\n\n/** The tools under which form fields take input: the pointer tools, which make nothing. */\nconst FORM_TOOLS: ReadonlySet<ToolId> = new Set<ToolId>(['select-text', 'select'])\n\nexport function mountViewer(opts: MountViewerOptions): ViewerEngine {\n const { container: el, document: doc } = opts\n let highlight = opts.formHighlight ?? true\n if (!highlight) el.dataset.inkFormHighlight = 'off'\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 stopFormTools: () => void = () => undefined\n let stopPageEvents: () => 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 /** Match highlights follow the controller for the engine's life, across rebuilds. */\n const highlights = opts.search && createSearchHighlights(opts.search)\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 formHighlight: highlight,\n // While a build mounts its pages, `tools` is unset or the old controller; the build\n // refreshes the fields once its controller exists.\n formActive: formsActive,\n onSignField: (req) => opts.onSignField?.(req),\n ...(layers ? { layers } : {}),\n ...(highlights ? { highlights } : {}),\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 if (tabWait?.page === page) tabWait.retry()\n }\n\n /** Whether form fields take input under the active tool. */\n const formsActive = (): boolean => {\n const id = (tools as ToolController | undefined)?.active.get()\n return id !== undefined && FORM_TOOLS.has(id)\n }\n\n /**\n * The first widget (`last`: the last) in Tab order on each page with a control to stop at,\n * by page index.\n */\n function tabEdges(last: boolean): Map<number, FormWidget> {\n const fields = doc.form.fields.get()\n const byId = new Map(\n fields.flatMap((f) =>\n hasControl(f) ? f.widgets.map((w) => [w.id, w] as const) : []\n )\n )\n const state = doc.form.widgetState.get()\n const edges = new Map<number, FormWidget>()\n for (const id of tabOrder(fields, doc.form._tabs, doc.pages, doc.form._structure)) {\n const w = byId.get(id)\n if (!w || (state[id]?.hidden ?? (w.hidden || w.printOnly))) continue\n if (last || !edges.has(w.page)) edges.set(w.page, w)\n }\n return edges\n }\n\n /** The page a Tab waits for: its stops were not mounted when the view scrolled to it. */\n let tabWait: { page: number; retry: () => void; cancel: () => void } | undefined\n\n /** The first stop of `page` (`back`: its last), once its form layer is mounted. */\n const edgeStop = (page: number, back: boolean): HTMLElement | undefined => {\n const stops = pages.get(page)?.form?.tabStops() ?? []\n return back ? stops.at(-1) : stops[0]\n }\n\n /**\n * Focuses `page`'s edge stop when the page mounts, or on the next animation frame,\n * whichever comes first. Tries once; when the page still has no stop, Tab goes where the\n * browser would have taken it from `from` (`nextFocusable`), or past the viewer when `from`\n * has unmounted. With nowhere to go, focus returns to the document.\n */\n function awaitTabStop(page: number, back: boolean, from: Element): void {\n tabWait?.cancel()\n const frame = requestAnimationFrame(() => wait.retry())\n const wait = {\n page,\n retry: () => {\n wait.cancel()\n if (destroyed) return\n const stop = edgeStop(page, back)\n if (stop) {\n stop.focus()\n return\n }\n const next = nextFocusable(from.isConnected ? from : el, back)\n if (next) next.focus()\n // Nothing to move to: give focus back to the document, as the browser would leave the\n // page, so the next Tab starts over from there.\n else if (from instanceof HTMLElement && from.isConnected) from.blur()\n else (el.ownerDocument.activeElement as HTMLElement | null)?.blur()\n },\n cancel: () => {\n cancelAnimationFrame(frame)\n if (tabWait === wait) tabWait = undefined\n },\n }\n tabWait = wait\n }\n\n /**\n * Tab on a page's last field stop (Shift+Tab on its first) goes to the first (last) stop of\n * the next (previous) page that has fields, mounting it and scrolling it into view. A page\n * that has not mounted once the view scrolls to it gets one more try, when it mounts or on the\n * next frame; after that, focus moves on as the browser's Tab would. Past the last page's\n * fields, Tab leaves the viewer as usual.\n */\n function onFormTab(e: KeyboardEvent): void {\n if (e.key !== 'Tab' || e.altKey || e.ctrlKey || e.metaKey || e.defaultPrevented)\n return\n const target = e.target\n if (!(target instanceof Element) || !target.closest('[data-ink-form-layer]')) return\n if (!formsActive()) return\n const back = e.shiftKey\n const from = [...pages].find(([, m]) => m.form?.element.contains(target))\n if (!from) return\n const [page, mount] = from\n if (mount.form?.tabStops().at(back ? 0 : -1) !== target) return\n const edges = [...tabEdges(back)]\n .filter(([p]) => (back ? p < page : p > page))\n .sort(([a], [b]) => (back ? b - a : a - b))\n for (const [next, widget] of edges) {\n viewport.scrollToRect(next, widget.rect)\n const to = edgeStop(next, back)\n if (to) {\n e.preventDefault()\n to.focus()\n return\n }\n if (!pages.get(next)?.form) {\n e.preventDefault()\n awaitTabStop(next, back, target)\n return\n }\n }\n }\n el.addEventListener('keydown', onFormTab)\n\n // What the form asks of the host, and a field's go-to action, which the viewer runs itself.\n const stopForm = [\n doc.form.on('action', (a) => opts.onFormAction?.(a)),\n doc.form.on('alert', (message) => opts.onFormAlert?.(message)),\n doc.form.on('goto', (page) => {\n if (!destroyed && page >= 0 && page < doc.pages.length) viewport.scrollToPage(page)\n }),\n ]\n\n /**\n * The page whose open scripts ran last, and has not closed since. Page open and close events\n * follow the viewport's current page, as Acrobat runs them for the page a person is on, not for\n * the pages mounted around it; a rebuild that keeps the page sends neither.\n */\n let openPage: number | undefined\n function openPageEvents(next: number | undefined): void {\n if (next === openPage) return\n if (openPage !== undefined) void doc.form._pageEvent(openPage, 'PageClose')\n openPage = next\n if (next !== undefined) void doc.form._pageEvent(next, 'PageOpen')\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 const refreshForms = () => {\n for (const mount of pages.values()) mount.form?.refresh()\n }\n stopFormTools = tc.active.subscribe(refreshForms)\n refreshForms()\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 openPageEvents(vp.currentPage.get())\n stopPageEvents = vp.currentPage.subscribe(openPageEvents)\n opts.onBuild?.(vp, tc)\n }\n\n function teardown(): void {\n stopKeys()\n stopActive()\n stopFormTools()\n stopPageEvents()\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 setFormHighlight(on) {\n if (destroyed || on === highlight) return\n highlight = on\n if (on) delete el.dataset.inkFormHighlight\n else el.dataset.inkFormHighlight = 'off'\n for (const mount of pages.values()) mount.form?.setHighlight(on)\n },\n destroy() {\n if (destroyed) return\n destroyed = true\n teardown()\n openPageEvents(undefined)\n layers?.destroy()\n highlights?.destroy()\n stopRedecorate?.()\n el.removeEventListener('keydown', onFormTab)\n tabWait?.cancel()\n for (const stop of stopForm) stop()\n if (!highlight) delete el.dataset.inkFormHighlight\n },\n }\n}\n","/*\n * The viewer's search state, shared by the find bar, the bindings and plugins. It owns the\n * query, the scan and the hits; the bar is only a view of it. Scans go through `doc.search`, so\n * the bar and a plugin running the same query see the same hits.\n */\nimport { readonly, writable, type Readable } from '../../model/readable'\nimport { isBlankQuery } from '../../model/search-text'\n\nimport type { InkDocument } from '../../model/document'\nimport type { SearchHit } from '../../model/search'\nimport type { Viewport } from '../viewport'\n\nexport interface SearchState {\n open: boolean\n query: string\n matchCase: boolean\n /** Found so far, in `(page, start)` order. */\n hits: readonly SearchHit[]\n /** Index into `hits`, -1 when none. */\n current: number\n scanning: boolean\n}\n\nexport interface ViewerSearch {\n readonly state: Readable<SearchState>\n /** Shows the bar, optionally with a query. */\n open(query?: string): void\n setQuery(query: string): void\n setMatchCase(on: boolean): void\n next(): void\n previous(): void\n /** Hides the bar and clears the hits; the query and match case are kept. */\n close(): void\n}\n\nexport interface SearchController extends ViewerSearch {\n /** @internal Registers a mounted find bar; returns the function that unregisters it. */\n attachBar(): () => void\n /** Whether any find bar is mounted for this viewer. */\n readonly barAttached: Readable<boolean>\n destroy(): void\n}\n\nexport interface SearchControllerOptions {\n document: Readable<InkDocument | null>\n /** The viewer's viewport, read on each call. */\n viewport: () => Viewport | null | undefined\n /** Default 150. */\n debounceMs?: number\n}\n\nfunction compare(a: SearchHit, b: SearchHit): number {\n return a.page - b.page || a.start - b.start\n}\n\n/** Where `hit` goes in `hits`, which is sorted by `(page, start)`. */\nfunction insertionIndex(hits: readonly SearchHit[], hit: SearchHit): number {\n let low = 0\n let high = hits.length\n while (low < high) {\n const mid = (low + high) >>> 1\n if (compare(hits[mid] as SearchHit, hit) <= 0) low = mid + 1\n else high = mid\n }\n return low\n}\n\nexport function createSearchController(opts: SearchControllerOptions): SearchController {\n const debounceMs = opts.debounceMs ?? 150\n const state = writable<SearchState>({\n open: false,\n query: '',\n matchCase: false,\n hits: [],\n current: -1,\n scanning: false,\n })\n const bars = writable(0)\n const patch = (changes: Partial<SearchState>): void =>\n state.update((s) => ({ ...s, ...changes }))\n\n let timer: ReturnType<typeof setTimeout> | undefined\n let scan: AbortController | undefined\n /** The current hit and its index in `hits`, kept in step as pages of hits arrive. */\n let currentHit: SearchHit | undefined\n let currentIndex = -1\n /** Hits of one page not yet in the state, in page order, and the task that adds them. */\n let pending: SearchHit[] = []\n let flushTimer: ReturnType<typeof setTimeout> | undefined\n let destroyed = false\n\n function scrollTo(hit: SearchHit): void {\n // The viewport leaves a fully visible rect where it is and centres one that is not.\n opts.viewport()?.scrollToRect(hit.page, hit.rect)\n }\n\n /** Stops the pending debounce and the running scan, and empties the hits. */\n function reset(): void {\n clearTimeout(timer)\n timer = undefined\n scan?.abort()\n scan = undefined\n currentHit = undefined\n currentIndex = -1\n pending = []\n clearTimeout(flushTimer)\n flushTimer = undefined\n patch({ hits: [], current: -1, scanning: false })\n }\n\n /**\n * Adds the pending page of hits to the state in one change. A page's hits sit together in\n * `(page, start)` order, so they go in with one splice, and `current` moves by their count\n * when they land before it. The first hit becomes current and is scrolled to, unless\n * `scroll` is false: a step flushes first and scrolls to where it lands instead.\n */\n function flush(scroll = true): void {\n clearTimeout(flushTimer)\n flushTimer = undefined\n if (pending.length === 0) return\n const batch = pending\n pending = []\n const first = batch[0] as SearchHit\n const { hits } = state.get()\n const at = insertionIndex(hits, first)\n const next = hits.slice(0, at).concat(batch, hits.slice(at))\n if (!currentHit) {\n currentHit = first\n currentIndex = at\n if (scroll) scrollTo(first)\n } else if (at <= currentIndex) currentIndex += batch.length\n patch({ hits: next, current: currentIndex })\n }\n\n /**\n * Holds `hit` until its page is done: the next page's first hit, the end of the scan, or the\n * next task, since a page's hits arrive together and the scan yields between pages.\n */\n function accept(hit: SearchHit): void {\n if (pending.length > 0 && pending[0]!.page !== hit.page) flush()\n pending.push(hit)\n flushTimer ??= setTimeout(() => flush())\n }\n\n async function run(doc: InkDocument, controller: AbortController): Promise<void> {\n const { query, matchCase } = state.get()\n const count = doc.pages.length\n const from = Math.min(\n Math.max(opts.viewport()?.currentPage.get() ?? 0, 0),\n Math.max(count - 1, 0)\n )\n const pages = [\n ...Array.from({ length: count - from }, (_, i) => from + i),\n ...Array.from({ length: from }, (_, i) => i),\n ]\n try {\n for await (const hit of doc.search(query, {\n matchCase,\n pages,\n signal: controller.signal,\n })) {\n if (controller.signal.aborted) return\n accept(hit)\n }\n } catch (error) {\n // An abort is our own doing; anything else is a real failure worth reporting.\n if (!controller.signal.aborted) {\n console.error(error)\n if (scan === controller) scan = undefined\n flush()\n patch({ scanning: false })\n return\n }\n }\n if (scan === controller) {\n scan = undefined\n flush()\n patch({ scanning: false })\n }\n }\n\n function start(): void {\n timer = undefined\n scan?.abort()\n scan = undefined\n const doc = opts.document.get()\n if (!doc || isBlankQuery(state.get().query)) {\n patch({ scanning: false })\n return\n }\n const controller = new AbortController()\n scan = controller\n patch({ scanning: true })\n void run(doc, controller)\n }\n\n /** Empties the hits now and scans again, after the debounce when `delay` is set. */\n function restart(delay: boolean): void {\n reset()\n if (isBlankQuery(state.get().query)) return\n patch({ scanning: true })\n if (delay) timer = setTimeout(start, debounceMs)\n else start()\n }\n\n function step(by: 1 | -1): void {\n const shown = currentHit !== undefined\n flush(false)\n const { hits, current } = state.get()\n if (hits.length === 0) return\n // With nothing current yet, a step lands on the hit the waiting page made current, the first\n // at or after the page in view, rather than moving past it unseen.\n const index = shown ? (current + by + hits.length) % hits.length : current\n const hit = hits[index] as SearchHit\n currentHit = hit\n currentIndex = index\n patch({ current: index })\n scrollTo(hit)\n }\n\n const stopDocument = opts.document.subscribe(() => {\n if (destroyed) return\n reset()\n if (state.get().open) restart(false)\n })\n\n function setQuery(query: string): void {\n patch({ query })\n restart(true)\n }\n\n function open(query?: string): void {\n const wasOpen = state.get().open\n patch({ open: true })\n if (query !== undefined) setQuery(query)\n else if (!wasOpen && !isBlankQuery(state.get().query)) restart(false)\n }\n\n return {\n state: readonly(state),\n open,\n setQuery,\n setMatchCase(on) {\n patch({ matchCase: on })\n restart(false)\n },\n next: () => step(1),\n previous: () => step(-1),\n close() {\n reset()\n patch({ open: false })\n },\n attachBar() {\n let attached = true\n bars.update((n) => n + 1)\n return () => {\n if (!attached) return\n attached = false\n bars.update((n) => n - 1)\n }\n },\n barAttached: {\n get: () => bars.get() > 0,\n subscribe(fn) {\n let last = bars.get() > 0\n return bars.subscribe((n) => {\n if (n > 0 === last) return\n last = n > 0\n fn(last)\n })\n },\n },\n destroy() {\n destroyed = true\n stopDocument()\n reset()\n },\n }\n}\n\n/**\n * The actions and state of `controller` without the bar registration: what callers of a viewer\n * or a plugin get.\n *\n * @internal Shared with the framework bindings.\n */\nexport function viewerSearchOf(controller: SearchController): ViewerSearch {\n return {\n state: controller.state,\n open: (query) => controller.open(query),\n setQuery: (query) => controller.setQuery(query),\n setMatchCase: (on) => controller.setMatchCase(on),\n next: () => controller.next(),\n previous: () => controller.previous(),\n close: () => controller.close(),\n }\n}\n","/*\n * Ctrl/Cmd+F for a viewer's root, and the page selection it takes as the query. Shared by\n * createViewer and the framework bindings.\n */\nimport type { SearchController } from './controller'\n\n/** Longest page selection that becomes the query. */\nconst MAX_SELECTION = 200\n\nconst FIELD = '[data-ink-find-bar] input'\n\n/**\n * The text selected on the page inside `root`, on one line and trimmed; '' when there is none,\n * when it is not in `root`, when it is in the find bar, or when it is too long to be a query.\n */\nexport function pageSelectionText(root: HTMLElement): string {\n const sel = root.ownerDocument.defaultView?.getSelection()\n if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return ''\n const { anchorNode, focusNode } = sel\n if (\n !anchorNode ||\n !focusNode ||\n !root.contains(anchorNode) ||\n !root.contains(focusNode)\n )\n return ''\n const bar = (node: Node): boolean =>\n (node instanceof Element ? node : node.parentElement)?.closest(\n '[data-ink-find-bar]'\n ) != null\n if (bar(anchorNode) || bar(focusNode)) return ''\n const text = sel.toString().replace(/\\s+/g, ' ').trim()\n return text.length > MAX_SELECTION ? '' : text\n}\n\n/**\n * F by its letter, or by its place on a layout without Latin letters (Cyrillic, Greek), where\n * `key` is that layout's letter. A Latin layout with another letter there keeps that letter.\n */\nfunction isFindKey(e: KeyboardEvent): boolean {\n if (e.key.toLowerCase() === 'f') return true\n return e.code === 'KeyF' && !/^[a-z]$/i.test(e.key)\n}\n\n/**\n * Ctrl/Cmd+F on a viewer's root. Call it from a `keydown` listener on that root (it reads\n * `currentTarget`). Takes the key only when a find bar is mounted for this viewer and the event\n * comes from inside the root; otherwise the browser keeps it. Opens the search with the page selection as\n * the query, if there is one, and focuses and selects the field. Returns whether it took the key.\n *\n * @internal Shared with the framework bindings.\n */\nexport function handleFindKey(\n e: KeyboardEvent,\n controller: SearchController,\n selection: () => string\n): boolean {\n if (!(e.ctrlKey || e.metaKey) || e.altKey || e.shiftKey || !isFindKey(e)) return false\n if (!controller.barAttached.get()) return false\n const root = e.currentTarget\n if (!(root instanceof HTMLElement)) return false\n if (!(e.target instanceof Node) || !root.contains(e.target)) return false\n e.preventDefault()\n const text = selection()\n controller.open(text === '' ? undefined : text)\n const field = root.querySelector<HTMLInputElement>(FIELD)\n field?.focus()\n field?.select()\n return true\n}\n","/*\n * The message box a form script's `app.alert` shows in createViewer, with the markup and data\n * attributes the bindings' `InkFormAlert` uses, so `@inkbar/theme` styles both. It does not\n * block: the page behind stays usable, and the script has already carried on. Showing it moves\n * focus to OK; OK or Escape closes it, and focus goes back where it was. The message is the\n * script's text, set as text only.\n */\nimport { FORM_LABELS } from '../ui'\n\nimport { h } from './dom'\n\nexport interface FormAlert {\n /** Shows `message`, replacing the one showing, if any. */\n show(message: string): void\n /** Closes it, if open, returning focus. */\n close(): void\n destroy(): void\n}\n\nlet alerts = 0\n\n/**\n * A non-modal alert for the viewer under `root` (`[data-ink-root]`), placed on `<body>`.\n * Escape closes it while focus is in it; elsewhere Escape stays the viewer's.\n */\nexport function createFormAlert(root: HTMLElement): FormAlert {\n const uid = `ink-form-alert-${++alerts}`\n const title = h(\n 'h2',\n { id: `${uid}-title`, class: 'ink-dialog-title' },\n FORM_LABELS.alert\n )\n const message = h('p', {\n id: `${uid}-message`,\n class: 'ink-form-alert-message',\n 'data-ink-form-alert-message': '',\n })\n const ok = h(\n 'button',\n {\n type: 'button',\n class: 'ink-button',\n 'data-variant': 'primary',\n 'data-ink-form-alert-ok': '',\n },\n FORM_LABELS.ok\n )\n const panel = h(\n 'div',\n {\n role: 'alertdialog',\n 'aria-labelledby': `${uid}-title`,\n 'aria-describedby': `${uid}-message`,\n class: 'ink-dialog ink-form-alert',\n 'data-ink-form-alert': '',\n 'data-state': 'open',\n tabindex: '-1',\n },\n title,\n message,\n h('div', { class: 'ink-dialog-actions' }, ok)\n )\n /** Where focus was when the alert opened. */\n let returnTo: HTMLElement | null = null\n let open = false\n\n const onKey = (e: KeyboardEvent): void => {\n if (e.key !== 'Escape' || e.defaultPrevented) return\n // Escape elsewhere is the viewer's (clearing a selection, ending a tool).\n const target = e.target\n if (!(target instanceof Node) || !panel.contains(target)) return\n e.preventDefault()\n e.stopPropagation()\n close()\n }\n\n function close(): void {\n if (!open) return\n open = false\n document.removeEventListener('keydown', onKey, true)\n const hadFocus = panel.contains(document.activeElement)\n panel.remove()\n // Focus that moved elsewhere while the alert showed stays there.\n if (!hadFocus) return\n const back =\n returnTo?.isConnected === true\n ? returnTo\n : root.querySelector<HTMLElement>('[data-ink-scroll]')\n back?.focus({ preventScroll: true })\n }\n\n ok.addEventListener('click', () => close())\n\n return {\n show(text) {\n message.textContent = text\n if (!open) {\n open = true\n const active = document.activeElement\n returnTo =\n active instanceof HTMLElement && active !== document.body ? active : null\n document.addEventListener('keydown', onKey, true)\n document.body.append(panel)\n }\n ok.focus({ preventScroll: true })\n },\n close,\n destroy() {\n close()\n panel.remove()\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 /**\n * The menu opens only through `open()`; the trigger's own clicks and keys stay its own. For a\n * menu a control opens as one of several things it does, such as a signature field's.\n */\n manual?: boolean\n /** The menu closed, for any reason; the trigger's `aria-expanded` and `data-state` are set. */\n onClose?(): void\n /**\n * Builds the items on first call and updates them in place after; called on open and\n * `refresh`.\n */\n render(menu: HTMLElement): void\n}\n\nexport interface Menu {\n readonly isOpen: boolean\n /** Opens the menu with its initial item focused, as a click on the trigger does. */\n open(): void\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 opts.onClose?.()\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 if (!opts.manual) {\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\n return {\n get isOpen() {\n return panel !== null\n },\n open: () => open('initial'),\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","// 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'\nimport type { SignatureTemplate } from '../../model/signatures'\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 /**\n * Opens the dialog. On close, focus goes to `returnFocus`, else to what had it before. Save\n * stores the template and selects it for the `signature` tool, or, with `onSave`, hands it\n * to `onSave` instead (to sign a form field with it).\n */\n open(opts?: {\n returnFocus?: HTMLElement | null\n onSave?: (t: SignatureTemplate) => void\n }): 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(\n o: { returnFocus?: HTMLElement | null; onSave?: (t: SignatureTemplate) => void } = {}\n ): 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 if (o.onSave) {\n close()\n o.onSave(t)\n return\n }\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 *\n * The same menu signs a signature field (`createSignFieldMenu`): anchored to the field's box,\n * picking a signature, or creating one, signs the field with it.\n */\nimport { ChevronDown, Plus, Signature, Trash2 } from '@inkbar/icons'\n\nimport { isInkError, type InkError } from '../../model/errors'\nimport { signField } from '../../model/form/sign'\nimport { signaturePreview } from '../signature-pad'\nimport { SIGNATURE_LABELS, signatureMenuModel, type SignatureMenuModel } from '../ui'\n\nimport { createIcon } from './controls'\nimport { h } from './dom'\nimport { createMenu, type Menu } 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 { SignFieldRequest } from '../form-layer'\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\ninterface SignatureMenuContent {\n /** Builds the panel on first call and updates it in place after. */\n paint(panel: HTMLElement): void\n}\n\n/**\n * The saved signatures, each with a remove button, then \"Create signature\": the panel both\n * signature menus show. `choose` and `create` are the menu's own.\n */\nfunction signatureMenuContent(opts: {\n library: () => SignatureLibrary | null\n model: () => SignatureMenuModel\n choose: (t: SignatureTemplate) => void\n create: () => void\n isOpen: () => boolean\n}): SignatureMenuContent {\n const { library, model } = opts\n /** The ids the open panel shows, to rebuild it only when the list changes. */\n let shown = ''\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()\n ?.remove(id)\n .then(\n () => {\n if (!opts.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): void {\n const m = model()\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', () => opts.choose(item.template))\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', () => opts.create())\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 return { paint }\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\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 const content = signatureMenuContent({\n library: () => library,\n model,\n choose: (t) => {\n tools?.set('signature', { templateId: t.id })\n menu.close(true)\n },\n create: () => {\n menu.close()\n dialog.open({ returnFocus: main })\n },\n isOpen: () => menu.isOpen,\n })\n const menu = createMenu(trigger, {\n label: SIGNATURE_LABELS.menu,\n anchor: root,\n attrs: { 'data-ink-menu': 'signature' },\n render: (panel) => content.paint(panel),\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\n/** Options for `createSignFieldMenu`. */\nexport interface SignFieldMenuOptions extends SignatureDialogOptions {\n /** Signing failed: the field was read-only by then, or already signed. */\n onError?(error: InkError): void\n}\n\n/** The signature menu for signature fields; see `createSignFieldMenu`. */\nexport interface SignFieldMenu {\n /** Opens the menu anchored to the field's box. Another field's open menu closes. */\n open(req: SignFieldRequest): void\n close(): void\n destroy(): void\n}\n\n/**\n * The signature menu, opened on a signature field (the engine's `onSignField`). It lists the\n * saved signatures and \"Create signature\", as the toolbar's menu does. Picking one signs the\n * field with it (`signField`); a new one from the dialog signs the field once saved. Focus\n * returns to the field.\n */\nexport function createSignFieldMenu(\n viewer: Viewer,\n opts: SignFieldMenuOptions = {}\n): SignFieldMenu {\n const dialog = createSignatureDialog(viewer, opts)\n let menu: Menu | null = null\n let destroyed = false\n\n const library = (): SignatureLibrary | null => viewer.engine.get()?.signatures ?? null\n const close = (): void => {\n menu?.close()\n menu = null\n }\n\n /** Signs the request's field with `t`, reporting a refusal. */\n const sign = (req: SignFieldRequest, t: SignatureTemplate): void => {\n const doc = viewer.document.get()\n if (!doc) return\n try {\n signField(doc, req.field, req.widget, t)\n } catch (e) {\n if (!isInkError(e)) throw e\n opts.onError?.(e)\n }\n }\n\n let stopLibrary: () => void = () => undefined\n const followLibrary = (engine: ViewerEngine | null): void => {\n stopLibrary()\n const lib = engine?.signatures\n const stops = lib\n ? [\n lib.templates.subscribe(() => menu?.refresh()),\n lib.removeError.subscribe(() => menu?.refresh()),\n ]\n : []\n stopLibrary = () => stops.forEach((stop) => stop())\n if (!engine) {\n close()\n dialog.close()\n }\n }\n followLibrary(viewer.engine.get())\n const stopEngine = viewer.engine.subscribe(followLibrary)\n\n return {\n open(req) {\n if (destroyed || !viewer.engine.get()) return\n close()\n const control = req.anchor.querySelector<HTMLButtonElement>(\n 'button.ink-form-control'\n )\n if (!control) return\n const model = (): SignatureMenuModel =>\n signatureMenuModel(library()?.templates.get() ?? [], {})\n let own: Menu | null = null\n const content = signatureMenuContent({\n library,\n model,\n choose: (t) => {\n own?.close(true)\n sign(req, t)\n },\n create: () => {\n own?.close()\n dialog.open({ returnFocus: control, onSave: (t) => sign(req, t) })\n },\n isOpen: () => own?.isOpen === true,\n })\n own = createMenu(control, {\n label: SIGNATURE_LABELS.menu,\n anchor: req.anchor,\n manual: true,\n attrs: { 'data-ink-menu': 'signature', 'data-ink-sign-field-menu': req.field },\n render: (panel) => content.paint(panel),\n // The field's button is a menu trigger only while its menu is open.\n onClose: () => {\n control.removeAttribute('aria-expanded')\n delete control.dataset.state\n },\n })\n menu = own\n own.open()\n },\n close,\n destroy() {\n if (destroyed) return\n destroyed = true\n close()\n dialog.destroy()\n stopEngine()\n stopLibrary()\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, the signature menu a signature field opens and the message box a form script\n * shows, with the bindings' markup so `@inkbar/theme` styles them 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 { attachHistoryKeys } from '../history-keys'\nimport { createPluginHost, type PluginHost } from '../plugins/host'\nimport { createFocusReturn } from '../popover-focus'\nimport {\n createSearchController,\n viewerSearchOf,\n type SearchController,\n type ViewerSearch,\n} from '../search/controller'\nimport { handleFindKey, pageSelectionText } from '../search/find-key'\nimport { createToolOptions } from '../tools'\nimport { mountViewer, type MountViewerOptions, type ViewerEngine } from '../viewer-engine'\n\nimport { h } from './dom'\nimport { createFormAlert } from './form-alert'\nimport { createSignFieldMenu, type SignFieldMenu } from './signature-menu'\nimport { createThreadPopover } from './thread-popover'\n\nimport type { PluginHistory } from '../../model/annotations/history'\nimport type { FormController } from '../../model/form/controller'\nimport type { FieldsMode } from '../../model/form/types'\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 | 'search'\n | 'onSignField'\n | 'onFormAlert'\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 * Form field values; defaults to uncontrolled, starting from the PDF's. Controlled:\n * `{ mode: 'controlled', initial, onChange }`, where `onChange` hears every commit with the\n * full map and the host pushes back with `viewer.form.get()?.setControlledValue(next)`.\n */\n fields?: FieldsMode\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 /** The document failed to open, a form script failed, or signing a field was refused. */\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 /** The open document's form (`document.form`) while it is ready; `null` otherwise. */\n readonly form: Readable<FormController | 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 * Turns the form field tint on or off (the `formHighlight` option) for the open document,\n * in place, and for the documents opened after it.\n */\n setFormHighlight(on: boolean): void\n /** The plugins' commands by namespaced id (`sandbox.suggest`); place one with `createCommandButton`. */\n readonly commands: { get(id: string): Command | undefined }\n /**\n * The search state and its actions, shared by the find bar, the toolbar button and plugins.\n * `open()` runs the search and draws the highlights even when no find bar is mounted.\n */\n readonly search: ViewerSearch\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 fields,\n plugins,\n threads: withThreads = true,\n onReady,\n onError,\n onActivate,\n onBuild,\n onPageMount,\n onPageUnmount,\n onPageError,\n formHighlight: initialHighlight,\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 onSignField: _onSignField,\n onFormAlert: _onFormAlert,\n signatures: signatureStore,\n search: _search,\n ...view\n } = opts as CreateViewerOptions &\n Pick<\n MountViewerOptions,\n | 'toolStyle'\n | 'toolOptions'\n | 'signatureLibrary'\n | 'search'\n | 'onSignField'\n | 'onFormAlert'\n >\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 form = writable<FormController | 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 let formHighlight = initialHighlight ?? true\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 // Anywhere in the root, toolbars included: the keys do what createUndo and createRedo do.\n const stopHistoryKeys = attachHistoryKeys(root, () => current.get()?.history)\n rootEl.set(scroll)\n\n /** One controller for the viewer's life: the host, the engine and the find bar share it. */\n const search = createSearchController({\n document: readonly(current),\n viewport: () => viewport.get(),\n })\n /** What callers get: the actions, not the bar registration. */\n const viewerSearch: ViewerSearch = viewerSearchOf(search)\n root.addEventListener('keydown', (e) => {\n handleFindKey(e, search, () => pageSelectionText(root))\n })\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 search: viewerSearch,\n })\n\n const focusReturn = createFocusReturn({\n root: () => root,\n activated: () => activated.get(),\n })\n /** For the viewer's life, like the signature library: the field menu and the script alert. */\n let signFieldMenu: SignFieldMenu | undefined\n const formAlert = createFormAlert(root)\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 // A failed script leaves the form fillable; its error reaches the host. Subscribed first,\n // so the form replays the errors from while the document opened here, and they are held\n // until `onReady` has run.\n let held: InkError[] | undefined = []\n const stopForm = doc.form.on('error', (error) => {\n if (held) held.push(error)\n else onError?.(error)\n })\n releaseFormErrors = () => {\n const early = held ?? []\n held = undefined\n for (const error of early) onError?.(error)\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 search,\n container: scroll,\n document: doc,\n formHighlight,\n toolOptions,\n signatureLibrary: signatures,\n onFormAlert: (message) => formAlert.show(message),\n // Pressed after `createViewer` returned, so `viewer` exists by then.\n onSignField: (req) => {\n signFieldMenu ??= createSignFieldMenu(viewer, {\n ...(view.signatureFonts ? { fonts: view.signatureFonts } : {}),\n onError: (error) => onError?.(error),\n })\n signFieldMenu.open(req)\n },\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 stopForm()\n releaseFormErrors = () => undefined\n signFieldMenu?.close()\n formAlert.close()\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 const destroyers: (() => void)[] = []\n let stop: () => void = () => undefined\n /** Hands the open document's held form errors to `onError`, once `onReady` has run. */\n let releaseFormErrors: () => 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 form.set(null)\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 fields,\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 form.set(doc.form)\n status.set({ state: 'ready' })\n // A status subscriber may have opened another document already.\n if (load !== loads) return\n onReady?.(doc)\n if (load === loads) releaseFormErrors()\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 form: readonly(form),\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 setFormHighlight(on) {\n formHighlight = on\n engine.get()?.setFormHighlight(on)\n },\n commands: { get: (id) => host.command(id) },\n search: viewerSearch,\n open,\n destroy() {\n if (destroyed) return\n destroyed = true\n loads++\n close()\n for (const fn of destroyers) fn()\n search.destroy()\n signFieldMenu?.destroy()\n formAlert.destroy()\n host.destroy()\n stopHistoryKeys()\n root.remove()\n },\n }\n toolsByViewer.set(viewer, [...(view.tools ?? []), ...host.tools])\n commandIdsByViewer.set(viewer, () => [...host.commands.keys()])\n internals.set(viewer, { search, destroyers, destroyed: () => destroyed })\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\nconst internals = new WeakMap<\n Viewer,\n { search: SearchController; destroyers: (() => void)[]; destroyed: () => boolean }\n>()\n\n/** @internal The viewer's search controller, which the find bar registers with. */\nexport function searchControllerOf(viewer: Viewer): SearchController {\n const found = internals.get(viewer)\n if (!found) throw new Error('Not a viewer made by createViewer')\n return found.search\n}\n\n/**\n * @internal Runs `fn` when the viewer is destroyed, for what a control set up on it; at once\n * when it already is.\n */\nexport function onViewerDestroy(viewer: Viewer, fn: () => void): void {\n const found = internals.get(viewer)\n if (!found) return\n if (found.destroyed()) fn()\n else found.destroyers.push(fn)\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 Search,\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 { keepHistoryFocus } from '../history-keys'\nimport { unknownCommand } from '../plugins/commands'\nimport { TOOL_LABELS, ZOOM_LEVELS } from '../ui'\n\nimport { hostCommandIdsOf, hostToolsOf, onViewerDestroy } 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`. Returns the function that\n * stops following.\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 const stopSource = source.subscribe(run)\n return () => {\n stopSource()\n for (const s of stops) s()\n stops = []\n }\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\n/** @internal A labelled icon button, as the toolbar controls make them. */\nexport function 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 * Opens the viewer's find bar; pressed while it is open. Pressing it again focuses the field.\n * The bar itself is `createFindBar`.\n */\nexport function createSearchButton(viewer: Viewer): HTMLButtonElement {\n const b = button(\n 'Find',\n { class: 'ink-search-button', 'data-ink-search-button': '', 'aria-pressed': 'false' },\n Search\n )\n b.addEventListener('click', () => {\n viewer.search.open()\n const field = viewer.element.querySelector<HTMLInputElement>(\n '[data-ink-find-bar] input'\n )\n field?.focus()\n field?.select()\n })\n const show = (s: { open: boolean }): void => {\n b.dataset.state = s.open ? 'on' : 'off'\n b.setAttribute('aria-pressed', String(s.open))\n }\n show(viewer.search.state.get())\n onViewerDestroy(viewer, viewer.search.state.subscribe(show))\n onViewerDestroy(\n viewer,\n follow(viewer.document, b, () => undefined)\n )\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 // Undoing the last step disables the focused button: focus goes back to the document.\n keepHistoryFocus(b, () =>\n viewer.element.querySelector<HTMLElement>('[data-ink-scroll]')\n )\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 onViewerDestroy(\n viewer,\n follow(viewer.viewport, b, () => undefined)\n )\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 onViewerDestroy(\n viewer,\n follow(viewer.viewport, b, () => undefined)\n )\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 * The find bar's copy, shared by the vanilla bar and the framework bindings so it cannot drift.\n */\nimport { isBlankQuery } from '../../model/search-text'\n\nimport type { SearchState } from './controller'\nimport type { SearchHit } from '../../model/search'\n\n/**\n * The count beside the field: \"3 of 17\", \"3 of 12…\" while scanning, \"No results\".\n *\n * @internal Shared with the framework bindings.\n */\nexport function findCountText(s: SearchState): string {\n if (isBlankQuery(s.query)) return ''\n if (s.hits.length === 0) return s.scanning ? '' : 'No results'\n return `${s.current + 1} of ${s.hits.length}${s.scanning ? '…' : ''}`\n}\n\n/**\n * Returns the function a bar calls with each search state for its live region's text.\n *\n * A settled scan reads \"Match 3 of 17, page 2\" or \"No results\". While a scan runs it says\n * nothing until a step moves the current hit, then \"Match 3 of 12 so far, page 2\", and keeps\n * that text as more hits arrive, so the region speaks once per step and once on settle rather\n * than once per hit.\n *\n * @internal Shared with the framework bindings; each bar keeps its own.\n */\nexport function findAnnouncer(): (s: SearchState) => string {\n let shown: SearchHit | undefined\n let said = ''\n return (s) => {\n const hit = s.hits[s.current]\n if (!s.open || isBlankQuery(s.query)) {\n shown = undefined\n said = ''\n } else if (!s.scanning) {\n shown = hit\n said = hit\n ? `Match ${s.current + 1} of ${s.hits.length}, page ${hit.page + 1}`\n : 'No results'\n } else {\n if (!hit) said = ''\n else if (shown && hit !== shown)\n said = `Match ${s.current + 1} of ${s.hits.length} so far, page ${hit.page + 1}`\n shown = hit\n }\n return said\n }\n}\n","/*\n * The find bar for createViewer: a view of the viewer's search state. Put it in the viewport\n * root (`viewer.element.querySelector('[data-ink-viewport-root]')`); the theme floats it over\n * the top-right of the pages. It is hidden while the search is closed, and while it is in the\n * document it registers with the search controller, which is what lets Ctrl/Cmd+F open it.\n */\nimport { ChevronDown, ChevronUp, CaseSensitive, X } from '@inkbar/icons'\n\nimport { button } from '../viewer/controls'\nimport { searchControllerOf, onViewerDestroy, type Viewer } from '../viewer/create-viewer'\nimport { h } from '../viewer/dom'\n\nimport { findAnnouncer, findCountText } from './find-text'\n\nimport type { SearchState } from './controller'\n\n/**\n * The find bar for `viewer`: a field, the match count, previous and next, a match-case toggle\n * and close. Its buttons keep focus while used; Enter in the field steps to the next match,\n * Shift+Enter to the previous, Escape closes. Closing returns focus to where it was before the\n * bar opened, else to the document.\n */\nexport function createFindBar(viewer: Viewer): HTMLElement {\n const controller = searchControllerOf(viewer)\n const { state } = controller\n\n const field = h('input', {\n type: 'text',\n 'aria-label': 'Find in document',\n autocomplete: 'off',\n spellcheck: 'false',\n })\n const count = h('span', {\n class: 'ink-find-count',\n 'data-ink-find-count': '',\n })\n const previous = button('Previous match', { 'data-ink-find-previous': '' }, ChevronUp)\n const next = button('Next match', { 'data-ink-find-next': '' }, ChevronDown)\n const matchCase = button(\n 'Match case',\n { 'data-ink-find-match-case': '', 'aria-pressed': 'false' },\n CaseSensitive\n )\n const close = button('Close find', { 'data-ink-find-close': '' }, X)\n const live = h('div', {\n class: 'ink-visually-hidden',\n 'data-ink-find-status': '',\n 'aria-live': 'polite',\n })\n const bar = h(\n 'div',\n { class: 'ink-find-bar', 'data-ink-find-bar': '', role: 'search', hidden: '' },\n field,\n count,\n previous,\n next,\n matchCase,\n close,\n live\n )\n\n field.addEventListener('input', () => controller.setQuery(field.value))\n previous.addEventListener('click', () => controller.previous())\n next.addEventListener('click', () => controller.next())\n matchCase.addEventListener('click', () =>\n controller.setMatchCase(!state.get().matchCase)\n )\n close.addEventListener('click', () => controller.close())\n field.addEventListener('keydown', (e) => {\n if (e.key !== 'Enter' || e.isComposing) return\n e.preventDefault()\n if (e.shiftKey) controller.previous()\n else controller.next()\n })\n bar.addEventListener('keydown', (e) => {\n if (e.key !== 'Escape' || e.defaultPrevented || e.isComposing) return\n e.preventDefault()\n e.stopPropagation()\n controller.close()\n })\n\n /** Where focus was when the bar opened. */\n let before: HTMLElement | null = null\n let wasOpen = false\n const announce = findAnnouncer()\n let announced = ''\n\n function restoreFocus(): void {\n const target =\n before?.isConnected && !bar.contains(before)\n ? before\n : viewer.element.querySelector<HTMLElement>('[data-ink-scroll]')\n before = null\n target?.focus({ preventScroll: true })\n }\n\n function show(s: SearchState): void {\n if (s.open !== wasOpen) {\n wasOpen = s.open\n if (s.open) {\n const active = bar.ownerDocument.activeElement\n before =\n active instanceof HTMLElement &&\n active !== bar.ownerDocument.body &&\n !bar.contains(active)\n ? active\n : null\n bar.hidden = false\n field.focus()\n field.select()\n } else {\n // Focus inside the bar is about to be lost with it; focus elsewhere is left alone.\n const active = bar.ownerDocument.activeElement\n const hadFocus = bar.contains(active) || active === bar.ownerDocument.body\n bar.hidden = true\n if (hadFocus) restoreFocus()\n else before = null\n }\n }\n if (field.value !== s.query) {\n field.value = s.query\n // A query set from code arrives after the bar opened: keep the new text selected.\n if (bar.ownerDocument.activeElement === field) field.select()\n }\n count.textContent = findCountText(s)\n matchCase.setAttribute('aria-pressed', String(s.matchCase))\n const say = announce(s)\n if (say !== announced) {\n announced = say\n live.textContent = say\n }\n }\n\n // Registered while inside the viewer's root, where Ctrl/Cmd+F looks for the field. The\n // observer sees the bar added and removed wherever the host puts it in there.\n let detach: (() => void) | null = null\n const sync = (): void => {\n const inside = viewer.element.contains(bar)\n if (inside && !detach) detach = controller.attachBar()\n else if (!inside && detach) {\n detach()\n detach = null\n }\n }\n const observer = new MutationObserver(sync)\n observer.observe(viewer.element, { childList: true, subtree: true })\n const stopState = state.subscribe(show)\n show(state.get())\n sync()\n onViewerDestroy(viewer, () => {\n observer.disconnect()\n stopState()\n detach?.()\n detach = null\n })\n return bar\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"],"mappings":"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CA;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;CAAK;CAAM;CAAG;CAAM;CAAK;CAAG;CAAG;AAAC;;AAG/E,MAAa,eAAkC;CAAC;CAAK;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;;AAGrE,MAAa,eAAkC,CAAC,GAAG,CAAC;;AAGpD,MAAa,mBAA+B;;AAK5C,MAAa,oBAIP;CACJ;EAAE,OAAO;EAAQ,OAAO;EAAiB,OAAO;GAAE,MAAM;GAAQ,MAAM;EAAO;CAAE;CAC/E;EACE,OAAO;EACP,OAAO;EACP,OAAO;GAAE,MAAM;GAAkB,MAAM;EAAO;CAChD;CACA;EACE,OAAO;EACP,OAAO;EACP,OAAO;GAAE,MAAM;GAAQ,MAAM;EAAiB;CAChD;CACA;EACE,OAAO;EACP,OAAO;EACP,OAAO;GAAE,MAAM;GAAkB,MAAM;EA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"}