@inkbar/react 0.1.1 → 0.2.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 CHANGED
@@ -20,7 +20,7 @@
20
20
 
21
21
  ---
22
22
 
23
- Drop a PDF viewer into your React app and let people highlight text, leave notes with replies and review redactions. `@inkbar/react` gives you a default toolbar and popovers styled by `@inkbar/theme`, plus the unstyled components and hooks they are made from, so you can keep the defaults or build your own UI.
23
+ Drop a PDF viewer into your React app and let people highlight text, leave notes with replies and review redactions. `@inkbar/react` gives you components and hooks to build your own toolbars, plus note and suggestion popovers, all styled by `@inkbar/theme`.
24
24
 
25
25
  Annotations are plain typed objects. Control them from your own state, or let Inkbar hold them with undo and redo.
26
26
 
@@ -39,7 +39,16 @@ import { useState } from 'react'
39
39
  import {
40
40
  InkRoot,
41
41
  InkViewport,
42
- DefaultToolbar,
42
+ InkToolbar,
43
+ InkToolButton,
44
+ InkToolbarSeparator,
45
+ InkUndo,
46
+ InkRedo,
47
+ InkPrevPage,
48
+ InkPageInput,
49
+ InkPageCount,
50
+ InkNextPage,
51
+ InkZoomSelect,
43
52
  InkNotePopover,
44
53
  InkSuggestionCard,
45
54
  } from '@inkbar/react'
