@embedpdf/react 3.0.0-next.12 → 3.0.0-next.13

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.
@@ -1 +1 @@
1
- {"version":3,"file":"annotation.js","names":["AnnotationHostToken"],"sources":["../src/annotation.tsx"],"sourcesContent":["/**\n * The React view of @embedpdf/plugin-annotation.\n *\n * Pure paint: it reads the per-page render items + chrome and draws them. Pointer\n * events arrive through the interaction hub (the Stage's forwarding), and the\n * CURSOR is driven by the hub too (the edit handler claims move/pointer/resize on\n * hover). Each annotation resolves to ONE native node — a vector SceneSvg, the\n * engine's baked /AP <img>, or a registered behavior — and the host\n * `customRenderer` may wrap or replace it.\n */\n\n// One-line-per-feature: registration travels with the UI.\nexport * from '@embedpdf/plugin-annotation';\nimport * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport {\n AnnotationToken,\n refKey,\n type AnnotationHydration,\n type AnnotationRef,\n type Behavior,\n type CommentsApi,\n type CommentThread,\n type SelectionFlags,\n type SelectionProps,\n type FilePickerProvider,\n type TextItem,\n previewBucket,\n} from '@embedpdf/plugin-annotation';\nimport { pickFile } from '@embedpdf/web';\n// The render layer is framework code, so it resolves the FULL host lens\n// (pageItems/chrome/appearances/…). Same runtime token as the public one — only\n// the type differs. App code never imports this.\nimport { AnnotationToken as AnnotationHostToken } from '@embedpdf/plugin-annotation/internal';\nimport {\n scene,\n MITER_LIMIT,\n pdfToContentRect,\n type AnnotationProps,\n type Paint,\n type Rect,\n type RenderItem,\n} from '@embedpdf/core-annotation';\n\nexport type {\n CreationDraftAnchor,\n RenderItem,\n Geom,\n LineEnding,\n LineEndings,\n Border,\n Style,\n AnnotationFlags,\n AnnotationProps,\n AnnotationPropsPatch,\n PropKey,\n PropSpec,\n TextAlign,\n TextStyle,\n} from '@embedpdf/core-annotation';\nexport type { SelectionFlags, SelectionProps } from '@embedpdf/plugin-annotation';\nimport {\n shallowArray,\n useCapability,\n useDocumentId,\n useKernelValue,\n useOptionalCapability,\n usePage,\n useSelector,\n} from './runtime';\nimport type { PageContextValue, PageLayout } from './runtime';\n\nexport { sameAnchor, sameCreationDraftAnchor, type SelectionAnchor } from './annotation-anchors';\nexport { useAnnotationSelected } from './annotation-hooks';\n\n/** `#rrggbb` → `rgba(...)` — the marquee's translucent fill derives from the\n * accent, so one `setChrome({ accent })` restyles every piece of chrome. */\nconst rgba = (hex: string, alpha: number): string => {\n const m = /^#?([0-9a-f]{6})$/i.exec(hex);\n if (!m) return hex;\n const n = parseInt(m[1], 16);\n return `rgba(${(n >> 16) & 255},${(n >> 8) & 255},${n & 255},${alpha})`;\n};\n\n/**\n * What an annotation renderer receives: the projected item (its `box` is LIVE —\n * it follows drags), the page context, the engine's baked /AP raster (the\n * \"picture\"), the default visual (`native` — wrap it or ignore it), and\n * whether this entry currently OWNS the pointer (`interactive`). While not\n * interactive the layer renders your component pointer-locked: the annotation\n * stays a first-class citizen of the annotation plane (select/move/resize).\n */\nexport interface AnnotationRendererProps {\n item: RenderItem;\n page: PageContextValue;\n appearance: { url: string; box: Rect } | null;\n native: React.ReactNode;\n interactive: boolean;\n}\n\n/**\n * ONE rule: \"for THESE annotations, render THIS component, and it owns the\n * pointer WHEN …\". The two shapes:\n *\n * - `{ for, component, interactive? }` — your own rule. Without\n * `interactive` it is a pure SKIN: pixels only, mechanically\n * pointer-locked, the annotation plane keeps selection/move/resize. With\n * `interactive` (boolean or live predicate) the layer registers a plugin\n * Behavior for you: while it holds, the annotation plane stands down\n * (hit-test-inert) and your component owns the input.\n * - `{ behavior, component }` — the renderer for a PLUGIN-registered\n * behavior (the form plugin's fill controls via `formWidgetRenderer`);\n * the plugin decides engagement, never the app.\n *\n * Resolution: ownership beats skin — an ENGAGED behavior's component is\n * authoritative; `for` rules apply only to plane-owned annotations, first\n * match wins. Define entries OUTSIDE render (module scope or useMemo): entry\n * identity keys the behavior registration.\n */\nexport type AnnotationRenderer =\n | { behavior: string; component: React.ComponentType<AnnotationRendererProps> }\n | {\n /** Stable id for the auto-registered behavior (optional; generated). */\n id?: string;\n for: Behavior['matches'];\n component: React.ComponentType<AnnotationRendererProps>;\n interactive?: boolean | (() => boolean);\n };\n\nexport interface AnnotationLayerProps {\n /** Annotation renderers — skins and interactive takeovers ({@link AnnotationRenderer}). */\n renderers?: AnnotationRenderer[];\n}\n\n/** Content rect → a view-px box (the page wrapper's own coordinate space). */\nfunction boxOf(r: Rect, page: PageContextValue) {\n const tl = page.transform.toPixels({ x: r.x, y: r.y });\n const br = page.transform.toPixels({ x: r.x + r.width, y: r.y + r.height });\n return { left: tl.x, top: tl.y, width: br.x - tl.x, height: br.y - tl.y };\n}\n\n/** Map a core `Paint` to SVG presentation attributes — the whole framework-facing\n * surface. Everything else about appearance is decided in the core's `scene`. */\nfunction paintAttrs(p: Paint) {\n return {\n fill: p.fill ?? 'none',\n stroke: p.stroke ?? 'none',\n strokeWidth: p.width,\n opacity: p.opacity,\n strokeLinejoin: p.join ?? ('miter' as const), // undefined → sharp miter; 'round' only for ink\n strokeMiterlimit: MITER_LIMIT, // must match the bounds math so spike vs bevel agree\n strokeLinecap: p.cap, // undefined → SVG default (butt); 'round' only for ink\n strokeDasharray: p.dash ? p.dash.join(' ') : undefined,\n ...(p.blend ? { style: { mixBlendMode: p.blend } } : {}),\n };\n}\n\n/**\n * The dumb painter. The pure core computed `item.box` and the painted `scene`; we\n * size the <svg> to the box with a content-space `viewBox` and map each SceneNode\n * to one element, applying its `paint`. No per-kind logic, no bounds math — so\n * shapes, cloudy borders and every text-markup type all render here, and a Vue /\n * Svelte painter is the same ~10-line loop.\n */\nfunction Shape({ item, page }: { item: RenderItem; page: PageContextValue }) {\n // Nothing to draw until the annotation has area (the 0×0 draft at mouse-down).\n if (item.box.width <= 0 || item.box.height <= 0) return null;\n const { left, top, width, height } = boxOf(item.box, page);\n // The viewBox (content units) and the <svg> on-screen size MUST stay proportional\n // (scale == zoom). Clamping either — e.g. a `max(1px)` floor on the element while\n // the viewBox keeps shrinking — decouples them, so a sub-pixel box scales content\n // up by ~1/size and a cloudy border's scallops flood the stage. No clamps here.\n const vb = `${item.box.x} ${item.box.y} ${item.box.width} ${item.box.height}`;\n // BOX-family kinds (square/circle, caret) carry an UNROTATED `box` + a `rot`\n // angle; rotate the whole <svg> about its centre. VERTEX kinds (line/poly/ink)\n // are already rotated in their geometry, so `rot` is advisory there — never\n // re-applied.\n const rot = item.geom.t === 'rect' || item.geom.t === 'caret' ? (item.rot ?? 0) : 0;\n return (\n <svg\n viewBox={vb}\n style={{\n position: 'absolute',\n left,\n top,\n width,\n height,\n overflow: 'visible',\n pointerEvents: 'none',\n ...(rot ? { transform: `rotate(${rot}deg)`, transformOrigin: 'center' } : {}),\n }}\n >\n {sceneNodes(item)}\n </svg>\n );\n}\n\n/** Map a core scene to SVG children. */\nfunction sceneNodes(item: RenderItem): React.ReactNode[] {\n return scene(item).map((n, i) => {\n const a = paintAttrs(n.paint);\n if (n.kind === 'rect')\n return (\n <rect\n key={i}\n x={n.rect.x}\n y={n.rect.y}\n width={n.rect.width}\n height={n.rect.height}\n {...a}\n />\n );\n if (n.kind === 'ellipse')\n return (\n <ellipse\n key={i}\n cx={n.rect.x + n.rect.width / 2}\n cy={n.rect.y + n.rect.height / 2}\n rx={n.rect.width / 2}\n ry={n.rect.height / 2}\n {...a}\n />\n );\n if (n.kind === 'line')\n return <line key={i} x1={n.a.x} y1={n.a.y} x2={n.b.x} y2={n.b.y} {...a} />;\n if (n.kind === 'path') return <path key={i} d={n.d} {...a} />;\n if (n.kind === 'text')\n return (\n <text\n key={i}\n x={n.at.x}\n y={n.at.y}\n fontSize={n.fontSize}\n {...(n.fontFamily ? { fontFamily: n.fontFamily } : {})}\n {...a}\n >\n {n.text}\n </text>\n );\n const pts = n.points.map((p) => `${p.x},${p.y}`).join(' ');\n return n.closed ? (\n <polygon key={i} points={pts} {...a} />\n ) : (\n <polyline key={i} points={pts} {...a} />\n );\n });\n}\n\nfunction BakedImage({\n box,\n url,\n page,\n blend,\n rot,\n}: {\n box: Rect;\n url: string;\n page: PageContextValue;\n blend?: Paint['blend'];\n /** The rotation (deg, CW) the engine STRIPPED from this raster\n * (`RenderItem.apRot`) — re-applied here as a view transform, so a live\n * rotate gesture spins the bitmap with zero engine re-renders. Unset for\n * rasters that already contain their rotation (vertex kinds). */\n rot?: number;\n}) {\n const b = boxOf(box, page);\n return (\n <img\n src={url}\n alt=\"\"\n draggable={false}\n style={{\n position: 'absolute',\n left: b.left,\n top: b.top,\n width: b.width,\n height: b.height,\n // The AP box is sized in content units; a global `img { max-width: 100% }`\n // reset would otherwise clamp it to the containing block and distort the\n // aspect. This bites specifically when the box is WIDER than that block —\n // a landscape stamp whose unrotated box overhangs a view-rotated (portrait)\n // page — so honour the explicit size and let `rot` place it.\n maxWidth: 'none',\n maxHeight: 'none',\n pointerEvents: 'none',\n mixBlendMode: blend,\n // Same CW convention as the free-text element: rotate about the centre.\n ...(rot ? { transform: `rotate(${rot}deg)`, transformOrigin: 'center' } : {}),\n }}\n />\n );\n}\n\n/**\n * The armed stamp's IMAGE footprint ghost: a translucent render of the payload\n * drawn in the EXACT box a click would place it (the plugin computes it with\n * the same fit + clamp as placement). Vector footprint ghosts never reach this\n * component — they ride `pageItems` like every draft preview. The preview\n * bytes live in the capability closure; this layer owns only the object-URL\n * lifetime, keyed on the arm epoch — a new arm swaps the image, a disarm (or\n * tool change) drops it.\n */\nfunction ToolGhostImage({ page }: { page: PageContextValue }) {\n const anno = useCapability(AnnotationHostToken);\n const ghost = useSelector(AnnotationHostToken, (c) => c.toolGhost(page.pon));\n const epoch = useSelector(AnnotationHostToken, (c) => c.stampArmEpoch());\n const [url, setUrl] = useState<string | null>(null);\n // The ghost is a bitmap of vector artwork, right at ONE size: ask for the\n // bucket that covers the box's DEVICE width (points × device px per point),\n // so it stays sharp at every zoom and density. The plugin caches per bucket.\n const bucket =\n ghost?.kind === 'image' ? previewBucket(ghost.box.width * page.transform.renderScale) : 0;\n\n useEffect(() => {\n if (!bucket) {\n setUrl(null);\n return;\n }\n let cancelled = false;\n let obj: string | null = null;\n void anno.armedStampPreview(bucket).then((preview) => {\n if (cancelled || !preview) return;\n // Copy into an EXACT ArrayBuffer (the engine idiom): a Uint8Array view\n // may sit on a larger or shared buffer, which Blob won't accept.\n const body = new ArrayBuffer(preview.bytes.byteLength);\n new Uint8Array(body).set(preview.bytes);\n const blob = new Blob([body], preview.mimeType ? { type: preview.mimeType } : {});\n obj = URL.createObjectURL(blob);\n // The previous bucket's image stays up until this one resolves — no\n // flicker while a zoom crosses a bucket boundary.\n setUrl(obj);\n });\n return () => {\n cancelled = true;\n if (obj) URL.revokeObjectURL(obj);\n };\n }, [anno, epoch, bucket]);\n\n if (!ghost || ghost.kind !== 'image' || !url) return null;\n const b = boxOf(ghost.box, page);\n return (\n <img\n src={url}\n alt=\"\"\n draggable={false}\n style={{\n position: 'absolute',\n left: b.left,\n top: b.top,\n width: b.width,\n height: b.height,\n // Same explicit-size rule as BakedImage: never let a global img reset\n // clamp the box and distort the aspect.\n maxWidth: 'none',\n maxHeight: 'none',\n pointerEvents: 'none',\n opacity: 0.5,\n ...(ghost.rot ? { transform: `rotate(${ghost.rot}deg)`, transformOrigin: 'center' } : {}),\n }}\n />\n );\n}\n\nfunction Chrome({ page }: { page: PageContextValue }) {\n // The page's view scale converts the CSS-px chrome settings into content\n // units inside the core (knob stalk, grab zones) — screen-constant at every\n // zoom. The painter's own px values (handle glyphs, dot radius) are drawn in\n // screen space and need no conversion.\n const scale = page.transform.viewScale;\n const rotation = page.transform.rotation;\n const zoom = page.transform.zoom;\n const nodes = useSelector(\n AnnotationHostToken,\n (c) => c.chrome(page.pon, scale, rotation, zoom),\n shallowArray,\n );\n const cs = useSelector(AnnotationHostToken, (c) => c.chromeSettings());\n // The accent cascade: each piece's color falls back to the one accent.\n const outlineStroke = cs.outline.color ?? cs.accent;\n const handleStroke = cs.handles.stroke ?? cs.accent;\n const knobStroke = cs.knob.stroke ?? cs.accent;\n // ONE outline style for the resting rect AND the rotated obb — the selection\n // box must never flip dashed↔solid when a rotation starts.\n const outlineDash = cs.outline.style === 'dashed' ? '4 3' : undefined;\n // The live rotation readout — an HTML chip (rounded box + padded text beats\n // hand-rolling it in SVG), riding the pointer like v2's.\n const chip = nodes.find((n) => n.kind === 'angle-chip');\n const chipAt = chip ? page.transform.toPixels(chip.at) : null;\n return (\n <>\n <svg style={{ position: 'absolute', inset: 0, overflow: 'visible', pointerEvents: 'none' }}>\n {nodes.map((n, i) => {\n if (n.kind === 'angle-chip') return null; // rendered as HTML below\n if (n.kind === 'handle') {\n const p = page.transform.toPixels(n.at);\n const hs = cs.handles.size;\n return (\n <rect\n key={i}\n x={p.x - hs / 2}\n y={p.y - hs / 2}\n width={hs}\n height={hs}\n fill={cs.handles.fill}\n stroke={handleStroke}\n strokeWidth={1.5}\n // The square rides a rotated box's orientation (spin about itself).\n {...(n.rot ? { transform: `rotate(${n.rot} ${p.x} ${p.y})` } : {})}\n />\n );\n }\n // A live alignment guide of a snapped move: a through-line at the snapped\n // edge/center, spanning both shapes.\n if (n.kind === 'guide') {\n const a = page.transform.toPixels(\n n.axis === 'x' ? { x: n.at, y: n.lo } : { x: n.lo, y: n.at },\n );\n const b = page.transform.toPixels(\n n.axis === 'x' ? { x: n.at, y: n.hi } : { x: n.hi, y: n.at },\n );\n return (\n <line\n key={i}\n x1={a.x}\n y1={a.y}\n x2={b.x}\n y2={b.y}\n stroke=\"#e91e63\"\n strokeWidth={1.5}\n shapeRendering=\"crispEdges\"\n />\n );\n }\n // An oriented selection box (a tilted shape/group): a closed quad through\n // the four content-space corners — replaces the axis-aligned outline.\n if (n.kind === 'obb') {\n const pts = n.corners\n .map((c) => {\n const p = page.transform.toPixels(c);\n return `${p.x},${p.y}`;\n })\n .join(' ');\n return (\n <polygon\n key={i}\n points={pts}\n fill=\"none\"\n stroke={outlineStroke}\n strokeWidth={cs.outline.width}\n strokeDasharray={outlineDash}\n />\n );\n }\n // Rotation guides (live rotate only): the faint 0°/90° reference cross\n // + the prominent indicator riding the angle — pre-cut page chords, so\n // this is a dumb line loop.\n if (n.kind === 'rotate-guides') {\n const guideDash = cs.guides.style === 'dashed' ? '4 3' : undefined;\n return (\n <g key={i}>\n {n.lines.map((l, j) => {\n const a = page.transform.toPixels(l.a);\n const b = page.transform.toPixels(l.b);\n const axis = l.role === 'axis';\n return (\n <line\n key={j}\n x1={a.x}\n y1={a.y}\n x2={b.x}\n y2={b.y}\n stroke={\n axis\n ? (cs.guides.axisColor ?? cs.accent)\n : (cs.guides.indicatorColor ?? cs.accent)\n }\n opacity={axis ? cs.guides.axisOpacity : cs.guides.indicatorOpacity}\n strokeWidth={cs.guides.width}\n strokeDasharray={guideDash}\n />\n );\n })}\n </g>\n );\n }\n // The rotate knob: a stalk from the top-edge midpoint out to a grab dot.\n if (n.kind === 'rotate-knob') {\n const at = page.transform.toPixels(n.at);\n const from = page.transform.toPixels(n.from);\n return (\n <g key={i}>\n {cs.knob.stalk && (\n <line\n x1={from.x}\n y1={from.y}\n x2={at.x}\n y2={at.y}\n stroke={knobStroke}\n strokeWidth={1}\n />\n )}\n <circle\n cx={at.x}\n cy={at.y}\n r={cs.knob.size / 2}\n fill={cs.knob.fill}\n stroke={knobStroke}\n strokeWidth={1.5}\n />\n </g>\n );\n }\n const b = boxOf(n.rect, page);\n // The marquee rubber band keeps its own look (translucent accent fill,\n // always dashed); the selection outline follows the settings.\n if (n.kind === 'marquee') {\n return (\n <rect\n key={i}\n x={b.left}\n y={b.top}\n width={b.width}\n height={b.height}\n fill={rgba(cs.accent, 0.08)}\n stroke={cs.accent}\n strokeWidth={1}\n strokeDasharray=\"4 3\"\n />\n );\n }\n return (\n <rect\n key={i}\n x={b.left}\n y={b.top}\n width={b.width}\n height={b.height}\n fill=\"none\"\n stroke={outlineStroke}\n strokeWidth={cs.outline.width}\n strokeDasharray={outlineDash}\n />\n );\n })}\n </svg>\n {chip && chipAt && (\n <div\n style={{\n position: 'absolute',\n left: chipAt.x + 16,\n top: chipAt.y - 28,\n background: 'rgba(0,0,0,0.8)',\n color: '#fff',\n padding: '2px 6px',\n borderRadius: 4,\n fontSize: 12,\n fontFamily: 'monospace',\n pointerEvents: 'none',\n whiteSpace: 'nowrap',\n zIndex: 1,\n }}\n >\n {chip.angle}°\n </div>\n )}\n </>\n );\n}\n\n/**\n * A free-text annotation: the SAME styled element for viewing and editing —\n * `contentEditable` just toggles, so the text never jumps. The plugin handed us a\n * ready-to-spread style (`item.css`); the browser owns layout, caret, selection,\n * IME and clipboard; the plugin owns the text truth + the debounced engine write.\n * This component is the ENTIRE per-framework surface for text editing.\n */\nfunction FreeText({ item, page }: { item: TextItem; page: PageContextValue }) {\n const anno = useCapability(AnnotationHostToken);\n const ref = React.useRef<HTMLDivElement>(null);\n const box = boxOf(item.box, page);\n const scale = item.box.width > 0 ? box.width / item.box.width : 1; // content units → screen px\n // The element IS the engine's text PLATE (`SetPlateRect` + its `re W n`\n // clip): positioned at the padding inset with ZERO CSS padding, so the\n // scrollport's edge is the plate edge. CSS padding does NOT clip overflow —\n // scrolled lines slide straight through it and paint over the border band —\n // so the border band must sit OUTSIDE the scrollport, never inside it.\n const pad = item.css.padding * scale;\n const plate = {\n left: box.left + pad,\n top: box.top + pad,\n width: Math.max(0, box.width - 2 * pad),\n height: Math.max(0, box.height - 2 * pad),\n };\n\n // DOM ← model, but ONLY when this element isn't being typed in — keeps the caret\n // stable while you type AND lets a remote (collab) edit land live when idle.\n useEffect(() => {\n const el = ref.current;\n if (el && document.activeElement !== el && el.innerText !== item.contents) {\n el.innerText = item.contents;\n }\n }, [item.contents, item.editing]);\n // Keep DOM focus in sync with the model's `editing` state. Focus follows the\n // model — it never drives it (exit is hub-driven, see the edit handler), so a\n // transient focus-steal by the page surface can't end the edit.\n useEffect(() => {\n if (item.editing) {\n const el = ref.current;\n if (!el) return;\n el.focus();\n // Enter at the TOP — the same anchoring the baked appearance uses\n // (/Q vertical-align top), so baked → edit → baked never jumps. The\n // browser still follows the caret once the user clicks or types.\n el.scrollTop = 0;\n }\n }, [item.editing]);\n\n // Isolate the editor from the interaction hub: a pointerdown inside it must NOT\n // bubble up to the Stage's native listener (which the edit handler reads as a\n // click-outside → exit). Stopping it here lets the browser own caret placement\n // and drag-selection inside the box, while clicks OUTSIDE still reach the hub and\n // commit the edit. Native listener (not React's) so it runs during real DOM\n // bubbling, before the Stage's own native listener on an ancestor.\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const stop = (e: Event) => e.stopPropagation();\n el.addEventListener('pointerdown', stop);\n return () => el.removeEventListener('pointerdown', stop);\n }, []);\n\n return (\n <div\n ref={ref}\n contentEditable={item.editing}\n suppressContentEditableWarning\n onInput={() => item.ref && anno.setContents(item.ref, ref.current!.innerText)}\n onBlur={(e) => {\n // The gesture that opens the editor fires a native `mousedown` on the\n // non-focusable page surface, which blurs us to <body> (relatedTarget null)\n // right after we focus. If the MODEL still has this box in edit, that blur\n // is a spurious steal — re-assert focus. A real click-away routes through\n // the hub, which clears `editing` BEFORE this fires, so we let it go (and a\n // focus move to a real element, relatedTarget != null, is always honoured).\n if (\n e.relatedTarget == null &&\n ref.current?.isConnected &&\n anno.currentEditing() === item.id\n ) {\n ref.current.focus();\n }\n }}\n onPaste={(e) => {\n e.preventDefault();\n document.execCommand('insertText', false, e.clipboardData.getData('text/plain'));\n }}\n style={{\n position: 'absolute',\n left: plate.left,\n top: plate.top,\n width: plate.width,\n // Fixed to the annotation rect's plate — the box never grows with\n // content; it scrolls while editing and clips otherwise, at the SAME\n // boundary the baked /AP clips at (`re W n` on the text body).\n height: plate.height,\n fontFamily: item.css.fontFamily,\n fontSize: item.css.fontSize * scale,\n lineHeight: `${item.css.lineHeight * scale}px`,\n color: item.css.color,\n textAlign: item.css.align,\n boxSizing: 'border-box',\n background: item.css.background ?? 'transparent',\n whiteSpace: 'pre-wrap',\n overflowWrap: 'break-word',\n overflowY: item.editing ? 'auto' : 'hidden',\n overflowX: 'hidden',\n outline: item.editing ? '1px solid #3858e9' : 'none',\n cursor: item.editing ? 'text' : 'default',\n // A plain text box rotates about its centre (the box model — same as the\n // baked /AP). `box` is the unrotated box; CSS rotate matches our CW `rot`.\n ...(item.rot ? { transform: `rotate(${item.rot}deg)`, transformOrigin: 'center' } : {}),\n // not editing → clicks fall through to the shape layer (select / move / resize)\n pointerEvents: item.editing ? 'auto' : 'none',\n }}\n />\n );\n}\n\n/**\n * Auto-registered behaviors for `interactive` renderer entries — refcounted\n * per (capability, entry) because the layer mounts once PER PAGE: the first\n * page registers, the last unregisters. Entry identity is the key, hence the\n * \"define entries outside render\" rule on {@link AnnotationRenderer}.\n */\nconst autoBehaviors = new WeakMap<\n object,\n Map<object, { id: string; count: number; unregister: () => void }>\n>();\nlet autoBehaviorSeq = 0;\n\nfunction useAutoBehaviors(\n anno: { registerBehavior(b: Behavior): () => void },\n renderers?: AnnotationRenderer[],\n): void {\n useEffect(() => {\n if (!renderers) return;\n const released: Array<() => void> = [];\n for (const r of renderers) {\n if (!('for' in r) || !r.interactive) continue;\n let perCap = autoBehaviors.get(anno);\n if (!perCap) autoBehaviors.set(anno, (perCap = new Map()));\n let rec = perCap.get(r);\n if (!rec) {\n const id = r.id ?? `renderer:${++autoBehaviorSeq}`;\n const engaged = typeof r.interactive === 'function' ? r.interactive : () => true;\n rec = { id, count: 0, unregister: anno.registerBehavior({ id, matches: r.for, engaged }) };\n perCap.set(r, rec);\n }\n rec.count++;\n const owned = rec;\n released.push(() => {\n owned.count--;\n if (owned.count === 0) {\n owned.unregister();\n autoBehaviors.get(anno)?.delete(r);\n }\n });\n }\n return () => released.forEach((f) => f());\n }, [anno, renderers]);\n}\n\n/** The behavior id a renderer entry answers for (plugin-owned or auto-registered). */\nfunction rendererBehaviorId(anno: object, r: AnnotationRenderer): string | null {\n if ('behavior' in r) return r.behavior;\n return autoBehaviors.get(anno)?.get(r)?.id ?? null;\n}\n\n/** React 18 spells the `inert` attribute as a string spread; it hard-disables\n * pointer AND focus for the whole subtree — the mechanical guarantee that a\n * non-interactive renderer entry (a skin) can never steal input. */\nconst INERT = { inert: '' } as Record<string, string>;\n\nexport function AnnotationLayer({ renderers }: AnnotationLayerProps = {}) {\n const page = usePage();\n const anno = useCapability(AnnotationHostToken);\n // The page's view env (RELATIVE zoom + total display rotation) projects\n // screen-anchored (`noZoom`/`noRotate`) annotations to their effective\n // footprint INSIDE the plugin — no flag logic lives in the framework.\n // `transform.zoom` (not `viewScale`): 1 = the page's physical 100%.\n const viewZoom = page.transform.zoom;\n const viewRotation = page.transform.rotation;\n const items = useSelector(\n AnnotationHostToken,\n (c) => c.pageItems(page.pon, { zoom: viewZoom, rotation: viewRotation }),\n shallowArray,\n );\n const texts = useSelector(\n AnnotationHostToken,\n (c) => c.textItems(page.pon, { zoom: viewZoom, rotation: viewRotation }),\n shallowArray,\n );\n const [urls, setUrls] = useState<Record<string, { url: string; box: Rect }>>({});\n useAutoBehaviors(anno, renderers);\n\n useEffect(() => {\n anno.ensurePage(page.pon);\n }, [anno, page.pon]);\n\n // Baked annotations render from engine rasters — refetch when the page's\n // baked set or an /AP content version changes (a freshly placed stamp, a\n // resize whose re-bake RESOLVED), plus at APPEARANCE-SCALE crossings. A move\n // or a rotate leaves the epoch untouched (the blit repositions the same\n // pixels), and live gesture previews don't touch it either — so no mid-drag\n // spam.\n const bakedKey = useSelector(AnnotationHostToken, (c) => c.appearanceEpoch(page.pon));\n // The bake scale conforms to the document's render policy — the plugin's\n // OWN capability over the kernel-materialized fact (no foreign tokens):\n // zoom ticks inside an appearance-lattice rung re-bake NOTHING; crossing\n // 1→2 re-bakes once; continuous is the identity.\n const bakeScale = useSelector(AnnotationHostToken, (c) =>\n c.bakeScale(page.transform.renderScale),\n );\n\n useEffect(() => {\n const controller = new AbortController();\n const revokers: Array<() => void> = [];\n (async () => {\n try {\n const imgs = await anno.appearances(page.pon, bakeScale, controller.signal);\n const map: Record<string, { url: string; box: Rect }> = {};\n for (const ap of imgs) {\n // Place the baked bitmap by its OWN /Rect (the box it was rendered into),\n // converted to content space by the plugin — never a recomputed bound.\n const box = anno.toContentBox(page.pon, ap.rect);\n if (!box) continue;\n const obj = await ap.image.objectUrl(controller.signal);\n if (controller.signal.aborted) {\n obj.revoke();\n return;\n }\n revokers.push(obj.revoke);\n map[refKey(ap.ref)] = { url: obj.url, box };\n }\n if (!controller.signal.aborted) setUrls(map);\n } catch {\n /* aborted / no appearances */\n }\n })();\n return () => {\n controller.abort();\n revokers.forEach((r) => r());\n };\n }, [anno, page.pon, bakeScale, bakedKey]);\n\n return (\n <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>\n {items.map((item) => {\n // The default visual: the engine's baked raster (blitted into the LIVE\n // AP box — `apBox` follows a move) or the vector scene.\n const baked = urls[item.id];\n const native: React.ReactNode =\n item.source === 'baked' ? (\n baked ? (\n <BakedImage\n box={item.apBox ?? baked.box}\n url={baked.url}\n page={page}\n blend={item.blend}\n rot={item.apRot}\n />\n ) : null\n ) : (\n <Shape item={item} page={page} /> // shapes, cloudy, markup — all painted via scene()\n );\n\n // Ownership beats skin: an ENGAGED behavior's renderer is authoritative\n // (form fill controls own their DOM); `for` rules apply only to\n // plane-owned annotations and render pointer-locked — a skin can change\n // pixels, never steal input.\n const behavior = anno.behaviorFor({ subtype: item.subtype, ref: item.ref });\n let out: React.ReactNode;\n if (behavior) {\n const entry = renderers?.find((r) => rendererBehaviorId(anno, r) === behavior.id);\n if (entry) {\n const Owner = entry.component;\n out = (\n <Owner\n item={item}\n page={page}\n appearance={baked ?? null}\n native={native}\n interactive\n />\n );\n } else {\n out = null; // engaged but no renderer wired — the owner shows nothing\n }\n } else {\n const entry = renderers?.find(\n (r) => 'for' in r && r.for({ subtype: item.subtype, ref: item.ref }),\n );\n if (entry) {\n const Skin = entry.component;\n out = (\n <div {...INERT} style={{ pointerEvents: 'none' }}>\n <Skin\n item={item}\n page={page}\n appearance={baked ?? null}\n native={native}\n interactive={false}\n />\n </div>\n );\n } else {\n out = native;\n }\n }\n return <React.Fragment key={item.id}>{out}</React.Fragment>;\n })}\n {texts.map((t) => (\n <FreeText key={t.id} item={t} page={page} />\n ))}\n <ToolGhostImage page={page} />\n <Chrome page={page} />\n </div>\n );\n}\n\n/**\n * The default file-picker provider: the built-in file dialog (from\n * `@embedpdf/web`), honouring the tool's `accept` filter. This is the ADAPTER\n * fulfilling the plugin's DOM-free port — the dialog lives here, in the\n * framework layer, never in the plugin. A picked `File` carries its own name\n * and mime, so it goes straight through as the engine's file source.\n */\nexport const filePickerProvider: FilePickerProvider = async (req) => {\n const file = await pickFile({ accept: req.accept ?? '*/*' });\n return file ? { data: file } : null;\n};\n\n/**\n * Install the file-picker provider for the active document — the ONE port\n * behind every click-then-pick tool (a stamp `'prompt'` source, the file-\n * attachment tool). Call ONCE at a document-scoped spot (not inside\n * `<AnnotationLayer>`, which is per page). Defaults to\n * {@link filePickerProvider}, so a bare `useFilePickerProvider()` makes all of\n * them work out of the box; pass a custom provider (asset library, cloud\n * drive — switch on `req.subtype` / `req.toolId`) or `null` to make\n * click-then-pick tools inert. Cleared on unmount.\n */\nexport function useFilePickerProvider(\n provider: FilePickerProvider | null = filePickerProvider,\n): void {\n const anno = useOptionalCapability(AnnotationToken);\n useEffect(() => {\n if (!anno) return;\n anno.setFilePickerProvider(provider);\n return () => anno.setFilePickerProvider(null);\n }, [anno, provider]);\n}\n\nexport function useAnnotation() {\n return useCapability(AnnotationToken);\n}\n\nexport function useAnnotationSelection() {\n return useSelector(AnnotationToken, (c) => c.selection(), shallowArray);\n}\n\n/** Structural equality for a resolved props bag — keeps the subscription from\n * re-rendering on unrelated dispatches, since `currentDefaults` returns a fresh\n * object each call. Small flat objects; JSON compare is exact and cheap here. */\nconst sameProps = (a: AnnotationProps, b: AnnotationProps): boolean =>\n a === b || JSON.stringify(a) === JSON.stringify(b);\n\n/**\n * A tool's RESOLVED defaults (base + per-tool override) as a full flat props\n * bag, subscribed so a `setDefaults` re-renders the consumer. Use this — not the\n * imperative `useAnnotation().currentDefaults(id)` — to drive default-editing\n * controls, so they reflect changes live. Pair with `propsForTool(id)` for the\n * specs to render.\n */\nexport function useAnnotationDefaults(toolId: string): AnnotationProps {\n return useSelector(AnnotationToken, (c) => c.currentDefaults(toolId), sameProps);\n}\n\n/**\n * The selection's editable properties — ordered specs shared by every selected\n * kind, current values, and which keys are mixed. THE hook a property sidebar\n * renders from; write back with `useAnnotation().updateSelection({ [key]: v })`.\n * Reference-stable between model changes (the capability memoizes by model\n * identity), so the default equality is enough.\n */\nexport function useSelectionProps(): SelectionProps {\n return useSelector(AnnotationToken, (c) => c.getSelectionProps());\n}\n\n/**\n * The selection's `/F` annotation flags — per-flag `true`/`false`, `null` where\n * the selected annotations disagree (render an indeterminate control), `null`\n * overall when nothing is selected. Write back with\n * `useAnnotation().updateSelectionFlags({ locked: true })`. Reference-stable\n * between model changes, like {@link useSelectionProps}.\n */\nexport function useSelectionFlags(): SelectionFlags | null {\n return useSelector(AnnotationToken, (c) => c.getSelectionFlags());\n}\n\n// ── Comments (the conversation plane) ────────────────────────────────────────\n\n/**\n * A {@link CommentThread} enriched with its page's live display position —\n * the framework-layer join. Identity stays `pageObjectNumber` (like every\n * annotation surface); these two fields are PRESENTATION, tracking page\n * moves and deletes.\n */\nexport interface CommentThreadView extends CommentThread {\n /** Current 0-based display index of the thread's page; `-1` when the page\n * is no longer in the document (one-frame teardown race on delete). */\n pageIndex: number;\n /** The page's `/PageLabels` label when the PDF declares one (\"iv\", \"A-2\"),\n * else the 1-based position as a string — print it verbatim. */\n pageLabel: string;\n /**\n * The root annotation's rect in CONTENT space (y-down, crop-relative,\n * unscaled points) — the space `StageCapability.reveal` takes, so a\n * \"jump to this comment\" is `stage.reveal(pageIndex, { rect: contentRect })`.\n * Null when the page is gone. Identity still travels as `pageObjectNumber`;\n * this, like `pageIndex`, is presentation.\n */\n contentRect: Rect | null;\n}\n\n/** Pure join behind {@link useCommentThreads} — exported for tests. */\nexport function enrichCommentThreads(\n threads: readonly CommentThread[],\n pages: readonly PageLayout[],\n): CommentThreadView[] {\n const byPon = new Map(pages.map((p) => [p.pageObjectNumber, p] as const));\n return threads.map((t) => {\n const page = byPon.get(t.pageObjectNumber);\n return {\n ...t,\n pageIndex: page ? page.index : -1,\n pageLabel: page ? (page.label ?? String(page.index + 1)) : '?',\n contentRect: page ? pdfToContentRect(t.root.rect, page.boxes.crop) : null,\n };\n });\n}\n\n/** The comments surface (verbs + `permissionsFor`) — imperative; pair with\n * {@link useCommentThreads} for the subscribed view. */\nexport function useComments(): CommentsApi {\n return useCapability(AnnotationToken).comments;\n}\n\nconst EMPTY_PAGES: readonly PageLayout[] = [];\n\n/**\n * Every comment thread in the document, display-ordered (page position →\n * top of page → creation date) and enriched with `pageIndex`/`pageLabel`.\n * Subscribed to BOTH stores: annotation writes (own, remote, hydration)\n * recompute the threads; page moves/deletes re-run the join. Reference-\n * stable between changes — safe to memo child renders on the array.\n */\nexport function useCommentThreads(): CommentThreadView[] {\n const docId = useDocumentId();\n const threads = useSelector(AnnotationToken, (c) => c.comments.threads());\n const pages = useKernelValue((k) =>\n docId ? (k.getState().core.documents[docId]?.pages ?? EMPTY_PAGES) : EMPTY_PAGES,\n );\n return React.useMemo(() => enrichCommentThreads(threads, pages), [threads, pages]);\n}\n\n/** The enriched thread containing ANY member ref (root, reply, grouped part,\n * state annotation), or null. */\nexport function useCommentThread(ref: AnnotationRef | null): CommentThreadView | null {\n const views = useCommentThreads();\n const api = useComments();\n if (ref == null) return null;\n const t = api.thread(ref);\n if (!t) return null;\n return views.find((v) => refKey(v.root.ref) === refKey(t.root.ref)) ?? null;\n}\n\n/** Whole-document hydration status — the comments sidebar's honest loading\n * state (`loading` until `listRawAll` lands, then `complete`/`error`). */\nexport function useCommentsHydration(): AnnotationHydration {\n return useSelector(AnnotationToken, (c) => c.comments.hydration());\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"annotation.js","names":["AnnotationHostToken"],"sources":["../src/annotation.tsx"],"sourcesContent":["/**\n * The React view of @embedpdf/plugin-annotation.\n *\n * Pure paint: it reads the per-page render items + chrome and draws them. Pointer\n * events arrive through the interaction hub (the Stage's forwarding), and the\n * CURSOR is driven by the hub too (the edit handler claims move/pointer/resize on\n * hover). Each annotation resolves to ONE native node — a vector SceneSvg, the\n * engine's baked /AP <img>, or a registered behavior — and the host\n * `customRenderer` may wrap or replace it.\n */\n\n// One-line-per-feature: registration travels with the UI.\nexport * from '@embedpdf/plugin-annotation';\nimport * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport {\n AnnotationToken,\n refKey,\n type AnnotationHydration,\n type AnnotationRef,\n type Behavior,\n type CommentsApi,\n type CommentThread,\n type SelectionFlags,\n type SelectionProps,\n type FilePickerProvider,\n type TextItem,\n previewBucket,\n} from '@embedpdf/plugin-annotation';\nimport {\n attachRichTextEditor,\n pickFile,\n type RichTextEditorBinding,\n type RichTextEditorHost,\n} from '@embedpdf/web';\n// The render layer is framework code, so it resolves the FULL host lens\n// (pageItems/chrome/appearances/…). Same runtime token as the public one — only\n// the type differs. App code never imports this.\nimport { AnnotationToken as AnnotationHostToken } from '@embedpdf/plugin-annotation/internal';\nimport {\n scene,\n MITER_LIMIT,\n pdfToContentRect,\n type AnnotationProps,\n type Paint,\n type Rect,\n type RenderItem,\n} from '@embedpdf/core-annotation';\n\nexport type {\n CreationDraftAnchor,\n RenderItem,\n Geom,\n LineEnding,\n LineEndings,\n Border,\n Style,\n AnnotationFlags,\n AnnotationProps,\n AnnotationPropsPatch,\n PropKey,\n PropSpec,\n TextAlign,\n TextStyle,\n} from '@embedpdf/core-annotation';\nexport type { SelectionFlags, SelectionProps } from '@embedpdf/plugin-annotation';\nimport {\n shallowArray,\n useCapability,\n useDocumentId,\n useKernelValue,\n useOptionalCapability,\n usePage,\n useSelector,\n} from './runtime';\nimport type { PageContextValue, PageLayout } from './runtime';\n\nexport { sameAnchor, sameCreationDraftAnchor, type SelectionAnchor } from './annotation-anchors';\nexport { useAnnotationSelected } from './annotation-hooks';\n\n/** `#rrggbb` → `rgba(...)` — the marquee's translucent fill derives from the\n * accent, so one `setChrome({ accent })` restyles every piece of chrome. */\nconst rgba = (hex: string, alpha: number): string => {\n const m = /^#?([0-9a-f]{6})$/i.exec(hex);\n if (!m) return hex;\n const n = parseInt(m[1], 16);\n return `rgba(${(n >> 16) & 255},${(n >> 8) & 255},${n & 255},${alpha})`;\n};\n\n/**\n * What an annotation renderer receives: the projected item (its `box` is LIVE —\n * it follows drags), the page context, the engine's baked /AP raster (the\n * \"picture\"), the default visual (`native` — wrap it or ignore it), and\n * whether this entry currently OWNS the pointer (`interactive`). While not\n * interactive the layer renders your component pointer-locked: the annotation\n * stays a first-class citizen of the annotation plane (select/move/resize).\n */\nexport interface AnnotationRendererProps {\n item: RenderItem;\n page: PageContextValue;\n appearance: { url: string; box: Rect } | null;\n native: React.ReactNode;\n interactive: boolean;\n}\n\n/**\n * ONE rule: \"for THESE annotations, render THIS component, and it owns the\n * pointer WHEN …\". The two shapes:\n *\n * - `{ for, component, interactive? }` — your own rule. Without\n * `interactive` it is a pure SKIN: pixels only, mechanically\n * pointer-locked, the annotation plane keeps selection/move/resize. With\n * `interactive` (boolean or live predicate) the layer registers a plugin\n * Behavior for you: while it holds, the annotation plane stands down\n * (hit-test-inert) and your component owns the input.\n * - `{ behavior, component }` — the renderer for a PLUGIN-registered\n * behavior (the form plugin's fill controls via `formWidgetRenderer`);\n * the plugin decides engagement, never the app.\n *\n * Resolution: ownership beats skin — an ENGAGED behavior's component is\n * authoritative; `for` rules apply only to plane-owned annotations, first\n * match wins. Define entries OUTSIDE render (module scope or useMemo): entry\n * identity keys the behavior registration.\n */\nexport type AnnotationRenderer =\n | { behavior: string; component: React.ComponentType<AnnotationRendererProps> }\n | {\n /** Stable id for the auto-registered behavior (optional; generated). */\n id?: string;\n for: Behavior['matches'];\n component: React.ComponentType<AnnotationRendererProps>;\n interactive?: boolean | (() => boolean);\n };\n\nexport interface AnnotationLayerProps {\n /** Annotation renderers — skins and interactive takeovers ({@link AnnotationRenderer}). */\n renderers?: AnnotationRenderer[];\n}\n\n/** Content rect → a view-px box (the page wrapper's own coordinate space). */\nfunction boxOf(r: Rect, page: PageContextValue) {\n const tl = page.transform.toPixels({ x: r.x, y: r.y });\n const br = page.transform.toPixels({ x: r.x + r.width, y: r.y + r.height });\n return { left: tl.x, top: tl.y, width: br.x - tl.x, height: br.y - tl.y };\n}\n\n/** Map a core `Paint` to SVG presentation attributes — the whole framework-facing\n * surface. Everything else about appearance is decided in the core's `scene`. */\nfunction paintAttrs(p: Paint) {\n return {\n fill: p.fill ?? 'none',\n stroke: p.stroke ?? 'none',\n strokeWidth: p.width,\n opacity: p.opacity,\n strokeLinejoin: p.join ?? ('miter' as const), // undefined → sharp miter; 'round' only for ink\n strokeMiterlimit: MITER_LIMIT, // must match the bounds math so spike vs bevel agree\n strokeLinecap: p.cap, // undefined → SVG default (butt); 'round' only for ink\n strokeDasharray: p.dash ? p.dash.join(' ') : undefined,\n ...(p.blend ? { style: { mixBlendMode: p.blend } } : {}),\n };\n}\n\n/**\n * The dumb painter. The pure core computed `item.box` and the painted `scene`; we\n * size the <svg> to the box with a content-space `viewBox` and map each SceneNode\n * to one element, applying its `paint`. No per-kind logic, no bounds math — so\n * shapes, cloudy borders and every text-markup type all render here, and a Vue /\n * Svelte painter is the same ~10-line loop.\n */\nfunction Shape({ item, page }: { item: RenderItem; page: PageContextValue }) {\n // Nothing to draw until the annotation has area (the 0×0 draft at mouse-down).\n if (item.box.width <= 0 || item.box.height <= 0) return null;\n const { left, top, width, height } = boxOf(item.box, page);\n // The viewBox (content units) and the <svg> on-screen size MUST stay proportional\n // (scale == zoom). Clamping either — e.g. a `max(1px)` floor on the element while\n // the viewBox keeps shrinking — decouples them, so a sub-pixel box scales content\n // up by ~1/size and a cloudy border's scallops flood the stage. No clamps here.\n const vb = `${item.box.x} ${item.box.y} ${item.box.width} ${item.box.height}`;\n // BOX-family kinds (square/circle, caret) carry an UNROTATED `box` + a `rot`\n // angle; rotate the whole <svg> about its centre. VERTEX kinds (line/poly/ink)\n // are already rotated in their geometry, so `rot` is advisory there — never\n // re-applied.\n const rot = item.geom.t === 'rect' || item.geom.t === 'caret' ? (item.rot ?? 0) : 0;\n return (\n <svg\n viewBox={vb}\n style={{\n position: 'absolute',\n left,\n top,\n width,\n height,\n overflow: 'visible',\n pointerEvents: 'none',\n ...(rot ? { transform: `rotate(${rot}deg)`, transformOrigin: 'center' } : {}),\n }}\n >\n {sceneNodes(item)}\n </svg>\n );\n}\n\n/** Map a core scene to SVG children. */\nfunction sceneNodes(item: RenderItem): React.ReactNode[] {\n return scene(item).map((n, i) => {\n const a = paintAttrs(n.paint);\n if (n.kind === 'rect')\n return (\n <rect\n key={i}\n x={n.rect.x}\n y={n.rect.y}\n width={n.rect.width}\n height={n.rect.height}\n {...a}\n />\n );\n if (n.kind === 'ellipse')\n return (\n <ellipse\n key={i}\n cx={n.rect.x + n.rect.width / 2}\n cy={n.rect.y + n.rect.height / 2}\n rx={n.rect.width / 2}\n ry={n.rect.height / 2}\n {...a}\n />\n );\n if (n.kind === 'line')\n return <line key={i} x1={n.a.x} y1={n.a.y} x2={n.b.x} y2={n.b.y} {...a} />;\n if (n.kind === 'path') return <path key={i} d={n.d} {...a} />;\n if (n.kind === 'text')\n return (\n <text\n key={i}\n x={n.at.x}\n y={n.at.y}\n fontSize={n.fontSize}\n {...(n.fontFamily ? { fontFamily: n.fontFamily } : {})}\n {...a}\n >\n {n.text}\n </text>\n );\n const pts = n.points.map((p) => `${p.x},${p.y}`).join(' ');\n return n.closed ? (\n <polygon key={i} points={pts} {...a} />\n ) : (\n <polyline key={i} points={pts} {...a} />\n );\n });\n}\n\nfunction BakedImage({\n box,\n url,\n page,\n blend,\n rot,\n}: {\n box: Rect;\n url: string;\n page: PageContextValue;\n blend?: Paint['blend'];\n /** The rotation (deg, CW) the engine STRIPPED from this raster\n * (`RenderItem.apRot`) — re-applied here as a view transform, so a live\n * rotate gesture spins the bitmap with zero engine re-renders. Unset for\n * rasters that already contain their rotation (vertex kinds). */\n rot?: number;\n}) {\n const b = boxOf(box, page);\n return (\n <img\n src={url}\n alt=\"\"\n draggable={false}\n style={{\n position: 'absolute',\n left: b.left,\n top: b.top,\n width: b.width,\n height: b.height,\n // The AP box is sized in content units; a global `img { max-width: 100% }`\n // reset would otherwise clamp it to the containing block and distort the\n // aspect. This bites specifically when the box is WIDER than that block —\n // a landscape stamp whose unrotated box overhangs a view-rotated (portrait)\n // page — so honour the explicit size and let `rot` place it.\n maxWidth: 'none',\n maxHeight: 'none',\n pointerEvents: 'none',\n mixBlendMode: blend,\n // Same CW convention as the free-text element: rotate about the centre.\n ...(rot ? { transform: `rotate(${rot}deg)`, transformOrigin: 'center' } : {}),\n }}\n />\n );\n}\n\n/**\n * The armed stamp's IMAGE footprint ghost: a translucent render of the payload\n * drawn in the EXACT box a click would place it (the plugin computes it with\n * the same fit + clamp as placement). Vector footprint ghosts never reach this\n * component — they ride `pageItems` like every draft preview. The preview\n * bytes live in the capability closure; this layer owns only the object-URL\n * lifetime, keyed on the arm epoch — a new arm swaps the image, a disarm (or\n * tool change) drops it.\n */\nfunction ToolGhostImage({ page }: { page: PageContextValue }) {\n const anno = useCapability(AnnotationHostToken);\n const ghost = useSelector(AnnotationHostToken, (c) => c.toolGhost(page.pon));\n const epoch = useSelector(AnnotationHostToken, (c) => c.stampArmEpoch());\n const [url, setUrl] = useState<string | null>(null);\n // The ghost is a bitmap of vector artwork, right at ONE size: ask for the\n // bucket that covers the box's DEVICE width (points × device px per point),\n // so it stays sharp at every zoom and density. The plugin caches per bucket.\n const bucket =\n ghost?.kind === 'image' ? previewBucket(ghost.box.width * page.transform.renderScale) : 0;\n\n useEffect(() => {\n if (!bucket) {\n setUrl(null);\n return;\n }\n let cancelled = false;\n let obj: string | null = null;\n void anno.armedStampPreview(bucket).then((preview) => {\n if (cancelled || !preview) return;\n // Copy into an EXACT ArrayBuffer (the engine idiom): a Uint8Array view\n // may sit on a larger or shared buffer, which Blob won't accept.\n const body = new ArrayBuffer(preview.bytes.byteLength);\n new Uint8Array(body).set(preview.bytes);\n const blob = new Blob([body], preview.mimeType ? { type: preview.mimeType } : {});\n obj = URL.createObjectURL(blob);\n // The previous bucket's image stays up until this one resolves — no\n // flicker while a zoom crosses a bucket boundary.\n setUrl(obj);\n });\n return () => {\n cancelled = true;\n if (obj) URL.revokeObjectURL(obj);\n };\n }, [anno, epoch, bucket]);\n\n if (!ghost || ghost.kind !== 'image' || !url) return null;\n const b = boxOf(ghost.box, page);\n return (\n <img\n src={url}\n alt=\"\"\n draggable={false}\n style={{\n position: 'absolute',\n left: b.left,\n top: b.top,\n width: b.width,\n height: b.height,\n // Same explicit-size rule as BakedImage: never let a global img reset\n // clamp the box and distort the aspect.\n maxWidth: 'none',\n maxHeight: 'none',\n pointerEvents: 'none',\n opacity: 0.5,\n ...(ghost.rot ? { transform: `rotate(${ghost.rot}deg)`, transformOrigin: 'center' } : {}),\n }}\n />\n );\n}\n\nfunction Chrome({ page }: { page: PageContextValue }) {\n // The page's view scale converts the CSS-px chrome settings into content\n // units inside the core (knob stalk, grab zones) — screen-constant at every\n // zoom. The painter's own px values (handle glyphs, dot radius) are drawn in\n // screen space and need no conversion.\n const scale = page.transform.viewScale;\n const rotation = page.transform.rotation;\n const zoom = page.transform.zoom;\n const nodes = useSelector(\n AnnotationHostToken,\n (c) => c.chrome(page.pon, scale, rotation, zoom),\n shallowArray,\n );\n const cs = useSelector(AnnotationHostToken, (c) => c.chromeSettings());\n // The accent cascade: each piece's color falls back to the one accent.\n const outlineStroke = cs.outline.color ?? cs.accent;\n const handleStroke = cs.handles.stroke ?? cs.accent;\n const knobStroke = cs.knob.stroke ?? cs.accent;\n // ONE outline style for the resting rect AND the rotated obb — the selection\n // box must never flip dashed↔solid when a rotation starts.\n const outlineDash = cs.outline.style === 'dashed' ? '4 3' : undefined;\n // The live rotation readout — an HTML chip (rounded box + padded text beats\n // hand-rolling it in SVG), riding the pointer like v2's.\n const chip = nodes.find((n) => n.kind === 'angle-chip');\n const chipAt = chip ? page.transform.toPixels(chip.at) : null;\n return (\n <>\n <svg style={{ position: 'absolute', inset: 0, overflow: 'visible', pointerEvents: 'none' }}>\n {nodes.map((n, i) => {\n if (n.kind === 'angle-chip') return null; // rendered as HTML below\n if (n.kind === 'handle') {\n const p = page.transform.toPixels(n.at);\n const hs = cs.handles.size;\n return (\n <rect\n key={i}\n x={p.x - hs / 2}\n y={p.y - hs / 2}\n width={hs}\n height={hs}\n fill={cs.handles.fill}\n stroke={handleStroke}\n strokeWidth={1.5}\n // The square rides a rotated box's orientation (spin about itself).\n {...(n.rot ? { transform: `rotate(${n.rot} ${p.x} ${p.y})` } : {})}\n />\n );\n }\n // A live alignment guide of a snapped move: a through-line at the snapped\n // edge/center, spanning both shapes.\n if (n.kind === 'guide') {\n const a = page.transform.toPixels(\n n.axis === 'x' ? { x: n.at, y: n.lo } : { x: n.lo, y: n.at },\n );\n const b = page.transform.toPixels(\n n.axis === 'x' ? { x: n.at, y: n.hi } : { x: n.hi, y: n.at },\n );\n return (\n <line\n key={i}\n x1={a.x}\n y1={a.y}\n x2={b.x}\n y2={b.y}\n stroke=\"#e91e63\"\n strokeWidth={1.5}\n shapeRendering=\"crispEdges\"\n />\n );\n }\n // An oriented selection box (a tilted shape/group): a closed quad through\n // the four content-space corners — replaces the axis-aligned outline.\n if (n.kind === 'obb') {\n const pts = n.corners\n .map((c) => {\n const p = page.transform.toPixels(c);\n return `${p.x},${p.y}`;\n })\n .join(' ');\n return (\n <polygon\n key={i}\n points={pts}\n fill=\"none\"\n stroke={outlineStroke}\n strokeWidth={cs.outline.width}\n strokeDasharray={outlineDash}\n />\n );\n }\n // Rotation guides (live rotate only): the faint 0°/90° reference cross\n // + the prominent indicator riding the angle — pre-cut page chords, so\n // this is a dumb line loop.\n if (n.kind === 'rotate-guides') {\n const guideDash = cs.guides.style === 'dashed' ? '4 3' : undefined;\n return (\n <g key={i}>\n {n.lines.map((l, j) => {\n const a = page.transform.toPixels(l.a);\n const b = page.transform.toPixels(l.b);\n const axis = l.role === 'axis';\n return (\n <line\n key={j}\n x1={a.x}\n y1={a.y}\n x2={b.x}\n y2={b.y}\n stroke={\n axis\n ? (cs.guides.axisColor ?? cs.accent)\n : (cs.guides.indicatorColor ?? cs.accent)\n }\n opacity={axis ? cs.guides.axisOpacity : cs.guides.indicatorOpacity}\n strokeWidth={cs.guides.width}\n strokeDasharray={guideDash}\n />\n );\n })}\n </g>\n );\n }\n // The rotate knob: a stalk from the top-edge midpoint out to a grab dot.\n if (n.kind === 'rotate-knob') {\n const at = page.transform.toPixels(n.at);\n const from = page.transform.toPixels(n.from);\n return (\n <g key={i}>\n {cs.knob.stalk && (\n <line\n x1={from.x}\n y1={from.y}\n x2={at.x}\n y2={at.y}\n stroke={knobStroke}\n strokeWidth={1}\n />\n )}\n <circle\n cx={at.x}\n cy={at.y}\n r={cs.knob.size / 2}\n fill={cs.knob.fill}\n stroke={knobStroke}\n strokeWidth={1.5}\n />\n </g>\n );\n }\n const b = boxOf(n.rect, page);\n // The marquee rubber band keeps its own look (translucent accent fill,\n // always dashed); the selection outline follows the settings.\n if (n.kind === 'marquee') {\n return (\n <rect\n key={i}\n x={b.left}\n y={b.top}\n width={b.width}\n height={b.height}\n fill={rgba(cs.accent, 0.08)}\n stroke={cs.accent}\n strokeWidth={1}\n strokeDasharray=\"4 3\"\n />\n );\n }\n return (\n <rect\n key={i}\n x={b.left}\n y={b.top}\n width={b.width}\n height={b.height}\n fill=\"none\"\n stroke={outlineStroke}\n strokeWidth={cs.outline.width}\n strokeDasharray={outlineDash}\n />\n );\n })}\n </svg>\n {chip && chipAt && (\n <div\n style={{\n position: 'absolute',\n left: chipAt.x + 16,\n top: chipAt.y - 28,\n background: 'rgba(0,0,0,0.8)',\n color: '#fff',\n padding: '2px 6px',\n borderRadius: 4,\n fontSize: 12,\n fontFamily: 'monospace',\n pointerEvents: 'none',\n whiteSpace: 'nowrap',\n zIndex: 1,\n }}\n >\n {chip.angle}°\n </div>\n )}\n </>\n );\n}\n\n/**\n * A free-text annotation: the SAME styled element for viewing and editing —\n * `contentEditable` just toggles, so the text never jumps. The plugin handed us\n * a ready-to-spread body style (`item.css`) and the rich paragraphs\n * (`item.richText`); the shared `attachRichTextEditor` binding renders them\n * as inline-styled spans, serialises typing back, maps the selection to flat\n * offsets and keeps the caret through a restyle; the browser owns layout,\n * caret, IME and clipboard; the plugin owns the text truth, the range\n * routing and the debounced engine write. This component is the ENTIRE\n * per-framework surface for text editing — React's part is the glue below.\n */\nfunction FreeText({ item, page }: { item: TextItem; page: PageContextValue }) {\n const anno = useCapability(AnnotationHostToken);\n const ref = React.useRef<HTMLDivElement>(null);\n const box = boxOf(item.box, page);\n const scale = item.box.width > 0 ? box.width / item.box.width : 1; // content units → screen px\n // The binding outlives renders; the host closes over the LATEST item.\n const binding = React.useRef<RichTextEditorBinding | null>(null);\n const latest = React.useRef({ item, scale });\n latest.current = { item, scale };\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const host: RichTextEditorHost = {\n onInput: (doc) => {\n const it = latest.current.item;\n if (it.ref) anno.setRichText(it.ref, doc);\n },\n onSelectionChange: (range) => {\n const it = latest.current.item;\n if (it.ref) anno.setTextSelection(it.ref, range);\n },\n onCommand: (command) => anno.toggleTextFormat(command),\n cssFontFamily: (family) => anno.cssFontFamily(family),\n };\n const b = attachRichTextEditor(el, host, {\n document: latest.current.item.richText,\n scale: latest.current.scale,\n });\n binding.current = b;\n return () => {\n b.detach();\n binding.current = null;\n };\n }, [anno]);\n // Model → DOM: the binding skips its own echo (so the caret never jumps\n // while typing) and re-renders — caret restored — for a restyle, a remote\n // edit, or a zoom.\n // Runs on every item change: the binding re-renders only when the document\n // differs, and otherwise just re-states the line model for the element's\n // (possibly restyled) font.\n useEffect(() => {\n binding.current?.update({ document: item.richText, scale });\n }, [item, scale]);\n // The element IS the engine's text PLATE (`SetPlateRect` + its `re W n`\n // clip): positioned at the padding inset with ZERO CSS padding, so the\n // scrollport's edge is the plate edge. CSS padding does NOT clip overflow —\n // scrolled lines slide straight through it and paint over the border band —\n // so the border band must sit OUTSIDE the scrollport, never inside it.\n const pad = item.css.padding * scale;\n const plate = {\n left: box.left + pad,\n top: box.top + pad,\n width: Math.max(0, box.width - 2 * pad),\n height: Math.max(0, box.height - 2 * pad),\n };\n\n // Keep DOM focus in sync with the model's `editing` state. Focus follows the\n // model — it never drives it (exit is hub-driven, see the edit handler), so a\n // transient focus-steal by the page surface can't end the edit.\n useEffect(() => {\n if (item.editing) {\n const el = ref.current;\n if (!el) return;\n el.focus();\n // Enter at the TOP — the same anchoring the baked appearance uses\n // (/Q vertical-align top), so baked → edit → baked never jumps. The\n // browser still follows the caret once the user clicks or types.\n el.scrollTop = 0;\n }\n }, [item.editing]);\n\n // Isolate the editor from the interaction hub: a pointerdown inside it must NOT\n // bubble up to the Stage's native listener (which the edit handler reads as a\n // click-outside → exit). Stopping it here lets the browser own caret placement\n // and drag-selection inside the box, while clicks OUTSIDE still reach the hub and\n // commit the edit. Native listener (not React's) so it runs during real DOM\n // bubbling, before the Stage's own native listener on an ancestor.\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const stop = (e: Event) => e.stopPropagation();\n el.addEventListener('pointerdown', stop);\n return () => el.removeEventListener('pointerdown', stop);\n }, []);\n\n return (\n <div\n ref={ref}\n contentEditable={item.editing}\n suppressContentEditableWarning\n onBlur={(e) => {\n // The gesture that opens the editor fires a native `mousedown` on the\n // non-focusable page surface, which blurs us to <body> (relatedTarget null)\n // right after we focus. If the MODEL still has this box in edit, that blur\n // is a spurious steal — re-assert focus. A real click-away routes through\n // the hub, which clears `editing` BEFORE this fires, so we let it go (and a\n // focus move to a real element, relatedTarget != null, is always honoured).\n if (\n e.relatedTarget == null &&\n ref.current?.isConnected &&\n anno.currentEditing() === item.id\n ) {\n ref.current.focus();\n }\n }}\n style={{\n position: 'absolute',\n left: plate.left,\n top: plate.top,\n width: plate.width,\n // Fixed to the annotation rect's plate — the box never grows with\n // content; it scrolls while editing and clips otherwise, at the SAME\n // boundary the baked /AP clips at (`re W n` on the text body).\n height: plate.height,\n fontFamily: item.css.fontFamily,\n fontSize: item.css.fontSize * scale,\n // No line-height here: the binding states the engine's line model on\n // the element per face (ascent + descent + Acrobat's leading).\n color: item.css.color,\n fontWeight: item.css.fontWeight,\n fontStyle: item.css.fontStyle,\n textDecoration: item.css.textDecoration,\n textAlign: item.css.align,\n boxSizing: 'border-box',\n // The box's fill and border are the vector scene's (below this\n // layer), so a translucent box is painted once.\n background: 'transparent',\n whiteSpace: 'pre-wrap',\n overflowWrap: 'break-word',\n overflowY: item.editing ? 'auto' : 'hidden',\n overflowX: 'hidden',\n outline: item.editing ? '1px solid #3858e9' : 'none',\n cursor: item.editing ? 'text' : 'default',\n // A plain text box rotates about its centre (the box model — same as the\n // baked /AP). `box` is the unrotated box; CSS rotate matches our CW `rot`.\n ...(item.rot ? { transform: `rotate(${item.rot}deg)`, transformOrigin: 'center' } : {}),\n // not editing → clicks fall through to the shape layer (select / move / resize)\n pointerEvents: item.editing ? 'auto' : 'none',\n }}\n />\n );\n}\n\n/**\n * Auto-registered behaviors for `interactive` renderer entries — refcounted\n * per (capability, entry) because the layer mounts once PER PAGE: the first\n * page registers, the last unregisters. Entry identity is the key, hence the\n * \"define entries outside render\" rule on {@link AnnotationRenderer}.\n */\nconst autoBehaviors = new WeakMap<\n object,\n Map<object, { id: string; count: number; unregister: () => void }>\n>();\nlet autoBehaviorSeq = 0;\n\nfunction useAutoBehaviors(\n anno: { registerBehavior(b: Behavior): () => void },\n renderers?: AnnotationRenderer[],\n): void {\n useEffect(() => {\n if (!renderers) return;\n const released: Array<() => void> = [];\n for (const r of renderers) {\n if (!('for' in r) || !r.interactive) continue;\n let perCap = autoBehaviors.get(anno);\n if (!perCap) autoBehaviors.set(anno, (perCap = new Map()));\n let rec = perCap.get(r);\n if (!rec) {\n const id = r.id ?? `renderer:${++autoBehaviorSeq}`;\n const engaged = typeof r.interactive === 'function' ? r.interactive : () => true;\n rec = { id, count: 0, unregister: anno.registerBehavior({ id, matches: r.for, engaged }) };\n perCap.set(r, rec);\n }\n rec.count++;\n const owned = rec;\n released.push(() => {\n owned.count--;\n if (owned.count === 0) {\n owned.unregister();\n autoBehaviors.get(anno)?.delete(r);\n }\n });\n }\n return () => released.forEach((f) => f());\n }, [anno, renderers]);\n}\n\n/** The behavior id a renderer entry answers for (plugin-owned or auto-registered). */\nfunction rendererBehaviorId(anno: object, r: AnnotationRenderer): string | null {\n if ('behavior' in r) return r.behavior;\n return autoBehaviors.get(anno)?.get(r)?.id ?? null;\n}\n\n/** React 18 spells the `inert` attribute as a string spread; it hard-disables\n * pointer AND focus for the whole subtree — the mechanical guarantee that a\n * non-interactive renderer entry (a skin) can never steal input. */\nconst INERT = { inert: '' } as Record<string, string>;\n\nexport function AnnotationLayer({ renderers }: AnnotationLayerProps = {}) {\n const page = usePage();\n const anno = useCapability(AnnotationHostToken);\n // The page's view env (RELATIVE zoom + total display rotation) projects\n // screen-anchored (`noZoom`/`noRotate`) annotations to their effective\n // footprint INSIDE the plugin — no flag logic lives in the framework.\n // `transform.zoom` (not `viewScale`): 1 = the page's physical 100%.\n const viewZoom = page.transform.zoom;\n const viewRotation = page.transform.rotation;\n const items = useSelector(\n AnnotationHostToken,\n (c) => c.pageItems(page.pon, { zoom: viewZoom, rotation: viewRotation }),\n shallowArray,\n );\n const texts = useSelector(\n AnnotationHostToken,\n (c) => c.textItems(page.pon, { zoom: viewZoom, rotation: viewRotation }),\n shallowArray,\n );\n const [urls, setUrls] = useState<Record<string, { url: string; box: Rect }>>({});\n useAutoBehaviors(anno, renderers);\n\n useEffect(() => {\n anno.ensurePage(page.pon);\n }, [anno, page.pon]);\n\n // Baked annotations render from engine rasters — refetch when the page's\n // baked set or an /AP content version changes (a freshly placed stamp, a\n // resize whose re-bake RESOLVED), plus at APPEARANCE-SCALE crossings. A move\n // or a rotate leaves the epoch untouched (the blit repositions the same\n // pixels), and live gesture previews don't touch it either — so no mid-drag\n // spam.\n const bakedKey = useSelector(AnnotationHostToken, (c) => c.appearanceEpoch(page.pon));\n // The bake scale conforms to the document's render policy — the plugin's\n // OWN capability over the kernel-materialized fact (no foreign tokens):\n // zoom ticks inside an appearance-lattice rung re-bake NOTHING; crossing\n // 1→2 re-bakes once; continuous is the identity.\n const bakeScale = useSelector(AnnotationHostToken, (c) =>\n c.bakeScale(page.transform.renderScale),\n );\n\n useEffect(() => {\n const controller = new AbortController();\n const revokers: Array<() => void> = [];\n (async () => {\n try {\n const imgs = await anno.appearances(page.pon, bakeScale, controller.signal);\n const map: Record<string, { url: string; box: Rect }> = {};\n for (const ap of imgs) {\n // Place the baked bitmap by its OWN /Rect (the box it was rendered into),\n // converted to content space by the plugin — never a recomputed bound.\n const box = anno.toContentBox(page.pon, ap.rect);\n if (!box) continue;\n const obj = await ap.image.objectUrl(controller.signal);\n if (controller.signal.aborted) {\n obj.revoke();\n return;\n }\n revokers.push(obj.revoke);\n map[refKey(ap.ref)] = { url: obj.url, box };\n }\n if (!controller.signal.aborted) setUrls(map);\n } catch {\n /* aborted / no appearances */\n }\n })();\n return () => {\n controller.abort();\n revokers.forEach((r) => r());\n };\n }, [anno, page.pon, bakeScale, bakedKey]);\n\n return (\n <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>\n {items.map((item) => {\n // The default visual: the engine's baked raster (blitted into the LIVE\n // AP box — `apBox` follows a move) or the vector scene.\n const baked = urls[item.id];\n const native: React.ReactNode =\n item.source === 'baked' ? (\n baked ? (\n <BakedImage\n box={item.apBox ?? baked.box}\n url={baked.url}\n page={page}\n blend={item.blend}\n rot={item.apRot}\n />\n ) : null\n ) : (\n <Shape item={item} page={page} /> // shapes, cloudy, markup — all painted via scene()\n );\n\n // Ownership beats skin: an ENGAGED behavior's renderer is authoritative\n // (form fill controls own their DOM); `for` rules apply only to\n // plane-owned annotations and render pointer-locked — a skin can change\n // pixels, never steal input.\n const behavior = anno.behaviorFor({ subtype: item.subtype, ref: item.ref });\n let out: React.ReactNode;\n if (behavior) {\n const entry = renderers?.find((r) => rendererBehaviorId(anno, r) === behavior.id);\n if (entry) {\n const Owner = entry.component;\n out = (\n <Owner\n item={item}\n page={page}\n appearance={baked ?? null}\n native={native}\n interactive\n />\n );\n } else {\n out = null; // engaged but no renderer wired — the owner shows nothing\n }\n } else {\n const entry = renderers?.find(\n (r) => 'for' in r && r.for({ subtype: item.subtype, ref: item.ref }),\n );\n if (entry) {\n const Skin = entry.component;\n out = (\n <div {...INERT} style={{ pointerEvents: 'none' }}>\n <Skin\n item={item}\n page={page}\n appearance={baked ?? null}\n native={native}\n interactive={false}\n />\n </div>\n );\n } else {\n out = native;\n }\n }\n return <React.Fragment key={item.id}>{out}</React.Fragment>;\n })}\n {texts.map((t) => (\n <FreeText key={t.id} item={t} page={page} />\n ))}\n <ToolGhostImage page={page} />\n <Chrome page={page} />\n </div>\n );\n}\n\n/**\n * The default file-picker provider: the built-in file dialog (from\n * `@embedpdf/web`), honouring the tool's `accept` filter. This is the ADAPTER\n * fulfilling the plugin's DOM-free port — the dialog lives here, in the\n * framework layer, never in the plugin. A picked `File` carries its own name\n * and mime, so it goes straight through as the engine's file source.\n */\nexport const filePickerProvider: FilePickerProvider = async (req) => {\n const file = await pickFile({ accept: req.accept ?? '*/*' });\n return file ? { data: file } : null;\n};\n\n/**\n * Install the file-picker provider for the active document — the ONE port\n * behind every click-then-pick tool (a stamp `'prompt'` source, the file-\n * attachment tool). Call ONCE at a document-scoped spot (not inside\n * `<AnnotationLayer>`, which is per page). Defaults to\n * {@link filePickerProvider}, so a bare `useFilePickerProvider()` makes all of\n * them work out of the box; pass a custom provider (asset library, cloud\n * drive — switch on `req.subtype` / `req.toolId`) or `null` to make\n * click-then-pick tools inert. Cleared on unmount.\n */\nexport function useFilePickerProvider(\n provider: FilePickerProvider | null = filePickerProvider,\n): void {\n const anno = useOptionalCapability(AnnotationToken);\n useEffect(() => {\n if (!anno) return;\n anno.setFilePickerProvider(provider);\n return () => anno.setFilePickerProvider(null);\n }, [anno, provider]);\n}\n\nexport function useAnnotation() {\n return useCapability(AnnotationToken);\n}\n\nexport function useAnnotationSelection() {\n return useSelector(AnnotationToken, (c) => c.selection(), shallowArray);\n}\n\n/** Structural equality for a resolved props bag — keeps the subscription from\n * re-rendering on unrelated dispatches, since `currentDefaults` returns a fresh\n * object each call. Small flat objects; JSON compare is exact and cheap here. */\nconst sameProps = (a: AnnotationProps, b: AnnotationProps): boolean =>\n a === b || JSON.stringify(a) === JSON.stringify(b);\n\n/**\n * A tool's RESOLVED defaults (base + per-tool override) as a full flat props\n * bag, subscribed so a `setDefaults` re-renders the consumer. Use this — not the\n * imperative `useAnnotation().currentDefaults(id)` — to drive default-editing\n * controls, so they reflect changes live. Pair with `propsForTool(id)` for the\n * specs to render.\n */\nexport function useAnnotationDefaults(toolId: string): AnnotationProps {\n return useSelector(AnnotationToken, (c) => c.currentDefaults(toolId), sameProps);\n}\n\n/**\n * The selection's editable properties — ordered specs shared by every selected\n * kind, current values, and which keys are mixed. THE hook a property sidebar\n * renders from; write back with `useAnnotation().updateSelection({ [key]: v })`.\n * Reference-stable between model changes (the capability memoizes by model\n * identity), so the default equality is enough.\n */\nexport function useSelectionProps(): SelectionProps {\n return useSelector(AnnotationToken, (c) => c.getSelectionProps());\n}\n\n/**\n * The selection's `/F` annotation flags — per-flag `true`/`false`, `null` where\n * the selected annotations disagree (render an indeterminate control), `null`\n * overall when nothing is selected. Write back with\n * `useAnnotation().updateSelectionFlags({ locked: true })`. Reference-stable\n * between model changes, like {@link useSelectionProps}.\n */\nexport function useSelectionFlags(): SelectionFlags | null {\n return useSelector(AnnotationToken, (c) => c.getSelectionFlags());\n}\n\n// ── Comments (the conversation plane) ────────────────────────────────────────\n\n/**\n * A {@link CommentThread} enriched with its page's live display position —\n * the framework-layer join. Identity stays `pageObjectNumber` (like every\n * annotation surface); these two fields are PRESENTATION, tracking page\n * moves and deletes.\n */\nexport interface CommentThreadView extends CommentThread {\n /** Current 0-based display index of the thread's page; `-1` when the page\n * is no longer in the document (one-frame teardown race on delete). */\n pageIndex: number;\n /** The page's `/PageLabels` label when the PDF declares one (\"iv\", \"A-2\"),\n * else the 1-based position as a string — print it verbatim. */\n pageLabel: string;\n /**\n * The root annotation's rect in CONTENT space (y-down, crop-relative,\n * unscaled points) — the space `StageCapability.reveal` takes, so a\n * \"jump to this comment\" is `stage.reveal(pageIndex, { rect: contentRect })`.\n * Null when the page is gone. Identity still travels as `pageObjectNumber`;\n * this, like `pageIndex`, is presentation.\n */\n contentRect: Rect | null;\n}\n\n/** Pure join behind {@link useCommentThreads} — exported for tests. */\nexport function enrichCommentThreads(\n threads: readonly CommentThread[],\n pages: readonly PageLayout[],\n): CommentThreadView[] {\n const byPon = new Map(pages.map((p) => [p.pageObjectNumber, p] as const));\n return threads.map((t) => {\n const page = byPon.get(t.pageObjectNumber);\n return {\n ...t,\n pageIndex: page ? page.index : -1,\n pageLabel: page ? (page.label ?? String(page.index + 1)) : '?',\n contentRect: page ? pdfToContentRect(t.root.rect, page.boxes.crop) : null,\n };\n });\n}\n\n/** The comments surface (verbs + `permissionsFor`) — imperative; pair with\n * {@link useCommentThreads} for the subscribed view. */\nexport function useComments(): CommentsApi {\n return useCapability(AnnotationToken).comments;\n}\n\nconst EMPTY_PAGES: readonly PageLayout[] = [];\n\n/**\n * Every comment thread in the document, display-ordered (page position →\n * top of page → creation date) and enriched with `pageIndex`/`pageLabel`.\n * Subscribed to BOTH stores: annotation writes (own, remote, hydration)\n * recompute the threads; page moves/deletes re-run the join. Reference-\n * stable between changes — safe to memo child renders on the array.\n */\nexport function useCommentThreads(): CommentThreadView[] {\n const docId = useDocumentId();\n const threads = useSelector(AnnotationToken, (c) => c.comments.threads());\n const pages = useKernelValue((k) =>\n docId ? (k.getState().core.documents[docId]?.pages ?? EMPTY_PAGES) : EMPTY_PAGES,\n );\n return React.useMemo(() => enrichCommentThreads(threads, pages), [threads, pages]);\n}\n\n/** The enriched thread containing ANY member ref (root, reply, grouped part,\n * state annotation), or null. */\nexport function useCommentThread(ref: AnnotationRef | null): CommentThreadView | null {\n const views = useCommentThreads();\n const api = useComments();\n if (ref == null) return null;\n const t = api.thread(ref);\n if (!t) return null;\n return views.find((v) => refKey(v.root.ref) === refKey(t.root.ref)) ?? null;\n}\n\n/** Whole-document hydration status — the comments sidebar's honest loading\n * state (`loading` until `listRawAll` lands, then `complete`/`error`). */\nexport function useCommentsHydration(): AnnotationHydration {\n return useSelector(AnnotationToken, (c) => c.comments.hydration());\n}\n"],"mappings":"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"}
@@ -6,6 +6,7 @@ let react = require("react");
6
6
  react = require_rolldown_runtime.__toESM(react, 1);
7
7
  let _embedpdf_plugin_interaction_contract = require("@embedpdf/plugin-interaction/contract");
8
8
  let _embedpdf_plugin_form = require("@embedpdf/plugin-form");
9
+ let _embedpdf_plugin_signature_contract = require("@embedpdf/plugin-signature/contract");
9
10
  //#region src/form-focus-ring.tsx
10
11
  /**
11
12
  * Paint the form focus indicator above baked PDF appearances and transparent
@@ -223,8 +224,68 @@ function FormWidget({ item, page, appearance }) {
223
224
  page,
224
225
  appearance
225
226
  });
227
+ case "signature": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SignatureWidget, {
228
+ fill,
229
+ item,
230
+ page,
231
+ appearance
232
+ });
226
233
  }
227
234
  }
235
+ /** The form plugin's field key → the engine ref (the inverse of `fieldKeyOf`). */
236
+ const fieldRefOfKey = (key) => key.startsWith("obj:") ? {
237
+ kind: "objectNumber",
238
+ fieldObjectNumber: Number(key.slice(4))
239
+ } : {
240
+ kind: "fqn",
241
+ name: key.slice(4)
242
+ };
243
+ /**
244
+ * A signature field's widget: the picture (the mark drawn into it, once
245
+ * there is one) with a click target on top. Unsigned → "sign here": the
246
+ * field becomes the signature plugin's TARGET, so the next mark picked
247
+ * from a signatures panel goes into it. Signed → `inspect`: the chrome shows
248
+ * what the signature says. Without the signature plugin the widget is
249
+ * picture only — the field plane has no fill control of its own here.
250
+ */
251
+ function SignatureWidget({ fill, item, page, appearance }) {
252
+ const signature = require_runtime.useOptionalCapability(_embedpdf_plugin_signature_contract.SignatureToken);
253
+ const wrap = useIsolated();
254
+ const events = useWidgetEvents(fill.key, item.ref);
255
+ const b = viewBox(item.box, page);
256
+ const ref = fieldRefOfKey(fill.key);
257
+ const signed = require_runtime.useOptionalSelector(_embedpdf_plugin_signature_contract.SignatureToken, (c) => c.signatureOf(ref)?.signed ?? fill.signed, fill.signed);
258
+ const actionable = signature != null && (signed || !fill.disabled);
259
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
260
+ ref: wrap,
261
+ ...events,
262
+ style: {
263
+ position: "absolute",
264
+ left: b.left,
265
+ top: b.top,
266
+ width: b.width,
267
+ height: b.height
268
+ },
269
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Picture, {
270
+ page,
271
+ appearance,
272
+ apBox: item.apBox,
273
+ frame: b
274
+ }), actionable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
275
+ type: "button",
276
+ "aria-label": fill.label,
277
+ "data-signed": signed ? "" : void 0,
278
+ onClick: () => signed ? signature.inspect(ref) : signature.setTarget(ref),
279
+ style: {
280
+ ...fillControl,
281
+ padding: 0,
282
+ border: 0,
283
+ background: "transparent",
284
+ cursor: "pointer"
285
+ }
286
+ }) : null]
287
+ });
288
+ }
228
289
  function ButtonWidget({ fill, item, page, appearance }) {
229
290
  const form = require_runtime.useCapability(_embedpdf_plugin_form.FormToken);
230
291
  const wrap = useIsolated();
@@ -740,6 +801,32 @@ function FillButton({ item, page }) {
740
801
  })
