@inkbar/react 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -30,7 +30,7 @@ Annotations are plain typed objects. Control them from your own state, or let In
30
30
  pnpm add @inkbar/react @inkbar/core @inkbar/theme
31
31
  ```
32
32
 
33
- React 19 is a peer dependency. Add the Vite plugin from `@inkbar/core/vite` so the PDF engine can load its worker and fonts; the [`@inkbar/core` README](https://github.com/inkbar/inkbar/tree/main/packages/core#serving-pdfjs-assets) covers it. The package is marked `'use client'`, so a React Server Components app can import it from a server component.
33
+ React 19 and React DOM 19 are peer dependencies. Add the Vite plugin from `@inkbar/core/vite` so PDF.js can load its worker and fonts; the [`@inkbar/core` README](https://github.com/inkbar/inkbar/tree/main/packages/core#serving-pdfjs-assets) covers it. The package is marked `'use client'`, so a React Server Components app can import it from a server component.
34
34
 
35
35
  ## Usage
36
36
 
@@ -72,6 +72,7 @@ export function Review({
72
72
  onAnnotationsChange={setAnnotations}
73
73
  >
74
74
  <InkToolbar>
75
+ <InkToolButton tool="view" />
75
76
  <InkToolButton tool="select" />
76
77
  <InkToolButton tool="highlight" />
77
78
  <InkToolButton tool="redact-area" />
@@ -144,15 +145,30 @@ Inside `InkRoot`, `useHistory()` returns the same object. Its `batch(fn)` runs `
144
145
 
145
146
  `InkNotePopover` opens the thread of the activated note. A new note has no text yet, so the form first writes the note's own text (labelled "Comment"); after that it adds replies.
146
147
 
147
- A root note with no text and no replies is removed when its popover closes, or when activation moves to another annotation, so abandoned notes do not stay on the page. Locked notes are never removed. If you add notes yourself (`add({ type: 'note', ... })`), give them `contents`, or they will be removed the first time someone opens and closes them.
148
+ A root note with no text and no replies is removed when its popover closes, or when activation moves to another annotation, so abandoned notes do not stay on the page. Locked notes are never removed. If you add notes yourself (`add({ type: 'text', ... })`), give them `contents`, or they will be removed the first time someone opens and closes them.
148
149
 
149
150
  ## Custom rendering
150
151
 
151
152
  Slots are render props. `InkViewport` takes `loading`, `empty`, `error`, `renderAnnotation` and `renderPageError`; `InkNotePopover` and `InkSuggestionCard` take a function as `children`; `InkToolButton` takes a node or a function of `{ active, label }`. The props each receives are typed as `AnnotationSlotProps`, `NotePopoverSlotProps` and `SuggestionCardSlotProps`, the same types the Vue package exports.
152
153
 
154
+ `InkRoot`, `InkToolbar`, `InkToolButton`, `InkUndo`, `InkRedo`, `InkPrevPage`, `InkNextPage`, `InkZoomIn` and `InkZoomOut` take `asChild` to render your own element in place of theirs, such as a button from your design system. Pass that element as the only child. The control keeps its behaviour and accessible name.
155
+
153
156
  ## Keyboard
154
157
 