@@ -62,8 +71,23 @@ export function Review({
62
71
  annotations={annotations}
63
72
  onAnnotationsChange={setAnnotations}
64
73
  >
65
- <DefaultToolbar />
74
+ <InkToolbar>
75
+ <InkToolButton tool="select" />
76
+ <InkToolButton tool="highlight" />
77
+ <InkToolButton tool="redact-area" />
78
+ <InkToolButton tool="note" />
79
+ <InkToolbarSeparator />
80
+ <InkUndo />
81
+ <InkRedo />
82
+ </InkToolbar>
66
83
  <InkViewport />
84
+ <InkToolbar label="Page and zoom">
85
+ <InkPrevPage />
86
+ <InkPageInput />
87
+ <InkPageCount />
88
+ <InkNextPage />
89
+ <InkZoomSelect />
90
+ </InkToolbar>
67
91
  <InkNotePopover />
68
92
  <InkSuggestionCard />
69
93
  </InkRoot>
@@ -71,6 +95,8 @@ export function Review({
71
95
  }
72
96
  ```
73
97
 
98
+ Each control is a separate component, so put them in any order or leave some out. Buttons show icons from `@inkbar/icons`. Pass your own as `children` to replace one, and use `InkIcon` to put the same icons on your own buttons.
99
+
74
100
  `annotations` with `onAnnotationsChange` makes your list the source of truth. Leave them off and Inkbar keeps the state itself, with undo and redo.
75
101
 
76
102
  ## Controlled mode
@@ -130,7 +156,7 @@ The scroll element takes focus. With the highlight or redact tool active, `Enter
130
156
 
131
157
  ## Styling
132
158
 
133
- Components carry state on data attributes, for example `[data-annotation][data-state="selected"]` and `[data-tool="highlight"][data-state="on"]`. `@inkbar/theme` gives a default look. Your own CSS overrides it without `!important`. `InkRoot`, `InkViewport`, `DefaultToolbar` and the toolbar controls accept `className`.
159
+ Components carry state on data attributes, for example `[data-annotation][data-state="selected"]` and `[data-tool="highlight"][data-state="on"]`. `@inkbar/theme` gives a default look. Your own CSS overrides it without `!important`. `InkRoot`, `InkViewport`, `InkToolbar` and the toolbar controls accept `className`.
134
160
 
135
161
  ## Hooks
136
162
 
package/dist/index.d.mts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { ComponentPropsWithoutRef, ReactNode, Ref } from "react";
2
2
  import { Annotation, AnnotationChange, AnnotationDefaults, AnnotationDocument, AnnotationInput, ConfidenceBucket, DocumentSource, ImportOptions, InkDocument, InkError, InkStatus, PageInfo, PdfAssets, Readable } from "@inkbar/core";
3
3
  import { AnnotationSlotProps, AnnotationSlotProps as AnnotationSlotProps$1, AnnotationState, LayoutMode, NotePopoverSlotProps, NotePopoverSlotProps as NotePopoverSlotProps$1, PageMount, SuggestionCardSlotProps, SuggestionCardSlotProps as SuggestionCardSlotProps$1, ToolController, ToolId, ViewRotation, Viewport, ZoomValue } from "@inkbar/core/dom";
4
+ import { Select } from "radix-ui";
5
+ import { IconNode } from "@inkbar/icons";
4
6
  //#region src/context.d.ts
5
7
  /** Undo and redo for the current document, whichever mode its annotations are in. */
6
8
  interface InkHistory {
@@ -1899,6 +1901,13 @@ interface InkToolbarProps extends Omit<ComponentPropsWithoutRef<'div'>, 'dir'> {
1899
1901
  }
1900
1902
  export declare function InkToolbar({ label, asChild, className, children, ...rest }: InkToolbarProps): import("react").JSX.Element;
1901
1903
  //#endregion
1904
+ //#region src/components/InkIcon.d.ts
1905
+ interface InkIconProps {
1906
+ icon: IconNode;
1907
+ size?: number;
1908
+ }
1909
+ export declare function InkIcon({ icon, size }: InkIconProps): import("react").JSX.Element;
1910
+ //#endregion
1902
1911
  //#region src/components/InkToolButton.d.ts
1903
1912
  interface InkToolButtonProps extends Omit<ComponentPropsWithoutRef<'button'>, 'children'> {
1904
1913
  tool: ToolId;
@@ -1911,6 +1920,26 @@ interface InkToolButtonProps extends Omit<ComponentPropsWithoutRef<'button'>, 'c
1911
1920
  }
1912
1921
  export declare function InkToolButton({ tool, label, asChild, className, children, onClick, ...rest }: InkToolButtonProps): import("react").JSX.Element;
1913
1922
  //#endregion
1923
+ //#region src/components/InkToolbarSeparator.d.ts
1924
+ type InkToolbarSeparatorProps = ComponentPropsWithoutRef<'div'>;
1925
+ /**
1926
+ * A divider between groups of controls in a horizontal toolbar. Not focusable. A plain div
1927
+ * rather than Radix's separator, which reads as horizontal inside a horizontal toolbar.
1928
+ */
1929
+ export declare function InkToolbarSeparator({ className, ...rest }: InkToolbarSeparatorProps): import("react").JSX.Element;
1930
+ //#endregion
1931
+ //#region src/components/history-button.d.ts
1932
+ /** Props of `InkUndo` and `InkRedo`: a toolbar button that may render as its child. */
1933
+ interface InkHistoryButtonProps extends ComponentPropsWithoutRef<'button'> {
1934
+ asChild?: boolean;
1935
+ }
1936
+ //#endregion
1937
+ //#region src/components/InkUndo.d.ts
1938
+ export declare function InkUndo({ asChild, className, children, disabled, onClick, ...rest }: InkHistoryButtonProps): import("react").JSX.Element;
1939
+ //#endregion
1940
+ //#region src/components/InkRedo.d.ts
1941
+ export declare function InkRedo({ asChild, className, children, disabled, onClick, ...rest }: InkHistoryButtonProps): import("react").JSX.Element;
1942
+ //#endregion
1914
1943
  //#region src/components/zoom-button.d.ts
1915
1944
  /** Props of `InkZoomIn` and `InkZoomOut`: a toolbar button that may render as its child. */
1916
1945
  interface InkZoomButtonProps extends ComponentPropsWithoutRef<'button'> {
@@ -1924,7 +1953,8 @@ export declare function InkZoomIn({ asChild, className, children, onClick, ...re
1924
1953
  export declare function InkZoomOut({ asChild, className, children, onClick, ...rest }: InkZoomButtonProps): import("react").JSX.Element;
1925
1954
  //#endregion
1926
1955
  //#region src/components/InkZoomSelect.d.ts
1927
- type InkZoomSelectProps = Omit<ComponentPropsWithoutRef<'select'>, 'value' | 'onChange'>;
1956
+ /** Props of the select's trigger button; the options come from the zoom levels. */
1957
+ type InkZoomSelectProps = Omit<ComponentPropsWithoutRef<typeof Select.Trigger>, 'children' | 'asChild'>;
1928
1958
  export declare function InkZoomSelect({ className, ...rest }: InkZoomSelectProps): import("react").JSX.Element;
1929
1959
  //#endregion
1930
1960
  //#region src/components/InkPageInput.d.ts
@@ -1934,13 +1964,17 @@ export declare function InkPageInput({ className, onKeyDown: onKeyDownProp, ...r
1934
1964
  //#region src/components/InkPageCount.d.ts
1935
1965
  export declare function InkPageCount({ className, ...rest }: ComponentPropsWithoutRef<'span'>): import("react").JSX.Element;
1936
1966
  //#endregion
1937
- //#region src/compositions/DefaultToolbar.d.ts
1938
- interface DefaultToolbarProps {
1939
- label?: string;
1940
- className?: string | undefined;
1941
- children?: ReactNode;
1967
+ //#region src/components/page-button.d.ts
1968
+ /** Props of `InkPrevPage` and `InkNextPage`: a toolbar button that may render as its child. */
1969
+ interface InkPageButtonProps extends ComponentPropsWithoutRef<'button'> {
1970
+ asChild?: boolean;
1942
1971
  }
1943
- export declare function DefaultToolbar({ label, className, children }: DefaultToolbarProps): import("react").JSX.Element;
1972
+ //#endregion
1973
+ //#region src/components/InkPrevPage.d.ts
1974
+ export declare function InkPrevPage({ asChild, className, children, disabled, onClick, ...rest }: InkPageButtonProps): import("react").JSX.Element;
1975
+ //#endregion
1976
+ //#region src/components/InkNextPage.d.ts
1977
+ export declare function InkNextPage({ asChild, className, children, disabled, onClick, ...rest }: InkPageButtonProps): import("react").JSX.Element;
1944
1978
  //#endregion
1945
1979
  //#region src/components/InkNotePopover.d.ts
1946
1980
  interface InkNotePopoverProps {
@@ -1954,5 +1988,5 @@ interface InkSuggestionCardProps {
1954
1988
  }
1955
1989
  export declare function InkSuggestionCard({ children }: InkSuggestionCardProps): import("react").JSX.Element;
1956
1990
  //#endregion
1957
- export type { AnnotationSlotProps, AnnotationState, ConfidenceBucket, DefaultToolbarProps, InkAnnotationProps, InkContext, InkHistory, InkNotePopoverProps, InkPageInputProps, InkPageProps, InkRootHandle, InkRootProps, InkStatus, InkSuggestionCardProps, InkToolButtonProps, InkToolbarProps, InkViewportProps, InkZoomButtonProps, InkZoomSelectProps, NotePopoverSlotProps, SuggestionCardSlotProps };
1991
+ export type { AnnotationSlotProps, AnnotationState, ConfidenceBucket, InkAnnotationProps, InkContext, InkHistory, InkHistoryButtonProps, InkIconProps, InkNotePopoverProps, InkPageButtonProps, InkPageInputProps, InkPageProps, InkRootHandle, InkRootProps, InkStatus, InkSuggestionCardProps, InkToolButtonProps, InkToolbarProps, InkToolbarSeparatorProps, InkViewportProps, InkZoomButtonProps, InkZoomSelectProps, NotePopoverSlotProps, SuggestionCardSlotProps };
1958
1992
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":["AnnotationSlotProps","AnnotationSlotProps","AnnotationSlotProps","NotePopoverSlotProps","SuggestionCardSlotProps"],"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/components/InkRoot.tsx","../src/components/InkViewport.tsx","../src/components/InkPage.tsx","../src/components/InkAnnotation.tsx","../src/components/InkToolbar.tsx","../src/components/InkToolButton.tsx","../src/components/zoom-button.ts","../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/InkNotePopover.tsx","../src/components/InkSuggestionCard.tsx"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":["AnnotationSlotProps","AnnotationSlotProps","AnnotationSlotProps","NotePopoverSlotProps","SuggestionCardSlotProps"],"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/components/InkRoot.tsx","../src/components/InkViewport.tsx","../src/components/InkPage.tsx","../src/components/InkAnnotation.tsx","../src/components/InkToolbar.tsx","../src/components/InkIcon.tsx","../src/components/InkToolButton.tsx","../src/components/InkToolbarSeparator.tsx","../src/components/history-button.ts","../src/components/InkUndo.tsx","../src/components/InkRedo.tsx","../src/components/zoom-button.ts","../src/components/InkZoomIn.tsx","../src/components/InkZoomOut.tsx","../src/components/InkZoomSelect.tsx","../src/components/InkPageInput.tsx","../src/components/InkPageCount.tsx","../src/components/page-button.ts","../src/components/InkPrevPage.tsx","../src/components/InkNextPage.tsx","../src/components/InkNotePopover.tsx","../src/components/InkSuggestionCard.tsx"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,11 +1,11 @@
1
1
  "use client";
2
- import { createContext, useCallback, useContext, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
2
+ import { createContext, createElement, useCallback, useContext, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
3
3
  import { InkError, acceptSuggestion, confidenceBucket, createSnapshotHistory, isAbandonedNote, openDocument, repliesTo, threadOf, threadRoot } from "@inkbar/core";
4
4
  import { TOOL_LABELS, ZOOM_LEVELS, createFocusReturn, cssVariableDefaults, mountViewer, observeAnnotationElement, shouldKeepOpenOnAnnotation } from "@inkbar/core/dom";
5
- import { Popover, Slot, Toolbar } from "radix-ui";
5
+ import { Popover, Select, Slot, Toolbar } from "radix-ui";
6
6
  import { createPortal, flushSync } from "react-dom";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
- import { Hand, Highlighter, MessageSquare, MousePointer2, Square, ZoomIn, ZoomOut } from "lucide-react";
8
+ import { Check, ChevronDown, ChevronLeft, ChevronRight, Hand, Highlighter, ICON_ATTRIBUTES, MessageSquare, MousePointer2, Redo2, Square, Undo2, ZoomIn, ZoomOut } from "@inkbar/icons";
9
9
  //#region src/context.ts
10
10
  const InkContextObject = createContext(null);
11
11
  /**
@@ -746,7 +746,32 @@ function InkToolbar({ label = "Document tools", asChild = false, className, chil
746
746
  });
747
747
  }
748
748
  //#endregion
749
+ //#region src/components/InkIcon.tsx
750
+ /** `stroke-width` to `strokeWidth`: React names SVG attributes in camelCase. */
751
+ const camel = (name) => name.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
752
+ const SVG_ATTRIBUTES = Object.fromEntries(Object.entries(ICON_ATTRIBUTES).map(([k, v]) => [camel(k), v]));
753
+ function InkIcon({ icon, size = 18 }) {
754
+ return /* @__PURE__ */ jsx("svg", {
755
+ ...SVG_ATTRIBUTES,
756
+ width: size,
757
+ height: size,
758
+ className: "ink-icon",
759
+ "aria-hidden": "true",
760
+ children: icon.map(([tag, attrs], i) => createElement(tag, {
761
+ key: i,
762
+ ...attrs
763
+ }))
764
+ });
765
+ }
766
+ //#endregion
749
767
  //#region src/components/InkToolButton.tsx
768
+ const ICONS = {
769
+ view: Hand,
770
+ select: MousePointer2,
771
+ highlight: Highlighter,
772
+ "redact-area": Square,
773
+ note: MessageSquare
774
+ };
750
775
  function InkToolButton({ tool, label, asChild = false, className, children, onClick, ...rest }) {
751
776
  const { tool: current, setTool } = useTool();
752
777
  const active = current === tool;
@@ -768,7 +793,60 @@ function InkToolButton({ tool, label, asChild = false, className, children, onCl
768
793
  children: typeof children === "function" ? children({
769
794
  active,
770
795
  label: name
771
- }) : children ?? name
796
+ }) : children ?? /* @__PURE__ */ jsx(InkIcon, { icon: ICONS[tool] })
797
+ });
798
+ }
799
+ //#endregion
800
+ //#region src/components/InkToolbarSeparator.tsx
801
+ /**
802
+ * A divider between groups of controls in a horizontal toolbar. Not focusable. A plain div
803
+ * rather than Radix's separator, which reads as horizontal inside a horizontal toolbar.
804
+ */
805
+ function InkToolbarSeparator({ className, ...rest }) {
806
+ return /* @__PURE__ */ jsx("div", {
807
+ role: "separator",
808
+ "aria-orientation": "vertical",
809
+ className: cx("ink-toolbar-separator", className),
810
+ "data-ink-toolbar-separator": "",
811
+ ...rest
812
+ });
813
+ }
814
+ //#endregion
815
+ //#region src/components/InkUndo.tsx
816
+ function InkUndo({ asChild = false, className, children, disabled, onClick, ...rest }) {
817
+ const { canUndo, undo } = useHistory();
818
+ return /* @__PURE__ */ jsx(Toolbar.Button, {
819
+ asChild,
820
+ className: cx("ink-undo", className),
821
+ "data-ink-undo": "",
822
+ "aria-label": "Undo",
823
+ title: "Undo",
824
+ ...rest,
825
+ disabled: disabled === true || !canUndo,
826
+ onClick: (e) => {
827
+ onClick?.(e);
828
+ if (!e.defaultPrevented) undo();
829
+ },
830
+ children: children ?? /* @__PURE__ */ jsx(InkIcon, { icon: Undo2 })
831
+ });
832
+ }
833
+ //#endregion
834
+ //#region src/components/InkRedo.tsx
835
+ function InkRedo({ asChild = false, className, children, disabled, onClick, ...rest }) {
836
+ const { canRedo, redo } = useHistory();
837
+ return /* @__PURE__ */ jsx(Toolbar.Button, {
838
+ asChild,
839
+ className: cx("ink-redo", className),
840
+ "data-ink-redo": "",
841
+ "aria-label": "Redo",
842
+ title: "Redo",
843
+ ...rest,
844
+ disabled: disabled === true || !canRedo,
845
+ onClick: (e) => {
846
+ onClick?.(e);
847
+ if (!e.defaultPrevented) redo();
848
+ },
849
+ children: children ?? /* @__PURE__ */ jsx(InkIcon, { icon: Redo2 })
772
850
  });
773
851
  }
774
852
  //#endregion
@@ -786,7 +864,7 @@ function InkZoomIn({ asChild = false, className, children, onClick, ...rest }) {
786
864
  onClick?.(e);
787
865
  if (!e.defaultPrevented) zoomIn();
788
866
  },
789
- children: children ?? "+"
867
+ children: children ?? /* @__PURE__ */ jsx(InkIcon, { icon: ZoomIn })
790
868
  });
791
869
  }
792
870
  //#endregion
@@ -804,48 +882,90 @@ function InkZoomOut({ asChild = false, className, children, onClick, ...rest })
804
882
  onClick?.(e);
805
883
  if (!e.defaultPrevented) zoomOut();
806
884
  },
807
- children: children ?? "−"
885
+ children: children ?? /* @__PURE__ */ jsx(InkIcon, { icon: ZoomOut })
808
886
  });
809
887
  }
810
888
  //#endregion
811
889
  //#region src/components/InkZoomSelect.tsx
812
890
  const CUSTOM = "custom:";
813
891
  const level = (z) => ZOOM_LEVELS.find((l) => Math.abs(l - z) < .001);
892
+ const percent = (z) => `${Math.round(z * 100)}%`;
893
+ const FITS = [{
894
+ value: "fit-width",
895
+ label: "Fit width"
896
+ }, {
897
+ value: "fit-page",
898
+ label: "Fit page"
899
+ }];
900
+ function Item({ value, label }) {
901
+ return /* @__PURE__ */ jsxs(Select.Item, {
902
+ value,
903
+ className: "ink-select-item",
904
+ "data-ink-select-item": "",
905
+ children: [/* @__PURE__ */ jsx(Select.ItemText, { children: label }), /* @__PURE__ */ jsx(Select.ItemIndicator, {
906
+ className: "ink-select-indicator",
907
+ children: /* @__PURE__ */ jsx(InkIcon, {
908
+ icon: Check,
909
+ size: 16
910
+ })
911
+ })]
912
+ });
913
+ }
814
914
  function InkZoomSelect({ className, ...rest }) {
815
915
  const { zoom, scale, setZoom } = useZoom();
816
916
  /** A numeric zoom that is not one of the levels (zoom in and out multiply). */
817
917
  const custom = typeof zoom === "number" && level(zoom) === void 0 ? zoom : null;
818
918
  const value = typeof zoom !== "number" ? zoom : custom === null ? String(level(zoom)) : `${CUSTOM}${zoom}`;
819
- function onChange(e) {
820
- const v = e.target.value;
919
+ /** The levels, with a custom zoom in its place among them. */
920
+ const levels = ZOOM_LEVELS.map((l) => ({
921
+ z: l,
922
+ value: String(l),
923
+ label: percent(l)
924
+ }));
925
+ if (custom !== null) levels.push({
926
+ z: custom,
927
+ value: `${CUSTOM}${custom}`,
928
+ label: percent(scale)
929
+ });
930
+ levels.sort((a, b) => a.z - b.z);
931
+ function onValueChange(v) {
932
+ if (v === value) return;
821
933
  const next = v === "fit-width" || v === "fit-page" ? v : Number(v.replace(CUSTOM, ""));
822
934
  setZoom(next);
823
935
  }
824
- return /* @__PURE__ */ jsxs("select", {
825
- className: cx("ink-zoom-select", className),
826
- "data-ink-zoom-select": "",
827
- "aria-label": "Zoom",
936
+ return /* @__PURE__ */ jsxs(Select.Root, {
828
937
  value,
829
- onChange,
830
- ...rest,
831
- children: [
832
- /* @__PURE__ */ jsx("option", {
833
- value: "fit-width",
834
- children: "Fit width"
835
- }),
836
- /* @__PURE__ */ jsx("option", {
837
- value: "fit-page",
838
- children: "Fit page"
839
- }),
840
- ZOOM_LEVELS.map((l) => /* @__PURE__ */ jsxs("option", {
841
- value: String(l),
842
- children: [Math.round(l * 100), "%"]
843
- }, l)),
844
- custom !== null ? /* @__PURE__ */ jsxs("option", {
845
- value: `${CUSTOM}${custom}`,
846
- children: [Math.round(scale * 100), "%"]
847
- }) : null
848
- ]
938
+ onValueChange,
939
+ children: [/* @__PURE__ */ jsxs(Select.Trigger, {
940
+ className: cx("ink-zoom-select ink-select-trigger", className),
941
+ "data-ink-zoom-select": "",
942
+ "aria-label": "Zoom",
943
+ ...rest,
944
+ children: [/* @__PURE__ */ jsx(Select.Value, { className: "ink-select-value" }), /* @__PURE__ */ jsx(Select.Icon, {
945
+ className: "ink-select-icon",
946
+ children: /* @__PURE__ */ jsx(InkIcon, {
947
+ icon: ChevronDown,
948
+ size: 16
949
+ })
950
+ })]
951
+ }), /* @__PURE__ */ jsx(Select.Portal, { children: /* @__PURE__ */ jsx(Select.Content, {
952
+ className: "ink-select-content",
953
+ "data-ink-select-content": "",
954
+ position: "popper",
955
+ side: "top",
956
+ sideOffset: 4,
957
+ children: /* @__PURE__ */ jsxs(Select.Viewport, { children: [
958
+ FITS.map((o) => /* @__PURE__ */ jsx(Item, {
959
+ value: o.value,
960
+ label: o.label
961
+ }, o.value)),
962
+ /* @__PURE__ */ jsx(Select.Separator, { className: "ink-select-separator" }),
963
+ levels.map((o) => /* @__PURE__ */ jsx(Item, {
964
+ value: o.value,
965
+ label: o.label
966
+ }, o.value))
967
+ ] })
968
+ }) })]
849
969
  });
850
970
  }
851
971
  //#endregion
@@ -911,83 +1031,41 @@ function InkPageCount({ className, ...rest }) {
911
1031
  });
912
1032
  }
913
1033
  //#endregion
914
- //#region src/compositions/DefaultToolbar.tsx
915
- const ICON = 18;
916
- function DefaultToolbar({ label = "Document tools", className, children }) {
917
- return /* @__PURE__ */ jsxs(InkToolbar, {
918
- label,
919
- className: cx("ink-default-toolbar", className),
920
- "data-ink-default-toolbar": "",
921
- children: [
922
- /* @__PURE__ */ jsxs("div", {
923
- className: "ink-toolbar-group",
924
- "data-ink-toolbar-group": "tools",
925
- role: "group",
926
- "aria-label": "Tools",
927
- children: [
928
- /* @__PURE__ */ jsx(InkToolButton, {
929
- tool: "view",
930
- children: /* @__PURE__ */ jsx(Hand, {
931
- size: ICON,
932
- "aria-hidden": "true"
933
- })
934
- }),
935
- /* @__PURE__ */ jsx(InkToolButton, {
936
- tool: "select",
937
- children: /* @__PURE__ */ jsx(MousePointer2, {
938
- size: ICON,
939
- "aria-hidden": "true"
940
- })
941
- }),
942
- /* @__PURE__ */ jsx(InkToolButton, {
943
- tool: "highlight",
944
- children: /* @__PURE__ */ jsx(Highlighter, {
945
- size: ICON,
946
- "aria-hidden": "true"
947
- })
948
- }),
949
- /* @__PURE__ */ jsx(InkToolButton, {
950
- tool: "redact-area",
951
- children: /* @__PURE__ */ jsx(Square, {
952
- size: ICON,
953
- "aria-hidden": "true"
954
- })
955
- }),
956
- /* @__PURE__ */ jsx(InkToolButton, {
957
- tool: "note",
958
- children: /* @__PURE__ */ jsx(MessageSquare, {
959
- size: ICON,
960
- "aria-hidden": "true"
961
- })
962
- })
963
- ]
964
- }),
965
- /* @__PURE__ */ jsxs("div", {
966
- className: "ink-toolbar-group",
967
- "data-ink-toolbar-group": "zoom",
968
- role: "group",
969
- "aria-label": "Zoom",
970
- children: [
971
- /* @__PURE__ */ jsx(InkZoomOut, { children: /* @__PURE__ */ jsx(ZoomOut, {
972
- size: ICON,
973
- "aria-hidden": "true"
974
- }) }),
975
- /* @__PURE__ */ jsx(InkZoomSelect, {}),
976
- /* @__PURE__ */ jsx(InkZoomIn, { children: /* @__PURE__ */ jsx(ZoomIn, {
977
- size: ICON,
978
- "aria-hidden": "true"
979
- }) })
980
- ]
981
- }),
982
- /* @__PURE__ */ jsxs("div", {
983
- className: "ink-toolbar-group",
984
- "data-ink-toolbar-group": "page",
985
- role: "group",
986
- "aria-label": "Page",
987
- children: [/* @__PURE__ */ jsx(InkPageInput, {}), /* @__PURE__ */ jsx(InkPageCount, {})]
988
- }),
989
- children
990
- ]
1034
+ //#region src/components/InkPrevPage.tsx
1035
+ function InkPrevPage({ asChild = false, className, children, disabled, onClick, ...rest }) {
1036
+ const { current, previous } = usePage();
1037
+ return /* @__PURE__ */ jsx(Toolbar.Button, {
1038
+ asChild,
1039
+ className: cx("ink-prev-page", className),
1040
+ "data-ink-prev-page": "",
1041
+ "aria-label": "Previous page",
1042
+ title: "Previous page",
1043
+ disabled: disabled === true || current <= 0,
1044
+ ...rest,
1045
+ onClick: (e) => {
1046
+ onClick?.(e);
1047
+ if (!e.defaultPrevented) previous();
1048
+ },
1049
+ children: children ?? /* @__PURE__ */ jsx(InkIcon, { icon: ChevronLeft })
1050
+ });
1051
+ }
1052
+ //#endregion
1053
+ //#region src/components/InkNextPage.tsx
1054
+ function InkNextPage({ asChild = false, className, children, disabled, onClick, ...rest }) {
1055
+ const { current, count, next } = usePage();
1056
+ return /* @__PURE__ */ jsx(Toolbar.Button, {
1057
+ asChild,
1058
+ className: cx("ink-next-page", className),
1059
+ "data-ink-next-page": "",
1060
+ "aria-label": "Next page",
1061
+ title: "Next page",
1062
+ disabled: disabled === true || current >= count - 1,
1063
+ ...rest,
1064
+ onClick: (e) => {
1065
+ onClick?.(e);
1066
+ if (!e.defaultPrevented) next();
1067
+ },
1068
+ children: children ?? /* @__PURE__ */ jsx(InkIcon, { icon: ChevronRight })
991
1069
  });
992
1070
  }
993
1071
  //#endregion
@@ -1275,6 +1353,6 @@ function InkSuggestionCard({ children }) {
1275
1353
  });
1276
1354
  }
1277
1355
  //#endregion
1278
- export { DefaultToolbar, InkAnnotation, InkNotePopover, InkPage, InkPageCount, InkPageInput, InkRoot, InkSuggestionCard, InkToolButton, InkToolbar, InkViewport, InkZoomIn, InkZoomOut, InkZoomSelect, useAnnotations, useDocument, useEmbedded, useHistory, useInkContext, usePage, useReadable, useSelection, useTool, useZoom };
1356
+ export { InkAnnotation, InkIcon, InkNextPage, InkNotePopover, InkPage, InkPageCount, InkPageInput, InkPrevPage, InkRedo, InkRoot, InkSuggestionCard, InkToolButton, InkToolbar, InkToolbarSeparator, InkUndo, InkViewport, InkZoomIn, InkZoomOut, InkZoomSelect, useAnnotations, useDocument, useEmbedded, useHistory, useInkContext, usePage, useReadable, useSelection, useTool, useZoom };
1279
1357
 
1280
1358
  //# sourceMappingURL=index.mjs.map
@@ -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 === '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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkbar/react",
3
- "version": "0.1.1",
3
+ "version": "0.2.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
- "lucide-react": "^1.55.0",
27
+ "@inkbar/icons": "^0.2.0",
28
28
  "radix-ui": "^1.8.1"
29
29
  },
30
30
  "peerDependencies": {
31
- "@inkbar/core": "^0.1.1",
31
+ "@inkbar/core": "^0.2.0",
32
32
  "react": "^19.0.0",
33
33
  "react-dom": "^19.0.0"
34
34
  },
35
35
  "devDependencies": {
36
- "@inkbar/core": "0.1.1",
36
+ "@inkbar/core": "0.2.0",
37
37
  "@inkbar/fixtures": "0.0.0",
38
- "@inkbar/theme": "0.1.1",
38
+ "@inkbar/theme": "0.2.0",
39
39
  "@playwright/experimental-ct-react": "1.62.1",
40
40
  "@playwright/test": "1.62.1",
41
41
  "@types/react": "^19.3.0",