741
802
  });
742
803
  }
804
+ /** The standalone layer's signature control: the same target/inspect
805
+ * hand-off as {@link SignatureWidget}, over the page raster. */
806
+ function FillSignature({ item, page }) {
807
+ const signature = require_runtime.useOptionalCapability(_embedpdf_plugin_signature_contract.SignatureToken);
808
+ const ref = fieldRefOfKey(item.key);
809
+ const signed = require_runtime.useOptionalSelector(_embedpdf_plugin_signature_contract.SignatureToken, (c) => c.signatureOf(ref)?.signed ?? item.signed, item.signed);
810
+ const actionable = signature != null && (signed || !item.disabled);
811
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FillEventBox, {
812
+ item,
813
+ page,
814
+ cursor: actionable ? "pointer" : "default",
815
+ children: actionable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
816
+ type: "button",
817
+ "aria-label": item.label,
818
+ "data-signed": signed ? "" : void 0,
819
+ onClick: () => signed ? signature.inspect(ref) : signature.setTarget(ref),
820
+ style: {
821
+ ...fillControl,
822
+ padding: 0,
823
+ border: 0,
824
+ background: "transparent",
825
+ cursor: "inherit"
826
+ }
827
+ }) : null
828
+ });
829
+ }
743
830
  /**
744
831
  * Fill-mode form controls for one page, positioned from the form model's own
745
832
  * widget geometry — the ANNOTATION-LESS path (a fill-only viewer whose page
@@ -778,6 +865,9 @@ function FormLayer() {
778
865
  }, `${item.key}:${item.annotObjectNumber}`) : item.control === "button" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FillButton, {
779
866
  item,
780
867
  page
868
+ }, `${item.key}:${item.annotObjectNumber}`) : item.control === "signature" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FillSignature, {
869
+ item,
870
+ page
781
871
  }, `${item.key}:${item.annotObjectNumber}`) : null)
782
872
  });
783
873
  }
@@ -833,4 +923,4 @@ Object.defineProperty(exports, "useFormSnapshot", {
833
923
  }
834
924
  });
835
925
 
836
- //# sourceMappingURL=form-D-ZSfGmB.cjs.map
926
+ //# sourceMappingURL=form-BVumS7up.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form-BVumS7up.cjs","names":["useCapability","FormToken","useSelector","useOptionalCapability","SignatureToken","useOptionalSelector","usePage","InteractionToken","shallowArray","useAnnotationSelected"],"sources":["../src/form-focus-ring.tsx","../src/form-listbox.tsx","../src/form.tsx"],"sourcesContent":["import * as React from 'react';\n\nexport interface FormFocusRingProps {\n visible: boolean;\n}\n\n/**\n * Paint the form focus indicator above baked PDF appearances and transparent\n * native controls. Putting an inset outline on the widget wrapper lets an\n * opaque child cover it, which makes rectangular checkboxes and combo boxes\n * appear unfocused even though they are active in the native Tab order.\n */\nexport function FormFocusRing({ visible }: FormFocusRingProps) {\n if (!visible) return null;\n return (\n <span\n aria-hidden=\"true\"\n data-embedpdf-form-focus-ring=\"\"\n style={{\n position: 'absolute',\n inset: 0,\n zIndex: 1,\n boxSizing: 'border-box',\n outline: '2px solid rgba(66, 133, 244, 0.8)',\n outlineOffset: -2,\n pointerEvents: 'none',\n }}\n />\n );\n}\n","import * as React from 'react';\nimport { useEffect, useRef, useState } from 'react';\n\nexport interface NativeListBoxOption {\n label: string;\n value: string;\n}\n\nexport interface NativeListBoxProps {\n ariaLabel: string;\n disabled: boolean;\n multi: boolean;\n options: NativeListBoxOption[];\n selected: string[];\n onSelect(values: string[]): void | Promise<void>;\n onFocus?: React.FocusEventHandler<HTMLSelectElement>;\n onBlur?: React.FocusEventHandler<HTMLSelectElement>;\n style?: React.CSSProperties;\n}\n\n/**\n * A PDF list box needs one owner for pixels, hit-testing, and scrolling. A\n * baked /AP picture with an invisible native select cannot provide that: the\n * browser and PDF each keep an independent top-visible row. This visible\n * native control keeps a local optimistic selection while the engine write is\n * pending and synchronizes when engine truth changes, without remounting the\n * DOM node or resetting its scroll position.\n */\nexport function NativeListBox({\n ariaLabel,\n disabled,\n multi,\n options,\n selected,\n onSelect,\n onFocus,\n onBlur,\n style,\n}: NativeListBoxProps) {\n const [draft, setDraft] = useState<string[]>(() => [...selected]);\n const controlRef = useRef<HTMLSelectElement>(null);\n const selectedRef = useRef(selected);\n selectedRef.current = selected;\n const selectedSignature = JSON.stringify(selected);\n\n useEffect(() => {\n const control = controlRef.current;\n if (!control) return;\n // The Stage's ambient wheel handler lives on an ancestor and\n // preventDefault()s to pan/zoom the page. Stop at the list box so the\n // browser can apply the same wheel event to this control's own scroll box.\n const isolateWheel = (event: WheelEvent) => event.stopPropagation();\n control.addEventListener('wheel', isolateWheel);\n return () => control.removeEventListener('wheel', isolateWheel);\n }, []);\n\n useEffect(() => {\n setDraft([...selectedRef.current]);\n }, [selectedSignature]);\n\n const rollback = () => setDraft([...selectedRef.current]);\n const choose = (values: string[]) => {\n setDraft(values);\n try {\n const result = onSelect(values);\n if (result) void result.catch(rollback);\n } catch {\n rollback();\n }\n };\n\n return (\n <select\n ref={controlRef}\n aria-label={ariaLabel}\n multiple={multi}\n size={Math.max(2, options.length)}\n disabled={disabled}\n value={multi ? draft : (draft[0] ?? '')}\n onFocus={onFocus}\n onBlur={onBlur}\n onChange={(event) =>\n choose(Array.from(event.currentTarget.selectedOptions).map((option) => option.value))\n }\n style={style}\n >\n {options.map((option, index) => (\n <option key={index} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n );\n}\n","/**\n * The React view of @embedpdf/plugin-form.\n *\n * TWO fill surfaces, one plugin:\n *\n * 1. `formWidgetRenderer` — the full-viewer path. Widgets are annotations,\n * so the fill controls plug into the annotation stack:\n * `<AnnotationLayer renderers={[formWidgetRenderer]} />` routes every\n * ENGAGED widget here with its live box and its baked /AP raster. The\n * picture IS the resting control (the engine's own rendering of value,\n * check state, borders, fonts); these components add exactly the\n * interaction skin on top:\n *\n * text → picture at rest; click swaps in an <input>/<textarea> (the\n * focused element IS the draft store — the plugin model only\n * learns a value on commit); blur/Enter commits, the engine\n * re-bakes the /AP, the refreshed picture replaces the editor.\n * toggle → the picture is the whole control; click writes the toggled\n * value; the re-baked appearance shows the new check state.\n * combo → an invisible native <select> over the picture: the browser\n * owns the dropdown, the engine owns the resting pixels.\n * list → a visible native <select>: one surface owns pixels, row\n * hit-testing, keyboard selection, and scrolling.\n * button → native keyboard/click target over the picture; activation is\n * delegated to the form plugin's isolated scripting pipeline.\n *\n * 2. `<FormLayer />` — the annotation-less path (fill-only viewers with no\n * annotation plugin): synthetic HTML controls positioned from the form\n * model's own widget geometry. Do NOT mount it next to an AnnotationLayer\n * wired with `formWidgetRenderer` — the controls would double up.\n *\n * Every control isolates its pointerdown from the interaction hub with a\n * NATIVE listener (the FreeText precedent): the Stage listens natively on an\n * ancestor, so React's synthetic events would run too late.\n */\n\n// One-line-per-feature (ADAPTERS.md): registration travels with the UI.\nexport * from '@embedpdf/plugin-form';\nimport * as React from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { PdfAnnotationEventKind } from '@embedpdf/plugin-actions/contract';\nimport type { AnnotationRef } from '@embedpdf/plugin-annotation/contract';\nimport { FormToken } from '@embedpdf/plugin-form';\nimport { SignatureToken } from '@embedpdf/plugin-signature/contract';\nimport type { FormFieldRef, FillItem, FormFieldDTO } from '@embedpdf/plugin-form';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\nimport { StageToken } from '@embedpdf/plugin-stage/contract';\nimport type { Rect } from '@embedpdf/core-annotation';\n\nimport { useAnnotationSelected } from './annotation-hooks';\nimport type { AnnotationRenderer, AnnotationRendererProps } from './annotation';\nimport {\n shallowArray,\n useCapability,\n useOptionalCapability,\n useOptionalSelector,\n usePage,\n useSelector,\n} from './runtime';\nimport type { PageContextValue } from './runtime';\nimport { FormFocusRing } from './form-focus-ring';\nimport { NativeListBox } from './form-listbox';\n\n/** Content rect → a view-px box (the page wrapper's own coordinate space). */\nfunction viewBox(r: Rect, page: PageContextValue) {\n const tl = page.transform.toPixels({ x: r.x, y: r.y });\n const br = page.transform.toPixels({ x: r.x + r.width, y: r.y + r.height });\n return { left: tl.x, top: tl.y, width: br.x - tl.x, height: br.y - tl.y };\n}\n\n/**\n * Keep the interaction hub out of gestures that begin inside a fill control.\n * Native listener (not React's) so it runs during real DOM bubbling, before\n * the Stage's own native listener on an ancestor — same trick as FreeText.\n */\nfunction useIsolated<T extends HTMLElement>() {\n const ref = useRef<T>(null);\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const stop = (e: Event) => e.stopPropagation();\n el.addEventListener('pointerdown', stop);\n return () => el.removeEventListener('pointerdown', stop);\n }, []);\n return ref;\n}\n\n/**\n * The widget DOM-event feed (Phase 2): wire one widget surface's pointer and\n * focus events to `form.notifyWidgetEvent` — the `/AA` E/X/D/U/Fo/Bl trigger\n * door. Handlers live on the ALWAYS-ACTIVE event surface, never the inner\n * control: \"may edit this field\" and \"may receive PDF action events\" are\n * different rights, and a read-only session (no `doc.forms.fill`) must still\n * see hover tooltips (session Hide needs no write authority).\n */\nfunction useWidgetEvents(\n key: string,\n annotationRef: AnnotationRef | null,\n): Pick<\n React.DOMAttributes<HTMLElement>,\n 'onPointerEnter' | 'onPointerLeave' | 'onPointerDown' | 'onPointerUp' | 'onFocus' | 'onBlur'\n> {\n const form = useCapability(FormToken);\n const refBox = useRef(annotationRef);\n refBox.current = annotationRef;\n return useMemo(() => {\n const notify = (event: PdfAnnotationEventKind) => {\n const target = refBox.current;\n if (target) form.notifyWidgetEvent(key, target, event);\n };\n return {\n onPointerEnter: () => notify('cursorEnter'),\n onPointerLeave: () => notify('cursorExit'),\n onPointerDown: () => notify('mouseDown'),\n onPointerUp: () => notify('mouseUp'),\n // React focus/blur bubble (focusin semantics), so the inner control's\n // focus reaches this surface; blur fires AFTER the control's own\n // commit handler, so a /Bl script always sees the committed value.\n onFocus: () => notify('focus'),\n onBlur: () => notify('blur'),\n };\n }, [form, key]);\n}\n\n/**\n * Widget ACTIVATION: a click on ANY widget runs its `/A`. ISO puts the\n * activate action on the annotation dictionary — any subtype, any field\n * type — so activation is a WIDGET behavior, not a push-button behavior:\n * real-world producers ship \"buttons\" as read-only text fields carrying an\n * `/A` (the Test Lab's Reset/Next/Hide controls), and Acrobat runs them.\n * A widget without an `/A` resolves inert — dispatching is the cheap,\n * honest way to ask (the dispatcher owns `/A`-vs-`/AA U` precedence).\n * Push buttons keep their own gated door: `disabled` still blocks\n * activation there — unchanged shipped semantics.\n */\nfunction useWidgetActivation(key: string, annotationRef: AnnotationRef | null): () => void {\n const form = useCapability(FormToken);\n const refBox = useRef(annotationRef);\n refBox.current = annotationRef;\n return useCallback(() => {\n const target = refBox.current;\n if (target) void form.activateWidget(key, target);\n }, [form, key]);\n}\n\n/* ══════════════════════════ behavior widgets ══════════════════════════ */\n\n/** The baked /AP raster, blitted by its OWN box (exactly like BakedImage). */\nfunction Picture({\n page,\n appearance,\n apBox,\n frame,\n hidden,\n}: {\n page: PageContextValue;\n appearance: { url: string; box: Rect } | null;\n /** The item's live AP box — wins over the fetched box when present. */\n apBox?: Rect;\n /** The positioned wrapper this renders INSIDE (its view box) — the blit is\n * page-frame, so subtract the wrapper's origin. Omit when rendering\n * directly in the layer container. */\n frame?: { left: number; top: number };\n hidden?: boolean;\n}) {\n if (!appearance) return null;\n const b = viewBox(apBox ?? appearance.box, page);\n return (\n <img\n src={appearance.url}\n alt=\"\"\n draggable={false}\n style={{\n position: 'absolute',\n left: b.left - (frame?.left ?? 0),\n top: b.top - (frame?.top ?? 0),\n width: b.width,\n height: b.height,\n // Content-unit sizing; a global `img { max-width: 100% }` reset would\n // otherwise clamp it to the containing block and distort the blit.\n maxWidth: 'none',\n pointerEvents: 'none',\n visibility: hidden ? 'hidden' : 'visible',\n }}\n />\n );\n}\n\ninterface WidgetProps<C extends FillItem['control']> {\n fill: Extract<FillItem, { control: C }>;\n item: AnnotationRendererProps['item'];\n page: PageContextValue;\n appearance: AnnotationRendererProps['appearance'];\n}\n\n/**\n * Dispatch one engaged widget to its fill control. The FIELD plane (value,\n * behavior, disabled) comes from the form plugin's single-widget projection;\n * the WIDGET plane (live box, /DA font, baked raster) rides in on the\n * renderer props — no geometry is read from the form model here.\n */\nfunction FormWidget({ item, page, appearance }: AnnotationRendererProps) {\n const annot = item.ref?.kind === 'objectNumber' ? item.ref.annotObjectNumber : 0;\n // Reference-stable per model change, so the default Object.is equality holds.\n const fill = useSelector(FormToken, (c) => (annot > 0 ? c.fillItem(annot) : null));\n // Field plane not loaded (or no fill control for this family) → picture only.\n if (!fill) return <Picture page={page} appearance={appearance} apBox={item.apBox} />;\n switch (fill.control) {\n case 'text':\n return <TextWidget fill={fill} item={item} page={page} appearance={appearance} />;\n case 'toggle':\n return <ToggleWidget fill={fill} item={item} page={page} appearance={appearance} />;\n case 'choice':\n return <ChoiceWidget fill={fill} item={item} page={page} appearance={appearance} />;\n case 'button':\n return <ButtonWidget fill={fill} item={item} page={page} appearance={appearance} />;\n case 'signature':\n return <SignatureWidget fill={fill} item={item} page={page} appearance={appearance} />;\n }\n}\n\n/** The form plugin's field key → the engine ref (the inverse of `fieldKeyOf`). */\nconst fieldRefOfKey = (key: string): FormFieldRef =>\n key.startsWith('obj:')\n ? { kind: 'objectNumber', fieldObjectNumber: Number(key.slice(4)) }\n : { kind: 'fqn', name: key.slice(4) };\n\n/**\n * A signature field's widget: the picture (the mark drawn into it, once\n * there is one) with a click target on top. Unsigned → \"sign here\": the\n * field becomes the signature plugin's TARGET, so the next mark picked\n * from a signatures panel goes into it. Signed → `inspect`: the chrome shows\n * what the signature says. Without the signature plugin the widget is\n * picture only — the field plane has no fill control of its own here.\n */\nfunction SignatureWidget({ fill, item, page, appearance }: WidgetProps<'signature'>) {\n const signature = useOptionalCapability(SignatureToken);\n const wrap = useIsolated<HTMLDivElement>();\n const events = useWidgetEvents(fill.key, item.ref);\n const b = viewBox(item.box, page);\n const ref = fieldRefOfKey(fill.key);\n // The signature plugin's snapshot is the authority on signed-ness (it\n // re-reads on every new version); the field plane's /V is the fallback.\n const signed = useOptionalSelector(\n SignatureToken,\n (c) => c.signatureOf(ref)?.signed ?? fill.signed,\n fill.signed,\n );\n const actionable = signature != null && (signed || !fill.disabled);\n return (\n <div\n ref={wrap}\n {...events}\n style={{ position: 'absolute', left: b.left, top: b.top, width: b.width, height: b.height }}\n >\n <Picture page={page} appearance={appearance} apBox={item.apBox} frame={b} />\n {actionable ? (\n <button\n type=\"button\"\n aria-label={fill.label}\n data-signed={signed ? '' : undefined}\n onClick={() => (signed ? signature.inspect(ref) : signature.setTarget(ref))}\n style={{\n ...fillControl,\n padding: 0,\n border: 0,\n background: 'transparent',\n cursor: 'pointer',\n }}\n />\n ) : null}\n </div>\n );\n}\n\nfunction ButtonWidget({ fill, item, page, appearance }: WidgetProps<'button'>) {\n const form = useCapability(FormToken);\n const wrap = useIsolated<HTMLDivElement>();\n const events = useWidgetEvents(fill.key, item.ref);\n const b = viewBox(item.box, page);\n // The OUTER div is the event surface — always pointer-active so /AA hover\n // and pointer triggers fire even for a disabled/read-only button; the\n // inner button keeps `disabled` as the ACTIVATION gate only.\n return (\n <div\n ref={wrap}\n {...events}\n style={{\n position: 'absolute',\n left: b.left,\n top: b.top,\n width: b.width,\n height: b.height,\n cursor: fill.disabled ? 'default' : 'pointer',\n pointerEvents: 'auto',\n }}\n >\n <button\n type=\"button\"\n aria-label={fill.label}\n disabled={fill.disabled}\n onClick={() => {\n if (item.ref) void form.activateWidget(fill.key, item.ref);\n }}\n style={{\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n boxSizing: 'border-box',\n padding: 0,\n border: 0,\n background: 'transparent',\n cursor: 'inherit',\n // The event surface is the wrapper; a disabled button must not\n // swallow the pointer stream before it bubbles.\n pointerEvents: fill.disabled ? 'none' : 'auto',\n }}\n >\n <Picture page={page} appearance={appearance} apBox={item.apBox} frame={b} />\n </button>\n </div>\n );\n}\n\nfunction TextWidget({ fill, item, page, appearance }: WidgetProps<'text'>) {\n const form = useCapability(FormToken);\n const wrap = useIsolated<HTMLDivElement>();\n const events = useWidgetEvents(fill.key, item.ref);\n const activate = useWidgetActivation(fill.key, item.ref);\n // The editor is ALWAYS MOUNTED (v2's pattern): transparent over the picture\n // at rest, visible while focused. That makes the DOM the focus manager —\n // native Tab order reaches every field, focus enters edit, blur commits —\n // with zero focus machinery of our own. The focused element holds the\n // draft; the plugin model only learns a value on commit (see model.ts).\n const [focused, setFocused] = useState(false);\n const [draft, setDraft] = useState(fill.value);\n const cancelled = useRef(false);\n // Adopt engine truth whenever it changes under us — but never mid-edit.\n useEffect(() => {\n if (!focused) setDraft(fill.value);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [fill.value, focused]);\n\n const b = viewBox(item.box, page);\n const scale = item.box.width > 0 ? b.width / item.box.width : 1;\n\n // /DA font, scaled to view px. Size 0 means \"auto\" in PDF: approximate with\n // the box height for a single line, Acrobat's 12pt default for multiline.\n const fontSize =\n item.text && item.text.fontSize > 0\n ? item.text.fontSize * scale\n : fill.multiline\n ? 12 * scale\n : Math.max(6, b.height * 0.72);\n const editorStyle: React.CSSProperties = {\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n boxSizing: 'border-box',\n border: 'none',\n outline: focused ? '2px solid rgba(66, 133, 244, 0.8)' : 'none',\n outlineOffset: -2,\n padding: '0 2px',\n margin: 0,\n background: item.style.interiorColor ?? '#fff',\n color: item.text?.fontColor ?? '#000',\n fontFamily: item.text?.fontFamily ?? 'Helvetica, Arial, sans-serif',\n fontSize,\n textAlign: item.text?.textAlign ?? 'left',\n resize: 'none',\n cursor: 'text',\n opacity: focused ? 1 : 0, // rest: the engine's picture IS the field\n // A DISABLED control suppresses click events entirely — it must not\n // swallow the stream before it reaches the wrapper, which owns /A\n // activation (the read-only \"fake button\" pattern) and the /AA feed.\n ...(fill.disabled ? { pointerEvents: 'none' as const } : {}),\n };\n const editorProps = {\n value: draft,\n maxLength: fill.maxLength ?? undefined,\n 'aria-label': fill.label,\n disabled: fill.disabled,\n onFocus: () => setFocused(true),\n onChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) =>\n setDraft(e.target.value),\n onBlur: () => {\n setFocused(false);\n if (cancelled.current) {\n cancelled.current = false;\n setDraft(fill.value);\n return;\n }\n if (draft !== fill.value) void form.setText(fill.key, draft);\n },\n style: editorStyle,\n };\n const onKeys = (e: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n if (e.key === 'Escape') {\n cancelled.current = true;\n e.currentTarget.blur();\n }\n if (e.key === 'Enter' && !fill.multiline) e.currentTarget.blur(); // blur commits\n };\n\n return (\n <div\n ref={wrap}\n {...events}\n // ANY widget click runs its /A (see useWidgetActivation): an editable\n // field's focus click bubbles here (Acrobat runs /A on that click\n // too); a read-only field's click lands here directly (the disabled\n // editor is pointer-transparent) — the fake-button pattern.\n onClick={activate}\n style={{\n position: 'absolute',\n left: b.left,\n top: b.top,\n width: b.width,\n height: b.height,\n // Always the event surface (see useWidgetEvents); the editor's own\n // `disabled` keeps read-only fields uneditable and unfocusable.\n pointerEvents: 'auto',\n }}\n >\n <Picture page={page} appearance={appearance} apBox={item.apBox} frame={b} hidden={focused} />\n {fill.multiline ? (\n <textarea {...editorProps} onKeyDown={onKeys} />\n ) : (\n <input {...editorProps} type={fill.password ? 'password' : 'text'} onKeyDown={onKeys} />\n )}\n </div>\n );\n}\n\nfunction ToggleWidget({ fill, item, page, appearance }: WidgetProps<'toggle'>) {\n const form = useCapability(FormToken);\n const wrap = useIsolated<HTMLDivElement>();\n const events = useWidgetEvents(fill.key, item.ref);\n const activate = useWidgetActivation(fill.key, item.ref);\n const [focused, setFocused] = useState(false);\n const b = viewBox(item.box, page);\n const press = () => {\n // Checkbox: click toggles on/off (null clears). Radio: click always\n // selects its own on-state — no untoggle, per PDF/Acrobat convention.\n // Acrobat's order: the VALUE change first, THEN the /A — so an /A\n // script reads the post-toggle state. A read-only toggle still\n // activates (it just doesn't flip).\n const flipped = fill.disabled\n ? undefined\n : form.toggle(fill.key, fill.kind === 'checkbox' && fill.checked ? null : fill.onState);\n void Promise.resolve(flipped).then(activate, activate);\n };\n return (\n <div\n ref={wrap}\n role={fill.kind === 'checkbox' ? 'checkbox' : 'radio'}\n aria-checked={fill.checked}\n aria-label={fill.label}\n tabIndex={fill.disabled ? -1 : 0}\n {...events}\n onClick={press}\n onFocus={(e) => {\n setFocused(true);\n events.onFocus?.(e);\n }}\n onBlur={(e) => {\n setFocused(false);\n events.onBlur?.(e);\n }}\n onKeyDown={(e) => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n press();\n }\n }}\n style={{\n position: 'absolute',\n left: b.left,\n top: b.top,\n width: b.width,\n height: b.height,\n cursor: fill.disabled ? 'default' : 'pointer',\n pointerEvents: 'auto', // always the event surface; toggle() self-gates\n outline: 'none', // the top-layer FormFocusRing owns focus indication\n }}\n >\n <Picture page={page} appearance={appearance} apBox={item.apBox} frame={b} />\n <FormFocusRing visible={focused} />\n </div>\n );\n}\n\nfunction ChoiceWidget(props: WidgetProps<'choice'>) {\n return props.fill.kind === 'list' ? <ListBoxWidget {...props} /> : <ComboBoxWidget {...props} />;\n}\n\nfunction ChoiceFrame({\n fill,\n item,\n page,\n focused,\n innerRef,\n children,\n}: Pick<WidgetProps<'choice'>, 'fill' | 'item' | 'page'> & {\n focused: boolean;\n innerRef: React.RefObject<HTMLDivElement>;\n children: React.ReactNode;\n}) {\n const events = useWidgetEvents(fill.key, item.ref);\n const activate = useWidgetActivation(fill.key, item.ref);\n const b = viewBox(item.box, page);\n return (\n <div\n ref={innerRef}\n {...events}\n onClick={activate}\n style={{\n position: 'absolute',\n left: b.left,\n top: b.top,\n width: b.width,\n height: b.height,\n pointerEvents: 'auto',\n outline: 'none', // the top-layer FormFocusRing owns focus indication\n }}\n >\n {children}\n <FormFocusRing visible={focused} />\n </div>\n );\n}\n\nfunction ComboBoxWidget({ fill, item, page, appearance }: WidgetProps<'choice'>) {\n const form = useCapability(FormToken);\n const wrap = useIsolated<HTMLDivElement>();\n const [focused, setFocused] = useState(false);\n const b = viewBox(item.box, page);\n return (\n <ChoiceFrame fill={fill} item={item} page={page} focused={focused} innerRef={wrap}>\n <Picture page={page} appearance={appearance} apBox={item.apBox} frame={b} />\n {/* A combo's popup is separate from its resting box, so the baked\n appearance and transparent native trigger do not maintain competing\n in-place row geometry or scroll state. */}\n <select\n key={fill.selected.join('\\0')}\n defaultValue={fill.selected[0] ?? ''}\n aria-label={fill.label}\n disabled={fill.disabled}\n onFocus={() => setFocused(true)}\n onBlur={() => setFocused(false)}\n onChange={(e) => {\n const values = Array.from(e.currentTarget.selectedOptions).map((o) => o.value);\n void form.choose(fill.key, values);\n }}\n style={{\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n opacity: 0,\n cursor: fill.disabled ? 'default' : 'pointer',\n // A disabled control suppresses clicks — the frame owns /A\n // activation and must still receive them.\n ...(fill.disabled ? { pointerEvents: 'none' as const } : {}),\n }}\n >\n {fill.options.map((o, i) => (\n <option key={i} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n </ChoiceFrame>\n );\n}\n\nfunction ListBoxWidget({ fill, item, page }: WidgetProps<'choice'>) {\n const form = useCapability(FormToken);\n const wrap = useIsolated<HTMLDivElement>();\n const [focused, setFocused] = useState(false);\n const b = viewBox(item.box, page);\n const scale = item.box.width > 0 ? b.width / item.box.width : 1;\n const strokeWidth = item.style.strokeWidth * scale;\n const borderStyle = item.style.border.kind === 'dashed' ? 'dashed' : 'solid';\n return (\n <ChoiceFrame fill={fill} item={item} page={page} focused={focused} innerRef={wrap}>\n <NativeListBox\n ariaLabel={fill.label}\n disabled={fill.disabled}\n multi={fill.multi}\n options={fill.options}\n selected={fill.selected}\n onFocus={() => setFocused(true)}\n onBlur={() => setFocused(false)}\n onSelect={(values) => form.choose(fill.key, values)}\n style={{\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n boxSizing: 'border-box',\n margin: 0,\n padding: 0,\n borderWidth: strokeWidth,\n borderStyle,\n borderColor: item.style.color,\n borderRadius: 0,\n outline: 'none',\n background: item.style.interiorColor ?? '#fff',\n color: item.text?.fontColor ?? '#000',\n fontFamily: item.text?.fontFamily ?? 'Helvetica, Arial, sans-serif',\n fontSize: (item.text?.fontSize || 12) * scale,\n textAlign: item.text?.textAlign ?? 'left',\n cursor: fill.disabled ? 'default' : 'pointer',\n // A disabled control suppresses clicks — the frame owns /A\n // activation and must still receive them.\n ...(fill.disabled ? { pointerEvents: 'none' as const } : {}),\n }}\n />\n </ChoiceFrame>\n );\n}\n\n/**\n * The form plugin's renderer entry, ready for\n * `<AnnotationLayer renderers={[formWidgetRenderer]} />`. It answers for the\n * PLUGIN-registered 'form-widgets' Behavior — the form plugin decides when\n * widgets are fill controls vs. editable annotations, never the app.\n */\nexport const formWidgetRenderer: AnnotationRenderer = {\n behavior: 'form-widgets',\n component: FormWidget,\n};\n\n/* ══════════════════════ standalone layer (no annotations) ══════════════════ */\n\nconst controlBase: React.CSSProperties = {\n position: 'absolute',\n boxSizing: 'border-box',\n border: '1px solid rgba(56, 88, 233, 0.55)',\n background: 'rgba(255, 255, 255, 0.92)',\n borderRadius: 2,\n font: 'inherit',\n};\n\nconst fillBox = (item: FillItem, page: PageContextValue) => viewBox(item.box, page);\n\n/** The standalone layer's event surface: positions ONE control's box and\n * carries the /AA DOM-event feed — always pointer-active (see\n * useWidgetEvents); the control inside fills it and self-gates edits.\n * With `activate`, a click on the box runs the widget's /A (see\n * useWidgetActivation — activation is a WIDGET behavior); push buttons\n * keep their own gated inner door and do NOT set it. */\nfunction FillEventBox({\n item,\n page,\n cursor,\n activate,\n children,\n}: {\n item: FillItem;\n page: PageContextValue;\n cursor?: string;\n activate?: boolean;\n children: React.ReactNode;\n}) {\n const events = useWidgetEvents(item.key, {\n kind: 'objectNumber',\n pageObjectNumber: page.pon,\n annotObjectNumber: item.annotObjectNumber,\n });\n const onActivate = useWidgetActivation(item.key, {\n kind: 'objectNumber',\n pageObjectNumber: page.pon,\n annotObjectNumber: item.annotObjectNumber,\n });\n const css = fillBox(item, page);\n return (\n <div\n {...events}\n onClick={activate ? onActivate : undefined}\n style={{ position: 'absolute', ...css, pointerEvents: 'auto', ...(cursor ? { cursor } : {}) }}\n >\n {children}\n </div>\n );\n}\n\nconst fillControl: React.CSSProperties = {\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n};\n\n/** Text control: keystrokes stay LOCAL (the input is the draft store);\n * the engine write happens on blur or Enter. */\nfunction FillText({\n item,\n page,\n}: {\n item: Extract<FillItem, { control: 'text' }>;\n page: PageContextValue;\n}) {\n const form = useCapability(FormToken);\n const [draft, setDraft] = useState(item.value);\n // Adopt engine truth whenever it changes under us (remote edit, reset).\n useEffect(() => setDraft(item.value), [item.value]);\n\n const css = fillBox(item, page);\n const fontSize = Math.max(9, Math.min(css.height * 0.62, 24));\n const commit = () => {\n if (draft !== item.value) void form.setText(item.key, draft).catch(() => setDraft(item.value));\n };\n const shared: React.CSSProperties = {\n ...controlBase,\n ...fillControl,\n fontSize,\n padding: '0 3px',\n ...(item.comb ? { letterSpacing: css.width / Math.max(1, item.maxLength ?? 1) / 2 } : {}),\n };\n // A disabled control suppresses clicks — the box owns /A activation and\n // must still receive them (the read-only \"fake button\" pattern).\n const editorGate = item.disabled ? ({ pointerEvents: 'none' } as const) : {};\n return (\n <FillEventBox item={item} page={page} activate>\n {item.multiline ? (\n <textarea\n aria-label={item.label}\n value={draft}\n disabled={item.disabled}\n onChange={(e) => setDraft(e.target.value)}\n onBlur={commit}\n style={{ ...shared, resize: 'none', ...editorGate }}\n />\n ) : (\n <input\n aria-label={item.label}\n type={item.password ? 'password' : 'text'}\n value={draft}\n maxLength={item.maxLength ?? undefined}\n disabled={item.disabled}\n onChange={(e) => setDraft(e.target.value)}\n onBlur={commit}\n onKeyDown={(e) => {\n if (e.key === 'Enter') (e.target as HTMLInputElement).blur();\n }}\n style={{ ...shared, ...editorGate }}\n />\n )}\n </FillEventBox>\n );\n}\n\nfunction FillToggle({\n item,\n page,\n}: {\n item: Extract<FillItem, { control: 'toggle' }>;\n page: PageContextValue;\n}) {\n const form = useCapability(FormToken);\n const activate = useWidgetActivation(item.key, {\n kind: 'objectNumber',\n pageObjectNumber: page.pon,\n annotObjectNumber: item.annotObjectNumber,\n });\n const css = fillBox(item, page);\n const glyphSize = Math.min(css.width, css.height) * 0.72;\n return (\n // `activate` covers the DISABLED path (pointer-transparent button → the\n // box click activates without toggling — a read-only toggle's /A still\n // runs); the enabled button below chains toggle-then-/A itself and\n // stops propagation so the click never double-activates.\n <FillEventBox item={item} page={page} cursor={item.disabled ? 'default' : 'pointer'} activate>\n <button\n role={item.kind}\n aria-checked={item.checked}\n aria-label={item.label}\n disabled={item.disabled}\n onClick={(e) => {\n e.stopPropagation();\n // Checkbox re-click clears; radio click always selects its state.\n // Acrobat's order: the VALUE change first, THEN the /A.\n void Promise.resolve(\n form.toggle(item.key, item.kind === 'checkbox' && item.checked ? null : item.onState),\n ).then(activate, activate);\n }}\n style={{\n ...controlBase,\n ...fillControl,\n cursor: 'inherit',\n display: 'grid',\n placeItems: 'center',\n padding: 0,\n borderRadius: item.kind === 'radio' ? '50%' : 2,\n fontSize: glyphSize,\n lineHeight: 1,\n color: '#1f2a44',\n // A disabled control suppresses clicks — the box must receive them.\n ...(item.disabled ? { pointerEvents: 'none' as const } : {}),\n }}\n >\n {item.checked ? (item.kind === 'radio' ? '●' : '✓') : ''}\n </button>\n </FillEventBox>\n );\n}\n\nfunction FillChoice({\n item,\n page,\n}: {\n item: Extract<FillItem, { control: 'choice' }>;\n page: PageContextValue;\n}) {\n const form = useCapability(FormToken);\n const css = fillBox(item, page);\n // A disabled control suppresses clicks — the box owns /A activation and\n // must still receive them.\n const controlGate = item.disabled ? ({ pointerEvents: 'none' } as const) : {};\n if (item.kind === 'list') {\n return (\n <FillEventBox item={item} page={page} activate>\n <NativeListBox\n ariaLabel={item.label}\n disabled={item.disabled}\n multi={item.multi}\n options={item.options}\n selected={item.selected}\n onSelect={(values) => form.choose(item.key, values)}\n style={{\n ...controlBase,\n ...fillControl,\n fontSize: Math.max(9, Math.min(css.height * 0.55, 18)),\n ...controlGate,\n }}\n />\n </FillEventBox>\n );\n }\n return (\n <FillEventBox item={item} page={page} activate>\n <select\n aria-label={item.label}\n disabled={item.disabled}\n value={item.selected[0] ?? ''}\n onChange={(e) => void form.choose(item.key, [e.target.value])}\n style={{\n ...controlBase,\n ...fillControl,\n fontSize: Math.max(9, Math.min(css.height * 0.55, 18)),\n ...controlGate,\n }}\n >\n {item.selected.length === 0 && <option value=\"\" />}\n {item.options.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n </FillEventBox>\n );\n}\n\nfunction FillButton({\n item,\n page,\n}: {\n item: Extract<FillItem, { control: 'button' }>;\n page: PageContextValue;\n}) {\n const form = useCapability(FormToken);\n return (\n <FillEventBox item={item} page={page} cursor={item.disabled ? 'default' : 'pointer'}>\n <button\n type=\"button\"\n aria-label={item.label}\n disabled={item.disabled}\n onClick={() =>\n void form.activateWidget(item.key, {\n kind: 'objectNumber',\n pageObjectNumber: page.pon,\n annotObjectNumber: item.annotObjectNumber,\n })\n }\n style={{\n ...controlBase,\n ...fillControl,\n padding: 0,\n border: 0,\n background: 'transparent',\n cursor: 'inherit',\n // Events live on the box; a disabled button must not swallow them.\n pointerEvents: item.disabled ? 'none' : 'auto',\n }}\n />\n </FillEventBox>\n );\n}\n\n/** The standalone layer's signature control: the same target/inspect\n * hand-off as {@link SignatureWidget}, over the page raster. */\nfunction FillSignature({\n item,\n page,\n}: {\n item: Extract<FillItem, { control: 'signature' }>;\n page: PageContextValue;\n}) {\n const signature = useOptionalCapability(SignatureToken);\n const ref = fieldRefOfKey(item.key);\n const signed = useOptionalSelector(\n SignatureToken,\n (c) => c.signatureOf(ref)?.signed ?? item.signed,\n item.signed,\n );\n const actionable = signature != null && (signed || !item.disabled);\n return (\n <FillEventBox item={item} page={page} cursor={actionable ? 'pointer' : 'default'}>\n {actionable ? (\n <button\n type=\"button\"\n aria-label={item.label}\n data-signed={signed ? '' : undefined}\n onClick={() => (signed ? signature.inspect(ref) : signature.setTarget(ref))}\n style={{\n ...fillControl,\n padding: 0,\n border: 0,\n background: 'transparent',\n cursor: 'inherit',\n }}\n />\n ) : null}\n </FillEventBox>\n );\n}\n\n/**\n * Fill-mode form controls for one page, positioned from the form model's own\n * widget geometry — the ANNOTATION-LESS path (a fill-only viewer whose page\n * pixels come from an annotated RenderLayer raster). Active whenever the\n * active tool carries the 'form-fill' tag (the built-in pointer/pan tools\n * do); any other tool stands the controls down. Do not mount next to an\n * AnnotationLayer wired with `formWidgetBehaviors`.\n */\nexport function FormLayer() {\n const page = usePage();\n const form = useCapability(FormToken);\n const active = useSelector(InteractionToken, (c) => c.activeTool().enables.has('form-fill'));\n\n useEffect(() => {\n if (active) form.ensureGeom(page.pon);\n }, [active, form, page.pon]);\n\n const items = useSelector(FormToken, (c) => c.fillItems(page.pon), shallowArray);\n if (!active) return null;\n\n return (\n <div style={{ position: 'absolute', inset: 0 }}>\n {items.map((item) =>\n item.control === 'text' ? (\n <FillText key={`${item.key}:${item.annotObjectNumber}`} item={item} page={page} />\n ) : item.control === 'toggle' ? (\n <FillToggle key={`${item.key}:${item.annotObjectNumber}`} item={item} page={page} />\n ) : item.control === 'choice' ? (\n <FillChoice key={`${item.key}:${item.annotObjectNumber}`} item={item} page={page} />\n ) : item.control === 'button' ? (\n <FillButton key={`${item.key}:${item.annotObjectNumber}`} item={item} page={page} />\n ) : item.control === 'signature' ? (\n <FillSignature key={`${item.key}:${item.annotObjectNumber}`} item={item} page={page} />\n ) : null,\n )}\n </div>\n );\n}\n\n/* ═══════════════════════════════ hooks ═══════════════════════════════ */\n\n/** The form capability — values, interchange, design-mode verbs. */\nexport function useForm() {\n return useCapability(FormToken);\n}\n\n/** The reconciled form snapshot (null until the first load lands),\n * re-rendering on every form model change. */\nexport function useFormSnapshot() {\n return useSelector(FormToken, (c) => c.snapshot());\n}\n\n/**\n * The FIELD behind the currently selected widget annotation (single\n * selection), or null. The design-mode join: widget selection lives in the\n * annotation plane, field properties live here.\n */\nexport function useFormField(): FormFieldDTO | null {\n const selected = useAnnotationSelected();\n const widget = selected.length === 1 && selected[0]!.subtype === 'widget' ? selected[0]! : null;\n const objnum = widget && widget.ref.kind === 'objectNumber' ? widget.ref.annotObjectNumber : 0;\n return useSelector(FormToken, (c) => (objnum > 0 ? c.fieldForWidget(objnum) : null));\n}\n"],"mappings":"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"}