155
- The scroll element takes focus. With the highlight or redact tool active, `Enter` turns the text selection into a mark; with the note tool, `Enter` places a note in the middle of the current page and opens it. On a focused annotation, `Enter` or `Space` selects and activates it (a note opens its thread and a suggested redaction its card; other types are only selected), `ArrowUp` and `ArrowDown` move between annotations, `Shift` + arrow moves it by 1 pt (add `Alt` for 10 pt), `Ctrl` or `Cmd` + `Shift` + arrow resizes an area mark, and `Delete` removes it. The full table is in the [`@inkbar/core` README](https://github.com/inkbar/inkbar/tree/main/packages/core#tools-and-keyboard).
158
+ The scroll area takes focus. From there:
159
+
160
+ - With the `highlight` or `redact-area` tool active, `Enter` turns the text selection into a mark.
161
+ - With the `note` tool active, `Enter` places a note at the centre of the current page and opens it.
162
+
163
+ On a focused annotation:
164
+
165
+ - `Enter` or `Space` selects and activates it. A note opens its thread and a suggested redaction its card; other types are only selected.
166
+ - `ArrowUp` and `ArrowDown` move to the previous or next annotation on the page.
167
+ - `Shift` + arrow moves it by 1 pt, or by 10 pt with `Alt` as well.
168
+ - `Ctrl` or `Cmd` + `Shift` + arrow resizes an area redaction, text box or shape.
169
+ - `Delete` or `Backspace` removes it.
170
+
171
+ The full table, with the zoom and page keys, is in the [`@inkbar/core` README](https://github.com/inkbar/inkbar/tree/main/packages/core#tools-and-keyboard).
156
172
 
157
173
  ## Styling
158
174
 
package/dist/index.d.mts CHANGED
@@ -124,8 +124,8 @@ export declare function useAnnotations(): {
124
124
  createdAt: string;
125
125
  modifiedAt: string;
126
126
  source: "session" | "pdf";
127
- type: "note";
128
- icon: "note" | "comment" | "help" | "insert" | "key" | "paragraph";
127
+ type: "text";
128
+ icon: "comment" | "note" | "help" | "insert" | "key" | "paragraph";
129
129
  author?: string | undefined;
130
130
  contents?: string | undefined;
131
131
  inReplyTo?: string | undefined;
@@ -145,13 +145,12 @@ export declare function useAnnotations(): {
145
145
  createdAt: string;
146
146
  modifiedAt: string;
147
147
  source: "session" | "pdf";
148
- type: "freeText";
149
- text: string;
148
+ type: "freetext";
149
+ contents: string;
150
150
  fontSize: number;
151
151
  fontFamily: string;
152
152
  align: "left" | "center" | "right";
153
153
  author?: string | undefined;
154
- contents?: string | undefined;
155
154
  inReplyTo?: string | undefined;
156
155
  locked?: boolean | undefined;
157
156
  custom?: Record<string, unknown> | undefined;
@@ -174,13 +173,13 @@ export declare function useAnnotations(): {
174
173
  modifiedAt: string;
175
174
  source: "session" | "pdf";
176
175
  type: "square" | "circle";
177
- strokeWidth: number;
176
+ width: number;
178
177
  author?: string | undefined;
179
178
  contents?: string | undefined;
180
179
  inReplyTo?: string | undefined;
181
180
  locked?: boolean | undefined;
182
181
  custom?: Record<string, unknown> | undefined;
183
- fill?: string | undefined;
182
+ interiorColor?: string | undefined;
184
183
  } | {
185
184
  id: string;
186
185
  page: number;
@@ -204,13 +203,14 @@ export declare function useAnnotations(): {
204
203
  x: number;
205
204
  y: number;
206
205
  };
207
- strokeWidth: number;
206
+ width: number;
208
207
  author?: string | undefined;
209
208
  contents?: string | undefined;
210
209
  inReplyTo?: string | undefined;
211
210
  locked?: boolean | undefined;
212
211
  custom?: Record<string, unknown> | undefined;
213
- endings?: ["square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash", "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash"] | undefined;
212
+ head?: "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash" | undefined;
213
+ tail?: "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash" | undefined;
214
214
  } | {
215
215
  id: string;
216
216
  page: number;
@@ -230,13 +230,13 @@ export declare function useAnnotations(): {
230
230
  x: number;
231
231
  y: number;
232
232
  }[];
233
- strokeWidth: number;
233
+ width: number;
234
234
  author?: string | undefined;
235
235
  contents?: string | undefined;
236
236
  inReplyTo?: string | undefined;
237
237
  locked?: boolean | undefined;
238
238
  custom?: Record<string, unknown> | undefined;
239
- fill?: string | undefined;
239
+ interiorColor?: string | undefined;
240
240
  } | {
241
241
  id: string;
242
242
  page: number;
@@ -252,11 +252,11 @@ export declare function useAnnotations(): {
252
252
  modifiedAt: string;
253
253
  source: "session" | "pdf";
254
254
  type: "ink";
255
- paths: {
255
+ inklist: {
256
256
  x: number;
257
257
  y: number;
258
258
  }[][];
259
- strokeWidth: number;
259
+ width: number;
260
260
  author?: string | undefined;
261
261
  contents?: string | undefined;
262
262
  inReplyTo?: string | undefined;
@@ -278,7 +278,7 @@ export declare function useAnnotations(): {
278
278
  source: "session" | "pdf";
279
279
  type: "redact";
280
280
  origin: "user" | "suggested";
281
- fill: string;
281
+ interiorColor: string;
282
282
  author?: string | undefined;
283
283
  contents?: string | undefined;
284
284
  inReplyTo?: string | undefined;
@@ -363,8 +363,8 @@ export declare function useAnnotations(): {
363
363
  createdAt: string;
364
364
  modifiedAt: string;
365
365
  source: "session" | "pdf";
366
- type: "note";
367
- icon: "note" | "comment" | "help" | "insert" | "key" | "paragraph";
366
+ type: "text";
367
+ icon: "comment" | "note" | "help" | "insert" | "key" | "paragraph";
368
368
  author?: string | undefined;
369
369
  contents?: string | undefined;
370
370
  inReplyTo?: string | undefined;
@@ -384,13 +384,12 @@ export declare function useAnnotations(): {
384
384
  createdAt: string;
385
385
  modifiedAt: string;
386
386
  source: "session" | "pdf";
387
- type: "freeText";
388
- text: string;
387
+ type: "freetext";
388
+ contents: string;
389
389
  fontSize: number;
390
390
  fontFamily: string;
391
391
  align: "left" | "center" | "right";
392
392
  author?: string | undefined;
393
- contents?: string | undefined;
394
393
  inReplyTo?: string | undefined;
395
394
  locked?: boolean | undefined;
396
395
  custom?: Record<string, unknown> | undefined;
@@ -413,13 +412,13 @@ export declare function useAnnotations(): {
413
412
  modifiedAt: string;
414
413
  source: "session" | "pdf";
415
414
  type: "square" | "circle";
416
- strokeWidth: number;
415
+ width: number;
417
416
  author?: string | undefined;
418
417
  contents?: string | undefined;
419
418
  inReplyTo?: string | undefined;
420
419
  locked?: boolean | undefined;
421
420
  custom?: Record<string, unknown> | undefined;
422
- fill?: string | undefined;
421
+ interiorColor?: string | undefined;
423
422
  } | {
424
423
  id: string;
425
424
  page: number;
@@ -443,13 +442,14 @@ export declare function useAnnotations(): {
443
442
  x: number;
444
443
  y: number;
445
444
  };
446
- strokeWidth: number;
445
+ width: number;
447
446
  author?: string | undefined;
448
447
  contents?: string | undefined;
449
448
  inReplyTo?: string | undefined;
450
449
  locked?: boolean | undefined;
451
450
  custom?: Record<string, unknown> | undefined;
452
- endings?: ["square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash", "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash"] | undefined;
451
+ head?: "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash" | undefined;
452
+ tail?: "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash" | undefined;
453
453
  } | {
454
454
  id: string;
455
455
  page: number;
@@ -469,13 +469,13 @@ export declare function useAnnotations(): {
469
469
  x: number;
470
470
  y: number;
471
471
  }[];
472
- strokeWidth: number;
472
+ width: number;
473
473
  author?: string | undefined;
474
474
  contents?: string | undefined;
475
475
  inReplyTo?: string | undefined;
476
476
  locked?: boolean | undefined;
477
477
  custom?: Record<string, unknown> | undefined;
478
- fill?: string | undefined;
478
+ interiorColor?: string | undefined;
479
479
  } | {
480
480
  id: string;
481
481
  page: number;
@@ -491,11 +491,11 @@ export declare function useAnnotations(): {
491
491
  modifiedAt: string;
492
492
  source: "session" | "pdf";
493
493
  type: "ink";
494
- paths: {
494
+ inklist: {
495
495
  x: number;
496
496
  y: number;
497
497
  }[][];
498
- strokeWidth: number;
498
+ width: number;
499
499
  author?: string | undefined;
500
500
  contents?: string | undefined;
501
501
  inReplyTo?: string | undefined;
@@ -517,7 +517,7 @@ export declare function useAnnotations(): {
517
517
  source: "session" | "pdf";
518
518
  type: "redact";
519
519
  origin: "user" | "suggested";
520
- fill: string;
520
+ interiorColor: string;
521
521
  author?: string | undefined;
522
522
  contents?: string | undefined;
523
523
  inReplyTo?: string | undefined;
@@ -605,8 +605,8 @@ export declare function useAnnotations(): {
605
605
  createdAt: string;
606
606
  modifiedAt: string;
607
607
  source: "session" | "pdf";
608
- type: "note";
609
- icon: "note" | "comment" | "help" | "insert" | "key" | "paragraph";
608
+ type: "text";
609
+ icon: "comment" | "note" | "help" | "insert" | "key" | "paragraph";
610
610
  author?: string | undefined;
611
611
  contents?: string | undefined;
612
612
  inReplyTo?: string | undefined;
@@ -626,13 +626,12 @@ export declare function useAnnotations(): {
626
626
  createdAt: string;
627
627
  modifiedAt: string;
628
628
  source: "session" | "pdf";
629
- type: "freeText";
630
- text: string;
629
+ type: "freetext";
630
+ contents: string;
631
631
  fontSize: number;
632
632
  fontFamily: string;
633
633
  align: "left" | "center" | "right";
634
634
  author?: string | undefined;
635
- contents?: string | undefined;
636
635
  inReplyTo?: string | undefined;
637
636
  locked?: boolean | undefined;
638
637
  custom?: Record<string, unknown> | undefined;
@@ -655,13 +654,13 @@ export declare function useAnnotations(): {
655
654
  modifiedAt: string;
656
655
  source: "session" | "pdf";
657
656
  type: "square" | "circle";
658
- strokeWidth: number;
657
+ width: number;
659
658
  author?: string | undefined;
660
659
  contents?: string | undefined;
661
660
  inReplyTo?: string | undefined;
662
661
  locked?: boolean | undefined;
663
662
  custom?: Record<string, unknown> | undefined;
664
- fill?: string | undefined;
663
+ interiorColor?: string | undefined;
665
664
  } | {
666
665
  id: string;
667
666
  page: number;
@@ -685,13 +684,14 @@ export declare function useAnnotations(): {
685
684
  x: number;
686
685
  y: number;
687
686
  };
688
- strokeWidth: number;
687
+ width: number;
689
688
  author?: string | undefined;
690
689
  contents?: string | undefined;
691
690
  inReplyTo?: string | undefined;
692
691
  locked?: boolean | undefined;
693
692
  custom?: Record<string, unknown> | undefined;
694
- endings?: ["square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash", "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash"] | undefined;
693
+ head?: "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash" | undefined;
694
+ tail?: "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash" | undefined;
695
695
  } | {
696
696
  id: string;
697
697
  page: number;
@@ -711,13 +711,13 @@ export declare function useAnnotations(): {
711
711
  x: number;
712
712
  y: number;
713
713
  }[];
714
- strokeWidth: number;
714
+ width: number;
715
715
  author?: string | undefined;
716
716
  contents?: string | undefined;
717
717
  inReplyTo?: string | undefined;
718
718
  locked?: boolean | undefined;
719
719
  custom?: Record<string, unknown> | undefined;
720
- fill?: string | undefined;
720
+ interiorColor?: string | undefined;
721
721
  } | {
722
722
  id: string;
723
723
  page: number;
@@ -733,11 +733,11 @@ export declare function useAnnotations(): {
733
733
  modifiedAt: string;
734
734
  source: "session" | "pdf";
735
735
  type: "ink";
736
- paths: {
736
+ inklist: {
737
737
  x: number;
738
738
  y: number;
739
739
  }[][];
740
- strokeWidth: number;
740
+ width: number;
741
741
  author?: string | undefined;
742
742
  contents?: string | undefined;
743
743
  inReplyTo?: string | undefined;
@@ -759,7 +759,7 @@ export declare function useAnnotations(): {
759
759
  source: "session" | "pdf";
760
760
  type: "redact";
761
761
  origin: "user" | "suggested";
762
- fill: string;
762
+ interiorColor: string;
763
763
  author?: string | undefined;
764
764
  contents?: string | undefined;
765
765
  inReplyTo?: string | undefined;
@@ -845,8 +845,8 @@ export declare function useAnnotations(): {
845
845
  createdAt: string;
846
846
  modifiedAt: string;
847
847
  source: "session" | "pdf";
848
- type: "note";
849
- icon: "note" | "comment" | "help" | "insert" | "key" | "paragraph";
848
+ type: "text";
849
+ icon: "comment" | "note" | "help" | "insert" | "key" | "paragraph";
850
850
  author?: string | undefined;
851
851
  contents?: string | undefined;
852
852
  inReplyTo?: string | undefined;
@@ -866,13 +866,12 @@ export declare function useAnnotations(): {
866
866
  createdAt: string;
867
867
  modifiedAt: string;
868
868
  source: "session" | "pdf";
869
- type: "freeText";
870
- text: string;
869
+ type: "freetext";
870
+ contents: string;
871
871
  fontSize: number;
872
872
  fontFamily: string;
873
873
  align: "left" | "center" | "right";
874
874
  author?: string | undefined;
875
- contents?: string | undefined;
876
875
  inReplyTo?: string | undefined;
877
876
  locked?: boolean | undefined;
878
877
  custom?: Record<string, unknown> | undefined;
@@ -895,13 +894,13 @@ export declare function useAnnotations(): {
895
894
  modifiedAt: string;
896
895
  source: "session" | "pdf";
897
896
  type: "square" | "circle";
898
- strokeWidth: number;
897
+ width: number;
899
898
  author?: string | undefined;
900
899
  contents?: string | undefined;
901
900
  inReplyTo?: string | undefined;
902
901
  locked?: boolean | undefined;
903
902
  custom?: Record<string, unknown> | undefined;
904
- fill?: string | undefined;
903
+ interiorColor?: string | undefined;
905
904
  } | {
906
905
  id: string;
907
906
  page: number;
@@ -925,13 +924,14 @@ export declare function useAnnotations(): {
925
924
  x: number;
926
925
  y: number;
927
926
  };
928
- strokeWidth: number;
927
+ width: number;
929
928
  author?: string | undefined;
930
929
  contents?: string | undefined;
931
930
  inReplyTo?: string | undefined;
932
931
  locked?: boolean | undefined;
933
932
  custom?: Record<string, unknown> | undefined;
934
- endings?: ["square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash", "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash"] | undefined;
933
+ head?: "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash" | undefined;
934
+ tail?: "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash" | undefined;
935
935
  } | {
936
936
  id: string;
937
937
  page: number;
@@ -951,13 +951,13 @@ export declare function useAnnotations(): {
951
951
  x: number;
952
952
  y: number;
953
953
  }[];
954
- strokeWidth: number;
954
+ width: number;
955
955
  author?: string | undefined;
956
956
  contents?: string | undefined;
957
957
  inReplyTo?: string | undefined;
958
958
  locked?: boolean | undefined;
959
959
  custom?: Record<string, unknown> | undefined;
960
- fill?: string | undefined;
960
+ interiorColor?: string | undefined;
961
961
  } | {
962
962
  id: string;
963
963
  page: number;
@@ -973,11 +973,11 @@ export declare function useAnnotations(): {
973
973
  modifiedAt: string;
974
974
  source: "session" | "pdf";
975
975
  type: "ink";
976
- paths: {
976
+ inklist: {
977
977
  x: number;
978
978
  y: number;
979
979
  }[][];
980
- strokeWidth: number;
980
+ width: number;
981
981
  author?: string | undefined;
982
982
  contents?: string | undefined;
983
983
  inReplyTo?: string | undefined;
@@ -999,7 +999,7 @@ export declare function useAnnotations(): {
999
999
  source: "session" | "pdf";
1000
1000
  type: "redact";
1001
1001
  origin: "user" | "suggested";
1002
- fill: string;
1002
+ interiorColor: string;
1003
1003
  author?: string | undefined;
1004
1004
  contents?: string | undefined;
1005
1005
  inReplyTo?: string | undefined;
@@ -1085,8 +1085,8 @@ export declare function useAnnotations(): {
1085
1085
  createdAt: string;
1086
1086
  modifiedAt: string;
1087
1087
  source: "session" | "pdf";
1088
- type: "note";
1089
- icon: "note" | "comment" | "help" | "insert" | "key" | "paragraph";
1088
+ type: "text";
1089
+ icon: "comment" | "note" | "help" | "insert" | "key" | "paragraph";
1090
1090
  author?: string | undefined;
1091
1091
  contents?: string | undefined;
1092
1092
  inReplyTo?: string | undefined;
@@ -1106,13 +1106,12 @@ export declare function useAnnotations(): {
1106
1106
  createdAt: string;
1107
1107
  modifiedAt: string;
1108
1108
  source: "session" | "pdf";
1109
- type: "freeText";
1110
- text: string;
1109
+ type: "freetext";
1110
+ contents: string;
1111
1111
  fontSize: number;
1112
1112
  fontFamily: string;
1113
1113
  align: "left" | "center" | "right";
1114
1114
  author?: string | undefined;
1115
- contents?: string | undefined;
1116
1115
  inReplyTo?: string | undefined;
1117
1116
  locked?: boolean | undefined;
1118
1117
  custom?: Record<string, unknown> | undefined;
@@ -1135,13 +1134,13 @@ export declare function useAnnotations(): {
1135
1134
  modifiedAt: string;
1136
1135
  source: "session" | "pdf";
1137
1136
  type: "square" | "circle";
1138
- strokeWidth: number;
1137
+ width: number;
1139
1138
  author?: string | undefined;
1140
1139
  contents?: string | undefined;
1141
1140
  inReplyTo?: string | undefined;
1142
1141
  locked?: boolean | undefined;
1143
1142
  custom?: Record<string, unknown> | undefined;
1144
- fill?: string | undefined;
1143
+ interiorColor?: string | undefined;
1145
1144
  } | {
1146
1145
  id: string;
1147
1146
  page: number;
@@ -1165,13 +1164,14 @@ export declare function useAnnotations(): {
1165
1164
  x: number;
1166
1165
  y: number;
1167
1166
  };
1168
- strokeWidth: number;
1167
+ width: number;
1169
1168
  author?: string | undefined;
1170
1169
  contents?: string | undefined;
1171
1170
  inReplyTo?: string | undefined;
1172
1171
  locked?: boolean | undefined;
1173
1172
  custom?: Record<string, unknown> | undefined;
1174
- endings?: ["square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash", "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash"] | undefined;
1173
+ head?: "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash" | undefined;
1174
+ tail?: "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash" | undefined;
1175
1175
  } | {
1176
1176
  id: string;
1177
1177
  page: number;
@@ -1191,13 +1191,13 @@ export declare function useAnnotations(): {
1191
1191
  x: number;
1192
1192
  y: number;
1193
1193
  }[];
1194
- strokeWidth: number;
1194
+ width: number;
1195
1195
  author?: string | undefined;
1196
1196
  contents?: string | undefined;
1197
1197
  inReplyTo?: string | undefined;
1198
1198
  locked?: boolean | undefined;
1199
1199
  custom?: Record<string, unknown> | undefined;
1200
- fill?: string | undefined;
1200
+ interiorColor?: string | undefined;
1201
1201
  } | {
1202
1202
  id: string;
1203
1203
  page: number;
@@ -1213,11 +1213,11 @@ export declare function useAnnotations(): {
1213
1213
  modifiedAt: string;
1214
1214
  source: "session" | "pdf";
1215
1215
  type: "ink";
1216
- paths: {
1216
+ inklist: {
1217
1217
  x: number;
1218
1218
  y: number;
1219
1219
  }[][];
1220
- strokeWidth: number;
1220
+ width: number;
1221
1221
  author?: string | undefined;
1222
1222
  contents?: string | undefined;
1223
1223
  inReplyTo?: string | undefined;
@@ -1239,7 +1239,7 @@ export declare function useAnnotations(): {
1239
1239
  source: "session" | "pdf";
1240
1240
  type: "redact";
1241
1241
  origin: "user" | "suggested";
1242
- fill: string;
1242
+ interiorColor: string;
1243
1243
  author?: string | undefined;
1244
1244
  contents?: string | undefined;
1245
1245
  inReplyTo?: string | undefined;
@@ -1324,8 +1324,8 @@ export declare function useAnnotations(): {
1324
1324
  createdAt: string;
1325
1325
  modifiedAt: string;
1326
1326
  source: "session" | "pdf";
1327
- type: "note";
1328
- icon: "note" | "comment" | "help" | "insert" | "key" | "paragraph";
1327
+ type: "text";
1328
+ icon: "comment" | "note" | "help" | "insert" | "key" | "paragraph";
1329
1329
  author?: string | undefined;
1330
1330
  contents?: string | undefined;
1331
1331
  inReplyTo?: string | undefined;
@@ -1345,13 +1345,12 @@ export declare function useAnnotations(): {
1345
1345
  createdAt: string;
1346
1346
  modifiedAt: string;
1347
1347
  source: "session" | "pdf";
1348
- type: "freeText";
1349
- text: string;
1348
+ type: "freetext";
1349
+ contents: string;
1350
1350
  fontSize: number;
1351
1351
  fontFamily: string;
1352
1352
  align: "left" | "center" | "right";
1353
1353
  author?: string | undefined;
1354
- contents?: string | undefined;
1355
1354
  inReplyTo?: string | undefined;
1356
1355
  locked?: boolean | undefined;
1357
1356
  custom?: Record<string, unknown> | undefined;
@@ -1374,13 +1373,13 @@ export declare function useAnnotations(): {
1374
1373
  modifiedAt: string;
1375
1374
  source: "session" | "pdf";
1376
1375
  type: "square" | "circle";
1377
- strokeWidth: number;
1376
+ width: number;
1378
1377
  author?: string | undefined;
1379
1378
  contents?: string | undefined;
1380
1379
  inReplyTo?: string | undefined;
1381
1380
  locked?: boolean | undefined;
1382
1381
  custom?: Record<string, unknown> | undefined;
1383
- fill?: string | undefined;
1382
+ interiorColor?: string | undefined;
1384
1383
  } | {
1385
1384
  id: string;
1386
1385
  page: number;
@@ -1404,13 +1403,14 @@ export declare function useAnnotations(): {
1404
1403
  x: number;
1405
1404
  y: number;
1406
1405
  };
1407
- strokeWidth: number;
1406
+ width: number;
1408
1407
  author?: string | undefined;
1409
1408
  contents?: string | undefined;
1410
1409
  inReplyTo?: string | undefined;
1411
1410
  locked?: boolean | undefined;
1412
1411
  custom?: Record<string, unknown> | undefined;
1413
- endings?: ["square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash", "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash"] | undefined;
1412
+ head?: "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash" | undefined;
1413
+ tail?: "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash" | undefined;
1414
1414
  } | {
1415
1415
  id: string;
1416
1416
  page: number;
@@ -1430,13 +1430,13 @@ export declare function useAnnotations(): {
1430
1430
  x: number;
1431
1431
  y: number;
1432
1432
  }[];
1433
- strokeWidth: number;
1433
+ width: number;
1434
1434
  author?: string | undefined;
1435
1435
  contents?: string | undefined;
1436
1436
  inReplyTo?: string | undefined;
1437
1437
  locked?: boolean | undefined;
1438
1438
  custom?: Record<string, unknown> | undefined;
1439
- fill?: string | undefined;
1439
+ interiorColor?: string | undefined;
1440
1440
  } | {
1441
1441
  id: string;
1442
1442
  page: number;
@@ -1452,11 +1452,11 @@ export declare function useAnnotations(): {
1452
1452
  modifiedAt: string;
1453
1453
  source: "session" | "pdf";
1454
1454
  type: "ink";
1455
- paths: {
1455
+ inklist: {
1456
1456
  x: number;
1457
1457
  y: number;
1458
1458
  }[][];
1459
- strokeWidth: number;
1459
+ width: number;
1460
1460
  author?: string | undefined;
1461
1461
  contents?: string | undefined;
1462
1462
  inReplyTo?: string | undefined;
@@ -1478,7 +1478,7 @@ export declare function useAnnotations(): {
1478
1478
  source: "session" | "pdf";
1479
1479
  type: "redact";
1480
1480
  origin: "user" | "suggested";
1481
- fill: string;
1481
+ interiorColor: string;
1482
1482
  author?: string | undefined;
1483
1483
  contents?: string | undefined;
1484
1484
  inReplyTo?: string | undefined;
@@ -1564,8 +1564,8 @@ export declare function useAnnotations(): {
1564
1564
  createdAt: string;
1565
1565
  modifiedAt: string;
1566
1566
  source: "session" | "pdf";
1567
- type: "note";
1568
- icon: "note" | "comment" | "help" | "insert" | "key" | "paragraph";
1567
+ type: "text";
1568
+ icon: "comment" | "note" | "help" | "insert" | "key" | "paragraph";
1569
1569
  author?: string | undefined;
1570
1570
  contents?: string | undefined;
1571
1571
  inReplyTo?: string | undefined;
@@ -1585,13 +1585,12 @@ export declare function useAnnotations(): {
1585
1585
  createdAt: string;
1586
1586
  modifiedAt: string;
1587
1587
  source: "session" | "pdf";
1588
- type: "freeText";
1589
- text: string;
1588
+ type: "freetext";
1589
+ contents: string;
1590
1590
  fontSize: number;
1591
1591
  fontFamily: string;
1592
1592
  align: "left" | "center" | "right";
1593
1593
  author?: string | undefined;
1594
- contents?: string | undefined;
1595
1594
  inReplyTo?: string | undefined;
1596
1595
  locked?: boolean | undefined;
1597
1596
  custom?: Record<string, unknown> | undefined;
@@ -1614,13 +1613,13 @@ export declare function useAnnotations(): {
1614
1613
  modifiedAt: string;
1615
1614
  source: "session" | "pdf";
1616
1615
  type: "square" | "circle";
1617
- strokeWidth: number;
1616
+ width: number;
1618
1617
  author?: string | undefined;
1619
1618
  contents?: string | undefined;
1620
1619
  inReplyTo?: string | undefined;
1621
1620
  locked?: boolean | undefined;
1622
1621
  custom?: Record<string, unknown> | undefined;
1623
- fill?: string | undefined;
1622
+ interiorColor?: string | undefined;
1624
1623
  } | {
1625
1624
  id: string;
1626
1625
  page: number;
@@ -1644,13 +1643,14 @@ export declare function useAnnotations(): {
1644
1643
  x: number;
1645
1644
  y: number;
1646
1645
  };
1647
- strokeWidth: number;
1646
+ width: number;
1648
1647
  author?: string | undefined;
1649
1648
  contents?: string | undefined;
1650
1649
  inReplyTo?: string | undefined;
1651
1650
  locked?: boolean | undefined;
1652
1651
  custom?: Record<string, unknown> | undefined;
1653
- endings?: ["square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash", "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash"] | undefined;
1652
+ head?: "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash" | undefined;
1653
+ tail?: "square" | "circle" | "none" | "openArrow" | "closedArrow" | "diamond" | "butt" | "slash" | undefined;
1654
1654
  } | {
1655
1655
  id: string;
1656
1656
  page: number;
@@ -1670,13 +1670,13 @@ export declare function useAnnotations(): {
1670
1670
  x: number;
1671
1671
  y: number;
1672
1672
  }[];
1673
- strokeWidth: number;
1673
+ width: number;
1674
1674
  author?: string | undefined;
1675
1675
  contents?: string | undefined;
1676
1676
  inReplyTo?: string | undefined;
1677
1677
  locked?: boolean | undefined;
1678
1678
  custom?: Record<string, unknown> | undefined;
1679
- fill?: string | undefined;
1679
+ interiorColor?: string | undefined;
1680
1680
  } | {
1681
1681
  id: string;
1682
1682
  page: number;
@@ -1692,11 +1692,11 @@ export declare function useAnnotations(): {
1692
1692
  modifiedAt: string;
1693
1693
  source: "session" | "pdf";
1694
1694
  type: "ink";
1695
- paths: {
1695
+ inklist: {
1696
1696
  x: number;
1697
1697
  y: number;
1698
1698
  }[][];
1699
- strokeWidth: number;
1699
+ width: number;
1700
1700
  author?: string | undefined;
1701
1701
  contents?: string | undefined;
1702
1702
  inReplyTo?: string | undefined;
@@ -1718,7 +1718,7 @@ export declare function useAnnotations(): {
1718
1718
  source: "session" | "pdf";
1719
1719
  type: "redact";
1720
1720
  origin: "user" | "suggested";
1721
- fill: string;
1721
+ interiorColor: string;
1722
1722
  author?: string | undefined;
1723
1723
  contents?: string | undefined;
1724
1724
  inReplyTo?: string | undefined;
package/dist/index.mjs CHANGED
@@ -1106,7 +1106,7 @@ function InkNotePopover({ children }) {
1106
1106
  const { annotations, add, update, remove } = useAnnotations();
1107
1107
  const note = useMemo(() => {
1108
1108
  const a = ctx.activated ? annotations.find((x) => x.id === ctx.activated) : void 0;
1109
- return a?.type === "note" ? threadRoot(annotations, a) : null;
1109
+ return a?.type === "text" ? threadRoot(annotations, a) : null;
1110
1110
  }, [annotations, ctx.activated]);
1111
1111
  const anchor = useAnnotationElement(ctx.rootEl, note?.id ?? null);
1112
1112
  const anchorRef = useMemo(() => ({ current: anchor }), [anchor]);
@@ -1148,7 +1148,7 @@ function InkNotePopover({ children }) {
1148
1148
  if (!root || !contents) return;
1149
1149
  written.current.add(root.id);
1150
1150
  add({
1151
- type: "note",
1151
+ type: "text",
1152
1152
  page: root.page,
1153
1153
  rect: root.rect,
1154
1154
  contents,
@@ -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/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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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/context.ts","../src/use-readable.ts","../src/hooks/useDocument.ts","../src/hooks/useAnnotations.ts","../src/hooks/useTool.ts","../src/hooks/useSelection.ts","../src/hooks/useZoom.ts","../src/hooks/usePage.ts","../src/hooks/useHistory.ts","../src/hooks/useEmbedded.ts","../src/use-latest.ts","../src/components/InkRoot.tsx","../src/class-names.ts","../src/components/InkAnnotation.tsx","../src/components/InkPage.tsx","../src/components/InkViewport.tsx","../src/components/InkToolbar.tsx","../src/components/InkIcon.tsx","../src/components/InkToolButton.tsx","../src/components/InkToolbarSeparator.tsx","../src/components/InkUndo.tsx","../src/components/InkRedo.tsx","../src/components/InkZoomIn.tsx","../src/components/InkZoomOut.tsx","../src/components/InkZoomSelect.tsx","../src/components/InkPageInput.tsx","../src/components/InkPageCount.tsx","../src/components/InkPrevPage.tsx","../src/components/InkNextPage.tsx","../src/components/annotation-element.ts","../src/components/popover-focus.ts","../src/components/InkNotePopover.tsx","../src/components/InkSuggestionCard.tsx"],"sourcesContent":["import { createContext, useContext } from 'react'\n\nimport type { Annotation, InkDocument, InkStatus, PdfAssets } from '@inkbar/core'\nimport type { ToolController, ToolId, Viewport, ZoomValue } from '@inkbar/core/dom'\n\nexport type { InkStatus }\n\n/** Undo and redo for the current document, whichever mode its annotations are in. */\nexport interface InkHistory {\n canUndo: boolean\n canRedo: boolean\n undo: () => void\n redo: () => void\n clear: () => void\n /**\n * Runs `fn` and records what it changes as one undo step. The host still receives one change\n * per add. Controlled, the history groups the resulting list changes into one step, and\n * `canUndo` updates once the current task ends. Any other change the host applies in that\n * same window joins the step.\n */\n batch: (fn: () => void) => void\n}\n\nexport interface InkContext {\n assets: PdfAssets\n document: InkDocument | null\n /** `loading` from the moment a document starts opening, then the document's own status. */\n status: InkStatus\n annotations: readonly Annotation[]\n selection: readonly string[]\n /** Set by InkViewport once it has built its viewport and tool controller. */\n viewport: Viewport | null\n tools: ToolController | null\n /** Desired tool; InkViewport applies it to the controller. */\n tool: ToolId\n setTool: (id: ToolId) => void\n /** Desired zoom and page from the host's props; InkViewport applies and reports back. */\n zoomModel: ZoomValue | undefined\n pageModel: number | undefined\n reportZoom: (z: ZoomValue) => void\n reportPage: (p: number) => void\n /** Last activated annotation (Enter, click with the note tool, etc.). Popovers key off this. */\n activated: string | null\n setActivated: (id: string | null) => void\n history: InkHistory\n rootEl: HTMLElement | null\n setViewport: (viewport: Viewport | null, tools: ToolController | null) => void\n}\n\nexport const InkContextObject = createContext<InkContext | null>(null)\n\n/**\n * The context for hooks: throws a readable error when called outside a component rendered\n * inside `InkRoot`.\n */\nexport function useInkContext(consumer: string): InkContext {\n const ctx = useContext(InkContextObject)\n if (!ctx)\n throw new Error(\n `[inkbar] ${consumer} must be called in a component inside <InkRoot>.`\n )\n return ctx\n}\n","import { useCallback, useSyncExternalStore } from 'react'\n\nimport type { Readable } from '@inkbar/core'\n\nconst noop = (): void => undefined\n\n/**\n * Mirrors a core `Readable` into React. A missing readable yields `fallback`, which must be a\n * stable reference (a module constant): `useSyncExternalStore` compares snapshots by identity\n * and loops on a fresh value. On the server the fallback is rendered.\n */\nexport function useReadable<T>(readable: Readable<T> | null | undefined, fallback: T): T {\n const subscribe = useCallback(\n (onChange: () => void) => (readable ? readable.subscribe(() => onChange()) : noop),\n [readable]\n )\n const get = useCallback(\n () => (readable ? readable.get() : fallback),\n [readable, fallback]\n )\n const server = useCallback(() => fallback, [fallback])\n return useSyncExternalStore(subscribe, get, server)\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nimport type { AnnotationDocument, ImportOptions, PageInfo } from '@inkbar/core'\n\nconst NO_PAGES: readonly PageInfo[] = []\n\nexport function useDocument() {\n const ctx = useInkContext('useDocument()')\n const { document, status } = ctx\n return useMemo(\n () => ({\n document,\n status,\n isReady: status.state === 'ready',\n error: status.state === 'error' ? status.error : null,\n pages: document?.pages ?? NO_PAGES,\n info: document?.info ?? null,\n exportAnnotations: () => document?.exportAnnotations('json'),\n importAnnotations: (data: AnnotationDocument | string, opts?: ImportOptions) =>\n document?.importAnnotations(data, opts),\n }),\n [document, status]\n )\n}\n","import { acceptSuggestion, repliesTo } from '@inkbar/core'\nimport { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nimport type { Annotation, AnnotationInput } from '@inkbar/core'\n\nexport function useAnnotations() {\n const ctx = useInkContext('useAnnotations()')\n const { annotations, selection, document } = ctx\n const store = document?.annotations\n const selected = useMemo(\n () =>\n selection\n .map((id) => annotations.find((a) => a.id === id))\n .filter((a): a is Annotation => !!a),\n [annotations, selection]\n )\n // Stable for the life of the document, so hosts can pass them as props or effect deps.\n const actions = useMemo(\n () => ({\n add: (input: AnnotationInput) => store?.add(input),\n update: (id: string, patch: Partial<Annotation>) => store?.update(id, patch),\n remove: (id: string) => store?.remove(id) ?? false,\n select: (ids: string[]) => store?.select(ids),\n /** Keeps a suggested redaction as the user's own, in the default redaction colour. */\n accept: (id: string) => (store ? acceptSuggestion(store, id) : undefined),\n dismiss: (id: string) => store?.remove(id) ?? false,\n }),\n [store]\n )\n return useMemo(\n () => ({\n annotations,\n selection,\n selected,\n byPage: (page: number) => annotations.filter((a) => a.page === page),\n /** Replies in creation order for a note id. */\n replies: (id: string) => repliesTo(annotations, id),\n ...actions,\n }),\n [annotations, selection, selected, actions]\n )\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nexport function useTool() {\n const ctx = useInkContext('useTool()')\n const { tool, setTool } = ctx\n return useMemo(() => ({ tool, setTool }), [tool, setTool])\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nexport function useSelection() {\n const ctx = useInkContext('useSelection()')\n const { selection, document } = ctx\n const store = document?.annotations\n return useMemo(\n () => ({\n selection,\n select: (ids: string[]) => store?.select(ids),\n clear: () => store?.select([]),\n }),\n [selection, store]\n )\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\nimport { useReadable } from '../use-readable'\n\nimport type { ZoomValue } from '@inkbar/core/dom'\n\nexport function useZoom() {\n const ctx = useInkContext('useZoom()')\n const { viewport } = ctx\n const zoom = useReadable<ZoomValue>(viewport?.zoom, 'fit-width')\n const scale = useReadable<number>(viewport?.scale, 1)\n return useMemo(\n () => ({\n zoom,\n scale,\n setZoom: (z: ZoomValue) => viewport?.setZoom(z),\n zoomIn: () => viewport?.zoomBy(1.25),\n zoomOut: () => viewport?.zoomBy(0.8),\n }),\n [viewport, zoom, scale]\n )\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\nimport { useReadable } from '../use-readable'\n\nexport function usePage() {\n const ctx = useInkContext('usePage()')\n const { viewport, document } = ctx\n const current = useReadable<number>(viewport?.currentPage, 0)\n return useMemo(\n () => ({\n /** 0-based. */\n current,\n count: document?.pages.length ?? 0,\n goTo: (index: number) => viewport?.scrollToPage(index),\n // Read the live page, so these stay the same functions as the reader scrolls.\n next: () => viewport?.scrollToPage(viewport.currentPage.get() + 1),\n previous: () => viewport?.scrollToPage(viewport.currentPage.get() - 1),\n scrollToAnnotation(id: string) {\n const a = document?.annotations.get(id)\n if (a) viewport?.scrollToRect(a.page, a.rect)\n },\n }),\n [viewport, document, current]\n )\n}\n","import { useInkContext, type InkHistory } from '../context'\n\n/**\n * Undo and redo. Uncontrolled documents use the core history; controlled hosts that pass\n * `history` to InkRoot get a snapshot stack over their own list, applied through\n * `onAnnotationsChange`.\n */\nexport function useHistory(): InkHistory {\n return useInkContext('useHistory()').history\n}\n","import { useMemo } from 'react'\n\nimport { useInkContext } from '../context'\n\nconst NONE: readonly never[] = []\n\nexport function useEmbedded() {\n const ctx = useInkContext('useEmbedded()')\n const summary = ctx.document?.embedded ?? NONE\n return useMemo(\n () => ({\n summary,\n total: summary.reduce((n, s) => n + s.count, 0),\n hasAny: summary.length > 0,\n }),\n [summary]\n )\n}\n","import { useLayoutEffect, useRef, type RefObject } from 'react'\n\n/**\n * A ref that always holds the latest render's value, for callbacks that outlive a render\n * (core's `onChange`, effects keyed on something else). Updated in a layout effect, so it is\n * current before the parent's own layout and passive effects and before any callback fired\n * after commit; declare it before the effects that read it.\n */\nexport function useLatest<T>(value: T): RefObject<T> {\n const ref = useRef(value)\n useLayoutEffect(() => {\n ref.current = value\n })\n return ref\n}\n","import { createSnapshotHistory, InkError, openDocument } from '@inkbar/core'\nimport { cssVariableDefaults } from '@inkbar/core/dom'\nimport { Slot } from 'radix-ui'\nimport {\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type ReactNode,\n type Ref,\n} from 'react'\nimport { flushSync } from 'react-dom'\n\nimport {\n InkContextObject,\n type InkContext,\n type InkHistory,\n type InkStatus,\n} from '../context'\nimport { useLatest } from '../use-latest'\nimport { useReadable } from '../use-readable'\n\nimport type {\n Annotation,\n AnnotationChange,\n AnnotationDefaults,\n DocumentSource,\n InkDocument,\n PdfAssets,\n} from '@inkbar/core'\nimport type { ToolController, ToolId, Viewport, ZoomValue } from '@inkbar/core/dom'\n\nexport interface InkRootHandle {\n readonly document: InkDocument | null\n readonly status: InkStatus\n readonly rootEl: HTMLElement | null\n /** What `useHistory()` returns inside the root. A controlled host calls `clear()` after loading its saved list. */\n readonly history: InkHistory\n}\n\nexport interface InkRootProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'children' | 'onChange' | 'onError'\n> {\n src: DocumentSource | null\n assets: PdfAssets\n password?: string | undefined\n /** Colour defaults. Without it, the theme's CSS variables on the root element apply. */\n defaults?: AnnotationDefaults | undefined\n /**\n * Pass (with `onAnnotationsChange`) to put annotations under the host's control. The mode\n * is fixed when a document opens: passing or dropping this prop later takes effect on the\n * next open.\n */\n annotations?: Annotation[] | undefined\n onAnnotationsChange?: ((next: Annotation[]) => void) | undefined\n onChange?: ((change: AnnotationChange) => void) | undefined\n tool?: ToolId | undefined\n onToolChange?: ((tool: ToolId) => void) | undefined\n page?: number | undefined\n onPageChange?: ((page: number) => void) | undefined\n zoom?: ZoomValue | undefined\n onZoomChange?: ((zoom: ZoomValue) => void) | undefined\n /** Undo history. Defaults to on for uncontrolled, off for controlled. */\n history?: boolean | undefined\n asChild?: boolean | undefined\n onReady?: ((doc: InkDocument) => void) | undefined\n onError?: ((error: InkError) => void) | undefined\n onActivate?: ((id: string) => void) | undefined\n children?:\n | ReactNode\n | ((props: { status: InkStatus; document: InkDocument | null }) => ReactNode)\n ref?: Ref<InkRootHandle>\n}\n\ntype TestHookElement = HTMLElement & { __inkDocument?: InkDocument | undefined }\n\nconst IDLE: InkStatus = { state: 'idle' }\nconst NO_ANNOTATIONS: readonly Annotation[] = []\nconst NO_IDS: readonly string[] = []\n\n/** Signed URLs change; the key does not. Bytes and Blobs are their own identity. */\nfunction identity(src: DocumentSource | null): unknown {\n if (src === null) return null\n if (typeof src === 'string') return src\n if ('key' in src) return src.key\n return src\n}\n\nfunction isDevelopment(): boolean {\n // Bundlers replace the expression with a literal; raw browser ESM has no `process`.\n try {\n return process.env.NODE_ENV !== 'production'\n } catch {\n return false\n }\n}\n\nfunction setTestHook(el: HTMLElement | null, doc: InkDocument | undefined): void {\n if (el && isDevelopment()) (el as TestHookElement).__inkDocument = doc\n}\n\nexport function InkRoot({\n src,\n assets,\n password,\n defaults,\n annotations,\n onAnnotationsChange,\n onChange,\n tool,\n onToolChange,\n page,\n onPageChange,\n zoom,\n onZoomChange,\n history,\n asChild = false,\n onReady,\n onError,\n onActivate,\n children,\n ref,\n ...rest\n}: InkRootProps) {\n const rootElRef = useRef<HTMLElement | null>(null)\n const [rootEl, setRootElState] = useState<HTMLElement | null>(null)\n const setRootEl = useCallback((el: HTMLElement | null) => {\n rootElRef.current = el\n setRootElState(el)\n }, [])\n\n const documentRef = useRef<InkDocument | null>(null)\n const [document, setDocument] = useState<InkDocument | null>(null)\n /** Overrides the document's status while opening, and when opening itself failed. */\n const [override, setOverride] = useState<InkStatus | null>(null)\n const [internalTool, setInternalTool] = useState<ToolId>(tool ?? 'view')\n const [activated, setActivatedState] = useState<string | null>(null)\n const [viewport, setViewportState] = useState<Viewport | null>(null)\n const [tools, setToolsState] = useState<ToolController | null>(null)\n\n const documentStatus = useReadable<InkStatus>(document?.status, IDLE)\n const status = override ?? documentStatus\n const annotationList = useReadable(document?.annotations.list, NO_ANNOTATIONS)\n const selection = useReadable(document?.annotations.selection, NO_IDS)\n\n // What the next open will do follows the prop; the open document's mode is fixed.\n const controlledProp = annotations !== undefined\n const controlled = document\n ? document.annotations.mode === 'controlled'\n : controlledProp\n const historyEnabled = controlled && history === true\n // Callbacks and options read later than the render that passed them.\n const latest = useLatest({\n src,\n assets,\n defaults,\n annotations,\n controlled: controlledProp,\n history,\n historyEnabled,\n onAnnotationsChange,\n onChange,\n onReady,\n onError,\n onActivate,\n onToolChange,\n onPageChange,\n onZoomChange,\n })\n\n const snapshotHistory = useMemo(\n () =>\n createSnapshotHistory({\n apply: (list) => documentRef.current?.annotations.replaceAll(list, 'history'),\n enabled: () => latest.current.historyEnabled,\n }),\n [latest]\n )\n useEffect(() => {\n snapshotHistory.observe(annotations)\n }, [annotations, snapshotHistory])\n\n const srcIdentity = identity(src)\n useEffect(() => {\n let cancelled = false\n snapshotHistory.clear()\n const source = latest.current.src\n if (source === null) {\n setOverride(null)\n return\n }\n setOverride({ state: 'loading' })\n let opened: InkDocument | null = null\n const run = async () => {\n try {\n const doc = await openDocument(source, {\n assets: latest.current.assets,\n password,\n defaults:\n latest.current.defaults ??\n (rootElRef.current ? cssVariableDefaults(rootElRef.current) : undefined),\n // Controlled hosts get the snapshot history below; core's own stack stays off.\n history: latest.current.controlled ? false : (latest.current.history ?? true),\n annotations: latest.current.controlled\n ? {\n mode: 'controlled',\n initial: latest.current.annotations ?? [],\n onChange: (next, change) => {\n // Apply the host's state update, its render and the layout effect that pushes\n // the list back before core's development check expires. The microtask\n // leaves React's render, commit and passive-effect contexts, where a host\n // may call the store, so `flushSync` is always legal; the host sees the\n // proposal one microtask after the store returned. A proposal made in the\n // tick this root unmounts or reopens never reaches the host.\n queueMicrotask(() => {\n if (cancelled) return\n flushSync(() => {\n latest.current.onAnnotationsChange?.(next)\n latest.current.onChange?.(change)\n })\n })\n },\n }\n : { mode: 'uncontrolled' },\n })\n if (cancelled) {\n doc.destroy()\n return\n }\n opened = doc\n // The prop may have changed while the file loaded, when there was no store to apply it to.\n const current = latest.current.annotations\n if (doc.annotations.mode === 'controlled' && current !== undefined)\n doc.annotations.setControlledValue(current)\n documentRef.current = doc\n setDocument(doc)\n setOverride(null)\n setTestHook(rootElRef.current, doc)\n const s = doc.status.get()\n if (s.state === 'ready') latest.current.onReady?.(doc)\n else if (s.state === 'error') latest.current.onError?.(s.error)\n } catch (cause) {\n if (cancelled) return\n const error =\n cause instanceof InkError\n ? cause\n : new InkError(\n 'InvalidPdf',\n cause instanceof Error ? cause.message : String(cause),\n {},\n cause\n )\n setOverride({ state: 'error', error })\n latest.current.onError?.(error)\n }\n }\n // StrictMode's simulated cleanup runs synchronously in the same commit, so deferring one\n // microtask means the discarded first attempt never starts a fetch.\n void Promise.resolve().then(() => {\n if (!cancelled) return run()\n })\n return () => {\n cancelled = true\n opened?.destroy()\n documentRef.current = null\n setDocument(null)\n setTestHook(rootElRef.current, undefined)\n }\n // `srcIdentity` stands in for `src`: a new URL with the same key is the same document.\n }, [srcIdentity, password, snapshotHistory, latest])\n\n useLayoutEffect(() => {\n if (annotations && document?.annotations.mode === 'controlled')\n document.annotations.setControlledValue(annotations)\n }, [annotations, document])\n\n useEffect(() => {\n if (tool) setInternalTool(tool)\n }, [tool])\n\n const setTool = useCallback(\n (id: ToolId) => {\n setInternalTool(id)\n latest.current.onToolChange?.(id)\n },\n [latest]\n )\n const setActivated = useCallback(\n (id: string | null) => {\n setActivatedState(id)\n if (id) latest.current.onActivate?.(id)\n },\n [latest]\n )\n const reportZoom = useCallback(\n (z: ZoomValue) => latest.current.onZoomChange?.(z),\n [latest]\n )\n const reportPage = useCallback(\n (p: number) => latest.current.onPageChange?.(p),\n [latest]\n )\n const setViewport = useCallback((vp: Viewport | null, tc: ToolController | null) => {\n setViewportState(vp)\n setToolsState(tc)\n }, [])\n\n const snapCanUndo = useReadable(snapshotHistory.canUndo, false)\n const snapCanRedo = useReadable(snapshotHistory.canRedo, false)\n const coreCanUndo = useReadable(document?.history.canUndo, false)\n const coreCanRedo = useReadable(document?.history.canRedo, false)\n const inkHistory = useMemo<InkHistory>(\n () => ({\n canUndo: controlled ? historyEnabled && snapCanUndo : coreCanUndo,\n canRedo: controlled ? historyEnabled && snapCanRedo : coreCanRedo,\n undo: () =>\n controlled ? snapshotHistory.undo() : documentRef.current?.history.undo(),\n redo: () =>\n controlled ? snapshotHistory.redo() : documentRef.current?.history.redo(),\n clear: () =>\n controlled ? snapshotHistory.clear() : documentRef.current?.history.clear(),\n batch: (fn) => {\n if (controlled) snapshotHistory.batch(fn)\n else if (documentRef.current) documentRef.current.history.batch(fn)\n else fn()\n },\n }),\n [\n controlled,\n historyEnabled,\n snapCanUndo,\n snapCanRedo,\n coreCanUndo,\n coreCanRedo,\n snapshotHistory,\n ]\n )\n\n useImperativeHandle(ref, () => ({ document, status, rootEl, history: inkHistory }), [\n document,\n status,\n rootEl,\n inkHistory,\n ])\n\n const ctx = useMemo<InkContext>(\n () => ({\n assets,\n document,\n status,\n annotations: annotationList,\n selection,\n viewport,\n tools,\n tool: internalTool,\n setTool,\n zoomModel: zoom,\n pageModel: page,\n reportZoom,\n reportPage,\n activated,\n setActivated,\n history: inkHistory,\n rootEl,\n setViewport,\n }),\n [\n assets,\n document,\n status,\n annotationList,\n selection,\n viewport,\n tools,\n internalTool,\n setTool,\n zoom,\n page,\n reportZoom,\n reportPage,\n activated,\n setActivated,\n inkHistory,\n rootEl,\n setViewport,\n ]\n )\n\n const Comp = asChild ? Slot.Root : 'div'\n return (\n <InkContextObject.Provider value={ctx}>\n <Comp ref={setRootEl} data-ink-root=\"\" data-state={status.state} {...rest}>\n {typeof children === 'function' ? children({ status, document }) : children}\n </Comp>\n </InkContextObject.Provider>\n )\n}\n","/** Joins class names, dropping empties. */\nexport function cx(...parts: (string | undefined | false)[]): string | undefined {\n const out = parts.filter(Boolean).join(' ')\n return out === '' ? undefined : out\n}\n","/*\n * Slot props for one annotation. It renders only its children: the overlay already draws the\n * default visual for every annotation that is not custom, so this never draws a second one.\n * InkPage portals it into the annotation's overlay element.\n */\nimport { acceptSuggestion } from '@inkbar/core'\nimport { useEffect, useMemo, useState, type ReactNode } from 'react'\n\nimport { useInkContext } from '../context'\n\nimport type { Annotation } from '@inkbar/core'\nimport type { AnnotationSlotProps, AnnotationState } from '@inkbar/core/dom'\n\nexport interface InkAnnotationProps {\n annotation: Annotation\n /** The overlay element; its `data-state` (which includes hover) drives `state`. */\n element?: HTMLElement | undefined\n children: (props: AnnotationSlotProps) => ReactNode\n}\n\nfunction readState(el: HTMLElement): AnnotationState | null {\n const s = el.dataset.state\n return s === 'idle' || s === 'hover' || s === 'selected' ? s : null\n}\n\nexport function InkAnnotation({ annotation, element, children }: InkAnnotationProps) {\n const ctx = useInkContext('InkAnnotation')\n const [observed, setObserved] = useState<AnnotationState | null>(() =>\n element ? readState(element) : null\n )\n useEffect(() => {\n if (!element) {\n setObserved(null)\n return\n }\n setObserved(readState(element))\n const observer = new MutationObserver(() => setObserved(readState(element)))\n observer.observe(element, { attributes: true, attributeFilter: ['data-state'] })\n return () => observer.disconnect()\n }, [element])\n\n const { id } = annotation\n const isSuggestion = annotation.type === 'redact' && annotation.origin === 'suggested'\n const locked = annotation.locked === true\n const selected = ctx.selection.includes(id)\n const store = ctx.document?.annotations\n const slotProps = useMemo<AnnotationSlotProps>(\n () => ({\n annotation,\n state: observed ?? (selected ? 'selected' : 'idle'),\n locked,\n select: () => store?.select([id]),\n remove: () => void store?.remove(id),\n accept: () => {\n if (store && isSuggestion) acceptSuggestion(store, id)\n },\n dismiss: () => {\n if (isSuggestion) store?.remove(id)\n },\n }),\n [annotation, observed, selected, locked, store, id, isSuggestion]\n )\n return <>{children(slotProps)}</>\n}\n","/*\n * One page the viewer engine mounted. Renders nothing in place; portals go into the host\n * (page error) and into each annotation's overlay element (custom annotations).\n *\n * The overlay creates and removes those elements as the annotation list changes, outside\n * React. So the portal targets come from a list read after every overlay render: this\n * component subscribes to the store after the overlay does (the engine created the mount\n * first), and core notifies subscribers in order, so the elements already exist when the list\n * arrives here.\n *\n * The engine tracks page errors and sets `data-state=\"error\"` on the host; this component\n * portals the page-error slot into it while `error` is set.\n */\nimport { useEffect, useState, type ReactNode } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { useInkContext } from '../context'\n\nimport { InkAnnotation } from './InkAnnotation'\n\nimport type { Annotation, InkError } from '@inkbar/core'\nimport type { AnnotationSlotProps, PageMount } from '@inkbar/core/dom'\n\nexport interface InkPageProps {\n page: number\n host: HTMLElement\n /** The engine's page mount in `host`. */\n mount: PageMount\n /** The engine's error for this page, `null` while it renders. */\n error: InkError | null\n /** Fixed for the life of the mount: the engine rebuilds when it changes. */\n customAnnotations?: boolean\n renderAnnotation?: ((props: AnnotationSlotProps) => ReactNode) | undefined\n renderPageError?: ((props: { error: InkError; page: number }) => ReactNode) | undefined\n}\n\ninterface Target {\n annotation: Annotation\n el: HTMLElement\n}\n\nfunction sameTargets(a: readonly Target[], b: readonly Target[]): boolean {\n return (\n a.length === b.length &&\n a.every((t, i) => t.annotation === b[i]!.annotation && t.el === b[i]!.el)\n )\n}\n\nexport function InkPage({\n page,\n host,\n mount,\n error,\n customAnnotations = false,\n renderAnnotation,\n renderPageError,\n}: InkPageProps) {\n const doc = useInkContext('InkPage').document\n const [targets, setTargets] = useState<Target[]>([])\n\n useEffect(() => {\n if (!doc || !customAnnotations) return\n const read = (): void => {\n const next = doc.annotations.byPage(page).flatMap((annotation) => {\n const el = mount.overlay.elementFor(annotation.id)\n return el ? [{ annotation, el }] : []\n })\n // A change elsewhere in the document leaves this page's targets as they were.\n setTargets((prev) => (sameTargets(prev, next) ? prev : next))\n }\n const stop = doc.annotations.list.subscribe(read)\n read()\n return () => {\n stop()\n setTargets([])\n }\n }, [doc, page, mount, customAnnotations])\n\n return (\n <>\n {error\n ? createPortal(\n <div className=\"ink-page-error\" data-ink-page-error=\"\" role=\"alert\">\n {renderPageError ? (\n renderPageError({ error, page })\n ) : (\n <>\n <p>Page {page + 1} could not be shown.</p>\n <code className=\"ink-error-code\">{error.code}</code>\n </>\n )}\n </div>,\n host\n )\n : null}\n {renderAnnotation\n ? targets.map((t) =>\n createPortal(\n <InkAnnotation annotation={t.annotation} element={t.el}>\n {renderAnnotation}\n </InkAnnotation>,\n t.el,\n t.annotation.id\n )\n )\n : null}\n </>\n )\n}\n","/*\n * The scroll element is handed to core's `mountViewer`, which builds the viewport, the page\n * layers, the tool controller and the keyboard shortcuts in it; React never renders children\n * into it. The engine reports each page host it mounts, and InkPage components rendered here\n * portal the page-error and custom-annotation slots into them.\n *\n * Two-way zoom and page: the viewport's own changes are reported through the context, and\n * the host's props are applied only when they differ from the viewport's state, so the echo\n * of a reported value does nothing.\n */\nimport { mountViewer } from '@inkbar/core/dom'\nimport {\n useEffect,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from 'react'\n\nimport { cx } from '../class-names'\nimport { useInkContext } from '../context'\nimport { useLatest } from '../use-latest'\n\nimport { InkPage } from './InkPage'\n\nimport type { InkError } from '@inkbar/core'\nimport type {\n AnnotationSlotProps,\n LayoutMode,\n PageMount,\n ViewerEngine,\n ViewRotation,\n ZoomValue,\n} from '@inkbar/core/dom'\n\nexport interface InkViewportProps extends ComponentPropsWithoutRef<'div'> {\n mode?: LayoutMode\n rotation?: ViewRotation\n /** Gap between pages, CSS px. */\n gap?: number\n /** Pages kept mounted either side of the visible ones. */\n buffer?: number\n loading?: ReactNode\n empty?: ReactNode\n error?: ReactNode | ((props: { error: InkError }) => ReactNode)\n renderAnnotation?: ((props: AnnotationSlotProps) => ReactNode) | undefined\n /** Shown inside a page that failed to render. The rest of the document stays usable. */\n renderPageError?: ((props: { error: InkError; page: number }) => ReactNode) | undefined\n}\n\ninterface MountedPage {\n /** The engine build the host belongs to; part of the InkPage key. */\n build: number\n page: number\n host: HTMLElement\n mount: PageMount\n error: InkError | null\n /** Whether the build that mounted the page renders the annotation slot. */\n custom: boolean\n}\n\nexport function InkViewport({\n mode = 'continuous',\n rotation = 0,\n gap = 16,\n buffer = 2,\n loading,\n empty,\n error,\n renderAnnotation,\n renderPageError,\n className,\n ...rest\n}: InkViewportProps) {\n const ctx = useInkContext('InkViewport')\n const scroll = useRef<HTMLDivElement>(null)\n const custom = !!renderAnnotation\n const latest = useLatest({ ctx, mode, rotation, gap, buffer, custom })\n\n const engine = useRef<ViewerEngine | null>(null)\n /** Page hosts, mounts and errors the engine reported; InkPage renders portals for them. */\n const [pages, setPages] = useState<MountedPage[]>([])\n /**\n * Numbered before each build starts, so the pages a build mounts carry its own number. A\n * rebuild gives each page a new host and mount, so pages from an earlier build must remount,\n * not be reused.\n */\n const buildCount = useRef(0)\n /** The construction options the engine was last built with, so a rebuild runs only on a change. */\n const builtWith = useRef<{ gap: number; buffer: number; custom: boolean } | null>(null)\n /** The zoom and page last reported to the host. */\n const lastReportedZoom = useRef<ZoomValue | undefined>(undefined)\n const lastReportedPage = useRef<number | undefined>(undefined)\n\n // Build for a new document or status; tear down on the next change and on unmount.\n useEffect(() => {\n const { ctx: c, mode: m, rotation: r, gap: g, buffer: b, custom: cu } = latest.current\n const doc = c.document\n const el = scroll.current\n lastReportedZoom.current = undefined\n lastReportedPage.current = undefined\n if (!doc || !el || c.status.state !== 'ready') return\n let first = true\n let stops: (() => void)[] = []\n buildCount.current += 1\n builtWith.current = { gap: g, buffer: b, custom: cu }\n const e = mountViewer({\n container: el,\n document: doc,\n zoom: c.zoomModel ?? 'fit-width',\n ...(c.pageModel === undefined ? {} : { page: c.pageModel }),\n mode: m,\n rotation: r,\n gap: g,\n buffer: b,\n tool: c.tool,\n customAnnotations: cu,\n onActivate: (id) => latest.current.ctx.setActivated(id),\n onBuild: (vp, tc) => {\n latest.current.ctx.setViewport(vp, tc)\n if (first) {\n // A new document starts from where the viewport opens (its zoom, on the first page);\n // only later changes are reported, the restored page among them.\n first = false\n lastReportedZoom.current = vp.zoom.get()\n lastReportedPage.current = 0\n }\n for (const stop of stops) stop()\n const reportZoom = (z: ZoomValue): void => {\n if (z === lastReportedZoom.current) return\n lastReportedZoom.current = z\n latest.current.ctx.reportZoom(z)\n }\n const reportPage = (p: number): void => {\n if (p === lastReportedPage.current) return\n lastReportedPage.current = p\n latest.current.ctx.reportPage(p)\n }\n stops = [vp.zoom.subscribe(reportZoom), vp.currentPage.subscribe(reportPage)]\n // Whatever the build restored is reported once; nothing is when it matched.\n reportZoom(vp.zoom.get())\n reportPage(vp.currentPage.get())\n },\n onPageMount: (page, mount, host) => {\n // `buildCount` and `builtWith` belong to the build in progress: both are set before it starts.\n const build = buildCount.current\n const custom = builtWith.current?.custom ?? false\n setPages((prev) => [...prev, { build, page, host, mount, error: null, custom }])\n },\n onPageUnmount: (page) => setPages((prev) => prev.filter((p) => p.page !== page)),\n onPageError: (page, err) =>\n setPages((prev) => prev.map((p) => (p.page === page ? { ...p, error: err } : p))),\n })\n engine.current = e\n return () => {\n for (const stop of stops) stop()\n e.destroy()\n engine.current = null\n builtWith.current = null\n c.setViewport(null, null)\n setPages((prev) => (prev.length === 0 ? prev : []))\n }\n }, [ctx.document, ctx.status.state, latest])\n\n // Construction-only options rebuild the engine for the same document, keeping zoom and page.\n useEffect(() => {\n const built = builtWith.current\n if (!engine.current || !built) return\n if (built.gap === gap && built.buffer === buffer && built.custom === custom) return\n buildCount.current += 1\n builtWith.current = { gap, buffer, custom }\n engine.current.rebuild({ gap, buffer, customAnnotations: custom })\n }, [gap, buffer, custom])\n\n useEffect(() => {\n const vp = engine.current?.viewport\n const z = ctx.zoomModel\n if (vp && z !== undefined && z !== vp.zoom.get()) vp.setZoom(z)\n }, [ctx.zoomModel])\n useEffect(() => {\n const vp = engine.current?.viewport\n const p = ctx.pageModel\n if (!vp || p === undefined || p === lastReportedPage.current) return\n if (p !== vp.currentPage.get()) vp.scrollToPage(p)\n }, [ctx.pageModel])\n useEffect(() => {\n const tc = engine.current?.tools\n if (tc && tc.active.get() !== ctx.tool) tc.set(ctx.tool)\n }, [ctx.tool])\n // The build applied both; these only act on a later change, not on mount.\n useEffect(() => {\n const vp = engine.current?.viewport\n if (vp && vp.mode.get() !== mode) vp.setMode(mode)\n }, [mode])\n useEffect(() => {\n const vp = engine.current?.viewport\n if (vp && vp.rotation.get() !== rotation) vp.setRotation(rotation)\n }, [rotation])\n\n const state = ctx.status.state\n const err = ctx.status.state === 'error' ? ctx.status.error : null\n\n return (\n <div\n {...rest}\n className={cx('ink-viewport-root', className)}\n data-ink-viewport-root=\"\"\n data-state={state}\n >\n {state === 'loading' ? (\n <div className=\"ink-status\" role=\"status\" aria-live=\"polite\">\n {loading === undefined ? 'Loading document…' : loading}\n </div>\n ) : err ? (\n <div className=\"ink-status ink-error\" role=\"alert\">\n {typeof error === 'function' ? (\n error({ error: err })\n ) : error !== undefined ? (\n error\n ) : (\n <>\n <p className=\"ink-error-title\">This document could not be opened.</p>\n {/* The message comes from the PDF engine and is not written for readers: it stays\n off the page, on the code's tooltip. */}\n <p>\n <code className=\"ink-error-code\" title={err.message}>\n {err.code}\n </code>\n </p>\n </>\n )}\n </div>\n ) : state === 'idle' ? (\n <div className=\"ink-status ink-empty\">{empty}</div>\n ) : null}\n <div\n ref={scroll}\n className=\"ink-scroll\"\n data-ink-scroll=\"\"\n tabIndex={0}\n role=\"document\"\n aria-label=\"Document\"\n />\n {pages.map((p) => (\n <InkPage\n key={`${p.build}:${p.page}`}\n page={p.page}\n host={p.host}\n mount={p.mount}\n error={p.error}\n customAnnotations={p.custom}\n renderAnnotation={renderAnnotation}\n renderPageError={renderPageError}\n />\n ))}\n </div>\n )\n}\n","import { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\n\nimport type { ComponentPropsWithoutRef } from 'react'\n\nexport interface InkToolbarProps extends Omit<ComponentPropsWithoutRef<'div'>, 'dir'> {\n /** Radix narrows text direction to these two values. */\n dir?: 'ltr' | 'rtl'\n label?: string\n asChild?: boolean\n}\n\nexport function InkToolbar({\n label = 'Document tools',\n asChild = false,\n className,\n children,\n ...rest\n}: InkToolbarProps) {\n return (\n <Toolbar.Root\n asChild={asChild}\n orientation=\"horizontal\"\n aria-label={label}\n data-ink-toolbar=\"\"\n className={cx('ink-toolbar', className)}\n {...rest}\n >\n {children}\n </Toolbar.Root>\n )\n}\n","/*\n * An icon from `@inkbar/icons`, hidden from assistive technology: the control it sits in\n * carries the name. The theme sizes it with `--ink-icon-size`.\n */\nimport { ICON_ATTRIBUTES } from '@inkbar/icons'\nimport { createElement, type SVGProps } from 'react'\n\nimport type { IconNode } from '@inkbar/icons'\n\nexport interface InkIconProps {\n icon: IconNode\n size?: number\n}\n\n/** `stroke-width` to `strokeWidth`: React names SVG attributes in camelCase. */\nconst camel = (name: string) =>\n name.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase())\n\nconst SVG_ATTRIBUTES = Object.fromEntries(\n Object.entries(ICON_ATTRIBUTES).map(([k, v]) => [camel(k), v])\n) as SVGProps<SVGSVGElement>\n\nexport function InkIcon({ icon, size = 18 }: InkIconProps) {\n return (\n <svg\n {...SVG_ATTRIBUTES}\n width={size}\n height={size}\n className=\"ink-icon\"\n aria-hidden=\"true\"\n >\n {icon.map(([tag, attrs], i) => createElement(tag, { key: i, ...attrs }))}\n </svg>\n )\n}\n","import { TOOL_LABELS, type ToolId } from '@inkbar/core/dom'\nimport { Hand, Highlighter, MessageSquare, MousePointer2, Square } from '@inkbar/icons'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useTool } from '../hooks/useTool'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { IconNode } from '@inkbar/icons'\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react'\n\nconst ICONS: Readonly<Record<ToolId, IconNode>> = {\n view: Hand,\n select: MousePointer2,\n highlight: Highlighter,\n 'redact-area': Square,\n note: MessageSquare,\n}\n\nexport interface InkToolButtonProps extends Omit<\n ComponentPropsWithoutRef<'button'>,\n 'children'\n> {\n tool: ToolId\n label?: string | undefined\n asChild?: boolean\n children?: ReactNode | ((props: { active: boolean; label: string }) => ReactNode)\n}\n\nexport function InkToolButton({\n tool,\n label,\n asChild = false,\n className,\n children,\n onClick,\n ...rest\n}: InkToolButtonProps) {\n const { tool: current, setTool } = useTool()\n const active = current === tool\n const name = label ?? TOOL_LABELS[tool]\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-tool-button', className)}\n data-ink-tool-button=\"\"\n data-tool={tool}\n data-state={active ? 'on' : 'off'}\n aria-pressed={active}\n aria-label={name}\n title={name}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) setTool(tool)\n }}\n {...rest}\n >\n {typeof children === 'function'\n ? children({ active, label: name })\n : (children ?? <InkIcon icon={ICONS[tool]} />)}\n </Toolbar.Button>\n )\n}\n","import { cx } from '../class-names'\n\nimport type { ComponentPropsWithoutRef } from 'react'\n\nexport type InkToolbarSeparatorProps = ComponentPropsWithoutRef<'div'>\n\n/**\n * A divider between groups of controls in a horizontal toolbar. Not focusable. A plain div\n * rather than Radix's separator, which reads as horizontal inside a horizontal toolbar.\n */\nexport function InkToolbarSeparator({ className, ...rest }: InkToolbarSeparatorProps) {\n return (\n <div\n role=\"separator\"\n aria-orientation=\"vertical\"\n className={cx('ink-toolbar-separator', className)}\n data-ink-toolbar-separator=\"\"\n {...rest}\n />\n )\n}\n","import { Undo2 } from '@inkbar/icons'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useHistory } from '../hooks/useHistory'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { InkHistoryButtonProps } from './history-button'\n\nexport function InkUndo({\n asChild = false,\n className,\n children,\n disabled,\n onClick,\n ...rest\n}: InkHistoryButtonProps) {\n const { canUndo, undo } = useHistory()\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-undo', className)}\n data-ink-undo=\"\"\n aria-label=\"Undo\"\n title=\"Undo\"\n {...rest}\n disabled={disabled === true || !canUndo}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) undo()\n }}\n >\n {children ?? <InkIcon icon={Undo2} />}\n </Toolbar.Button>\n )\n}\n","import { Redo2 } from '@inkbar/icons'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useHistory } from '../hooks/useHistory'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { InkHistoryButtonProps } from './history-button'\n\nexport function InkRedo({\n asChild = false,\n className,\n children,\n disabled,\n onClick,\n ...rest\n}: InkHistoryButtonProps) {\n const { canRedo, redo } = useHistory()\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-redo', className)}\n data-ink-redo=\"\"\n aria-label=\"Redo\"\n title=\"Redo\"\n {...rest}\n disabled={disabled === true || !canRedo}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) redo()\n }}\n >\n {children ?? <InkIcon icon={Redo2} />}\n </Toolbar.Button>\n )\n}\n","import { ZoomIn } from '@inkbar/icons'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useZoom } from '../hooks/useZoom'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { InkZoomButtonProps } from './zoom-button'\n\nexport function InkZoomIn({\n asChild = false,\n className,\n children,\n onClick,\n ...rest\n}: InkZoomButtonProps) {\n const { zoomIn } = useZoom()\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-zoom-in', className)}\n data-ink-zoom-in=\"\"\n aria-label=\"Zoom in\"\n title=\"Zoom in\"\n {...rest}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) zoomIn()\n }}\n >\n {children ?? <InkIcon icon={ZoomIn} />}\n </Toolbar.Button>\n )\n}\n","import { ZoomOut } from '@inkbar/icons'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useZoom } from '../hooks/useZoom'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { InkZoomButtonProps } from './zoom-button'\n\nexport function InkZoomOut({\n asChild = false,\n className,\n children,\n onClick,\n ...rest\n}: InkZoomButtonProps) {\n const { zoomOut } = useZoom()\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-zoom-out', className)}\n data-ink-zoom-out=\"\"\n aria-label=\"Zoom out\"\n title=\"Zoom out\"\n {...rest}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) zoomOut()\n }}\n >\n {children ?? <InkIcon icon={ZoomOut} />}\n </Toolbar.Button>\n )\n}\n","import { ZOOM_LEVELS, type ZoomValue } from '@inkbar/core/dom'\nimport { Check, ChevronDown } from '@inkbar/icons'\nimport { Select } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { useZoom } from '../hooks/useZoom'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { ComponentPropsWithoutRef } from 'react'\n\nconst CUSTOM = 'custom:'\nconst level = (z: number) => ZOOM_LEVELS.find((l) => Math.abs(l - z) < 0.001)\nconst percent = (z: number) => `${Math.round(z * 100)}%`\n\nconst FITS = [\n { value: 'fit-width', label: 'Fit width' },\n { value: 'fit-page', label: 'Fit page' },\n]\n\n/** Props of the select's trigger button; the options come from the zoom levels. */\nexport type InkZoomSelectProps = Omit<\n ComponentPropsWithoutRef<typeof Select.Trigger>,\n 'children' | 'asChild'\n>\n\nfunction Item({ value, label }: { value: string; label: string }) {\n return (\n <Select.Item value={value} className=\"ink-select-item\" data-ink-select-item=\"\">\n <Select.ItemText>{label}</Select.ItemText>\n <Select.ItemIndicator className=\"ink-select-indicator\">\n <InkIcon icon={Check} size={16} />\n </Select.ItemIndicator>\n </Select.Item>\n )\n}\n\nexport function InkZoomSelect({ className, ...rest }: InkZoomSelectProps) {\n const { zoom, scale, setZoom } = useZoom()\n /** A numeric zoom that is not one of the levels (zoom in and out multiply). */\n const custom = typeof zoom === 'number' && level(zoom) === undefined ? zoom : null\n const value =\n typeof zoom !== 'number'\n ? zoom\n : custom === null\n ? String(level(zoom))\n : `${CUSTOM}${zoom}`\n /** The levels, with a custom zoom in its place among them. */\n const levels = ZOOM_LEVELS.map((l) => ({ z: l, value: String(l), label: percent(l) }))\n if (custom !== null)\n levels.push({ z: custom, value: `${CUSTOM}${custom}`, label: percent(scale) })\n levels.sort((a, b) => a.z - b.z)\n\n function onValueChange(v: string): void {\n if (v === value) return\n const next: ZoomValue =\n v === 'fit-width' || v === 'fit-page' ? v : Number(v.replace(CUSTOM, ''))\n setZoom(next)\n }\n return (\n <Select.Root value={value} onValueChange={onValueChange}>\n <Select.Trigger\n className={cx('ink-zoom-select ink-select-trigger', className)}\n data-ink-zoom-select=\"\"\n aria-label=\"Zoom\"\n {...rest}\n >\n <Select.Value className=\"ink-select-value\" />\n <Select.Icon className=\"ink-select-icon\">\n <InkIcon icon={ChevronDown} size={16} />\n </Select.Icon>\n </Select.Trigger>\n <Select.Portal>\n <Select.Content\n className=\"ink-select-content\"\n data-ink-select-content=\"\"\n position=\"popper\"\n side=\"top\"\n sideOffset={4}\n >\n <Select.Viewport>\n {FITS.map((o) => (\n <Item key={o.value} value={o.value} label={o.label} />\n ))}\n <Select.Separator className=\"ink-select-separator\" />\n {levels.map((o) => (\n <Item key={o.value} value={o.value} label={o.label} />\n ))}\n </Select.Viewport>\n </Select.Content>\n </Select.Portal>\n </Select.Root>\n )\n}\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type KeyboardEvent,\n} from 'react'\n\nimport { cx } from '../class-names'\nimport { usePage } from '../hooks/usePage'\nimport { useLatest } from '../use-latest'\n\nexport type InkPageInputProps = Omit<\n ComponentPropsWithoutRef<'input'>,\n 'value' | 'onChange' | 'type' | 'min' | 'max'\n>\n\nexport function InkPageInput({\n className,\n onKeyDown: onKeyDownProp,\n ...rest\n}: InkPageInputProps) {\n const { current, count, goTo } = usePage()\n const [draft, setDraft] = useState(String(current + 1))\n useEffect(() => {\n setDraft(String(current + 1))\n }, [current])\n const input = useRef<HTMLInputElement>(null)\n const latest = useLatest({ current, count, goTo })\n\n /** 1-based in the input, 0-based in the viewport. Out of range resets to the current page. */\n const commit = useCallback(\n (value: string) => {\n const { current: page, count: total, goTo: go } = latest.current\n const n = Number(value)\n if (Number.isInteger(n) && n >= 1 && n <= total) {\n if (n - 1 !== page) go(n - 1)\n } else setDraft(String(page + 1))\n },\n [latest]\n )\n // The native `change` event fires when an edit is committed: on blur after typing, and on\n // each step of the spinner or the arrow keys. React's `onChange` is the `input` event, which\n // fires for every keystroke, so the commit listens to the DOM event itself.\n useEffect(() => {\n const el = input.current\n if (!el) return\n const onNativeChange = (): void => commit(el.value)\n el.addEventListener('change', onNativeChange)\n return () => el.removeEventListener('change', onNativeChange)\n }, [commit])\n\n function onKeyDown(e: KeyboardEvent<HTMLInputElement>): void {\n onKeyDownProp?.(e)\n if (e.defaultPrevented || e.key !== 'Enter') return\n e.preventDefault()\n commit(draft)\n }\n return (\n <input\n ref={input}\n className={cx('ink-page-input', className)}\n data-ink-page-input=\"\"\n type=\"number\"\n inputMode=\"numeric\"\n aria-label=\"Page\"\n min={1}\n max={count}\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={onKeyDown}\n {...rest}\n />\n )\n}\n","import { cx } from '../class-names'\nimport { usePage } from '../hooks/usePage'\n\nimport type { ComponentPropsWithoutRef } from 'react'\n\nexport function InkPageCount({ className, ...rest }: ComponentPropsWithoutRef<'span'>) {\n const { count } = usePage()\n return (\n <span\n className={cx('ink-page-count', className)}\n data-ink-page-count=\"\"\n aria-live=\"polite\"\n {...rest}\n >\n {`of ${count}`}\n </span>\n )\n}\n","import { ChevronLeft } from '@inkbar/icons'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { usePage } from '../hooks/usePage'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { InkPageButtonProps } from './page-button'\n\nexport function InkPrevPage({\n asChild = false,\n className,\n children,\n disabled,\n onClick,\n ...rest\n}: InkPageButtonProps) {\n const { current, previous } = usePage()\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-prev-page', className)}\n data-ink-prev-page=\"\"\n aria-label=\"Previous page\"\n title=\"Previous page\"\n disabled={disabled === true || current <= 0}\n {...rest}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) previous()\n }}\n >\n {children ?? <InkIcon icon={ChevronLeft} />}\n </Toolbar.Button>\n )\n}\n","import { ChevronRight } from '@inkbar/icons'\nimport { Toolbar } from 'radix-ui'\n\nimport { cx } from '../class-names'\nimport { usePage } from '../hooks/usePage'\n\nimport { InkIcon } from './InkIcon'\n\nimport type { InkPageButtonProps } from './page-button'\n\nexport function InkNextPage({\n asChild = false,\n className,\n children,\n disabled,\n onClick,\n ...rest\n}: InkPageButtonProps) {\n const { current, count, next } = usePage()\n return (\n <Toolbar.Button\n asChild={asChild}\n className={cx('ink-next-page', className)}\n data-ink-next-page=\"\"\n aria-label=\"Next page\"\n title=\"Next page\"\n disabled={disabled === true || current >= count - 1}\n {...rest}\n onClick={(e) => {\n onClick?.(e)\n if (!e.defaultPrevented) next()\n }}\n >\n {children ?? <InkIcon icon={ChevronRight} />}\n </Toolbar.Button>\n )\n}\n","import { observeAnnotationElement } from '@inkbar/core/dom'\nimport { useEffect, useState } from 'react'\n\n/**\n * The overlay element core draws for an annotation, for anchoring a popover to it. Core\n * creates and removes these elements outside React, so this follows the root's subtree while\n * an id is wanted.\n */\nexport function useAnnotationElement(\n root: HTMLElement | null,\n id: string | null\n): HTMLElement | null {\n const [element, setElement] = useState<HTMLElement | null>(null)\n useEffect(() => {\n if (!root || !id) {\n setElement(null)\n return\n }\n return observeAnnotationElement(root, id, setElement)\n }, [root, id])\n return element\n}\n","import {\n createFocusReturn,\n shouldKeepOpenOnAnnotation,\n type FocusReturn,\n} from '@inkbar/core/dom'\nimport { useMemo } from 'react'\n\nimport { useLatest } from '../use-latest'\n\nimport type { InkContext } from '../context'\n\nexport type { FocusReturn }\n\n/** Radix's `onInteractOutside` handler: a press that will activate an annotation keeps the popover open. */\nexport function keepOpenOnAnnotation(event: CustomEvent<{ originalEvent: Event }>): void {\n if (shouldKeepOpenOnAnnotation(event.detail.originalEvent.target))\n event.preventDefault()\n}\n\nexport function useFocusReturn(ctx: InkContext): FocusReturn {\n const latest = useLatest(ctx)\n return useMemo(\n () =>\n createFocusReturn({\n root: () => latest.current.rootEl,\n activated: () => latest.current.activated,\n }),\n [latest]\n )\n}\n","/*\n * The thread for the activated note, anchored to the note's overlay element. Activating a\n * reply opens the whole thread from its root. Closing (Close, Escape, a press outside) clears\n * `activated`.\n *\n * A new note has no text. While its root is empty (and unlocked) the default form writes the\n * root's own `contents`, labelled \"Comment\", and the thread list stays hidden until there is\n * something in it; after that the form adds replies. Closing a root that is still empty and\n * has no replies removes it, so an abandoned note does not stay on the page.\n */\nimport { isAbandonedNote, threadOf, threadRoot } from '@inkbar/core'\nimport { Popover } from 'radix-ui'\nimport {\n useEffect,\n useMemo,\n useRef,\n useState,\n type FormEvent,\n type ReactNode,\n} from 'react'\n\nimport { useInkContext } from '../context'\nimport { useAnnotations } from '../hooks/useAnnotations'\nimport { useLatest } from '../use-latest'\n\nimport { useAnnotationElement } from './annotation-element'\nimport { keepOpenOnAnnotation, useFocusReturn } from './popover-focus'\n\nimport type { Annotation, NoteAnnotation } from '@inkbar/core'\nimport type { NotePopoverSlotProps } from '@inkbar/core/dom'\n\nexport interface InkNotePopoverProps {\n children?: ((props: NotePopoverSlotProps) => ReactNode) | undefined\n}\n\nexport function InkNotePopover({ children }: InkNotePopoverProps) {\n const ctx = useInkContext('InkNotePopover')\n const { annotations, add, update, remove } = useAnnotations()\n\n const note = useMemo<NoteAnnotation | null>(() => {\n const a = ctx.activated ? annotations.find((x) => x.id === ctx.activated) : undefined\n return a?.type === 'text' ? threadRoot(annotations, a) : null\n }, [annotations, ctx.activated])\n const anchor = useAnnotationElement(ctx.rootEl, note?.id ?? null)\n const anchorRef = useMemo(() => ({ current: anchor }), [anchor])\n const focusReturn = useFocusReturn(ctx)\n const open = note !== null && anchor !== null\n /** The root, then every reply below it, depth first, each level in creation order. */\n const thread = useMemo<Annotation[]>(\n () => (note ? threadOf(annotations, note) : []),\n [annotations, note]\n )\n /** True while the default form writes the root note's own text rather than a reply. */\n const editingRoot = note !== null && !note.locked && !note.contents?.trim()\n\n /**\n * Notes this popover wrote text or a reply for. In controlled mode the write is a proposal\n * the host may not have applied yet, so the applied list still shows the note empty; these\n * are never dropped as abandoned.\n */\n const written = useRef(new Set<string>())\n /** Notes this popover has already asked to remove, so a slow host is asked once. */\n const dropped = useRef(new Set<string>())\n const latest = useLatest({ annotations, remove })\n\n function dropIfEmpty(id: string): boolean {\n if (\n dropped.current.has(id) ||\n written.current.has(id) ||\n !isAbandonedNote(latest.current.annotations, id)\n )\n return false\n dropped.current.add(id)\n latest.current.remove(id)\n return true\n }\n\n // Activation moved on from a note that never got any text: drop it.\n const noteId = note?.id\n const previousId = useRef<string | undefined>(undefined)\n useEffect(() => {\n const previous = previousId.current\n if (previous === noteId) return\n previousId.current = noteId\n if (previous !== undefined) dropIfEmpty(previous)\n // dropIfEmpty reads through `latest`; it is stable for the effect's purposes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [noteId])\n\n function reply(text: string): void {\n const root = note\n const contents = text.trim()\n if (!root || !contents) return\n written.current.add(root.id)\n add({ type: 'text', page: root.page, rect: root.rect, contents, inReplyTo: root.id })\n }\n function isEmptyRoot(root: NoteAnnotation): boolean {\n return (\n !written.current.has(root.id) &&\n !root.locked &&\n !root.contents?.trim() &&\n thread.length === 1\n )\n }\n function close(): void {\n const root = note\n if (root && annotations.some((a) => a.id === root.id) && isEmptyRoot(root)) {\n focusReturn.beforeRemove(anchor)\n dropIfEmpty(root.id)\n }\n ctx.setActivated(null)\n }\n function updateContents(contents: string): void {\n if (!note || note.locked) return\n if (contents.trim()) written.current.add(note.id)\n update(note.id, { contents })\n }\n /** Locked notes cannot be removed: removing one does nothing and keeps the popover. */\n function removeThread(): void {\n const root = note\n if (!root || root.locked) return\n focusReturn.beforeRemove(anchor)\n // Under a slow controlled host the note stays listed for a while; it is not asked for again.\n dropped.current.add(root.id)\n remove(root.id)\n ctx.setActivated(null)\n }\n\n return (\n <Popover.Root open={open} onOpenChange={(next) => !next && close()}>\n <Popover.Anchor virtualRef={anchorRef} />\n <Popover.Portal>\n {note && anchor ? (\n <Popover.Content\n className=\"ink-note-popover\"\n data-ink-note-popover=\"\"\n side=\"right\"\n sideOffset={8}\n collisionPadding={8}\n aria-label=\"Note thread\"\n onInteractOutside={keepOpenOnAnnotation}\n onCloseAutoFocus={(e) => focusReturn.onCloseAutoFocus(e, anchor)}\n >\n {children ? (\n children({\n note,\n replies: thread.slice(1),\n reply,\n update: updateContents,\n remove: removeThread,\n close,\n })\n ) : (\n <>\n {!editingRoot || thread.length > 1 ? (\n <ol className=\"ink-thread\" data-ink-thread=\"\">\n {thread.map((item) => (\n <li\n key={item.id}\n className=\"ink-thread-item\"\n data-ink-thread-item=\"\"\n data-reply={item.inReplyTo ? '' : undefined}\n >\n <span className=\"ink-thread-author\">\n {item.author ?? 'Anonymous'}\n </span>\n <time className=\"ink-thread-time\" dateTime={item.createdAt}>\n {new Date(item.createdAt).toLocaleString()}\n </time>\n <p className=\"ink-thread-text\">{item.contents}</p>\n </li>\n ))}\n </ol>\n ) : null}\n <ThreadForm\n // Keyed by note: moving to another note starts with an empty draft at once.\n key={note.id}\n editingRoot={editingRoot}\n locked={!!note.locked}\n onSubmit={(text) => (editingRoot ? updateContents(text) : reply(text))}\n onRemove={removeThread}\n onClose={close}\n />\n </>\n )}\n </Popover.Content>\n ) : null}\n </Popover.Portal>\n </Popover.Root>\n )\n}\n\n/** The default form: the root note's own text while it is empty, replies after that. */\nfunction ThreadForm({\n editingRoot,\n locked,\n onSubmit,\n onRemove,\n onClose,\n}: {\n editingRoot: boolean\n locked: boolean\n onSubmit: (text: string) => void\n onRemove: () => void\n onClose: () => void\n}) {\n const [draft, setDraft] = useState('')\n function submit(e: FormEvent): void {\n e.preventDefault()\n const text = draft.trim()\n if (!text) return\n onSubmit(text)\n setDraft('')\n }\n return (\n <form className=\"ink-thread-reply\" data-ink-thread-reply=\"\" onSubmit={submit}>\n <textarea\n aria-label={editingRoot ? 'Comment' : 'Reply'}\n rows={2}\n placeholder={editingRoot ? 'Comment' : 'Reply'}\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n />\n <div className=\"ink-thread-actions\">\n <button type=\"submit\" disabled={!draft.trim()}>\n {editingRoot ? 'Comment' : 'Reply'}\n </button>\n {!locked ? (\n <button type=\"button\" onClick={onRemove}>\n Delete\n </button>\n ) : null}\n <button type=\"button\" onClick={onClose}>\n Close\n </button>\n </div>\n </form>\n )\n}\n","/*\n * Review card for a suggested redaction: opens when the activated annotation, or the only\n * selected one, is a redaction with `origin: 'suggested'`. Locked suggestions cannot be\n * dismissed, so they get no Dismiss button. A press on the overlay selects and activates, so a\n * click opens it whatever the tool. Closing clears `activated` and the selection.\n */\nimport { confidenceBucket } from '@inkbar/core'\nimport { Popover } from 'radix-ui'\nimport { useMemo, type ReactNode } from 'react'\n\nimport { useInkContext } from '../context'\nimport { useAnnotations } from '../hooks/useAnnotations'\n\nimport { useAnnotationElement } from './annotation-element'\nimport { keepOpenOnAnnotation, useFocusReturn } from './popover-focus'\n\nimport type { ConfidenceBucket, RedactAnnotation } from '@inkbar/core'\nimport type { SuggestionCardSlotProps } from '@inkbar/core/dom'\n\nexport interface InkSuggestionCardProps {\n children?: ((props: SuggestionCardSlotProps) => ReactNode) | undefined\n}\n\nexport function InkSuggestionCard({ children }: InkSuggestionCardProps) {\n const ctx = useInkContext('InkSuggestionCard')\n const {\n annotations,\n selection,\n accept: acceptId,\n dismiss: dismissId,\n select,\n } = useAnnotations()\n\n function suggestion(id: string | null | undefined): RedactAnnotation | null {\n const a = id ? annotations.find((x) => x.id === id) : undefined\n return a?.type === 'redact' && a.origin === 'suggested' ? a : null\n }\n // The activated annotation when it is a suggestion; otherwise the only selected one (a\n // marquee selects without activating).\n const target =\n suggestion(ctx.activated) ??\n (selection.length === 1 ? suggestion(selection[0]) : null)\n const anchor = useAnnotationElement(ctx.rootEl, target?.id ?? null)\n const anchorRef = useMemo(() => ({ current: anchor }), [anchor])\n const focusReturn = useFocusReturn(ctx)\n const open = target !== null && anchor !== null\n const bucket: ConfidenceBucket | undefined = target?.suggestion\n ? confidenceBucket(target.suggestion.confidence)\n : undefined\n\n function close(): void {\n ctx.setActivated(null)\n select([])\n }\n function accept(): void {\n if (target) acceptId(target.id)\n close()\n }\n /** Locked annotations cannot be removed: dismissing one does nothing and keeps the card. */\n function dismiss(): void {\n if (!target || target.locked) return\n focusReturn.beforeRemove(anchor, '[data-origin=\"suggested\"]')\n dismissId(target.id)\n close()\n }\n\n return (\n <Popover.Root open={open} onOpenChange={(next) => !next && close()}>\n <Popover.Anchor virtualRef={anchorRef} />\n <Popover.Portal>\n {target && anchor ? (\n <Popover.Content\n className=\"ink-suggestion-card\"\n data-ink-suggestion-card=\"\"\n side=\"bottom\"\n sideOffset={6}\n collisionPadding={8}\n aria-label=\"Suggested redaction\"\n onInteractOutside={keepOpenOnAnnotation}\n onCloseAutoFocus={(e) => focusReturn.onCloseAutoFocus(e, anchor)}\n >\n {children ? (\n children({\n annotation: target,\n suggestion: target.suggestion,\n bucket,\n accept,\n dismiss,\n close,\n })\n ) : (\n <>\n <p className=\"ink-suggestion-reason\">\n <strong>{target.suggestion?.reason ?? 'Suggested redaction'}</strong>\n {bucket ? (\n <span className=\"ink-suggestion-confidence\" data-confidence={bucket}>\n {bucket} confidence\n </span>\n ) : null}\n </p>\n {target.suggestion?.explanation ? (\n <p className=\"ink-suggestion-explanation\">\n {target.suggestion.explanation}\n </p>\n ) : null}\n <div className=\"ink-suggestion-actions\">\n <button type=\"button\" onClick={accept}>\n Accept\n </button>\n {!target.locked ? (\n <button type=\"button\" onClick={dismiss}>\n Dismiss\n </button>\n ) : null}\n </div>\n </>\n )}\n </Popover.Content>\n ) : null}\n </Popover.Portal>\n </Popover.Root>\n )\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkbar/react",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "React components and hooks for Inkbar, the browser PDF viewer and editor.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://inkbar.dev",
@@ -24,18 +24,18 @@
24
24
  "./package.json": "./package.json"
25
25
  },
26
26
  "dependencies": {
27
- "@inkbar/icons": "^0.2.0",
27
+ "@inkbar/icons": "^0.3.0",
28
28
  "radix-ui": "^1.8.1"
29
29
  },
30
30
  "peerDependencies": {
31
- "@inkbar/core": "^0.2.0",
31
+ "@inkbar/core": "^0.3.0",
32
32
  "react": "^19.0.0",
33
33
  "react-dom": "^19.0.0"
34
34
  },
35
35
  "devDependencies": {
36
- "@inkbar/core": "0.2.0",
36
+ "@inkbar/core": "0.3.0",
37
37
  "@inkbar/fixtures": "0.0.0",
38
- "@inkbar/theme": "0.2.0",
38
+ "@inkbar/theme": "0.3.0",
39
39
  "@playwright/experimental-ct-react": "1.62.1",
40
40
  "@playwright/test": "1.62.1",
41
41
  "@types/react": "^19.3.0",