@inkbar/react 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -7
- package/dist/index.d.mts +140 -106
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +190 -112
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/context.ts","../src/use-readable.ts","../src/hooks/useDocument.ts","../src/hooks/useAnnotations.ts","../src/hooks/useTool.ts","../src/hooks/useSelection.ts","../src/hooks/useZoom.ts","../src/hooks/usePage.ts","../src/hooks/useHistory.ts","../src/hooks/useEmbedded.ts","../src/use-latest.ts","../src/components/InkRoot.tsx","../src/class-names.ts","../src/components/InkAnnotation.tsx","../src/components/InkPage.tsx","../src/components/InkViewport.tsx","../src/components/InkToolbar.tsx","../src/components/InkToolButton.tsx","../src/components/InkZoomIn.tsx","../src/components/InkZoomOut.tsx","../src/components/InkZoomSelect.tsx","../src/components/InkPageInput.tsx","../src/components/InkPageCount.tsx","../src/compositions/DefaultToolbar.tsx","../src/components/annotation-element.ts","../src/components/popover-focus.ts","../src/components/InkNotePopover.tsx","../src/components/InkSuggestionCard.tsx"],"sourcesContent":["import { createContext, useContext } from 'react'\n\nimport type { Annotation, InkDocument, InkStatus, PdfAssets } from '@inkbar/core'\nimport type { ToolController, ToolId, Viewport, ZoomValue } from '@inkbar/core/dom'\n\nexport type { InkStatus }\n\n/** Undo and redo for the current document, whichever mode its annotations are in. */\nexport interface InkHistory {\n canUndo: boolean\n canRedo: boolean\n undo: () => void\n redo: () => void\n clear: () => void\n /**\n * Runs `fn` and records what it changes as one undo step. The host still receives one change\n * per add. Controlled, the history groups the resulting list changes into one step, and\n * `canUndo` updates once the current task ends. Any other change the host applies in that\n * same window joins the step.\n */\n batch: (fn: () => void) => void\n}\n\nexport interface InkContext {\n assets: PdfAssets\n document: InkDocument | null\n /** `loading` from the moment a document starts opening, then the document's own status. */\n status: InkStatus\n annotations: readonly Annotation[]\n selection: readonly string[]\n /** Set by InkViewport once it has built its viewport and tool controller. */\n viewport: Viewport | null\n tools: ToolController | null\n /** Desired tool; InkViewport applies it to the controller. */\n tool: ToolId\n setTool: (id: ToolId) => void\n /** Desired zoom and page from the host's props; InkViewport applies and reports back. */\n zoomModel: ZoomValue | undefined\n pageModel: number | undefined\n reportZoom: (z: ZoomValue) => void\n reportPage: (p: number) => void\n /** Last activated annotation (Enter, click with the note tool, etc.). Popovers key off this. */\n activated: string | null\n setActivated: (id: string | null) => void\n history: InkHistory\n rootEl: HTMLElement | null\n setViewport: (viewport: Viewport | null, tools: ToolController | null) => void\n}\n\nexport const InkContextObject = createContext<InkContext | null>(null)\n\n/**\n * The context for hooks: throws a readable error when called outside a component rendered\n * inside `InkRoot`.\n */\nexport function useInkContext(consumer: string): InkContext {\n const ctx = useContext(InkContextObject)\n if (!ctx)\n throw new Error(\n `[inkbar] ${consumer} must be called in a component inside <InkRoot>.`\n )\n return ctx\n}\n","import { useCallback, useSyncExternalStore } from 'react'\n\nimport type { Readable } from '@inkbar/core'\n\nconst noop = (): void => undefined\n\n/**\n * Mirrors a core `Readable` into React. A missing readable yields `fallback`, which must be a\n * stable reference (a module constant): `useSyncExternalStore` compares snapshots by identity\n * and loops on a fresh value. On the server the fallback is rendered.\n */\nexport function useReadable<T>(readable: Readable<T> | null | undefined, fallback: T): T {\n const subscribe = useCallback(\n (onChange: () => void) => (readable ? readable.subscribe(() => onChange()) : noop),\n [readable]\n )\n const get = useCallback(\n () => (readable ? readable.get() : fallback),\n [readable, fallback]\n )\n const server = useCallback(() => fallback, [fallback])\n return useSyncExternalStore(subscribe, get, server)\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nimport type { AnnotationDocument, ImportOptions, PageInfo } from '@inkbar/core'\n\nconst NO_PAGES: readonly PageInfo[] = []\n\nexport function useDocument() {\n const ctx = useInkContext('useDocument()')\n const { document, status } = ctx\n return useMemo(\n () => ({\n document,\n status,\n isReady: status.state === 'ready',\n error: status.state === 'error' ? status.error : null,\n pages: document?.pages ?? NO_PAGES,\n info: document?.info ?? null,\n exportAnnotations: () => document?.exportAnnotations('json'),\n importAnnotations: (data: AnnotationDocument | string, opts?: ImportOptions) =>\n document?.importAnnotations(data, opts),\n }),\n [document, status]\n )\n}\n","import { acceptSuggestion, repliesTo } from '@inkbar/core'\nimport { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nimport type { Annotation, AnnotationInput } from '@inkbar/core'\n\nexport function useAnnotations() {\n const ctx = useInkContext('useAnnotations()')\n const { annotations, selection, document } = ctx\n const store = document?.annotations\n const selected = useMemo(\n () =>\n selection\n .map((id) => annotations.find((a) => a.id === id))\n .filter((a): a is Annotation => !!a),\n [annotations, selection]\n )\n // Stable for the life of the document, so hosts can pass them as props or effect deps.\n const actions = useMemo(\n () => ({\n add: (input: AnnotationInput) => store?.add(input),\n update: (id: string, patch: Partial<Annotation>) => store?.update(id, patch),\n remove: (id: string) => store?.remove(id) ?? false,\n select: (ids: string[]) => store?.select(ids),\n /** Keeps a suggested redaction as the user's own, in the default redaction colour. */\n accept: (id: string) => (store ? acceptSuggestion(store, id) : undefined),\n dismiss: (id: string) => store?.remove(id) ?? false,\n }),\n [store]\n )\n return useMemo(\n () => ({\n annotations,\n selection,\n selected,\n byPage: (page: number) => annotations.filter((a) => a.page === page),\n /** Replies in creation order for a note id. */\n replies: (id: string) => repliesTo(annotations, id),\n ...actions,\n }),\n [annotations, selection, selected, actions]\n )\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nexport function useTool() {\n const ctx = useInkContext('useTool()')\n const { tool, setTool } = ctx\n return useMemo(() => ({ tool, setTool }), [tool, setTool])\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nexport function useSelection() {\n const ctx = useInkContext('useSelection()')\n const { selection, document } = ctx\n const store = document?.annotations\n return useMemo(\n () => ({\n selection,\n select: (ids: string[]) => store?.select(ids),\n clear: () => store?.select([]),\n }),\n [selection, store]\n )\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\nimport { useReadable } from '../use-readable'\n\nimport type { ZoomValue } from '@inkbar/core/dom'\n\nexport function useZoom() {\n const ctx = useInkContext('useZoom()')\n const { viewport } = ctx\n const zoom = useReadable<ZoomValue>(viewport?.zoom, 'fit-width')\n const scale = useReadable<number>(viewport?.scale, 1)\n return useMemo(\n () => ({\n zoom,\n scale,\n setZoom: (z: ZoomValue) => viewport?.setZoom(z),\n zoomIn: () => viewport?.zoomBy(1.25),\n zoomOut: () => viewport?.zoomBy(0.8),\n }),\n [viewport, zoom, scale]\n )\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\nimport { useReadable } from '../use-readable'\n\nexport function usePage() {\n const ctx = useInkContext('usePage()')\n const { viewport, document } = ctx\n const current = useReadable<number>(viewport?.currentPage, 0)\n return useMemo(\n () => ({\n /** 0-based. */\n current,\n count: document?.pages.length ?? 0,\n goTo: (index: number) => viewport?.scrollToPage(index),\n // Read the live page, so these stay the same functions as the reader scrolls.\n next: () => viewport?.scrollToPage(viewport.currentPage.get() + 1),\n previous: () => viewport?.scrollToPage(viewport.currentPage.get() - 1),\n scrollToAnnotation(id: string) {\n const a = document?.annotations.get(id)\n if (a) viewport?.scrollToRect(a.page, a.rect)\n },\n }),\n [viewport, document, current]\n )\n}\n","import { useInkContext, type InkHistory } from '../context'\n\n/**\n * Undo and redo. Uncontrolled documents use the core history; controlled hosts that pass\n * `history` to InkRoot get a snapshot stack over their own list, applied through\n * `onAnnotationsChange`.\n */\nexport function useHistory(): InkHistory {\n return useInkContext('useHistory()').history\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nconst NONE: readonly never[] = []\n\nexport function useEmbedded() {\n const ctx = useInkContext('useEmbedded()')\n const summary = ctx.document?.embedded ?? NONE\n return useMemo(\n () => ({\n summary,\n total: summary.reduce((n, s) => n + s.count, 0),\n hasAny: summary.length > 0,\n }),\n [summary]\n )\n}\n","import { useLayoutEffect, useRef, type RefObject } from 'react'\n\n/**\n * A ref that always holds the latest render's value, for callbacks that outlive a render\n * (core's `onChange`, effects keyed on something else). Updated in a layout effect, so it is\n * current before the parent's own layout and passive effects and before any callback fired\n * after commit; declare it before the effects that read it.\n */\nexport function useLatest<T>(value: T): RefObject<T> {\n const ref = useRef(value)\n useLayoutEffect(() => {\n ref.current = value\n })\n return ref\n}\n","import { createSnapshotHistory, InkError, openDocument } from '@inkbar/core'\nimport { cssVariableDefaults } from '@inkbar/core/dom'\nimport { Slot } from 'radix-ui'\nimport {\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type ReactNode,\n type Ref,\n} from 'react'\nimport { flushSync } from 'react-dom'\n\nimport {\n InkContextObject,\n type InkContext,\n type InkHistory,\n type InkStatus,\n} from '../context'\nimport { useLatest } from '../use-latest'\nimport { useReadable } from '../use-readable'\n\nimport type {\n Annotation,\n AnnotationChange,\n AnnotationDefaults,\n DocumentSource,\n InkDocument,\n PdfAssets,\n} from '@inkbar/core'\nimport type { ToolController, ToolId, Viewport, ZoomValue } from '@inkbar/core/dom'\n\nexport interface InkRootHandle {\n readonly document: InkDocument | null\n readonly status: InkStatus\n readonly rootEl: HTMLElement | null\n /** What `useHistory()` returns inside the root. A controlled host calls `clear()` after loading its saved list. */\n readonly history: InkHistory\n}\n\nexport interface InkRootProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'children' | 'onChange' | 'onError'\n> {\n src: DocumentSource | null\n assets: PdfAssets\n password?: string | undefined\n /** Colour defaults. Without it, the theme's CSS variables on the root element apply. */\n defaults?: AnnotationDefaults | undefined\n /**\n * Pass (with `onAnnotationsChange`) to put annotations under the host's control. The mode\n * is fixed when a document opens: passing or dropping this prop later takes effect on the\n * next open.\n */\n annotations?: Annotation[] | undefined\n onAnnotationsChange?: ((next: Annotation[]) => void) | undefined\n onChange?: ((change: AnnotationChange) => void) | undefined\n tool?: ToolId | undefined\n onToolChange?: ((tool: ToolId) => void) | undefined\n page?: number | undefined\n onPageChange?: ((page: number) => void) | undefined\n zoom?: ZoomValue | undefined\n onZoomChange?: ((zoom: ZoomValue) => void) | undefined\n /** Undo history. Defaults to on for uncontrolled, off for controlled. */\n history?: boolean | undefined\n asChild?: boolean | undefined\n onReady?: ((doc: InkDocument) => void) | undefined\n onError?: ((error: InkError) => void) | undefined\n onActivate?: ((id: string) => void) | undefined\n children?:\n | ReactNode\n | ((props: { status: InkStatus; document: InkDocument | null }) => ReactNode)\n ref?: Ref<InkRootHandle>\n}\n\ntype TestHookElement = HTMLElement & { __inkDocument?: InkDocument | undefined }\n\nconst IDLE: InkStatus = { state: 'idle' }\nconst NO_ANNOTATIONS: readonly Annotation[] = []\nconst NO_IDS: readonly string[] = []\n\n/** Signed URLs change; the key does not. Bytes and Blobs are their own identity. */\nfunction identity(src: DocumentSource | null): unknown {\n if (src === null) return null\n if (typeof src === 'string') return src\n if ('key' in src) return src.key\n return src\n}\n\nfunction isDevelopment(): boolean {\n // Bundlers replace the expression with a literal; raw browser ESM has no `process`.\n try {\n return process.env.NODE_ENV !== 'production'\n } catch {\n return false\n }\n}\n\nfunction setTestHook(el: HTMLElement | null, doc: InkDocument | undefined): void {\n if (el && isDevelopment()) (el as TestHookElement).__inkDocument = doc\n}\n\nexport function InkRoot({\n src,\n assets,\n password,\n defaults,\n annotations,\n onAnnotationsChange,\n onChange,\n tool,\n onToolChange,\n page,\n onPageChange,\n zoom,\n onZoomChange,\n history,\n asChild = false,\n onReady,\n onError,\n onActivate,\n children,\n ref,\n ...rest\n}: InkRootProps) {\n const rootElRef = useRef<HTMLElement | null>(null)\n const [rootEl, setRootElState] = useState<HTMLElement | null>(null)\n const setRootEl = useCallback((el: HTMLElement | null) => {\n rootElRef.current = el\n setRootElState(el)\n }, [])\n\n const documentRef = useRef<InkDocument | null>(null)\n const [document, setDocument] = useState<InkDocument | null>(null)\n /** Overrides the document's status while opening, and when opening itself failed. */\n const [override, setOverride] = useState<InkStatus | null>(null)\n const [internalTool, setInternalTool] = useState<ToolId>(tool ?? 'view')\n const [activated, setActivatedState] = useState<string | null>(null)\n const [viewport, setViewportState] = useState<Viewport | null>(null)\n const [tools, setToolsState] = useState<ToolController | null>(null)\n\n const documentStatus = useReadable<InkStatus>(document?.status, IDLE)\n const status = override ?? documentStatus\n const annotationList = useReadable(document?.annotations.list, NO_ANNOTATIONS)\n const selection = useReadable(document?.annotations.selection, NO_IDS)\n\n // What the next open will do follows the prop; the open document's mode is fixed.\n const controlledProp = annotations !== undefined\n const controlled = document\n ? document.annotations.mode === 'controlled'\n : controlledProp\n const historyEnabled = controlled && history === true\n // Callbacks and options read later than the render that passed them.\n const latest = useLatest({\n src,\n assets,\n defaults,\n annotations,\n controlled: controlledProp,\n history,\n historyEnabled,\n onAnnotationsChange,\n onChange,\n onReady,\n onError,\n onActivate,\n onToolChange,\n onPageChange,\n onZoomChange,\n })\n\n const snapshotHistory = useMemo(\n () =>\n createSnapshotHistory({\n apply: (list) => documentRef.current?.annotations.replaceAll(list, 'history'),\n enabled: () => latest.current.historyEnabled,\n }),\n [latest]\n )\n useEffect(() => {\n snapshotHistory.observe(annotations)\n }, [annotations, snapshotHistory])\n\n const srcIdentity = identity(src)\n useEffect(() => {\n let cancelled = false\n snapshotHistory.clear()\n const source = latest.current.src\n if (source === null) {\n setOverride(null)\n return\n }\n setOverride({ state: 'loading' })\n let opened: InkDocument | null = null\n const run = async () => {\n try {\n const doc = await openDocument(source, {\n assets: latest.current.assets,\n password,\n defaults:\n latest.current.defaults ??\n (rootElRef.current ? cssVariableDefaults(rootElRef.current) : undefined),\n // Controlled hosts get the snapshot history below; core's own stack stays off.\n history: latest.current.controlled ? false : (latest.current.history ?? true),\n annotations: latest.current.controlled\n ? {\n mode: 'controlled',\n initial: latest.current.annotations ?? [],\n onChange: (next, change) => {\n // Apply the host's state update, its render and the layout effect that pushes\n // the list back before core's development check expires. The microtask\n // leaves React's render, commit and passive-effect contexts, where a host\n // may call the store, so `flushSync` is always legal; the host sees the\n // proposal one microtask after the store returned. A proposal made in the\n // tick this root unmounts or reopens never reaches the host.\n queueMicrotask(() => {\n if (cancelled) return\n flushSync(() => {\n latest.current.onAnnotationsChange?.(next)\n latest.current.onChange?.(change)\n })\n })\n },\n }\n : { mode: 'uncontrolled' },\n })\n if (cancelled) {\n doc.destroy()\n return\n }\n opened = doc\n // The prop may have changed while the file loaded, when there was no store to apply it to.\n const current = latest.current.annotations\n if (doc.annotations.mode === 'controlled' && current !== undefined)\n doc.annotations.setControlledValue(current)\n documentRef.current = doc\n setDocument(doc)\n setOverride(null)\n setTestHook(rootElRef.current, doc)\n const s = doc.status.get()\n if (s.state === 'ready') latest.current.onReady?.(doc)\n else if (s.state === 'error') latest.current.onError?.(s.error)\n } catch (cause) {\n if (cancelled) return\n const error =\n cause instanceof InkError\n ? cause\n : new InkError(\n 'InvalidPdf',\n cause instanceof Error ? cause.message : String(cause),\n {},\n cause\n )\n setOverride({ state: 'error', error })\n latest.current.onError?.(error)\n }\n }\n // StrictMode's simulated cleanup runs synchronously in the same commit, so deferring one\n // microtask means the discarded first attempt never starts a fetch.\n void Promise.resolve().then(() => {\n if (!cancelled) return run()\n })\n return () => {\n cancelled = true\n opened?.destroy()\n documentRef.current = null\n setDocument(null)\n setTestHook(rootElRef.current, undefined)\n }\n // `srcIdentity` stands in for `src`: a new URL with the same key is the same document.\n }, [srcIdentity, password, snapshotHistory, latest])\n\n useLayoutEffect(() => {\n if (annotations && document?.annotations.mode === 'controlled')\n document.annotations.setControlledValue(annotations)\n }, [annotations, document])\n\n useEffect(() => {\n if (tool) setInternalTool(tool)\n }, [tool])\n\n const setTool = useCallback(\n (id: ToolId) => {\n setInternalTool(id)\n latest.current.onToolChange?.(id)\n },\n [latest]\n )\n const setActivated = useCallback(\n (id: string | null) => {\n setActivatedState(id)\n if (id) latest.current.onActivate?.(id)\n },\n [latest]\n )\n const reportZoom = useCallback(\n (z: ZoomValue) => latest.current.onZoomChange?.(z),\n [latest]\n )\n const reportPage = useCallback(\n (p: number) => latest.current.onPageChange?.(p),\n [latest]\n )\n const setViewport = useCallback((vp: Viewport | null, tc: ToolController | null) => {\n setViewportState(vp)\n setToolsState(tc)\n }, [])\n\n const snapCanUndo = useReadable(snapshotHistory.canUndo, false)\n const snapCanRedo = useReadable(snapshotHistory.canRedo, false)\n const coreCanUndo = useReadable(document?.history.canUndo, false)\n const coreCanRedo = useReadable(document?.history.canRedo, false)\n const inkHistory = useMemo<InkHistory>(\n () => ({\n canUndo: controlled ? historyEnabled && snapCanUndo : coreCanUndo,\n canRedo: controlled ? historyEnabled && snapCanRedo : coreCanRedo,\n undo: () =>\n controlled ? snapshotHistory.undo() : documentRef.current?.history.undo(),\n redo: () =>\n controlled ? snapshotHistory.redo() : documentRef.current?.history.redo(),\n clear: () =>\n controlled ? snapshotHistory.clear() : documentRef.current?.history.clear(),\n batch: (fn) => {\n if (controlled) snapshotHistory.batch(fn)\n else if (documentRef.current) documentRef.current.history.batch(fn)\n else fn()\n },\n }),\n [\n controlled,\n historyEnabled,\n snapCanUndo,\n snapCanRedo,\n coreCanUndo,\n coreCanRedo,\n snapshotHistory,\n ]\n )\n\n useImperativeHandle(ref, () => ({ document, status, rootEl, history: inkHistory }), [\n document,\n status,\n rootEl,\n inkHistory,\n ])\n\n const ctx = useMemo<InkContext>(\n () => ({\n assets,\n document,\n status,\n annotations: annotationList,\n selection,\n viewport,\n tools,\n tool: internalTool,\n setTool,\n zoomModel: zoom,\n pageModel: page,\n reportZoom,\n reportPage,\n activated,\n setActivated,\n history: inkHistory,\n rootEl,\n setViewport,\n }),\n [\n assets,\n document,\n status,\n annotationList,\n selection,\n viewport,\n tools,\n internalTool,\n setTool,\n zoom,\n page,\n reportZoom,\n reportPage,\n activated,\n setActivated,\n inkHistory,\n rootEl,\n setViewport,\n ]\n )\n\n const Comp = asChild ? Slot.Root : 'div'\n return (\n <InkContextObject.Provider value={ctx}>\n <Comp ref={setRootEl} data-ink-root=\"\" data-state={status.state} {...rest}>\n {typeof children === 'function' ? children({ status, document }) : children}\n </Comp>\n </InkContextObject.Provider>\n )\n}\n","/** Joins class names, dropping empties. */\nexport function cx(...parts: (string | undefined | false)[]): string | undefined {\n const out = parts.filter(Boolean).join(' ')\n return out === '' ? undefined : out\n}\n","/*\n * Slot props for one annotation. It renders only its children: the overlay already draws the\n * default visual for every annotation that is not custom, so this never draws a second one.\n * InkPage portals it into the annotation's overlay element.\n */\nimport { acceptSuggestion } from '@inkbar/core'\nimport { useEffect, useMemo, useState, type ReactNode } from 'react'\n\nimport { useInkContext } from '../context'\n\nimport type { Annotation } from '@inkbar/core'\nimport type { AnnotationSlotProps, AnnotationState } from '@inkbar/core/dom'\n\nexport interface InkAnnotationProps {\n annotation: Annotation\n /** The overlay element; its `data-state` (which includes hover) drives `state`. */\n element?: HTMLElement | undefined\n children: (props: AnnotationSlotProps) => ReactNode\n}\n\nfunction readState(el: HTMLElement): AnnotationState | null {\n const s = el.dataset.state\n return s === 'idle' || s === 'hover' || s === 'selected' ? s : null\n}\n\nexport function InkAnnotation({ annotation, element, children }: InkAnnotationProps) {\n const ctx = useInkContext('InkAnnotation')\n const [observed, setObserved] = useState<AnnotationState | null>(() =>\n element ? readState(element) : null\n )\n useEffect(() => {\n if (!element) {\n setObserved(null)\n return\n }\n setObserved(readState(element))\n const observer = new MutationObserver(() => setObserved(readState(element)))\n observer.observe(element, { attributes: true, attributeFilter: ['data-state'] })\n return () => observer.disconnect()\n }, [element])\n\n const { id } = annotation\n const isSuggestion = annotation.type === 'redact' && annotation.origin === 'suggested'\n const locked = annotation.locked === true\n const selected = ctx.selection.includes(id)\n const store = ctx.document?.annotations\n const slotProps = useMemo<AnnotationSlotProps>(\n () => ({\n annotation,\n state: observed ?? (selected ? 'selected' : 'idle'),\n locked,\n select: () => store?.select([id]),\n remove: () => void store?.remove(id),\n accept: () => {\n if (store && isSuggestion) acceptSuggestion(store, id)\n },\n dismiss: () => {\n if (isSuggestion) store?.remove(id)\n },\n }),\n [annotation, observed, selected, locked, store, id, isSuggestion]\n )\n return <>{children(slotProps)}</>\n}\n","/*\n * One page the viewer engine mounted. Renders nothing in place; portals go into the host\n * (page error) and into each annotation's overlay element (custom annotations).\n *\n * The overlay creates and removes those elements as the annotation list changes, outside\n * React. So the portal targets come from a list read after every overlay render: this\n * component subscribes to the store after the overlay does (the engine created the mount\n * first), and core notifies subscribers in order, so the elements already exist when the list\n * arrives here.\n *\n * The engine tracks page errors and sets `data-state=\"error\"` on the host; this component\n * portals the page-error slot into it while `error` is set.\n */\nimport { useEffect, useState, type ReactNode } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { useInkContext } from '../context'\n\nimport { InkAnnotation } from './InkAnnotation'\n\nimport type { Annotation, InkError } from '@inkbar/core'\nimport type { AnnotationSlotProps, PageMount } from '@inkbar/core/dom'\n\nexport interface InkPageProps {\n page: number\n host: HTMLElement\n /** The engine's page mount in `host`. */\n mount: PageMount\n /** The engine's error for this page, `null` while it renders. */\n error: InkError | null\n /** Fixed for the life of the mount: the engine rebuilds when it changes. */\n customAnnotations?: boolean\n renderAnnotation?: ((props: AnnotationSlotProps) => ReactNode) | undefined\n renderPageError?: ((props: { error: InkError; page: number }) => ReactNode) | undefined\n}\n\ninterface Target {\n annotation: Annotation\n el: HTMLElement\n}\n\nfunction sameTargets(a: readonly Target[], b: readonly Target[]): boolean {\n return (\n a.length === b.length &&\n a.every((t, i) => t.annotation === b[i]!.annotation && t.el === b[i]!.el)\n )\n}\n\nexport function InkPage({\n page,\n host,\n mount,\n error,\n customAnnotations = false,\n renderAnnotation,\n renderPageError,\n}: InkPageProps) {\n const doc = useInkContext('InkPage').document\n const [targets, setTargets] = useState<Target[]>([])\n\n useEffect(() => {\n if (!doc || !customAnnotations) return\n const read = (): void => {\n const next = doc.annotations.byPage(page).flatMap((annotation) => {\n const el = mount.overlay.elementFor(annotation.id)\n return el ? [{ annotation, el }] : []\n })\n // A change elsewhere in the document leaves this page's targets as they were.\n setTargets((prev) => (sameTargets(prev, next) ? prev : next))\n }\n const stop = doc.annotations.list.subscribe(read)\n read()\n return () => {\n stop()\n setTargets([])\n }\n }, [doc, page, mount, customAnnotations])\n\n return (\n <>\n {error\n ? createPortal(\n <div className=\"ink-page-error\" data-ink-page-error=\"\" role=\"alert\">\n {renderPageError ? (\n renderPageError({ error, page })\n ) : (\n <>\n <p>Page {page + 1} could not be shown.</p>\n <code className=\"ink-error-code\">{error.code}</code>\n </>\n )}\n </div>,\n host\n )\n : null}\n {renderAnnotation\n ? targets.map((t) =>\n createPortal(\n <InkAnnotation annotation={t.annotation} element={t.el}>\n {renderAnnotation}\n </InkAnnotation>,\n t.el,\n t.annotation.id\n )\n )\n : null}\n </>\n )\n}\n","/*\n * The scroll element is handed to core's `mountViewer`, which builds the viewport, the page\n * layers, the tool controller and the keyboard shortcuts in it; React never renders children\n * into it. The engine reports each page host it mounts, and InkPage components rendered here\n * portal the page-error and custom-annotation slots into them.\n *\n * Two-way zoom and page: the viewport's own changes are reported through the context, and\n * the host's props are applied only when they differ from the viewport's state, so the echo\n * of a reported value does nothing.\n */\nimport { mountViewer } from '@inkbar/core/dom'\nimport {\n useEffect,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from 'react'\n\nimport { cx } from '../class-names'\nimport { useInkContext } from '../context'\nimport { useLatest } from '../use-latest'\n\nimport { InkPage } from './InkPage'\n\nimport type { InkError } from '@inkbar/core'\nimport type {\n AnnotationSlotProps,\n LayoutMode,\n PageMount,\n ViewerEngine,\n ViewRotation,\n ZoomValue,\n} from '@inkbar/core/dom'\n\nexport interface InkViewportProps extends ComponentPropsWithoutRef<'div'> {\n mode?: LayoutMode\n rotation?: ViewRotation\n /** Gap between pages, CSS px. */\n gap?: number\n /** Pages kept mounted either side of the visible ones. */\n buffer?: number\n loading?: ReactNode\n empty?: ReactNode\n error?: ReactNode | ((props: { error: InkError }) => ReactNode)\n renderAnnotation?: ((props: AnnotationSlotProps) => ReactNode) | undefined\n /** Shown inside a page that failed to render. The rest of the document stays usable. */\n renderPageError?: ((props: { error: InkError; page: number }) => ReactNode) | undefined\n}\n\ninterface MountedPage {\n /** The engine build the host belongs to; part of the InkPage key. */\n build: number\n page: number\n host: HTMLElement\n mount: PageMount\n error: InkError | null\n /** Whether the build that mounted the page renders the annotation slot. */\n custom: boolean\n}\n\nexport function InkViewport({\n mode = 'continuous',\n rotation = 0,\n gap = 16,\n buffer = 2,\n loading,\n empty,\n error,\n renderAnnotation,\n renderPageError,\n className,\n ...rest\n}: InkViewportProps) {\n const ctx = useInkContext('InkViewport')\n const scroll = useRef<HTMLDivElement>(null)\n const custom = !!renderAnnotation\n const latest = useLatest({ ctx, mode, rotation, gap, buffer, custom })\n\n const engine = useRef<ViewerEngine | null>(null)\n /** Page hosts, mounts and errors the engine reported; InkPage renders portals for them. */\n const [pages, setPages] = useState<MountedPage[]>([])\n /**\n * Numbered before each build starts, so the pages a build mounts carry its own number. A\n * rebuild gives each page a new host and mount, so pages from an earlier build must remount,\n * not be reused.\n */\n const buildCount = useRef(0)\n /** The construction options the engine was last built with, so a rebuild runs only on a change. */\n const builtWith = useRef<{ gap: number; buffer: number; custom: boolean } | null>(null)\n /** The zoom and page last reported to the host. */\n const lastReportedZoom = useRef<ZoomValue | undefined>(undefined)\n const lastReportedPage = useRef<number | undefined>(undefined)\n\n // Build for a new document or status; tear down on the next change and on unmount.\n useEffect(() => {\n const { ctx: c, mode: m, rotation: r, gap: g, buffer: b, custom: cu } = latest.current\n const doc = c.document\n const el = scroll.current\n lastReportedZoom.current = undefined\n lastReportedPage.current = undefined\n if (!doc || !el || c.status.state !== 'ready') return\n let first = true\n let stops: (() => void)[] = []\n buildCount.current += 1\n builtWith.current = { gap: g, buffer: b, custom: cu }\n const e = mountViewer({\n container: el,\n document: doc,\n zoom: c.zoomModel ?? 'fit-width',\n ...(c.pageModel === undefined ? {} : { page: c.pageModel }),\n mode: m,\n rotation: r,\n gap: g,\n buffer: b,\n tool: c.tool,\n customAnnotations: cu,\n onActivate: (id) => latest.current.ctx.setActivated(id),\n onBuild: (vp, tc) => {\n latest.current.ctx.setViewport(vp, tc)\n if (first) {\n // A new document starts from where the viewport opens (its zoom, on the first page);\n // only later changes are reported, the restored page among them.\n first = false\n lastReportedZoom.current = vp.zoom.get()\n lastReportedPage.current = 0\n }\n for (const stop of stops) stop()\n const reportZoom = (z: ZoomValue): void => {\n if (z === lastReportedZoom.current) return\n lastReportedZoom.current = z\n latest.current.ctx.reportZoom(z)\n }\n const reportPage = (p: number): void => {\n if (p === lastReportedPage.current) return\n lastReportedPage.current = p\n latest.current.ctx.reportPage(p)\n }\n stops = [vp.zoom.subscribe(reportZoom), vp.currentPage.subscribe(reportPage)]\n // Whatever the build restored is reported once; nothing is when it matched.\n reportZoom(vp.zoom.get())\n reportPage(vp.currentPage.get())\n },\n onPageMount: (page, mount, host) => {\n // `buildCount` and `builtWith` belong to the build in progress: both are set before it starts.\n const build = buildCount.current\n const custom = builtWith.current?.custom ?? false\n setPages((prev) => [...prev, { build, page, host, mount, error: null, custom }])\n },\n onPageUnmount: (page) => setPages((prev) => prev.filter((p) => p.page !== page)),\n onPageError: (page, err) =>\n setPages((prev) => prev.map((p) => (p.page === page ? { ...p, error: err } : p))),\n })\n engine.current = e\n return () => {\n for (const stop of stops) stop()\n e.destroy()\n engine.current = null\n builtWith.current = null\n c.setViewport(null, null)\n setPages((prev) => (prev.length === 0 ? prev : []))\n }\n }, [ctx.document, ctx.status.state, latest])\n\n // Construction-only options rebuild the engine for the same document, keeping zoom and page.\n useEffect(() => {\n const built = builtWith.current\n if (!engine.current || !built) return\n if (built.gap === gap && built.buffer === buffer && built.custom === custom) return\n buildCount.current += 1\n builtWith.current = { gap, buffer, custom }\n engine.current.rebuild({ gap, buffer, customAnnotations: custom })\n }, [gap, buffer, custom])\n\n useEffect(() => {\n const vp = engine.current?.viewport\n const z = ctx.zoomModel\n if (vp && z !== undefined && z !== vp.zoom.get()) vp.setZoom(z)\n }, [ctx.zoomModel])\n useEffect(() => {\n const vp = engine.current?.viewport\n const p = ctx.pageModel\n if (!vp || p === undefined || p === lastReportedPage.current) return\n if (p !== vp.currentPage.get()) vp.scrollToPage(p)\n }, [ctx.pageModel])\n useEffect(() => {\n const tc = engine.current?.tools\n if (tc && tc.active.get() !== ctx.tool) tc.set(ctx.tool)\n }, [ctx.tool])\n // The build applied both; these only act on a later change, not on mount.\n useEffect(() => {\n const vp = engine.current?.viewport\n if (vp && vp.mode.get() !== mode) vp.setMode(mode)\n }, [mode])\n useEffect(() => {\n const vp = engine.current?.viewport\n if (vp && vp.rotation.get() !== rotation) vp.setRotation(rotation)\n }, [rotation])\n\n const state = ctx.status.state\n const err = ctx.status.state === 'error' ? ctx.status.error : null\n\n return (\n <div\n {...rest}\n className={cx('ink-viewport-root', className)}\n data-ink-viewport-root=\"\"\n data-state={state}\n >\n {state === 'loading' ? (\n <div className=\"ink-status\" role=\"status\" aria-live=\"polite\">\n {loading === undefined ? 'Loading document…' : loading}\n </div>\n ) : err ? (\n <div className=\"ink-status ink-error\" role=\"alert\">\n {typeof error === 'function' ? (\n error({ error: err })\n ) : error !== undefined ? (\n error\n ) : (\n <>\n <p className=\"ink-error-title\">This document could not be opened.</p>\n {/* The message comes from the PDF engine and is not written for readers: it stays\n off the page, on the code's tooltip. */}\n <p>\n <code className=\"ink-error-code\" title={err.message}>\n {err.code}\n </code>\n </p>\n </>\n )}\n </div>\n ) : state === 'idle' ? (\n <div className=\"ink-status ink-empty\">{empty}</div>\n ) : null}\n <div\n ref={scroll}\n className=\"ink-scroll\"\n data-ink-scroll=\"\"\n tabIndex={0}\n role=\"document\"\n aria-label=\"Document\"\n />\n {pages.map((p) => (\n <InkPage\n key={`${p.build}:${p.page}`}\n page={p.page}\n host={p.host}\n mount={p.mount}\n error={p.error}\n customAnnotations={p.custom}\n renderAnnotation={renderAnnotation}\n renderPageError={renderPageError}\n />\n ))}\n </div>\n )\n}\n","import { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\n\nimport type { ComponentPropsWithoutRef } from 'react'\n\nexport interface InkToolbarProps extends Omit<ComponentPropsWithoutRef<'div'>, 'dir'> {\n /** Radix narrows text direction to these two values. */\n dir?: 'ltr' | 'rtl'\n label?: string\n asChild?: boolean\n}\n\nexport function InkToolbar({\n label = 'Document tools',\n asChild = false,\n className,\n children,\n ...rest\n}: InkToolbarProps) {\n return (\n <Toolbar.Root\n asChild={asChild}\n orientation=\"horizontal\"\n aria-label={label}\n data-ink-toolbar=\"\"\n className={cx('ink-toolbar', className)}\n {...rest}\n >\n {children}\n </Toolbar.Root>\n )\n}\n","import { TOOL_LABELS, type ToolId } from '@inkbar/core/dom'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useTool } from '../hooks/useTool'\n\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react'\n\nexport interface InkToolButtonProps extends Omit<\n ComponentPropsWithoutRef<'button'>,\n 'children'\n> {\n tool: ToolId\n label?: string | undefined\n asChild?: boolean\n children?: ReactNode | ((props: { active: boolean; label: string }) => ReactNode)\n}\n\nexport function InkToolButton({\n tool,\n label,\n asChild = false,\n className,\n children,\n onClick,\n ...rest\n}: InkToolButtonProps) {\n const { tool: current, setTool } = useTool()\n const active = current === tool\n const name = label ?? TOOL_LABELS[tool]\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-tool-button', className)}\n data-ink-tool-button=\"\"\n data-tool={tool}\n data-state={active ? 'on' : 'off'}\n aria-pressed={active}\n aria-label={name}\n title={name}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) setTool(tool)\n }}\n {...rest}\n >\n {typeof children === 'function'\n ? children({ active, label: name })\n : (children ?? name)}\n </Toolbar.Button>\n )\n}\n","import { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useZoom } from '../hooks/useZoom'\n\nimport type { InkZoomButtonProps } from './zoom-button'\n\nexport function InkZoomIn({\n asChild = false,\n className,\n children,\n onClick,\n ...rest\n}: InkZoomButtonProps) {\n const { zoomIn } = useZoom()\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-zoom-in', className)}\n data-ink-zoom-in=\"\"\n aria-label=\"Zoom in\"\n title=\"Zoom in\"\n {...rest}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) zoomIn()\n }}\n >\n {children ?? '+'}\n </Toolbar.Button>\n )\n}\n","import { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useZoom } from '../hooks/useZoom'\n\nimport type { InkZoomButtonProps } from './zoom-button'\n\nexport function InkZoomOut({\n asChild = false,\n className,\n children,\n onClick,\n ...rest\n}: InkZoomButtonProps) {\n const { zoomOut } = useZoom()\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-zoom-out', className)}\n data-ink-zoom-out=\"\"\n aria-label=\"Zoom out\"\n title=\"Zoom out\"\n {...rest}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) zoomOut()\n }}\n >\n {children ?? '−'}\n </Toolbar.Button>\n )\n}\n","import { ZOOM_LEVELS, type ZoomValue } from '@inkbar/core/dom'\n\nimport { cx } from '../class-names'\nimport { useZoom } from '../hooks/useZoom'\n\nimport type { ChangeEvent, ComponentPropsWithoutRef } from 'react'\n\nconst CUSTOM = 'custom:'\nconst level = (z: number) => ZOOM_LEVELS.find((l) => Math.abs(l - z) < 0.001)\n\nexport type InkZoomSelectProps = Omit<\n ComponentPropsWithoutRef<'select'>,\n 'value' | 'onChange'\n>\n\nexport function InkZoomSelect({ className, ...rest }: InkZoomSelectProps) {\n const { zoom, scale, setZoom } = useZoom()\n /** A numeric zoom that is not one of the levels (zoom in and out multiply). */\n const custom = typeof zoom === 'number' && level(zoom) === undefined ? zoom : null\n const value =\n typeof zoom !== 'number'\n ? zoom\n : custom === null\n ? String(level(zoom))\n : `${CUSTOM}${zoom}`\n function onChange(e: ChangeEvent<HTMLSelectElement>): void {\n const v = e.target.value\n const next: ZoomValue =\n v === 'fit-width' || v === 'fit-page' ? v : Number(v.replace(CUSTOM, ''))\n setZoom(next)\n }\n return (\n <select\n className={cx('ink-zoom-select', className)}\n data-ink-zoom-select=\"\"\n aria-label=\"Zoom\"\n value={value}\n onChange={onChange}\n {...rest}\n >\n <option value=\"fit-width\">Fit width</option>\n <option value=\"fit-page\">Fit page</option>\n {ZOOM_LEVELS.map((l) => (\n <option key={l} value={String(l)}>\n {Math.round(l * 100)}%\n </option>\n ))}\n {custom !== null ? (\n <option value={`${CUSTOM}${custom}`}>{Math.round(scale * 100)}%</option>\n ) : null}\n </select>\n )\n}\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type KeyboardEvent,\n} from 'react'\n\nimport { cx } from '../class-names'\nimport { usePage } from '../hooks/usePage'\nimport { useLatest } from '../use-latest'\n\nexport type InkPageInputProps = Omit<\n ComponentPropsWithoutRef<'input'>,\n 'value' | 'onChange' | 'type' | 'min' | 'max'\n>\n\nexport function InkPageInput({\n className,\n onKeyDown: onKeyDownProp,\n ...rest\n}: InkPageInputProps) {\n const { current, count, goTo } = usePage()\n const [draft, setDraft] = useState(String(current + 1))\n useEffect(() => {\n setDraft(String(current + 1))\n }, [current])\n const input = useRef<HTMLInputElement>(null)\n const latest = useLatest({ current, count, goTo })\n\n /** 1-based in the input, 0-based in the viewport. Out of range resets to the current page. */\n const commit = useCallback(\n (value: string) => {\n const { current: page, count: total, goTo: go } = latest.current\n const n = Number(value)\n if (Number.isInteger(n) && n >= 1 && n <= total) {\n if (n - 1 !== page) go(n - 1)\n } else setDraft(String(page + 1))\n },\n [latest]\n )\n // The native `change` event fires when an edit is committed: on blur after typing, and on\n // each step of the spinner or the arrow keys. React's `onChange` is the `input` event, which\n // fires for every keystroke, so the commit listens to the DOM event itself.\n useEffect(() => {\n const el = input.current\n if (!el) return\n const onNativeChange = (): void => commit(el.value)\n el.addEventListener('change', onNativeChange)\n return () => el.removeEventListener('change', onNativeChange)\n }, [commit])\n\n function onKeyDown(e: KeyboardEvent<HTMLInputElement>): void {\n onKeyDownProp?.(e)\n if (e.defaultPrevented || e.key !== 'Enter') return\n e.preventDefault()\n commit(draft)\n }\n return (\n <input\n ref={input}\n className={cx('ink-page-input', className)}\n data-ink-page-input=\"\"\n type=\"number\"\n inputMode=\"numeric\"\n aria-label=\"Page\"\n min={1}\n max={count}\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={onKeyDown}\n {...rest}\n />\n )\n}\n","import { cx } from '../class-names'\nimport { usePage } from '../hooks/usePage'\n\nimport type { ComponentPropsWithoutRef } from 'react'\n\nexport function InkPageCount({ className, ...rest }: ComponentPropsWithoutRef<'span'>) {\n const { count } = usePage()\n return (\n <span\n className={cx('ink-page-count', className)}\n data-ink-page-count=\"\"\n aria-live=\"polite\"\n {...rest}\n >\n {`of ${count}`}\n </span>\n )\n}\n","/*\n * The standard toolbar: tools, zoom and page controls with icons. It adds no styles of its\n * own; the theme styles the `data-ink-*` hooks. Extra controls go in `children`.\n */\nimport {\n Hand,\n Highlighter,\n MessageSquare,\n MousePointer2,\n Square,\n ZoomIn,\n ZoomOut,\n} from 'lucide-react'\n\nimport { cx } from '../class-names'\nimport { InkPageCount } from '../components/InkPageCount'\nimport { InkPageInput } from '../components/InkPageInput'\nimport { InkToolbar } from '../components/InkToolbar'\nimport { InkToolButton } from '../components/InkToolButton'\nimport { InkZoomIn } from '../components/InkZoomIn'\nimport { InkZoomOut } from '../components/InkZoomOut'\nimport { InkZoomSelect } from '../components/InkZoomSelect'\n\nimport type { ReactNode } from 'react'\n\nexport interface DefaultToolbarProps {\n label?: string\n className?: string | undefined\n children?: ReactNode\n}\n\nconst ICON = 18\n\nexport function DefaultToolbar({\n label = 'Document tools',\n className,\n children,\n}: DefaultToolbarProps) {\n return (\n <InkToolbar\n label={label}\n className={cx('ink-default-toolbar', className)}\n data-ink-default-toolbar=\"\"\n >\n <div\n className=\"ink-toolbar-group\"\n data-ink-toolbar-group=\"tools\"\n role=\"group\"\n aria-label=\"Tools\"\n >\n <InkToolButton tool=\"view\">\n <Hand size={ICON} aria-hidden=\"true\" />\n </InkToolButton>\n <InkToolButton tool=\"select\">\n <MousePointer2 size={ICON} aria-hidden=\"true\" />\n </InkToolButton>\n <InkToolButton tool=\"highlight\">\n <Highlighter size={ICON} aria-hidden=\"true\" />\n </InkToolButton>\n <InkToolButton tool=\"redact-area\">\n <Square size={ICON} aria-hidden=\"true\" />\n </InkToolButton>\n <InkToolButton tool=\"note\">\n <MessageSquare size={ICON} aria-hidden=\"true\" />\n </InkToolButton>\n </div>\n <div\n className=\"ink-toolbar-group\"\n data-ink-toolbar-group=\"zoom\"\n role=\"group\"\n aria-label=\"Zoom\"\n >\n <InkZoomOut>\n <ZoomOut size={ICON} aria-hidden=\"true\" />\n </InkZoomOut>\n <InkZoomSelect />\n <InkZoomIn>\n <ZoomIn size={ICON} aria-hidden=\"true\" />\n </InkZoomIn>\n </div>\n <div\n className=\"ink-toolbar-group\"\n data-ink-toolbar-group=\"page\"\n role=\"group\"\n aria-label=\"Page\"\n >\n <InkPageInput />\n <InkPageCount />\n </div>\n {children}\n </InkToolbar>\n )\n}\n","import { observeAnnotationElement } from '@inkbar/core/dom'\nimport { useEffect, useState } from 'react'\n\n/**\n * The overlay element core draws for an annotation, for anchoring a popover to it. Core\n * creates and removes these elements outside React, so this follows the root's subtree while\n * an id is wanted.\n */\nexport function useAnnotationElement(\n root: HTMLElement | null,\n id: string | null\n): HTMLElement | null {\n const [element, setElement] = useState<HTMLElement | null>(null)\n useEffect(() => {\n if (!root || !id) {\n setElement(null)\n return\n }\n return observeAnnotationElement(root, id, setElement)\n }, [root, id])\n return element\n}\n","import {\n createFocusReturn,\n shouldKeepOpenOnAnnotation,\n type FocusReturn,\n} from '@inkbar/core/dom'\nimport { useMemo } from 'react'\n\nimport { useLatest } from '../use-latest'\n\nimport type { InkContext } from '../context'\n\nexport type { FocusReturn }\n\n/** Radix's `onInteractOutside` handler: a press that will activate an annotation keeps the popover open. */\nexport function keepOpenOnAnnotation(event: CustomEvent<{ originalEvent: Event }>): void {\n if (shouldKeepOpenOnAnnotation(event.detail.originalEvent.target))\n event.preventDefault()\n}\n\nexport function useFocusReturn(ctx: InkContext): FocusReturn {\n const latest = useLatest(ctx)\n return useMemo(\n () =>\n createFocusReturn({\n root: () => latest.current.rootEl,\n activated: () => latest.current.activated,\n }),\n [latest]\n )\n}\n","/*\n * The thread for the activated note, anchored to the note's overlay element. Activating a\n * reply opens the whole thread from its root. Closing (Close, Escape, a press outside) clears\n * `activated`.\n *\n * A new note has no text. While its root is empty (and unlocked) the default form writes the\n * root's own `contents`, labelled \"Comment\", and the thread list stays hidden until there is\n * something in it; after that the form adds replies. Closing a root that is still empty and\n * has no replies removes it, so an abandoned note does not stay on the page.\n */\nimport { isAbandonedNote, threadOf, threadRoot } from '@inkbar/core'\nimport { Popover } from 'radix-ui'\nimport {\n useEffect,\n useMemo,\n useRef,\n useState,\n type FormEvent,\n type ReactNode,\n} from 'react'\n\nimport { useInkContext } from '../context'\nimport { useAnnotations } from '../hooks/useAnnotations'\nimport { useLatest } from '../use-latest'\n\nimport { useAnnotationElement } from './annotation-element'\nimport { keepOpenOnAnnotation, useFocusReturn } from './popover-focus'\n\nimport type { Annotation, NoteAnnotation } from '@inkbar/core'\nimport type { NotePopoverSlotProps } from '@inkbar/core/dom'\n\nexport interface InkNotePopoverProps {\n children?: ((props: NotePopoverSlotProps) => ReactNode) | undefined\n}\n\nexport function InkNotePopover({ children }: InkNotePopoverProps) {\n const ctx = useInkContext('InkNotePopover')\n const { annotations, add, update, remove } = useAnnotations()\n\n const note = useMemo<NoteAnnotation | null>(() => {\n const a = ctx.activated ? annotations.find((x) => x.id === ctx.activated) : undefined\n return a?.type === 'note' ? threadRoot(annotations, a) : null\n }, [annotations, ctx.activated])\n const anchor = useAnnotationElement(ctx.rootEl, note?.id ?? null)\n const anchorRef = useMemo(() => ({ current: anchor }), [anchor])\n const focusReturn = useFocusReturn(ctx)\n const open = note !== null && anchor !== null\n /** The root, then every reply below it, depth first, each level in creation order. */\n const thread = useMemo<Annotation[]>(\n () => (note ? threadOf(annotations, note) : []),\n [annotations, note]\n )\n /** True while the default form writes the root note's own text rather than a reply. */\n const editingRoot = note !== null && !note.locked && !note.contents?.trim()\n\n /**\n * Notes this popover wrote text or a reply for. In controlled mode the write is a proposal\n * the host may not have applied yet, so the applied list still shows the note empty; these\n * are never dropped as abandoned.\n */\n const written = useRef(new Set<string>())\n /** Notes this popover has already asked to remove, so a slow host is asked once. */\n const dropped = useRef(new Set<string>())\n const latest = useLatest({ annotations, remove })\n\n function dropIfEmpty(id: string): boolean {\n if (\n dropped.current.has(id) ||\n written.current.has(id) ||\n !isAbandonedNote(latest.current.annotations, id)\n )\n return false\n dropped.current.add(id)\n latest.current.remove(id)\n return true\n }\n\n // Activation moved on from a note that never got any text: drop it.\n const noteId = note?.id\n const previousId = useRef<string | undefined>(undefined)\n useEffect(() => {\n const previous = previousId.current\n if (previous === noteId) return\n previousId.current = noteId\n if (previous !== undefined) dropIfEmpty(previous)\n // dropIfEmpty reads through `latest`; it is stable for the effect's purposes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [noteId])\n\n function reply(text: string): void {\n const root = note\n const contents = text.trim()\n if (!root || !contents) return\n written.current.add(root.id)\n add({ type: 'note', page: root.page, rect: root.rect, contents, inReplyTo: root.id })\n }\n function isEmptyRoot(root: NoteAnnotation): boolean {\n return (\n !written.current.has(root.id) &&\n !root.locked &&\n !root.contents?.trim() &&\n thread.length === 1\n )\n }\n function close(): void {\n const root = note\n if (root && annotations.some((a) => a.id === root.id) && isEmptyRoot(root)) {\n focusReturn.beforeRemove(anchor)\n dropIfEmpty(root.id)\n }\n ctx.setActivated(null)\n }\n function updateContents(contents: string): void {\n if (!note || note.locked) return\n if (contents.trim()) written.current.add(note.id)\n update(note.id, { contents })\n }\n /** Locked notes cannot be removed: removing one does nothing and keeps the popover. */\n function removeThread(): void {\n const root = note\n if (!root || root.locked) return\n focusReturn.beforeRemove(anchor)\n // Under a slow controlled host the note stays listed for a while; it is not asked for again.\n dropped.current.add(root.id)\n remove(root.id)\n ctx.setActivated(null)\n }\n\n return (\n <Popover.Root open={open} onOpenChange={(next) => !next && close()}>\n <Popover.Anchor virtualRef={anchorRef} />\n <Popover.Portal>\n {note && anchor ? (\n <Popover.Content\n className=\"ink-note-popover\"\n data-ink-note-popover=\"\"\n side=\"right\"\n sideOffset={8}\n collisionPadding={8}\n aria-label=\"Note thread\"\n onInteractOutside={keepOpenOnAnnotation}\n onCloseAutoFocus={(e) => focusReturn.onCloseAutoFocus(e, anchor)}\n >\n {children ? (\n children({\n note,\n replies: thread.slice(1),\n reply,\n update: updateContents,\n remove: removeThread,\n close,\n })\n ) : (\n <>\n {!editingRoot || thread.length > 1 ? (\n <ol className=\"ink-thread\" data-ink-thread=\"\">\n {thread.map((item) => (\n <li\n key={item.id}\n className=\"ink-thread-item\"\n data-ink-thread-item=\"\"\n data-reply={item.inReplyTo ? '' : undefined}\n >\n <span className=\"ink-thread-author\">\n {item.author ?? 'Anonymous'}\n </span>\n <time className=\"ink-thread-time\" dateTime={item.createdAt}>\n {new Date(item.createdAt).toLocaleString()}\n </time>\n <p className=\"ink-thread-text\">{item.contents}</p>\n </li>\n ))}\n </ol>\n ) : null}\n <ThreadForm\n // Keyed by note: moving to another note starts with an empty draft at once.\n key={note.id}\n editingRoot={editingRoot}\n locked={!!note.locked}\n onSubmit={(text) => (editingRoot ? updateContents(text) : reply(text))}\n onRemove={removeThread}\n onClose={close}\n />\n </>\n )}\n </Popover.Content>\n ) : null}\n </Popover.Portal>\n </Popover.Root>\n )\n}\n\n/** The default form: the root note's own text while it is empty, replies after that. */\nfunction ThreadForm({\n editingRoot,\n locked,\n onSubmit,\n onRemove,\n onClose,\n}: {\n editingRoot: boolean\n locked: boolean\n onSubmit: (text: string) => void\n onRemove: () => void\n onClose: () => void\n}) {\n const [draft, setDraft] = useState('')\n function submit(e: FormEvent): void {\n e.preventDefault()\n const text = draft.trim()\n if (!text) return\n onSubmit(text)\n setDraft('')\n }\n return (\n <form className=\"ink-thread-reply\" data-ink-thread-reply=\"\" onSubmit={submit}>\n <textarea\n aria-label={editingRoot ? 'Comment' : 'Reply'}\n rows={2}\n placeholder={editingRoot ? 'Comment' : 'Reply'}\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n />\n <div className=\"ink-thread-actions\">\n <button type=\"submit\" disabled={!draft.trim()}>\n {editingRoot ? 'Comment' : 'Reply'}\n </button>\n {!locked ? (\n <button type=\"button\" onClick={onRemove}>\n Delete\n </button>\n ) : null}\n <button type=\"button\" onClick={onClose}>\n Close\n </button>\n </div>\n </form>\n )\n}\n","/*\n * Review card for a suggested redaction: opens when the activated annotation, or the only\n * selected one, is a redaction with `origin: 'suggested'`. Locked suggestions cannot be\n * dismissed, so they get no Dismiss button. A press on the overlay selects and activates, so a\n * click opens it whatever the tool. Closing clears `activated` and the selection.\n */\nimport { confidenceBucket } from '@inkbar/core'\nimport { Popover } from 'radix-ui'\nimport { useMemo, type ReactNode } from 'react'\n\nimport { useInkContext } from '../context'\nimport { useAnnotations } from '../hooks/useAnnotations'\n\nimport { useAnnotationElement } from './annotation-element'\nimport { keepOpenOnAnnotation, useFocusReturn } from './popover-focus'\n\nimport type { ConfidenceBucket, RedactAnnotation } from '@inkbar/core'\nimport type { SuggestionCardSlotProps } from '@inkbar/core/dom'\n\nexport interface InkSuggestionCardProps {\n children?: ((props: SuggestionCardSlotProps) => ReactNode) | undefined\n}\n\nexport function InkSuggestionCard({ children }: InkSuggestionCardProps) {\n const ctx = useInkContext('InkSuggestionCard')\n const {\n annotations,\n selection,\n accept: acceptId,\n dismiss: dismissId,\n select,\n } = useAnnotations()\n\n function suggestion(id: string | null | undefined): RedactAnnotation | null {\n const a = id ? annotations.find((x) => x.id === id) : undefined\n return a?.type === 'redact' && a.origin === 'suggested' ? a : null\n }\n // The activated annotation when it is a suggestion; otherwise the only selected one (a\n // marquee selects without activating).\n const target =\n suggestion(ctx.activated) ??\n (selection.length === 1 ? suggestion(selection[0]) : null)\n const anchor = useAnnotationElement(ctx.rootEl, target?.id ?? null)\n const anchorRef = useMemo(() => ({ current: anchor }), [anchor])\n const focusReturn = useFocusReturn(ctx)\n const open = target !== null && anchor !== null\n const bucket: ConfidenceBucket | undefined = target?.suggestion\n ? confidenceBucket(target.suggestion.confidence)\n : undefined\n\n function close(): void {\n ctx.setActivated(null)\n select([])\n }\n function accept(): void {\n if (target) acceptId(target.id)\n close()\n }\n /** Locked annotations cannot be removed: dismissing one does nothing and keeps the card. */\n function dismiss(): void {\n if (!target || target.locked) return\n focusReturn.beforeRemove(anchor, '[data-origin=\"suggested\"]')\n dismissId(target.id)\n close()\n }\n\n return (\n <Popover.Root open={open} onOpenChange={(next) => !next && close()}>\n <Popover.Anchor virtualRef={anchorRef} />\n <Popover.Portal>\n {target && anchor ? (\n <Popover.Content\n className=\"ink-suggestion-card\"\n data-ink-suggestion-card=\"\"\n side=\"bottom\"\n sideOffset={6}\n collisionPadding={8}\n aria-label=\"Suggested redaction\"\n onInteractOutside={keepOpenOnAnnotation}\n onCloseAutoFocus={(e) => focusReturn.onCloseAutoFocus(e, anchor)}\n >\n {children ? (\n children({\n annotation: target,\n suggestion: target.suggestion,\n bucket,\n accept,\n dismiss,\n close,\n })\n ) : (\n <>\n <p className=\"ink-suggestion-reason\">\n <strong>{target.suggestion?.reason ?? 'Suggested redaction'}</strong>\n {bucket ? (\n <span className=\"ink-suggestion-confidence\" data-confidence={bucket}>\n {bucket} confidence\n </span>\n ) : null}\n </p>\n {target.suggestion?.explanation ? (\n <p className=\"ink-suggestion-explanation\">\n {target.suggestion.explanation}\n </p>\n ) : null}\n <div className=\"ink-suggestion-actions\">\n <button type=\"button\" onClick={accept}>\n Accept\n </button>\n {!target.locked ? (\n <button type=\"button\" onClick={dismiss}>\n Dismiss\n </button>\n ) : null}\n </div>\n </>\n )}\n </Popover.Content>\n ) : null}\n </Popover.Portal>\n </Popover.Root>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/context.ts","../src/use-readable.ts","../src/hooks/useDocument.ts","../src/hooks/useAnnotations.ts","../src/hooks/useTool.ts","../src/hooks/useSelection.ts","../src/hooks/useZoom.ts","../src/hooks/usePage.ts","../src/hooks/useHistory.ts","../src/hooks/useEmbedded.ts","../src/use-latest.ts","../src/components/InkRoot.tsx","../src/class-names.ts","../src/components/InkAnnotation.tsx","../src/components/InkPage.tsx","../src/components/InkViewport.tsx","../src/components/InkToolbar.tsx","../src/components/InkIcon.tsx","../src/components/InkToolButton.tsx","../src/components/InkToolbarSeparator.tsx","../src/components/InkUndo.tsx","../src/components/InkRedo.tsx","../src/components/InkZoomIn.tsx","../src/components/InkZoomOut.tsx","../src/components/InkZoomSelect.tsx","../src/components/InkPageInput.tsx","../src/components/InkPageCount.tsx","../src/components/InkPrevPage.tsx","../src/components/InkNextPage.tsx","../src/components/annotation-element.ts","../src/components/popover-focus.ts","../src/components/InkNotePopover.tsx","../src/components/InkSuggestionCard.tsx"],"sourcesContent":["import { createContext, useContext } from 'react'\n\nimport type { Annotation, InkDocument, InkStatus, PdfAssets } from '@inkbar/core'\nimport type { ToolController, ToolId, Viewport, ZoomValue } from '@inkbar/core/dom'\n\nexport type { InkStatus }\n\n/** Undo and redo for the current document, whichever mode its annotations are in. */\nexport interface InkHistory {\n canUndo: boolean\n canRedo: boolean\n undo: () => void\n redo: () => void\n clear: () => void\n /**\n * Runs `fn` and records what it changes as one undo step. The host still receives one change\n * per add. Controlled, the history groups the resulting list changes into one step, and\n * `canUndo` updates once the current task ends. Any other change the host applies in that\n * same window joins the step.\n */\n batch: (fn: () => void) => void\n}\n\nexport interface InkContext {\n assets: PdfAssets\n document: InkDocument | null\n /** `loading` from the moment a document starts opening, then the document's own status. */\n status: InkStatus\n annotations: readonly Annotation[]\n selection: readonly string[]\n /** Set by InkViewport once it has built its viewport and tool controller. */\n viewport: Viewport | null\n tools: ToolController | null\n /** Desired tool; InkViewport applies it to the controller. */\n tool: ToolId\n setTool: (id: ToolId) => void\n /** Desired zoom and page from the host's props; InkViewport applies and reports back. */\n zoomModel: ZoomValue | undefined\n pageModel: number | undefined\n reportZoom: (z: ZoomValue) => void\n reportPage: (p: number) => void\n /** Last activated annotation (Enter, click with the note tool, etc.). Popovers key off this. */\n activated: string | null\n setActivated: (id: string | null) => void\n history: InkHistory\n rootEl: HTMLElement | null\n setViewport: (viewport: Viewport | null, tools: ToolController | null) => void\n}\n\nexport const InkContextObject = createContext<InkContext | null>(null)\n\n/**\n * The context for hooks: throws a readable error when called outside a component rendered\n * inside `InkRoot`.\n */\nexport function useInkContext(consumer: string): InkContext {\n const ctx = useContext(InkContextObject)\n if (!ctx)\n throw new Error(\n `[inkbar] ${consumer} must be called in a component inside <InkRoot>.`\n )\n return ctx\n}\n","import { useCallback, useSyncExternalStore } from 'react'\n\nimport type { Readable } from '@inkbar/core'\n\nconst noop = (): void => undefined\n\n/**\n * Mirrors a core `Readable` into React. A missing readable yields `fallback`, which must be a\n * stable reference (a module constant): `useSyncExternalStore` compares snapshots by identity\n * and loops on a fresh value. On the server the fallback is rendered.\n */\nexport function useReadable<T>(readable: Readable<T> | null | undefined, fallback: T): T {\n const subscribe = useCallback(\n (onChange: () => void) => (readable ? readable.subscribe(() => onChange()) : noop),\n [readable]\n )\n const get = useCallback(\n () => (readable ? readable.get() : fallback),\n [readable, fallback]\n )\n const server = useCallback(() => fallback, [fallback])\n return useSyncExternalStore(subscribe, get, server)\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nimport type { AnnotationDocument, ImportOptions, PageInfo } from '@inkbar/core'\n\nconst NO_PAGES: readonly PageInfo[] = []\n\nexport function useDocument() {\n const ctx = useInkContext('useDocument()')\n const { document, status } = ctx\n return useMemo(\n () => ({\n document,\n status,\n isReady: status.state === 'ready',\n error: status.state === 'error' ? status.error : null,\n pages: document?.pages ?? NO_PAGES,\n info: document?.info ?? null,\n exportAnnotations: () => document?.exportAnnotations('json'),\n importAnnotations: (data: AnnotationDocument | string, opts?: ImportOptions) =>\n document?.importAnnotations(data, opts),\n }),\n [document, status]\n )\n}\n","import { acceptSuggestion, repliesTo } from '@inkbar/core'\nimport { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nimport type { Annotation, AnnotationInput } from '@inkbar/core'\n\nexport function useAnnotations() {\n const ctx = useInkContext('useAnnotations()')\n const { annotations, selection, document } = ctx\n const store = document?.annotations\n const selected = useMemo(\n () =>\n selection\n .map((id) => annotations.find((a) => a.id === id))\n .filter((a): a is Annotation => !!a),\n [annotations, selection]\n )\n // Stable for the life of the document, so hosts can pass them as props or effect deps.\n const actions = useMemo(\n () => ({\n add: (input: AnnotationInput) => store?.add(input),\n update: (id: string, patch: Partial<Annotation>) => store?.update(id, patch),\n remove: (id: string) => store?.remove(id) ?? false,\n select: (ids: string[]) => store?.select(ids),\n /** Keeps a suggested redaction as the user's own, in the default redaction colour. */\n accept: (id: string) => (store ? acceptSuggestion(store, id) : undefined),\n dismiss: (id: string) => store?.remove(id) ?? false,\n }),\n [store]\n )\n return useMemo(\n () => ({\n annotations,\n selection,\n selected,\n byPage: (page: number) => annotations.filter((a) => a.page === page),\n /** Replies in creation order for a note id. */\n replies: (id: string) => repliesTo(annotations, id),\n ...actions,\n }),\n [annotations, selection, selected, actions]\n )\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nexport function useTool() {\n const ctx = useInkContext('useTool()')\n const { tool, setTool } = ctx\n return useMemo(() => ({ tool, setTool }), [tool, setTool])\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nexport function useSelection() {\n const ctx = useInkContext('useSelection()')\n const { selection, document } = ctx\n const store = document?.annotations\n return useMemo(\n () => ({\n selection,\n select: (ids: string[]) => store?.select(ids),\n clear: () => store?.select([]),\n }),\n [selection, store]\n )\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\nimport { useReadable } from '../use-readable'\n\nimport type { ZoomValue } from '@inkbar/core/dom'\n\nexport function useZoom() {\n const ctx = useInkContext('useZoom()')\n const { viewport } = ctx\n const zoom = useReadable<ZoomValue>(viewport?.zoom, 'fit-width')\n const scale = useReadable<number>(viewport?.scale, 1)\n return useMemo(\n () => ({\n zoom,\n scale,\n setZoom: (z: ZoomValue) => viewport?.setZoom(z),\n zoomIn: () => viewport?.zoomBy(1.25),\n zoomOut: () => viewport?.zoomBy(0.8),\n }),\n [viewport, zoom, scale]\n )\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\nimport { useReadable } from '../use-readable'\n\nexport function usePage() {\n const ctx = useInkContext('usePage()')\n const { viewport, document } = ctx\n const current = useReadable<number>(viewport?.currentPage, 0)\n return useMemo(\n () => ({\n /** 0-based. */\n current,\n count: document?.pages.length ?? 0,\n goTo: (index: number) => viewport?.scrollToPage(index),\n // Read the live page, so these stay the same functions as the reader scrolls.\n next: () => viewport?.scrollToPage(viewport.currentPage.get() + 1),\n previous: () => viewport?.scrollToPage(viewport.currentPage.get() - 1),\n scrollToAnnotation(id: string) {\n const a = document?.annotations.get(id)\n if (a) viewport?.scrollToRect(a.page, a.rect)\n },\n }),\n [viewport, document, current]\n )\n}\n","import { useInkContext, type InkHistory } from '../context'\n\n/**\n * Undo and redo. Uncontrolled documents use the core history; controlled hosts that pass\n * `history` to InkRoot get a snapshot stack over their own list, applied through\n * `onAnnotationsChange`.\n */\nexport function useHistory(): InkHistory {\n return useInkContext('useHistory()').history\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nconst NONE: readonly never[] = []\n\nexport function useEmbedded() {\n const ctx = useInkContext('useEmbedded()')\n const summary = ctx.document?.embedded ?? NONE\n return useMemo(\n () => ({\n summary,\n total: summary.reduce((n, s) => n + s.count, 0),\n hasAny: summary.length > 0,\n }),\n [summary]\n )\n}\n","import { useLayoutEffect, useRef, type RefObject } from 'react'\n\n/**\n * A ref that always holds the latest render's value, for callbacks that outlive a render\n * (core's `onChange`, effects keyed on something else). Updated in a layout effect, so it is\n * current before the parent's own layout and passive effects and before any callback fired\n * after commit; declare it before the effects that read it.\n */\nexport function useLatest<T>(value: T): RefObject<T> {\n const ref = useRef(value)\n useLayoutEffect(() => {\n ref.current = value\n })\n return ref\n}\n","import { createSnapshotHistory, InkError, openDocument } from '@inkbar/core'\nimport { cssVariableDefaults } from '@inkbar/core/dom'\nimport { Slot } from 'radix-ui'\nimport {\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type ReactNode,\n type Ref,\n} from 'react'\nimport { flushSync } from 'react-dom'\n\nimport {\n InkContextObject,\n type InkContext,\n type InkHistory,\n type InkStatus,\n} from '../context'\nimport { useLatest } from '../use-latest'\nimport { useReadable } from '../use-readable'\n\nimport type {\n Annotation,\n AnnotationChange,\n AnnotationDefaults,\n DocumentSource,\n InkDocument,\n PdfAssets,\n} from '@inkbar/core'\nimport type { ToolController, ToolId, Viewport, ZoomValue } from '@inkbar/core/dom'\n\nexport interface InkRootHandle {\n readonly document: InkDocument | null\n readonly status: InkStatus\n readonly rootEl: HTMLElement | null\n /** What `useHistory()` returns inside the root. A controlled host calls `clear()` after loading its saved list. */\n readonly history: InkHistory\n}\n\nexport interface InkRootProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'children' | 'onChange' | 'onError'\n> {\n src: DocumentSource | null\n assets: PdfAssets\n password?: string | undefined\n /** Colour defaults. Without it, the theme's CSS variables on the root element apply. */\n defaults?: AnnotationDefaults | undefined\n /**\n * Pass (with `onAnnotationsChange`) to put annotations under the host's control. The mode\n * is fixed when a document opens: passing or dropping this prop later takes effect on the\n * next open.\n */\n annotations?: Annotation[] | undefined\n onAnnotationsChange?: ((next: Annotation[]) => void) | undefined\n onChange?: ((change: AnnotationChange) => void) | undefined\n tool?: ToolId | undefined\n onToolChange?: ((tool: ToolId) => void) | undefined\n page?: number | undefined\n onPageChange?: ((page: number) => void) | undefined\n zoom?: ZoomValue | undefined\n onZoomChange?: ((zoom: ZoomValue) => void) | undefined\n /** Undo history. Defaults to on for uncontrolled, off for controlled. */\n history?: boolean | undefined\n asChild?: boolean | undefined\n onReady?: ((doc: InkDocument) => void) | undefined\n onError?: ((error: InkError) => void) | undefined\n onActivate?: ((id: string) => void) | undefined\n children?:\n | ReactNode\n | ((props: { status: InkStatus; document: InkDocument | null }) => ReactNode)\n ref?: Ref<InkRootHandle>\n}\n\ntype TestHookElement = HTMLElement & { __inkDocument?: InkDocument | undefined }\n\nconst IDLE: InkStatus = { state: 'idle' }\nconst NO_ANNOTATIONS: readonly Annotation[] = []\nconst NO_IDS: readonly string[] = []\n\n/** Signed URLs change; the key does not. Bytes and Blobs are their own identity. */\nfunction identity(src: DocumentSource | null): unknown {\n if (src === null) return null\n if (typeof src === 'string') return src\n if ('key' in src) return src.key\n return src\n}\n\nfunction isDevelopment(): boolean {\n // Bundlers replace the expression with a literal; raw browser ESM has no `process`.\n try {\n return process.env.NODE_ENV !== 'production'\n } catch {\n return false\n }\n}\n\nfunction setTestHook(el: HTMLElement | null, doc: InkDocument | undefined): void {\n if (el && isDevelopment()) (el as TestHookElement).__inkDocument = doc\n}\n\nexport function InkRoot({\n src,\n assets,\n password,\n defaults,\n annotations,\n onAnnotationsChange,\n onChange,\n tool,\n onToolChange,\n page,\n onPageChange,\n zoom,\n onZoomChange,\n history,\n asChild = false,\n onReady,\n onError,\n onActivate,\n children,\n ref,\n ...rest\n}: InkRootProps) {\n const rootElRef = useRef<HTMLElement | null>(null)\n const [rootEl, setRootElState] = useState<HTMLElement | null>(null)\n const setRootEl = useCallback((el: HTMLElement | null) => {\n rootElRef.current = el\n setRootElState(el)\n }, [])\n\n const documentRef = useRef<InkDocument | null>(null)\n const [document, setDocument] = useState<InkDocument | null>(null)\n /** Overrides the document's status while opening, and when opening itself failed. */\n const [override, setOverride] = useState<InkStatus | null>(null)\n const [internalTool, setInternalTool] = useState<ToolId>(tool ?? 'view')\n const [activated, setActivatedState] = useState<string | null>(null)\n const [viewport, setViewportState] = useState<Viewport | null>(null)\n const [tools, setToolsState] = useState<ToolController | null>(null)\n\n const documentStatus = useReadable<InkStatus>(document?.status, IDLE)\n const status = override ?? documentStatus\n const annotationList = useReadable(document?.annotations.list, NO_ANNOTATIONS)\n const selection = useReadable(document?.annotations.selection, NO_IDS)\n\n // What the next open will do follows the prop; the open document's mode is fixed.\n const controlledProp = annotations !== undefined\n const controlled = document\n ? document.annotations.mode === 'controlled'\n : controlledProp\n const historyEnabled = controlled && history === true\n // Callbacks and options read later than the render that passed them.\n const latest = useLatest({\n src,\n assets,\n defaults,\n annotations,\n controlled: controlledProp,\n history,\n historyEnabled,\n onAnnotationsChange,\n onChange,\n onReady,\n onError,\n onActivate,\n onToolChange,\n onPageChange,\n onZoomChange,\n })\n\n const snapshotHistory = useMemo(\n () =>\n createSnapshotHistory({\n apply: (list) => documentRef.current?.annotations.replaceAll(list, 'history'),\n enabled: () => latest.current.historyEnabled,\n }),\n [latest]\n )\n useEffect(() => {\n snapshotHistory.observe(annotations)\n }, [annotations, snapshotHistory])\n\n const srcIdentity = identity(src)\n useEffect(() => {\n let cancelled = false\n snapshotHistory.clear()\n const source = latest.current.src\n if (source === null) {\n setOverride(null)\n return\n }\n setOverride({ state: 'loading' })\n let opened: InkDocument | null = null\n const run = async () => {\n try {\n const doc = await openDocument(source, {\n assets: latest.current.assets,\n password,\n defaults:\n latest.current.defaults ??\n (rootElRef.current ? cssVariableDefaults(rootElRef.current) : undefined),\n // Controlled hosts get the snapshot history below; core's own stack stays off.\n history: latest.current.controlled ? false : (latest.current.history ?? true),\n annotations: latest.current.controlled\n ? {\n mode: 'controlled',\n initial: latest.current.annotations ?? [],\n onChange: (next, change) => {\n // Apply the host's state update, its render and the layout effect that pushes\n // the list back before core's development check expires. The microtask\n // leaves React's render, commit and passive-effect contexts, where a host\n // may call the store, so `flushSync` is always legal; the host sees the\n // proposal one microtask after the store returned. A proposal made in the\n // tick this root unmounts or reopens never reaches the host.\n queueMicrotask(() => {\n if (cancelled) return\n flushSync(() => {\n latest.current.onAnnotationsChange?.(next)\n latest.current.onChange?.(change)\n })\n })\n },\n }\n : { mode: 'uncontrolled' },\n })\n if (cancelled) {\n doc.destroy()\n return\n }\n opened = doc\n // The prop may have changed while the file loaded, when there was no store to apply it to.\n const current = latest.current.annotations\n if (doc.annotations.mode === 'controlled' && current !== undefined)\n doc.annotations.setControlledValue(current)\n documentRef.current = doc\n setDocument(doc)\n setOverride(null)\n setTestHook(rootElRef.current, doc)\n const s = doc.status.get()\n if (s.state === 'ready') latest.current.onReady?.(doc)\n else if (s.state === 'error') latest.current.onError?.(s.error)\n } catch (cause) {\n if (cancelled) return\n const error =\n cause instanceof InkError\n ? cause\n : new InkError(\n 'InvalidPdf',\n cause instanceof Error ? cause.message : String(cause),\n {},\n cause\n )\n setOverride({ state: 'error', error })\n latest.current.onError?.(error)\n }\n }\n // StrictMode's simulated cleanup runs synchronously in the same commit, so deferring one\n // microtask means the discarded first attempt never starts a fetch.\n void Promise.resolve().then(() => {\n if (!cancelled) return run()\n })\n return () => {\n cancelled = true\n opened?.destroy()\n documentRef.current = null\n setDocument(null)\n setTestHook(rootElRef.current, undefined)\n }\n // `srcIdentity` stands in for `src`: a new URL with the same key is the same document.\n }, [srcIdentity, password, snapshotHistory, latest])\n\n useLayoutEffect(() => {\n if (annotations && document?.annotations.mode === 'controlled')\n document.annotations.setControlledValue(annotations)\n }, [annotations, document])\n\n useEffect(() => {\n if (tool) setInternalTool(tool)\n }, [tool])\n\n const setTool = useCallback(\n (id: ToolId) => {\n setInternalTool(id)\n latest.current.onToolChange?.(id)\n },\n [latest]\n )\n const setActivated = useCallback(\n (id: string | null) => {\n setActivatedState(id)\n if (id) latest.current.onActivate?.(id)\n },\n [latest]\n )\n const reportZoom = useCallback(\n (z: ZoomValue) => latest.current.onZoomChange?.(z),\n [latest]\n )\n const reportPage = useCallback(\n (p: number) => latest.current.onPageChange?.(p),\n [latest]\n )\n const setViewport = useCallback((vp: Viewport | null, tc: ToolController | null) => {\n setViewportState(vp)\n setToolsState(tc)\n }, [])\n\n const snapCanUndo = useReadable(snapshotHistory.canUndo, false)\n const snapCanRedo = useReadable(snapshotHistory.canRedo, false)\n const coreCanUndo = useReadable(document?.history.canUndo, false)\n const coreCanRedo = useReadable(document?.history.canRedo, false)\n const inkHistory = useMemo<InkHistory>(\n () => ({\n canUndo: controlled ? historyEnabled && snapCanUndo : coreCanUndo,\n canRedo: controlled ? historyEnabled && snapCanRedo : coreCanRedo,\n undo: () =>\n controlled ? snapshotHistory.undo() : documentRef.current?.history.undo(),\n redo: () =>\n controlled ? snapshotHistory.redo() : documentRef.current?.history.redo(),\n clear: () =>\n controlled ? snapshotHistory.clear() : documentRef.current?.history.clear(),\n batch: (fn) => {\n if (controlled) snapshotHistory.batch(fn)\n else if (documentRef.current) documentRef.current.history.batch(fn)\n else fn()\n },\n }),\n [\n controlled,\n historyEnabled,\n snapCanUndo,\n snapCanRedo,\n coreCanUndo,\n coreCanRedo,\n snapshotHistory,\n ]\n )\n\n useImperativeHandle(ref, () => ({ document, status, rootEl, history: inkHistory }), [\n document,\n status,\n rootEl,\n inkHistory,\n ])\n\n const ctx = useMemo<InkContext>(\n () => ({\n assets,\n document,\n status,\n annotations: annotationList,\n selection,\n viewport,\n tools,\n tool: internalTool,\n setTool,\n zoomModel: zoom,\n pageModel: page,\n reportZoom,\n reportPage,\n activated,\n setActivated,\n history: inkHistory,\n rootEl,\n setViewport,\n }),\n [\n assets,\n document,\n status,\n annotationList,\n selection,\n viewport,\n tools,\n internalTool,\n setTool,\n zoom,\n page,\n reportZoom,\n reportPage,\n activated,\n setActivated,\n inkHistory,\n rootEl,\n setViewport,\n ]\n )\n\n const Comp = asChild ? Slot.Root : 'div'\n return (\n <InkContextObject.Provider value={ctx}>\n <Comp ref={setRootEl} data-ink-root=\"\" data-state={status.state} {...rest}>\n {typeof children === 'function' ? children({ status, document }) : children}\n </Comp>\n </InkContextObject.Provider>\n )\n}\n","/** Joins class names, dropping empties. */\nexport function cx(...parts: (string | undefined | false)[]): string | undefined {\n const out = parts.filter(Boolean).join(' ')\n return out === '' ? undefined : out\n}\n","/*\n * Slot props for one annotation. It renders only its children: the overlay already draws the\n * default visual for every annotation that is not custom, so this never draws a second one.\n * InkPage portals it into the annotation's overlay element.\n */\nimport { acceptSuggestion } from '@inkbar/core'\nimport { useEffect, useMemo, useState, type ReactNode } from 'react'\n\nimport { useInkContext } from '../context'\n\nimport type { Annotation } from '@inkbar/core'\nimport type { AnnotationSlotProps, AnnotationState } from '@inkbar/core/dom'\n\nexport interface InkAnnotationProps {\n annotation: Annotation\n /** The overlay element; its `data-state` (which includes hover) drives `state`. */\n element?: HTMLElement | undefined\n children: (props: AnnotationSlotProps) => ReactNode\n}\n\nfunction readState(el: HTMLElement): AnnotationState | null {\n const s = el.dataset.state\n return s === 'idle' || s === 'hover' || s === 'selected' ? s : null\n}\n\nexport function InkAnnotation({ annotation, element, children }: InkAnnotationProps) {\n const ctx = useInkContext('InkAnnotation')\n const [observed, setObserved] = useState<AnnotationState | null>(() =>\n element ? readState(element) : null\n )\n useEffect(() => {\n if (!element) {\n setObserved(null)\n return\n }\n setObserved(readState(element))\n const observer = new MutationObserver(() => setObserved(readState(element)))\n observer.observe(element, { attributes: true, attributeFilter: ['data-state'] })\n return () => observer.disconnect()\n }, [element])\n\n const { id } = annotation\n const isSuggestion = annotation.type === 'redact' && annotation.origin === 'suggested'\n const locked = annotation.locked === true\n const selected = ctx.selection.includes(id)\n const store = ctx.document?.annotations\n const slotProps = useMemo<AnnotationSlotProps>(\n () => ({\n annotation,\n state: observed ?? (selected ? 'selected' : 'idle'),\n locked,\n select: () => store?.select([id]),\n remove: () => void store?.remove(id),\n accept: () => {\n if (store && isSuggestion) acceptSuggestion(store, id)\n },\n dismiss: () => {\n if (isSuggestion) store?.remove(id)\n },\n }),\n [annotation, observed, selected, locked, store, id, isSuggestion]\n )\n return <>{children(slotProps)}</>\n}\n","/*\n * One page the viewer engine mounted. Renders nothing in place; portals go into the host\n * (page error) and into each annotation's overlay element (custom annotations).\n *\n * The overlay creates and removes those elements as the annotation list changes, outside\n * React. So the portal targets come from a list read after every overlay render: this\n * component subscribes to the store after the overlay does (the engine created the mount\n * first), and core notifies subscribers in order, so the elements already exist when the list\n * arrives here.\n *\n * The engine tracks page errors and sets `data-state=\"error\"` on the host; this component\n * portals the page-error slot into it while `error` is set.\n */\nimport { useEffect, useState, type ReactNode } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { useInkContext } from '../context'\n\nimport { InkAnnotation } from './InkAnnotation'\n\nimport type { Annotation, InkError } from '@inkbar/core'\nimport type { AnnotationSlotProps, PageMount } from '@inkbar/core/dom'\n\nexport interface InkPageProps {\n page: number\n host: HTMLElement\n /** The engine's page mount in `host`. */\n mount: PageMount\n /** The engine's error for this page, `null` while it renders. */\n error: InkError | null\n /** Fixed for the life of the mount: the engine rebuilds when it changes. */\n customAnnotations?: boolean\n renderAnnotation?: ((props: AnnotationSlotProps) => ReactNode) | undefined\n renderPageError?: ((props: { error: InkError; page: number }) => ReactNode) | undefined\n}\n\ninterface Target {\n annotation: Annotation\n el: HTMLElement\n}\n\nfunction sameTargets(a: readonly Target[], b: readonly Target[]): boolean {\n return (\n a.length === b.length &&\n a.every((t, i) => t.annotation === b[i]!.annotation && t.el === b[i]!.el)\n )\n}\n\nexport function InkPage({\n page,\n host,\n mount,\n error,\n customAnnotations = false,\n renderAnnotation,\n renderPageError,\n}: InkPageProps) {\n const doc = useInkContext('InkPage').document\n const [targets, setTargets] = useState<Target[]>([])\n\n useEffect(() => {\n if (!doc || !customAnnotations) return\n const read = (): void => {\n const next = doc.annotations.byPage(page).flatMap((annotation) => {\n const el = mount.overlay.elementFor(annotation.id)\n return el ? [{ annotation, el }] : []\n })\n // A change elsewhere in the document leaves this page's targets as they were.\n setTargets((prev) => (sameTargets(prev, next) ? prev : next))\n }\n const stop = doc.annotations.list.subscribe(read)\n read()\n return () => {\n stop()\n setTargets([])\n }\n }, [doc, page, mount, customAnnotations])\n\n return (\n <>\n {error\n ? createPortal(\n <div className=\"ink-page-error\" data-ink-page-error=\"\" role=\"alert\">\n {renderPageError ? (\n renderPageError({ error, page })\n ) : (\n <>\n <p>Page {page + 1} could not be shown.</p>\n <code className=\"ink-error-code\">{error.code}</code>\n </>\n )}\n </div>,\n host\n )\n : null}\n {renderAnnotation\n ? targets.map((t) =>\n createPortal(\n <InkAnnotation annotation={t.annotation} element={t.el}>\n {renderAnnotation}\n </InkAnnotation>,\n t.el,\n t.annotation.id\n )\n )\n : null}\n </>\n )\n}\n","/*\n * The scroll element is handed to core's `mountViewer`, which builds the viewport, the page\n * layers, the tool controller and the keyboard shortcuts in it; React never renders children\n * into it. The engine reports each page host it mounts, and InkPage components rendered here\n * portal the page-error and custom-annotation slots into them.\n *\n * Two-way zoom and page: the viewport's own changes are reported through the context, and\n * the host's props are applied only when they differ from the viewport's state, so the echo\n * of a reported value does nothing.\n */\nimport { mountViewer } from '@inkbar/core/dom'\nimport {\n useEffect,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from 'react'\n\nimport { cx } from '../class-names'\nimport { useInkContext } from '../context'\nimport { useLatest } from '../use-latest'\n\nimport { InkPage } from './InkPage'\n\nimport type { InkError } from '@inkbar/core'\nimport type {\n AnnotationSlotProps,\n LayoutMode,\n PageMount,\n ViewerEngine,\n ViewRotation,\n ZoomValue,\n} from '@inkbar/core/dom'\n\nexport interface InkViewportProps extends ComponentPropsWithoutRef<'div'> {\n mode?: LayoutMode\n rotation?: ViewRotation\n /** Gap between pages, CSS px. */\n gap?: number\n /** Pages kept mounted either side of the visible ones. */\n buffer?: number\n loading?: ReactNode\n empty?: ReactNode\n error?: ReactNode | ((props: { error: InkError }) => ReactNode)\n renderAnnotation?: ((props: AnnotationSlotProps) => ReactNode) | undefined\n /** Shown inside a page that failed to render. The rest of the document stays usable. */\n renderPageError?: ((props: { error: InkError; page: number }) => ReactNode) | undefined\n}\n\ninterface MountedPage {\n /** The engine build the host belongs to; part of the InkPage key. */\n build: number\n page: number\n host: HTMLElement\n mount: PageMount\n error: InkError | null\n /** Whether the build that mounted the page renders the annotation slot. */\n custom: boolean\n}\n\nexport function InkViewport({\n mode = 'continuous',\n rotation = 0,\n gap = 16,\n buffer = 2,\n loading,\n empty,\n error,\n renderAnnotation,\n renderPageError,\n className,\n ...rest\n}: InkViewportProps) {\n const ctx = useInkContext('InkViewport')\n const scroll = useRef<HTMLDivElement>(null)\n const custom = !!renderAnnotation\n const latest = useLatest({ ctx, mode, rotation, gap, buffer, custom })\n\n const engine = useRef<ViewerEngine | null>(null)\n /** Page hosts, mounts and errors the engine reported; InkPage renders portals for them. */\n const [pages, setPages] = useState<MountedPage[]>([])\n /**\n * Numbered before each build starts, so the pages a build mounts carry its own number. A\n * rebuild gives each page a new host and mount, so pages from an earlier build must remount,\n * not be reused.\n */\n const buildCount = useRef(0)\n /** The construction options the engine was last built with, so a rebuild runs only on a change. */\n const builtWith = useRef<{ gap: number; buffer: number; custom: boolean } | null>(null)\n /** The zoom and page last reported to the host. */\n const lastReportedZoom = useRef<ZoomValue | undefined>(undefined)\n const lastReportedPage = useRef<number | undefined>(undefined)\n\n // Build for a new document or status; tear down on the next change and on unmount.\n useEffect(() => {\n const { ctx: c, mode: m, rotation: r, gap: g, buffer: b, custom: cu } = latest.current\n const doc = c.document\n const el = scroll.current\n lastReportedZoom.current = undefined\n lastReportedPage.current = undefined\n if (!doc || !el || c.status.state !== 'ready') return\n let first = true\n let stops: (() => void)[] = []\n buildCount.current += 1\n builtWith.current = { gap: g, buffer: b, custom: cu }\n const e = mountViewer({\n container: el,\n document: doc,\n zoom: c.zoomModel ?? 'fit-width',\n ...(c.pageModel === undefined ? {} : { page: c.pageModel }),\n mode: m,\n rotation: r,\n gap: g,\n buffer: b,\n tool: c.tool,\n customAnnotations: cu,\n onActivate: (id) => latest.current.ctx.setActivated(id),\n onBuild: (vp, tc) => {\n latest.current.ctx.setViewport(vp, tc)\n if (first) {\n // A new document starts from where the viewport opens (its zoom, on the first page);\n // only later changes are reported, the restored page among them.\n first = false\n lastReportedZoom.current = vp.zoom.get()\n lastReportedPage.current = 0\n }\n for (const stop of stops) stop()\n const reportZoom = (z: ZoomValue): void => {\n if (z === lastReportedZoom.current) return\n lastReportedZoom.current = z\n latest.current.ctx.reportZoom(z)\n }\n const reportPage = (p: number): void => {\n if (p === lastReportedPage.current) return\n lastReportedPage.current = p\n latest.current.ctx.reportPage(p)\n }\n stops = [vp.zoom.subscribe(reportZoom), vp.currentPage.subscribe(reportPage)]\n // Whatever the build restored is reported once; nothing is when it matched.\n reportZoom(vp.zoom.get())\n reportPage(vp.currentPage.get())\n },\n onPageMount: (page, mount, host) => {\n // `buildCount` and `builtWith` belong to the build in progress: both are set before it starts.\n const build = buildCount.current\n const custom = builtWith.current?.custom ?? false\n setPages((prev) => [...prev, { build, page, host, mount, error: null, custom }])\n },\n onPageUnmount: (page) => setPages((prev) => prev.filter((p) => p.page !== page)),\n onPageError: (page, err) =>\n setPages((prev) => prev.map((p) => (p.page === page ? { ...p, error: err } : p))),\n })\n engine.current = e\n return () => {\n for (const stop of stops) stop()\n e.destroy()\n engine.current = null\n builtWith.current = null\n c.setViewport(null, null)\n setPages((prev) => (prev.length === 0 ? prev : []))\n }\n }, [ctx.document, ctx.status.state, latest])\n\n // Construction-only options rebuild the engine for the same document, keeping zoom and page.\n useEffect(() => {\n const built = builtWith.current\n if (!engine.current || !built) return\n if (built.gap === gap && built.buffer === buffer && built.custom === custom) return\n buildCount.current += 1\n builtWith.current = { gap, buffer, custom }\n engine.current.rebuild({ gap, buffer, customAnnotations: custom })\n }, [gap, buffer, custom])\n\n useEffect(() => {\n const vp = engine.current?.viewport\n const z = ctx.zoomModel\n if (vp && z !== undefined && z !== vp.zoom.get()) vp.setZoom(z)\n }, [ctx.zoomModel])\n useEffect(() => {\n const vp = engine.current?.viewport\n const p = ctx.pageModel\n if (!vp || p === undefined || p === lastReportedPage.current) return\n if (p !== vp.currentPage.get()) vp.scrollToPage(p)\n }, [ctx.pageModel])\n useEffect(() => {\n const tc = engine.current?.tools\n if (tc && tc.active.get() !== ctx.tool) tc.set(ctx.tool)\n }, [ctx.tool])\n // The build applied both; these only act on a later change, not on mount.\n useEffect(() => {\n const vp = engine.current?.viewport\n if (vp && vp.mode.get() !== mode) vp.setMode(mode)\n }, [mode])\n useEffect(() => {\n const vp = engine.current?.viewport\n if (vp && vp.rotation.get() !== rotation) vp.setRotation(rotation)\n }, [rotation])\n\n const state = ctx.status.state\n const err = ctx.status.state === 'error' ? ctx.status.error : null\n\n return (\n <div\n {...rest}\n className={cx('ink-viewport-root', className)}\n data-ink-viewport-root=\"\"\n data-state={state}\n >\n {state === 'loading' ? (\n <div className=\"ink-status\" role=\"status\" aria-live=\"polite\">\n {loading === undefined ? 'Loading document…' : loading}\n </div>\n ) : err ? (\n <div className=\"ink-status ink-error\" role=\"alert\">\n {typeof error === 'function' ? (\n error({ error: err })\n ) : error !== undefined ? (\n error\n ) : (\n <>\n <p className=\"ink-error-title\">This document could not be opened.</p>\n {/* The message comes from the PDF engine and is not written for readers: it stays\n off the page, on the code's tooltip. */}\n <p>\n <code className=\"ink-error-code\" title={err.message}>\n {err.code}\n </code>\n </p>\n </>\n )}\n </div>\n ) : state === 'idle' ? (\n <div className=\"ink-status ink-empty\">{empty}</div>\n ) : null}\n <div\n ref={scroll}\n className=\"ink-scroll\"\n data-ink-scroll=\"\"\n tabIndex={0}\n role=\"document\"\n aria-label=\"Document\"\n />\n {pages.map((p) => (\n <InkPage\n key={`${p.build}:${p.page}`}\n page={p.page}\n host={p.host}\n mount={p.mount}\n error={p.error}\n customAnnotations={p.custom}\n renderAnnotation={renderAnnotation}\n renderPageError={renderPageError}\n />\n ))}\n </div>\n )\n}\n","import { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\n\nimport type { ComponentPropsWithoutRef } from 'react'\n\nexport interface InkToolbarProps extends Omit<ComponentPropsWithoutRef<'div'>, 'dir'> {\n /** Radix narrows text direction to these two values. */\n dir?: 'ltr' | 'rtl'\n label?: string\n asChild?: boolean\n}\n\nexport function InkToolbar({\n label = 'Document tools',\n asChild = false,\n className,\n children,\n ...rest\n}: InkToolbarProps) {\n return (\n <Toolbar.Root\n asChild={asChild}\n orientation=\"horizontal\"\n aria-label={label}\n data-ink-toolbar=\"\"\n className={cx('ink-toolbar', className)}\n {...rest}\n >\n {children}\n </Toolbar.Root>\n )\n}\n","/*\n * An icon from `@inkbar/icons`, hidden from assistive technology: the control it sits in\n * carries the name. The theme sizes it with `--ink-icon-size`.\n */\nimport { ICON_ATTRIBUTES } from '@inkbar/icons'\nimport { createElement, type SVGProps } from 'react'\n\nimport type { IconNode } from '@inkbar/icons'\n\nexport interface InkIconProps {\n icon: IconNode\n size?: number\n}\n\n/** `stroke-width` to `strokeWidth`: React names SVG attributes in camelCase. */\nconst camel = (name: string) =>\n name.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase())\n\nconst SVG_ATTRIBUTES = Object.fromEntries(\n Object.entries(ICON_ATTRIBUTES).map(([k, v]) => [camel(k), v])\n) as SVGProps<SVGSVGElement>\n\nexport function InkIcon({ icon, size = 18 }: InkIconProps) {\n return (\n <svg\n {...SVG_ATTRIBUTES}\n width={size}\n height={size}\n className=\"ink-icon\"\n aria-hidden=\"true\"\n >\n {icon.map(([tag, attrs], i) => createElement(tag, { key: i, ...attrs }))}\n </svg>\n )\n}\n","import { TOOL_LABELS, type ToolId } from '@inkbar/core/dom'\nimport { Hand, Highlighter, MessageSquare, MousePointer2, Square } from '@inkbar/icons'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useTool } from '../hooks/useTool'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { IconNode } from '@inkbar/icons'\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react'\n\nconst ICONS: Readonly<Record<ToolId, IconNode>> = {\n view: Hand,\n select: MousePointer2,\n highlight: Highlighter,\n 'redact-area': Square,\n note: MessageSquare,\n}\n\nexport interface InkToolButtonProps extends Omit<\n ComponentPropsWithoutRef<'button'>,\n 'children'\n> {\n tool: ToolId\n label?: string | undefined\n asChild?: boolean\n children?: ReactNode | ((props: { active: boolean; label: string }) => ReactNode)\n}\n\nexport function InkToolButton({\n tool,\n label,\n asChild = false,\n className,\n children,\n onClick,\n ...rest\n}: InkToolButtonProps) {\n const { tool: current, setTool } = useTool()\n const active = current === tool\n const name = label ?? TOOL_LABELS[tool]\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-tool-button', className)}\n data-ink-tool-button=\"\"\n data-tool={tool}\n data-state={active ? 'on' : 'off'}\n aria-pressed={active}\n aria-label={name}\n title={name}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) setTool(tool)\n }}\n {...rest}\n >\n {typeof children === 'function'\n ? children({ active, label: name })\n : (children ?? <InkIcon icon={ICONS[tool]} />)}\n </Toolbar.Button>\n )\n}\n","import { cx } from '../class-names'\n\nimport type { ComponentPropsWithoutRef } from 'react'\n\nexport type InkToolbarSeparatorProps = ComponentPropsWithoutRef<'div'>\n\n/**\n * A divider between groups of controls in a horizontal toolbar. Not focusable. A plain div\n * rather than Radix's separator, which reads as horizontal inside a horizontal toolbar.\n */\nexport function InkToolbarSeparator({ className, ...rest }: InkToolbarSeparatorProps) {\n return (\n <div\n role=\"separator\"\n aria-orientation=\"vertical\"\n className={cx('ink-toolbar-separator', className)}\n data-ink-toolbar-separator=\"\"\n {...rest}\n />\n )\n}\n","import { Undo2 } from '@inkbar/icons'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useHistory } from '../hooks/useHistory'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { InkHistoryButtonProps } from './history-button'\n\nexport function InkUndo({\n asChild = false,\n className,\n children,\n disabled,\n onClick,\n ...rest\n}: InkHistoryButtonProps) {\n const { canUndo, undo } = useHistory()\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-undo', className)}\n data-ink-undo=\"\"\n aria-label=\"Undo\"\n title=\"Undo\"\n {...rest}\n disabled={disabled === true || !canUndo}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) undo()\n }}\n >\n {children ?? <InkIcon icon={Undo2} />}\n </Toolbar.Button>\n )\n}\n","import { Redo2 } from '@inkbar/icons'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useHistory } from '../hooks/useHistory'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { InkHistoryButtonProps } from './history-button'\n\nexport function InkRedo({\n asChild = false,\n className,\n children,\n disabled,\n onClick,\n ...rest\n}: InkHistoryButtonProps) {\n const { canRedo, redo } = useHistory()\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-redo', className)}\n data-ink-redo=\"\"\n aria-label=\"Redo\"\n title=\"Redo\"\n {...rest}\n disabled={disabled === true || !canRedo}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) redo()\n }}\n >\n {children ?? <InkIcon icon={Redo2} />}\n </Toolbar.Button>\n )\n}\n","import { ZoomIn } from '@inkbar/icons'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useZoom } from '../hooks/useZoom'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { InkZoomButtonProps } from './zoom-button'\n\nexport function InkZoomIn({\n asChild = false,\n className,\n children,\n onClick,\n ...rest\n}: InkZoomButtonProps) {\n const { zoomIn } = useZoom()\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-zoom-in', className)}\n data-ink-zoom-in=\"\"\n aria-label=\"Zoom in\"\n title=\"Zoom in\"\n {...rest}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) zoomIn()\n }}\n >\n {children ?? <InkIcon icon={ZoomIn} />}\n </Toolbar.Button>\n )\n}\n","import { ZoomOut } from '@inkbar/icons'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useZoom } from '../hooks/useZoom'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { InkZoomButtonProps } from './zoom-button'\n\nexport function InkZoomOut({\n asChild = false,\n className,\n children,\n onClick,\n ...rest\n}: InkZoomButtonProps) {\n const { zoomOut } = useZoom()\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-zoom-out', className)}\n data-ink-zoom-out=\"\"\n aria-label=\"Zoom out\"\n title=\"Zoom out\"\n {...rest}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) zoomOut()\n }}\n >\n {children ?? <InkIcon icon={ZoomOut} />}\n </Toolbar.Button>\n )\n}\n","import { ZOOM_LEVELS, type ZoomValue } from '@inkbar/core/dom'\nimport { Check, ChevronDown } from '@inkbar/icons'\nimport { Select } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useZoom } from '../hooks/useZoom'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { ComponentPropsWithoutRef } from 'react'\n\nconst CUSTOM = 'custom:'\nconst level = (z: number) => ZOOM_LEVELS.find((l) => Math.abs(l - z) < 0.001)\nconst percent = (z: number) => `${Math.round(z * 100)}%`\n\nconst FITS = [\n { value: 'fit-width', label: 'Fit width' },\n { value: 'fit-page', label: 'Fit page' },\n]\n\n/** Props of the select's trigger button; the options come from the zoom levels. */\nexport type InkZoomSelectProps = Omit<\n ComponentPropsWithoutRef<typeof Select.Trigger>,\n 'children' | 'asChild'\n>\n\nfunction Item({ value, label }: { value: string; label: string }) {\n return (\n <Select.Item value={value} className=\"ink-select-item\" data-ink-select-item=\"\">\n <Select.ItemText>{label}</Select.ItemText>\n <Select.ItemIndicator className=\"ink-select-indicator\">\n <InkIcon icon={Check} size={16} />\n </Select.ItemIndicator>\n </Select.Item>\n )\n}\n\nexport function InkZoomSelect({ className, ...rest }: InkZoomSelectProps) {\n const { zoom, scale, setZoom } = useZoom()\n /** A numeric zoom that is not one of the levels (zoom in and out multiply). */\n const custom = typeof zoom === 'number' && level(zoom) === undefined ? zoom : null\n const value =\n typeof zoom !== 'number'\n ? zoom\n : custom === null\n ? String(level(zoom))\n : `${CUSTOM}${zoom}`\n /** The levels, with a custom zoom in its place among them. */\n const levels = ZOOM_LEVELS.map((l) => ({ z: l, value: String(l), label: percent(l) }))\n if (custom !== null)\n levels.push({ z: custom, value: `${CUSTOM}${custom}`, label: percent(scale) })\n levels.sort((a, b) => a.z - b.z)\n\n function onValueChange(v: string): void {\n if (v === value) return\n const next: ZoomValue =\n v === 'fit-width' || v === 'fit-page' ? v : Number(v.replace(CUSTOM, ''))\n setZoom(next)\n }\n return (\n <Select.Root value={value} onValueChange={onValueChange}>\n <Select.Trigger\n className={cx('ink-zoom-select ink-select-trigger', className)}\n data-ink-zoom-select=\"\"\n aria-label=\"Zoom\"\n {...rest}\n >\n <Select.Value className=\"ink-select-value\" />\n <Select.Icon className=\"ink-select-icon\">\n <InkIcon icon={ChevronDown} size={16} />\n </Select.Icon>\n </Select.Trigger>\n <Select.Portal>\n <Select.Content\n className=\"ink-select-content\"\n data-ink-select-content=\"\"\n position=\"popper\"\n side=\"top\"\n sideOffset={4}\n >\n <Select.Viewport>\n {FITS.map((o) => (\n <Item key={o.value} value={o.value} label={o.label} />\n ))}\n <Select.Separator className=\"ink-select-separator\" />\n {levels.map((o) => (\n <Item key={o.value} value={o.value} label={o.label} />\n ))}\n </Select.Viewport>\n </Select.Content>\n </Select.Portal>\n </Select.Root>\n )\n}\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type KeyboardEvent,\n} from 'react'\n\nimport { cx } from '../class-names'\nimport { usePage } from '../hooks/usePage'\nimport { useLatest } from '../use-latest'\n\nexport type InkPageInputProps = Omit<\n ComponentPropsWithoutRef<'input'>,\n 'value' | 'onChange' | 'type' | 'min' | 'max'\n>\n\nexport function InkPageInput({\n className,\n onKeyDown: onKeyDownProp,\n ...rest\n}: InkPageInputProps) {\n const { current, count, goTo } = usePage()\n const [draft, setDraft] = useState(String(current + 1))\n useEffect(() => {\n setDraft(String(current + 1))\n }, [current])\n const input = useRef<HTMLInputElement>(null)\n const latest = useLatest({ current, count, goTo })\n\n /** 1-based in the input, 0-based in the viewport. Out of range resets to the current page. */\n const commit = useCallback(\n (value: string) => {\n const { current: page, count: total, goTo: go } = latest.current\n const n = Number(value)\n if (Number.isInteger(n) && n >= 1 && n <= total) {\n if (n - 1 !== page) go(n - 1)\n } else setDraft(String(page + 1))\n },\n [latest]\n )\n // The native `change` event fires when an edit is committed: on blur after typing, and on\n // each step of the spinner or the arrow keys. React's `onChange` is the `input` event, which\n // fires for every keystroke, so the commit listens to the DOM event itself.\n useEffect(() => {\n const el = input.current\n if (!el) return\n const onNativeChange = (): void => commit(el.value)\n el.addEventListener('change', onNativeChange)\n return () => el.removeEventListener('change', onNativeChange)\n }, [commit])\n\n function onKeyDown(e: KeyboardEvent<HTMLInputElement>): void {\n onKeyDownProp?.(e)\n if (e.defaultPrevented || e.key !== 'Enter') return\n e.preventDefault()\n commit(draft)\n }\n return (\n <input\n ref={input}\n className={cx('ink-page-input', className)}\n data-ink-page-input=\"\"\n type=\"number\"\n inputMode=\"numeric\"\n aria-label=\"Page\"\n min={1}\n max={count}\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={onKeyDown}\n {...rest}\n />\n )\n}\n","import { cx } from '../class-names'\nimport { usePage } from '../hooks/usePage'\n\nimport type { ComponentPropsWithoutRef } from 'react'\n\nexport function InkPageCount({ className, ...rest }: ComponentPropsWithoutRef<'span'>) {\n const { count } = usePage()\n return (\n <span\n className={cx('ink-page-count', className)}\n data-ink-page-count=\"\"\n aria-live=\"polite\"\n {...rest}\n >\n {`of ${count}`}\n </span>\n )\n}\n","import { ChevronLeft } from '@inkbar/icons'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { usePage } from '../hooks/usePage'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { InkPageButtonProps } from './page-button'\n\nexport function InkPrevPage({\n asChild = false,\n className,\n children,\n disabled,\n onClick,\n ...rest\n}: InkPageButtonProps) {\n const { current, previous } = usePage()\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-prev-page', className)}\n data-ink-prev-page=\"\"\n aria-label=\"Previous page\"\n title=\"Previous page\"\n disabled={disabled === true || current <= 0}\n {...rest}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) previous()\n }}\n >\n {children ?? <InkIcon icon={ChevronLeft} />}\n </Toolbar.Button>\n )\n}\n","import { ChevronRight } from '@inkbar/icons'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { usePage } from '../hooks/usePage'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { InkPageButtonProps } from './page-button'\n\nexport function InkNextPage({\n asChild = false,\n className,\n children,\n disabled,\n onClick,\n ...rest\n}: InkPageButtonProps) {\n const { current, count, next } = usePage()\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-next-page', className)}\n data-ink-next-page=\"\"\n aria-label=\"Next page\"\n title=\"Next page\"\n disabled={disabled === true || current >= count - 1}\n {...rest}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) next()\n }}\n >\n {children ?? <InkIcon icon={ChevronRight} />}\n </Toolbar.Button>\n )\n}\n","import { observeAnnotationElement } from '@inkbar/core/dom'\nimport { useEffect, useState } from 'react'\n\n/**\n * The overlay element core draws for an annotation, for anchoring a popover to it. Core\n * creates and removes these elements outside React, so this follows the root's subtree while\n * an id is wanted.\n */\nexport function useAnnotationElement(\n root: HTMLElement | null,\n id: string | null\n): HTMLElement | null {\n const [element, setElement] = useState<HTMLElement | null>(null)\n useEffect(() => {\n if (!root || !id) {\n setElement(null)\n return\n }\n return observeAnnotationElement(root, id, setElement)\n }, [root, id])\n return element\n}\n","import {\n createFocusReturn,\n shouldKeepOpenOnAnnotation,\n type FocusReturn,\n} from '@inkbar/core/dom'\nimport { useMemo } from 'react'\n\nimport { useLatest } from '../use-latest'\n\nimport type { InkContext } from '../context'\n\nexport type { FocusReturn }\n\n/** Radix's `onInteractOutside` handler: a press that will activate an annotation keeps the popover open. */\nexport function keepOpenOnAnnotation(event: CustomEvent<{ originalEvent: Event }>): void {\n if (shouldKeepOpenOnAnnotation(event.detail.originalEvent.target))\n event.preventDefault()\n}\n\nexport function useFocusReturn(ctx: InkContext): FocusReturn {\n const latest = useLatest(ctx)\n return useMemo(\n () =>\n createFocusReturn({\n root: () => latest.current.rootEl,\n activated: () => latest.current.activated,\n }),\n [latest]\n )\n}\n","/*\n * The thread for the activated note, anchored to the note's overlay element. Activating a\n * reply opens the whole thread from its root. Closing (Close, Escape, a press outside) clears\n * `activated`.\n *\n * A new note has no text. While its root is empty (and unlocked) the default form writes the\n * root's own `contents`, labelled \"Comment\", and the thread list stays hidden until there is\n * something in it; after that the form adds replies. Closing a root that is still empty and\n * has no replies removes it, so an abandoned note does not stay on the page.\n */\nimport { isAbandonedNote, threadOf, threadRoot } from '@inkbar/core'\nimport { Popover } from 'radix-ui'\nimport {\n useEffect,\n useMemo,\n useRef,\n useState,\n type FormEvent,\n type ReactNode,\n} from 'react'\n\nimport { useInkContext } from '../context'\nimport { useAnnotations } from '../hooks/useAnnotations'\nimport { useLatest } from '../use-latest'\n\nimport { useAnnotationElement } from './annotation-element'\nimport { keepOpenOnAnnotation, useFocusReturn } from './popover-focus'\n\nimport type { Annotation, NoteAnnotation } from '@inkbar/core'\nimport type { NotePopoverSlotProps } from '@inkbar/core/dom'\n\nexport interface InkNotePopoverProps {\n children?: ((props: NotePopoverSlotProps) => ReactNode) | undefined\n}\n\nexport function InkNotePopover({ children }: InkNotePopoverProps) {\n const ctx = useInkContext('InkNotePopover')\n const { annotations, add, update, remove } = useAnnotations()\n\n const note = useMemo<NoteAnnotation | null>(() => {\n const a = ctx.activated ? annotations.find((x) => x.id === ctx.activated) : undefined\n return a?.type === 'text' ? threadRoot(annotations, a) : null\n }, [annotations, ctx.activated])\n const anchor = useAnnotationElement(ctx.rootEl, note?.id ?? null)\n const anchorRef = useMemo(() => ({ current: anchor }), [anchor])\n const focusReturn = useFocusReturn(ctx)\n const open = note !== null && anchor !== null\n /** The root, then every reply below it, depth first, each level in creation order. */\n const thread = useMemo<Annotation[]>(\n () => (note ? threadOf(annotations, note) : []),\n [annotations, note]\n )\n /** True while the default form writes the root note's own text rather than a reply. */\n const editingRoot = note !== null && !note.locked && !note.contents?.trim()\n\n /**\n * Notes this popover wrote text or a reply for. In controlled mode the write is a proposal\n * the host may not have applied yet, so the applied list still shows the note empty; these\n * are never dropped as abandoned.\n */\n const written = useRef(new Set<string>())\n /** Notes this popover has already asked to remove, so a slow host is asked once. */\n const dropped = useRef(new Set<string>())\n const latest = useLatest({ annotations, remove })\n\n function dropIfEmpty(id: string): boolean {\n if (\n dropped.current.has(id) ||\n written.current.has(id) ||\n !isAbandonedNote(latest.current.annotations, id)\n )\n return false\n dropped.current.add(id)\n latest.current.remove(id)\n return true\n }\n\n // Activation moved on from a note that never got any text: drop it.\n const noteId = note?.id\n const previousId = useRef<string | undefined>(undefined)\n useEffect(() => {\n const previous = previousId.current\n if (previous === noteId) return\n previousId.current = noteId\n if (previous !== undefined) dropIfEmpty(previous)\n // dropIfEmpty reads through `latest`; it is stable for the effect's purposes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [noteId])\n\n function reply(text: string): void {\n const root = note\n const contents = text.trim()\n if (!root || !contents) return\n written.current.add(root.id)\n add({ type: 'text', page: root.page, rect: root.rect, contents, inReplyTo: root.id })\n }\n function isEmptyRoot(root: NoteAnnotation): boolean {\n return (\n !written.current.has(root.id) &&\n !root.locked &&\n !root.contents?.trim() &&\n thread.length === 1\n )\n }\n function close(): void {\n const root = note\n if (root && annotations.some((a) => a.id === root.id) && isEmptyRoot(root)) {\n focusReturn.beforeRemove(anchor)\n dropIfEmpty(root.id)\n }\n ctx.setActivated(null)\n }\n function updateContents(contents: string): void {\n if (!note || note.locked) return\n if (contents.trim()) written.current.add(note.id)\n update(note.id, { contents })\n }\n /** Locked notes cannot be removed: removing one does nothing and keeps the popover. */\n function removeThread(): void {\n const root = note\n if (!root || root.locked) return\n focusReturn.beforeRemove(anchor)\n // Under a slow controlled host the note stays listed for a while; it is not asked for again.\n dropped.current.add(root.id)\n remove(root.id)\n ctx.setActivated(null)\n }\n\n return (\n <Popover.Root open={open} onOpenChange={(next) => !next && close()}>\n <Popover.Anchor virtualRef={anchorRef} />\n <Popover.Portal>\n {note && anchor ? (\n <Popover.Content\n className=\"ink-note-popover\"\n data-ink-note-popover=\"\"\n side=\"right\"\n sideOffset={8}\n collisionPadding={8}\n aria-label=\"Note thread\"\n onInteractOutside={keepOpenOnAnnotation}\n onCloseAutoFocus={(e) => focusReturn.onCloseAutoFocus(e, anchor)}\n >\n {children ? (\n children({\n note,\n replies: thread.slice(1),\n reply,\n update: updateContents,\n remove: removeThread,\n close,\n })\n ) : (\n <>\n {!editingRoot || thread.length > 1 ? (\n <ol className=\"ink-thread\" data-ink-thread=\"\">\n {thread.map((item) => (\n <li\n key={item.id}\n className=\"ink-thread-item\"\n data-ink-thread-item=\"\"\n data-reply={item.inReplyTo ? '' : undefined}\n >\n <span className=\"ink-thread-author\">\n {item.author ?? 'Anonymous'}\n </span>\n <time className=\"ink-thread-time\" dateTime={item.createdAt}>\n {new Date(item.createdAt).toLocaleString()}\n </time>\n <p className=\"ink-thread-text\">{item.contents}</p>\n </li>\n ))}\n </ol>\n ) : null}\n <ThreadForm\n // Keyed by note: moving to another note starts with an empty draft at once.\n key={note.id}\n editingRoot={editingRoot}\n locked={!!note.locked}\n onSubmit={(text) => (editingRoot ? updateContents(text) : reply(text))}\n onRemove={removeThread}\n onClose={close}\n />\n </>\n )}\n </Popover.Content>\n ) : null}\n </Popover.Portal>\n </Popover.Root>\n )\n}\n\n/** The default form: the root note's own text while it is empty, replies after that. */\nfunction ThreadForm({\n editingRoot,\n locked,\n onSubmit,\n onRemove,\n onClose,\n}: {\n editingRoot: boolean\n locked: boolean\n onSubmit: (text: string) => void\n onRemove: () => void\n onClose: () => void\n}) {\n const [draft, setDraft] = useState('')\n function submit(e: FormEvent): void {\n e.preventDefault()\n const text = draft.trim()\n if (!text) return\n onSubmit(text)\n setDraft('')\n }\n return (\n <form className=\"ink-thread-reply\" data-ink-thread-reply=\"\" onSubmit={submit}>\n <textarea\n aria-label={editingRoot ? 'Comment' : 'Reply'}\n rows={2}\n placeholder={editingRoot ? 'Comment' : 'Reply'}\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n />\n <div className=\"ink-thread-actions\">\n <button type=\"submit\" disabled={!draft.trim()}>\n {editingRoot ? 'Comment' : 'Reply'}\n </button>\n {!locked ? (\n <button type=\"button\" onClick={onRemove}>\n Delete\n </button>\n ) : null}\n <button type=\"button\" onClick={onClose}>\n Close\n </button>\n </div>\n </form>\n )\n}\n","/*\n * Review card for a suggested redaction: opens when the activated annotation, or the only\n * selected one, is a redaction with `origin: 'suggested'`. Locked suggestions cannot be\n * dismissed, so they get no Dismiss button. A press on the overlay selects and activates, so a\n * click opens it whatever the tool. Closing clears `activated` and the selection.\n */\nimport { confidenceBucket } from '@inkbar/core'\nimport { Popover } from 'radix-ui'\nimport { useMemo, type ReactNode } from 'react'\n\nimport { useInkContext } from '../context'\nimport { useAnnotations } from '../hooks/useAnnotations'\n\nimport { useAnnotationElement } from './annotation-element'\nimport { keepOpenOnAnnotation, useFocusReturn } from './popover-focus'\n\nimport type { ConfidenceBucket, RedactAnnotation } from '@inkbar/core'\nimport type { SuggestionCardSlotProps } from '@inkbar/core/dom'\n\nexport interface InkSuggestionCardProps {\n children?: ((props: SuggestionCardSlotProps) => ReactNode) | undefined\n}\n\nexport function InkSuggestionCard({ children }: InkSuggestionCardProps) {\n const ctx = useInkContext('InkSuggestionCard')\n const {\n annotations,\n selection,\n accept: acceptId,\n dismiss: dismissId,\n select,\n } = useAnnotations()\n\n function suggestion(id: string | null | undefined): RedactAnnotation | null {\n const a = id ? annotations.find((x) => x.id === id) : undefined\n return a?.type === 'redact' && a.origin === 'suggested' ? a : null\n }\n // The activated annotation when it is a suggestion; otherwise the only selected one (a\n // marquee selects without activating).\n const target =\n suggestion(ctx.activated) ??\n (selection.length === 1 ? suggestion(selection[0]) : null)\n const anchor = useAnnotationElement(ctx.rootEl, target?.id ?? null)\n const anchorRef = useMemo(() => ({ current: anchor }), [anchor])\n const focusReturn = useFocusReturn(ctx)\n const open = target !== null && anchor !== null\n const bucket: ConfidenceBucket | undefined = target?.suggestion\n ? confidenceBucket(target.suggestion.confidence)\n : undefined\n\n function close(): void {\n ctx.setActivated(null)\n select([])\n }\n function accept(): void {\n if (target) acceptId(target.id)\n close()\n }\n /** Locked annotations cannot be removed: dismissing one does nothing and keeps the card. */\n function dismiss(): void {\n if (!target || target.locked) return\n focusReturn.beforeRemove(anchor, '[data-origin=\"suggested\"]')\n dismissId(target.id)\n close()\n }\n\n return (\n <Popover.Root open={open} onOpenChange={(next) => !next && close()}>\n <Popover.Anchor virtualRef={anchorRef} />\n <Popover.Portal>\n {target && anchor ? (\n <Popover.Content\n className=\"ink-suggestion-card\"\n data-ink-suggestion-card=\"\"\n side=\"bottom\"\n sideOffset={6}\n collisionPadding={8}\n aria-label=\"Suggested redaction\"\n onInteractOutside={keepOpenOnAnnotation}\n onCloseAutoFocus={(e) => focusReturn.onCloseAutoFocus(e, anchor)}\n >\n {children ? (\n children({\n annotation: target,\n suggestion: target.suggestion,\n bucket,\n accept,\n dismiss,\n close,\n })\n ) : (\n <>\n <p className=\"ink-suggestion-reason\">\n <strong>{target.suggestion?.reason ?? 'Suggested redaction'}</strong>\n {bucket ? (\n <span className=\"ink-suggestion-confidence\" data-confidence={bucket}>\n {bucket} confidence\n </span>\n ) : null}\n </p>\n {target.suggestion?.explanation ? (\n <p className=\"ink-suggestion-explanation\">\n {target.suggestion.explanation}\n </p>\n ) : null}\n <div className=\"ink-suggestion-actions\">\n <button type=\"button\" onClick={accept}>\n Accept\n </button>\n {!target.locked ? (\n <button type=\"button\" onClick={dismiss}>\n Dismiss\n </button>\n ) : null}\n </div>\n </>\n )}\n </Popover.Content>\n ) : null}\n </Popover.Portal>\n </Popover.Root>\n )\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inkbar/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "React components and hooks for Inkbar, the browser PDF viewer and editor.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://inkbar.dev",
|
|
@@ -24,18 +24,18 @@
|
|
|
24
24
|
"./package.json": "./package.json"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"
|
|
27
|
+
"@inkbar/icons": "^0.3.0",
|
|
28
28
|
"radix-ui": "^1.8.1"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@inkbar/core": "^0.
|
|
31
|
+
"@inkbar/core": "^0.3.0",
|
|
32
32
|
"react": "^19.0.0",
|
|
33
33
|
"react-dom": "^19.0.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@inkbar/core": "0.
|
|
36
|
+
"@inkbar/core": "0.3.0",
|
|
37
37
|
"@inkbar/fixtures": "0.0.0",
|
|
38
|
-
"@inkbar/theme": "0.
|
|
38
|
+
"@inkbar/theme": "0.3.0",
|
|
39
39
|
"@playwright/experimental-ct-react": "1.62.1",
|
|
40
40
|
"@playwright/test": "1.62.1",
|
|
41
41
|
"@types/react": "^19.3.0",
|