@inkbar/react 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { Fragment, createContext, createElement, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
3
- import { InkError, acceptSuggestion, confidenceBucket, createMemorySignatureStore, createSignatureLibrary, createSnapshotHistory, isAbandonedNote, openDocument, repliesTo, threadOf, threadRoot } from "@inkbar/core";
3
+ import { InkError, createMemorySignatureStore, createSignatureLibrary, createSnapshotHistory, isAbandonedNote, openDocument, repliesTo, threadOf, threadRoot } from "@inkbar/core";
4
4
  import { COLOR_COLUMNS, FONT_FAMILIES, MARKUP_ICONS, MARKUP_KINDS, SHAPE_COLUMNS, SHAPE_ICONS, SHAPE_KINDS, SIGNATURE_FONTS, SIGNATURE_LABELS, SIGNATURE_TABS, TOOL_LABELS, ZOOM_LEVELS, colorMenuModel, createFocusReturn, createSignatureDraft, createToolOptions, cssVariableDefaults, focusInitialMenuItem, fontFamilyValue, handleMenuKeys, handleRadioKeys, handleTabKeys, highlightMenuModel, lineStyleMenuModel, menuItems, mountViewer, observeAnnotationElement, shapeMenuModel, shouldKeepOpenOnAnnotation, signatureMenuModel, signaturePreview, textStyleMenuModel, threadDeleteLabel, threadPopoverLabel, trackToolStyle } from "@inkbar/core/dom";
5
5
  import { Dialog, Popover, Select, Slot, Toolbar } from "radix-ui";
6
6
  import { createPortal, flushSync } from "react-dom";
@@ -57,10 +57,7 @@ function useAnnotations() {
57
57
  add: (input) => store?.add(input),
58
58
  update: (id, patch) => store?.update(id, patch),
59
59
  remove: (id) => store?.remove(id) ?? false,
60
- select: (ids) => store?.select(ids),
61
- /** Keeps a suggested redaction as the user's own, in the default redaction colour. */
62
- accept: (id) => store ? acceptSuggestion(store, id) : void 0,
63
- dismiss: (id) => store?.remove(id) ?? false
60
+ select: (ids) => store?.select(ids)
64
61
  }), [store]);
65
62
  return useMemo(() => ({
66
63
  annotations,
@@ -229,7 +226,7 @@ function isDevelopment() {
229
226
  function setTestHook(el, doc) {
230
227
  if (el && isDevelopment()) el.__inkDocument = doc;
231
228
  }
232
- function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsChange, onChange, tool, onToolChange, tools: hostTools, fonts: fontsProp, signatures: signatureStore, signatureFonts: signatureFontsProp, page, onPageChange, zoom, onZoomChange, history, asChild = false, onReady, onError, onActivate, children, ref, ...rest }) {
229
+ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsChange, onChange, tool, onToolChange, tools: hostTools, decorateAnnotation, fonts: fontsProp, signatures: signatureStore, signatureFonts: signatureFontsProp, page, onPageChange, zoom, onZoomChange, history, asChild = false, onReady, onError, onActivate, children, ref, ...rest }) {
233
230
  const rootElRef = useRef(null);
234
231
  const [rootEl, setRootElState] = useState(null);
235
232
  const setRootEl = useCallback((el) => {
@@ -268,7 +265,9 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
268
265
  onPageChange,
269
266
  onZoomChange,
270
267
  hostTools,
271
- tool: internalTool
268
+ decorateAnnotation,
269
+ tool: internalTool,
270
+ tools
272
271
  });
273
272
  const snapshotHistory = useMemo(() => createSnapshotHistory({
274
273
  apply: (list) => documentRef.current?.annotations.replaceAll(list, "history"),
@@ -356,6 +355,8 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
356
355
  if (tool) setInternalTool(tool);
357
356
  }, [tool]);
358
357
  const setTool = useCallback((id) => {
358
+ const tc = latest.current.tools;
359
+ if (latest.current.tool === id && tc?.active.get() === id) tc.set(id);
359
360
  setInternalTool(id);
360
361
  latest.current.onToolChange?.(id);
361
362
  }, [latest]);
@@ -427,6 +428,22 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
427
428
  }, [signatures]);
428
429
  /** Tool options last as long as the root; the tool style is per document. */
429
430
  const [toolOptions] = useState(createToolOptions);
431
+ const decorate = useCallback((a) => latest.current.decorateAnnotation?.(a), [latest]);
432
+ const [decorateListeners] = useState(() => /* @__PURE__ */ new Set());
433
+ const onDecorateAnnotationChange = useCallback((listener) => {
434
+ decorateListeners.add(listener);
435
+ return () => {
436
+ decorateListeners.delete(listener);
437
+ };
438
+ }, [decorateListeners]);
439
+ const decoratedOnce = useRef(false);
440
+ useEffect(() => {
441
+ if (!decoratedOnce.current) {
442
+ decoratedOnce.current = true;
443
+ return;
444
+ }
445
+ for (const listener of decorateListeners) listener();
446
+ }, [decorateAnnotation, decorateListeners]);
430
447
  const ctx = useMemo(() => ({
431
448
  assets,
432
449
  document,
@@ -438,6 +455,8 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
438
455
  tool: internalTool,
439
456
  setTool,
440
457
  hostTools,
458
+ decorateAnnotation: decorate,
459
+ onDecorateAnnotationChange,
441
460
  fonts,
442
461
  toolOptions,
443
462
  signatures,
@@ -463,6 +482,8 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
463
482
  internalTool,
464
483
  setTool,
465
484
  hostTools,
485
+ decorate,
486
+ onDecorateAnnotationChange,
466
487
  fonts,
467
488
  toolOptions,
468
489
  signatures,
@@ -523,7 +544,6 @@ function InkAnnotation({ annotation, element, children }) {
523
544
  return () => observer.disconnect();
524
545
  }, [element]);
525
546
  const { id } = annotation;
526
- const isSuggestion = annotation.type === "redact" && annotation.origin === "suggested";
527
547
  const locked = annotation.locked === true;
528
548
  const selected = ctx.selection.includes(id);
529
549
  const store = ctx.document?.annotations;
@@ -532,21 +552,14 @@ function InkAnnotation({ annotation, element, children }) {
532
552
  state: observed ?? (selected ? "selected" : "idle"),
533
553
  locked,
534
554
  select: () => store?.select([id]),
535
- remove: () => void store?.remove(id),
536
- accept: () => {
537
- if (store && isSuggestion) acceptSuggestion(store, id);
538
- },
539
- dismiss: () => {
540
- if (isSuggestion) store?.remove(id);
541
- }
555
+ remove: () => void store?.remove(id)
542
556
  }), [
543
557
  annotation,
544
558
  observed,
545
559
  selected,
546
560
  locked,
547
561
  store,
548
- id,
549
- isSuggestion
562
+ id
550
563
  ]);
551
564
  return /* @__PURE__ */ jsx(Fragment$1, { children: children(slotProps) });
552
565
  }
@@ -657,6 +670,7 @@ function InkViewport({ mode = "continuous", rotation = 0, gap = 16, buffer = 2,
657
670
  buffer: b,
658
671
  tool: c.tool,
659
672
  ...c.hostTools ? { tools: c.hostTools } : {},
673
+ decorateAnnotation: (a) => latest.current.ctx.decorateAnnotation(a),
660
674
  ...c.toolStyle ? { toolStyle: c.toolStyle } : {},
661
675
  toolHistory: { batch: (fn) => latest.current.ctx.history.batch(fn) },
662
676
  toolOptions: c.toolOptions,
@@ -682,7 +696,14 @@ function InkViewport({ mode = "continuous", rotation = 0, gap = 16, buffer = 2,
682
696
  lastReportedPage.current = p;
683
697
  latest.current.ctx.reportPage(p);
684
698
  };
685
- stops = [vp.zoom.subscribe(reportZoom), vp.currentPage.subscribe(reportPage)];
699
+ const followTool = (id) => {
700
+ if (id !== latest.current.ctx.tool) latest.current.ctx.setTool(id);
701
+ };
702
+ stops = [
703
+ vp.zoom.subscribe(reportZoom),
704
+ vp.currentPage.subscribe(reportPage),
705
+ tc.active.subscribe(followTool)
706
+ ];
686
707
  reportZoom(vp.zoom.get());
687
708
  reportPage(vp.currentPage.get());
688
709
  },
@@ -718,6 +739,8 @@ function InkViewport({ mode = "continuous", rotation = 0, gap = 16, buffer = 2,
718
739
  ctx.status.state,
719
740
  latest
720
741
  ]);
742
+ const { onDecorateAnnotationChange } = ctx;
743
+ useEffect(() => onDecorateAnnotationChange(() => engine.current?.redecorate()), [onDecorateAnnotationChange]);
721
744
  useEffect(() => {
722
745
  const built = builtWith.current;
723
746
  if (!engine.current || !built) return;
@@ -1152,11 +1175,11 @@ function InkNextPage({ asChild = false, className, children, disabled, onClick,
1152
1175
  }
1153
1176
  //#endregion
1154
1177
  //#region src/components/InkColorMenu.tsx
1155
- function InkColorMenu({ property, label, className, children, standalone = false, group, disabled, ...rest }) {
1178
+ function InkColorMenu({ property, label, className, children, standalone = false, group, fallback, disabled, ...rest }) {
1156
1179
  const Wrap = standalone ? Fragment : Toolbar.Button;
1157
1180
  const { current, supported, set } = useToolStyle(group);
1158
1181
  const [open, setOpen] = useState(false);
1159
- const model = colorMenuModel(property, current, supported);
1182
+ const model = colorMenuModel(property, current, supported, fallback);
1160
1183
  const name = label ?? model.label;
1161
1184
  /** ArrowDown opens on the first item; a click opens on the checked one. */
1162
1185
  const focusFirst = useRef(false);
@@ -1295,93 +1318,100 @@ function InkShapeMenu({ className, children, ...rest }) {
1295
1318
  const active = tool === "shape";
1296
1319
  /** ArrowDown opens on the first item; a click opens on the checked one. */
1297
1320
  const focusFirst = useRef(false);
1298
- return /* @__PURE__ */ jsxs("div", {
1299
- role: "group",
1300
- "aria-label": "Shape",
1301
- className: cx("ink-split-button ink-shape-menu", className),
1302
- "data-ink-shape-menu": "",
1303
- ...rest,
1304
- children: [/* @__PURE__ */ jsx(Toolbar.Button, {
1305
- className: "ink-tool-button ink-shape-button",
1306
- "data-ink-tool-button": "",
1307
- "data-ink-shape-button": "",
1308
- "data-tool": "shape",
1309
- "data-kind": model.kind,
1310
- "data-state": active ? "on" : "off",
1311
- "aria-pressed": active,
1312
- "aria-label": model.label,
1313
- title: model.label,
1314
- onClick: () => setTool("shape"),
1315
- children: children ?? /* @__PURE__ */ jsx(InkIcon, { icon: SHAPE_ICONS[model.kind] })
1316
- }), /* @__PURE__ */ jsxs(Popover.Root, {
1317
- open,
1318
- onOpenChange: setOpen,
1319
- children: [/* @__PURE__ */ jsx(Toolbar.Button, {
1320
- asChild: true,
1321
- children: /* @__PURE__ */ jsx(Popover.Trigger, {
1322
- asChild: true,
1323
- children: /* @__PURE__ */ jsx("button", {
1324
- type: "button",
1325
- className: "ink-menu-trigger ink-shape-menu-trigger",
1326
- "data-ink-shape-menu-trigger": "",
1327
- "data-state": open ? "open" : "closed",
1328
- "aria-label": "Choose shape",
1329
- title: "Choose shape",
1330
- "aria-haspopup": "menu",
1331
- onKeyDown: (e) => {
1332
- if (e.key !== "ArrowDown" || e.defaultPrevented || open) return;
1321
+ return /* @__PURE__ */ jsx(Popover.Root, {
1322
+ open,
1323
+ onOpenChange: setOpen,
1324
+ children: /* @__PURE__ */ jsx(Popover.Anchor, {
1325
+ asChild: true,
1326
+ children: /* @__PURE__ */ jsxs("div", {
1327
+ role: "group",
1328
+ "aria-label": "Shape",
1329
+ className: cx("ink-split-button ink-shape-menu", className),
1330
+ "data-ink-shape-menu": "",
1331
+ ...rest,
1332
+ children: [
1333
+ /* @__PURE__ */ jsx(Toolbar.Button, {
1334
+ className: "ink-tool-button ink-shape-button",
1335
+ "data-ink-tool-button": "",
1336
+ "data-ink-shape-button": "",
1337
+ "data-tool": "shape",
1338
+ "data-kind": model.kind,
1339
+ "data-state": active ? "on" : "off",
1340
+ "aria-pressed": active,
1341
+ "aria-label": model.label,
1342
+ title: model.label,
1343
+ onClick: () => setTool("shape"),
1344
+ children: children ?? /* @__PURE__ */ jsx(InkIcon, { icon: SHAPE_ICONS[model.kind] })
1345
+ }),
1346
+ /* @__PURE__ */ jsx(Toolbar.Button, {
1347
+ asChild: true,
1348
+ children: /* @__PURE__ */ jsx(Popover.Trigger, {
1349
+ asChild: true,
1350
+ children: /* @__PURE__ */ jsx("button", {
1351
+ type: "button",
1352
+ className: "ink-menu-trigger ink-shape-menu-trigger",
1353
+ "data-ink-shape-menu-trigger": "",
1354
+ "data-state": open ? "open" : "closed",
1355
+ "aria-label": "Choose shape",
1356
+ title: "Choose shape",
1357
+ "aria-haspopup": "menu",
1358
+ onKeyDown: (e) => {
1359
+ if (e.key !== "ArrowDown" || e.defaultPrevented || open) return;
1360
+ e.preventDefault();
1361
+ focusFirst.current = true;
1362
+ setOpen(true);
1363
+ },
1364
+ children: /* @__PURE__ */ jsx(InkIcon, { icon: ChevronDown })
1365
+ })
1366
+ })
1367
+ }),
1368
+ /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Content, {
1369
+ role: "menu",
1370
+ "aria-label": "Shapes",
1371
+ className: "ink-select-content ink-menu-content",
1372
+ "data-ink-select-content": "",
1373
+ "data-ink-menu": "shape",
1374
+ side: "bottom",
1375
+ align: "start",
1376
+ sideOffset: 4,
1377
+ collisionPadding: 8,
1378
+ onOpenAutoFocus: (e) => {
1333
1379
  e.preventDefault();
1334
- focusFirst.current = true;
1335
- setOpen(true);
1380
+ const menu = e.currentTarget;
1381
+ if (focusFirst.current) menuItems(menu)[0]?.focus({ preventScroll: true });
1382
+ else focusInitialMenuItem(menu);
1383
+ focusFirst.current = false;
1336
1384
  },
1337
- children: /* @__PURE__ */ jsx(InkIcon, { icon: ChevronDown })
1338
- })
1339
- })
1340
- }), /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Content, {
1341
- role: "menu",
1342
- "aria-label": "Shapes",
1343
- className: "ink-select-content ink-menu-content",
1344
- "data-ink-select-content": "",
1345
- "data-ink-menu": "shape",
1346
- side: "bottom",
1347
- align: "start",
1348
- sideOffset: 4,
1349
- collisionPadding: 8,
1350
- onOpenAutoFocus: (e) => {
1351
- e.preventDefault();
1352
- const menu = e.currentTarget;
1353
- if (focusFirst.current) menuItems(menu)[0]?.focus({ preventScroll: true });
1354
- else focusInitialMenuItem(menu);
1355
- focusFirst.current = false;
1356
- },
1357
- onKeyDown: (e) => handleMenuKeys(e.nativeEvent, e.currentTarget),
1358
- children: /* @__PURE__ */ jsx("div", {
1359
- role: "group",
1360
- "aria-label": "Shapes",
1361
- className: "ink-shape-grid",
1362
- "data-ink-menu-columns": SHAPE_COLUMNS,
1363
- children: model.items.map((item) => /* @__PURE__ */ jsxs("button", {
1364
- type: "button",
1365
- role: "menuitemradio",
1366
- "aria-checked": item.checked,
1367
- tabIndex: -1,
1368
- className: "ink-select-item ink-menu-item ink-shape-item",
1369
- "data-ink-select-item": "",
1370
- "data-key": item.kind,
1371
- "data-state": item.checked ? "checked" : "unchecked",
1372
- onClick: () => {
1373
- setOptions({ kind: item.kind });
1374
- setTool("shape");
1375
- setOpen(false);
1376
- },
1377
- children: [/* @__PURE__ */ jsx(InkIcon, {
1378
- icon: SHAPE_ICONS[item.kind],
1379
- size: 16
1380
- }), item.label]
1381
- }, item.kind))
1382
- })
1383
- }) })]
1384
- })]
1385
+ onKeyDown: (e) => handleMenuKeys(e.nativeEvent, e.currentTarget),
1386
+ children: /* @__PURE__ */ jsx("div", {
1387
+ role: "group",
1388
+ "aria-label": "Shapes",
1389
+ className: "ink-shape-grid",
1390
+ "data-ink-menu-columns": SHAPE_COLUMNS,
1391
+ children: model.items.map((item) => /* @__PURE__ */ jsxs("button", {
1392
+ type: "button",
1393
+ role: "menuitemradio",
1394
+ "aria-checked": item.checked,
1395
+ tabIndex: -1,
1396
+ className: "ink-select-item ink-menu-item ink-shape-item",
1397
+ "data-ink-select-item": "",
1398
+ "data-key": item.kind,
1399
+ "data-state": item.checked ? "checked" : "unchecked",
1400
+ onClick: () => {
1401
+ setOptions({ kind: item.kind });
1402
+ setTool("shape");
1403
+ setOpen(false);
1404
+ },
1405
+ children: [/* @__PURE__ */ jsx(InkIcon, {
1406
+ icon: SHAPE_ICONS[item.kind],
1407
+ size: 16
1408
+ }), item.label]
1409
+ }, item.kind))
1410
+ })
1411
+ }) })
1412
+ ]
1413
+ })
1414
+ })
1385
1415
  });
1386
1416
  }
1387
1417
  //#endregion
@@ -1654,153 +1684,157 @@ function InkSignatureMenu({ className, children, fonts, ...rest }) {
1654
1684
  removedRow.current = null;
1655
1685
  });
1656
1686
  };
1657
- return /* @__PURE__ */ jsxs("div", {
1658
- role: "group",
1659
- "aria-label": SIGNATURE_LABELS.sign,
1660
- className: cx("ink-split-button ink-signature-menu", className),
1661
- "data-ink-signature-menu": "",
1662
- ...rest,
1663
- children: [
1664
- /* @__PURE__ */ jsx(Toolbar.Button, {
1665
- ref: main,
1666
- className: "ink-tool-button ink-signature-button",
1667
- "data-ink-tool-button": "",
1668
- "data-ink-signature-button": "",
1669
- "data-tool": "signature",
1670
- "data-state": active ? "on" : "off",
1671
- "aria-pressed": active,
1687
+ return /* @__PURE__ */ jsx(Popover.Root, {
1688
+ open,
1689
+ onOpenChange: setOpen,
1690
+ children: /* @__PURE__ */ jsx(Popover.Anchor, {
1691
+ asChild: true,
1692
+ children: /* @__PURE__ */ jsxs("div", {
1693
+ role: "group",
1672
1694
  "aria-label": SIGNATURE_LABELS.sign,
1673
- title: SIGNATURE_LABELS.sign,
1674
- onClick: () => {
1675
- if (model.selected) setTool("signature");
1676
- else setOpen(true);
1677
- },
1678
- children: children ?? /* @__PURE__ */ jsx(InkIcon, { icon: Signature })
1679
- }),
1680
- /* @__PURE__ */ jsxs(Popover.Root, {
1681
- open,
1682
- onOpenChange: setOpen,
1683
- children: [/* @__PURE__ */ jsx(Toolbar.Button, {
1684
- asChild: true,
1685
- children: /* @__PURE__ */ jsx(Popover.Trigger, {
1695
+ className: cx("ink-split-button ink-signature-menu", className),
1696
+ "data-ink-signature-menu": "",
1697
+ ...rest,
1698
+ children: [
1699
+ /* @__PURE__ */ jsx(Toolbar.Button, {
1700
+ ref: main,
1701
+ className: "ink-tool-button ink-signature-button",
1702
+ "data-ink-tool-button": "",
1703
+ "data-ink-signature-button": "",
1704
+ "data-tool": "signature",
1705
+ "data-state": active ? "on" : "off",
1706
+ "aria-pressed": active,
1707
+ "aria-label": SIGNATURE_LABELS.sign,
1708
+ title: SIGNATURE_LABELS.sign,
1709
+ onClick: () => {
1710
+ if (model.selected) setTool("signature");
1711
+ else setOpen(true);
1712
+ },
1713
+ children: children ?? /* @__PURE__ */ jsx(InkIcon, { icon: Signature })
1714
+ }),
1715
+ /* @__PURE__ */ jsx(Toolbar.Button, {
1686
1716
  asChild: true,
1687
- children: /* @__PURE__ */ jsx("button", {
1688
- type: "button",
1689
- className: "ink-menu-trigger ink-signature-menu-trigger",
1690
- "data-ink-signature-menu-trigger": "",
1691
- "data-state": open ? "open" : "closed",
1692
- "aria-label": SIGNATURE_LABELS.trigger,
1693
- title: SIGNATURE_LABELS.trigger,
1694
- "aria-haspopup": "menu",
1695
- onKeyDown: (e) => {
1696
- if (e.key !== "ArrowDown" || e.defaultPrevented || open) return;
1697
- e.preventDefault();
1698
- focusFirst.current = true;
1699
- setOpen(true);
1700
- },
1701
- children: /* @__PURE__ */ jsx(InkIcon, { icon: ChevronDown })
1717
+ children: /* @__PURE__ */ jsx(Popover.Trigger, {
1718
+ asChild: true,
1719
+ children: /* @__PURE__ */ jsx("button", {
1720
+ type: "button",
1721
+ className: "ink-menu-trigger ink-signature-menu-trigger",
1722
+ "data-ink-signature-menu-trigger": "",
1723
+ "data-state": open ? "open" : "closed",
1724
+ "aria-label": SIGNATURE_LABELS.trigger,
1725
+ title: SIGNATURE_LABELS.trigger,
1726
+ "aria-haspopup": "menu",
1727
+ onKeyDown: (e) => {
1728
+ if (e.key !== "ArrowDown" || e.defaultPrevented || open) return;
1729
+ e.preventDefault();
1730
+ focusFirst.current = true;
1731
+ setOpen(true);
1732
+ },
1733
+ children: /* @__PURE__ */ jsx(InkIcon, { icon: ChevronDown })
1734
+ })
1702
1735
  })
1703
- })
1704
- }), /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(Popover.Content, {
1705
- ref: menu,
1706
- role: "menu",
1707
- "aria-label": SIGNATURE_LABELS.menu,
1708
- className: "ink-select-content ink-menu-content",
1709
- "data-ink-select-content": "",
1710
- "data-ink-menu": "signature",
1711
- side: "bottom",
1712
- align: "start",
1713
- sideOffset: 4,
1714
- collisionPadding: 8,
1715
- onOpenAutoFocus: (e) => {
1716
- e.preventDefault();
1717
- const el = e.currentTarget;
1718
- if (focusFirst.current) menuItems(el)[0]?.focus({ preventScroll: true });
1719
- else focusInitialMenuItem(el);
1720
- focusFirst.current = false;
1721
- },
1722
- onCloseAutoFocus: (e) => {
1723
- if (toDialog.current) e.preventDefault();
1724
- toDialog.current = false;
1725
- },
1726
- onKeyDown: (e) => handleMenuKeys(e.nativeEvent, e.currentTarget),
1727
- children: [
1728
- model.items.length > 0 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
1729
- role: "group",
1730
- "aria-label": SIGNATURE_LABELS.saved,
1731
- className: "ink-signature-list",
1732
- "data-ink-menu-columns": 2,
1733
- children: model.items.map((item, row) => [/* @__PURE__ */ jsx("button", {
1736
+ }),
1737
+ /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(Popover.Content, {
1738
+ ref: menu,
1739
+ role: "menu",
1740
+ "aria-label": SIGNATURE_LABELS.menu,
1741
+ className: "ink-select-content ink-menu-content",
1742
+ "data-ink-select-content": "",
1743
+ "data-ink-menu": "signature",
1744
+ side: "bottom",
1745
+ align: "start",
1746
+ sideOffset: 4,
1747
+ collisionPadding: 8,
1748
+ onOpenAutoFocus: (e) => {
1749
+ e.preventDefault();
1750
+ const el = e.currentTarget;
1751
+ if (focusFirst.current) menuItems(el)[0]?.focus({ preventScroll: true });
1752
+ else focusInitialMenuItem(el);
1753
+ focusFirst.current = false;
1754
+ },
1755
+ onCloseAutoFocus: (e) => {
1756
+ if (toDialog.current) e.preventDefault();
1757
+ toDialog.current = false;
1758
+ },
1759
+ onKeyDown: (e) => handleMenuKeys(e.nativeEvent, e.currentTarget),
1760
+ children: [
1761
+ model.items.length > 0 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
1762
+ role: "group",
1763
+ "aria-label": SIGNATURE_LABELS.saved,
1764
+ className: "ink-signature-list",
1765
+ "data-ink-menu-columns": 2,
1766
+ children: model.items.map((item, row) => [/* @__PURE__ */ jsx("button", {
1767
+ type: "button",
1768
+ role: "menuitemradio",
1769
+ "aria-checked": item.checked,
1770
+ "aria-label": item.label,
1771
+ tabIndex: -1,
1772
+ className: "ink-select-item ink-menu-item ink-signature-item",
1773
+ "data-ink-select-item": "",
1774
+ "data-key": item.id,
1775
+ "data-state": item.checked ? "checked" : "unchecked",
1776
+ onClick: () => {
1777
+ setOptions({ templateId: item.id });
1778
+ setTool("signature");
1779
+ setOpen(false);
1780
+ },
1781
+ children: /* @__PURE__ */ jsx(SignaturePreview, { template: item.template })
1782
+ }, `${item.id}-choose`), /* @__PURE__ */ jsx("button", {
1783
+ type: "button",
1784
+ role: "menuitem",
1785
+ "aria-label": item.removeLabel,
1786
+ title: item.removeLabel,
1787
+ tabIndex: -1,
1788
+ className: "ink-menu-item ink-signature-remove",
1789
+ "data-ink-signature-remove": "",
1790
+ "data-key": item.id,
1791
+ onClick: () => remove(item.id, row),
1792
+ children: /* @__PURE__ */ jsx(InkIcon, {
1793
+ icon: Trash2,
1794
+ size: 16
1795
+ })
1796
+ }, `${item.id}-remove`)])
1797
+ }), /* @__PURE__ */ jsx("div", {
1798
+ role: "separator",
1799
+ className: "ink-select-separator"
1800
+ })] }) : null,
1801
+ /* @__PURE__ */ jsxs("button", {
1734
1802
  type: "button",
1735
- role: "menuitemradio",
1736
- "aria-checked": item.checked,
1737
- "aria-label": item.label,
1803
+ role: "menuitem",
1738
1804
  tabIndex: -1,
1739
- className: "ink-select-item ink-menu-item ink-signature-item",
1805
+ className: "ink-select-item ink-menu-item ink-signature-create",
1740
1806
  "data-ink-select-item": "",
1741
- "data-key": item.id,
1742
- "data-state": item.checked ? "checked" : "unchecked",
1807
+ "data-ink-signature-create": "",
1743
1808
  onClick: () => {
1744
- setOptions({ templateId: item.id });
1745
- setTool("signature");
1809
+ toDialog.current = true;
1746
1810
  setOpen(false);
1811
+ setCreating(true);
1747
1812
  },
1748
- children: /* @__PURE__ */ jsx(SignaturePreview, { template: item.template })
1749
- }, `${item.id}-choose`), /* @__PURE__ */ jsx("button", {
1750
- type: "button",
1751
- role: "menuitem",
1752
- "aria-label": item.removeLabel,
1753
- title: item.removeLabel,
1754
- tabIndex: -1,
1755
- className: "ink-menu-item ink-signature-remove",
1756
- "data-ink-signature-remove": "",
1757
- "data-key": item.id,
1758
- onClick: () => remove(item.id, row),
1759
- children: /* @__PURE__ */ jsx(InkIcon, {
1760
- icon: Trash2,
1813
+ children: [/* @__PURE__ */ jsx(InkIcon, {
1814
+ icon: Plus,
1761
1815
  size: 16
1762
- })
1763
- }, `${item.id}-remove`)])
1764
- }), /* @__PURE__ */ jsx("div", {
1765
- role: "separator",
1766
- className: "ink-select-separator"
1767
- })] }) : null,
1768
- /* @__PURE__ */ jsxs("button", {
1769
- type: "button",
1770
- role: "menuitem",
1771
- tabIndex: -1,
1772
- className: "ink-select-item ink-menu-item ink-signature-create",
1773
- "data-ink-select-item": "",
1774
- "data-ink-signature-create": "",
1775
- onClick: () => {
1776
- toDialog.current = true;
1777
- setOpen(false);
1778
- setCreating(true);
1779
- },
1780
- children: [/* @__PURE__ */ jsx(InkIcon, {
1781
- icon: Plus,
1782
- size: 16
1783
- }), SIGNATURE_LABELS.create]
1784
- }),
1785
- removeError ? /* @__PURE__ */ jsx("p", {
1786
- className: "ink-field-error ink-signature-remove-error",
1787
- role: "alert",
1788
- "data-ink-signature-remove-error": "",
1789
- children: removeError
1790
- }) : null
1791
- ]
1792
- }) })]
1793
- }),
1794
- /* @__PURE__ */ jsx(InkSignatureDialog, {
1795
- open: creating,
1796
- onOpenChange: setCreating,
1797
- fonts,
1798
- onCloseAutoFocus: (e) => {
1799
- e.preventDefault();
1800
- main.current?.focus({ preventScroll: true });
1801
- }
1816
+ }), SIGNATURE_LABELS.create]
1817
+ }),
1818
+ removeError ? /* @__PURE__ */ jsx("p", {
1819
+ className: "ink-field-error ink-signature-remove-error",
1820
+ role: "alert",
1821
+ "data-ink-signature-remove-error": "",
1822
+ children: removeError
1823
+ }) : null
1824
+ ]
1825
+ }) }),
1826
+ /* @__PURE__ */ jsx(InkSignatureDialog, {
1827
+ open: creating,
1828
+ onOpenChange: setCreating,
1829
+ fonts,
1830
+ onCloseAutoFocus: (e) => {
1831
+ e.preventDefault();
1832
+ main.current?.focus({ preventScroll: true });
1833
+ }
1834
+ })
1835
+ ]
1802
1836
  })
1803
- ]
1837
+ })
1804
1838
  });
1805
1839
  }
1806
1840
  //#endregion
@@ -1808,122 +1842,131 @@ function InkSignatureMenu({ className, children, fonts, ...rest }) {
1808
1842
  function InkHighlightMenu({ className, children, ...rest }) {
1809
1843
  const { tool, setTool } = useTool();
1810
1844
  const [options, setOptions] = useToolOptions("highlight");
1845
+ const { document: doc } = useDocument();
1811
1846
  const [open, setOpen] = useState(false);
1812
1847
  const model = highlightMenuModel(options, MARKUP_KINDS);
1813
1848
  const active = tool === "highlight";
1814
1849
  /** ArrowDown opens on the first item; a click opens on the checked one. */
1815
1850
  const focusFirst = useRef(false);
1816
- return /* @__PURE__ */ jsxs("div", {
1817
- role: "group",
1818
- "aria-label": "Highlight",
1819
- className: cx("ink-split-button ink-highlight-menu", className),
1820
- "data-ink-highlight-menu": "",
1821
- ...rest,
1822
- children: [/* @__PURE__ */ jsx(Toolbar.Button, {
1823
- className: "ink-tool-button ink-highlight-button",
1824
- "data-ink-tool-button": "",
1825
- "data-ink-highlight-button": "",
1826
- "data-tool": "highlight",
1827
- "data-kind": model.kind,
1828
- "data-state": active ? "on" : "off",
1829
- "aria-pressed": active,
1830
- "aria-label": model.label,
1831
- title: model.label,
1832
- onClick: () => setTool("highlight"),
1833
- children: children ?? /* @__PURE__ */ jsx(InkIcon, { icon: MARKUP_ICONS[model.kind] })
1834
- }), /* @__PURE__ */ jsxs(Popover.Root, {
1835
- open,
1836
- onOpenChange: setOpen,
1837
- children: [/* @__PURE__ */ jsx(Toolbar.Button, {
1838
- asChild: true,
1839
- children: /* @__PURE__ */ jsx(Popover.Trigger, {
1840
- asChild: true,
1841
- children: /* @__PURE__ */ jsx("button", {
1842
- type: "button",
1843
- className: "ink-menu-trigger ink-highlight-menu-trigger",
1844
- "data-ink-highlight-menu-trigger": "",
1845
- "data-state": open ? "open" : "closed",
1846
- "aria-label": "Choose highlight",
1847
- title: "Choose highlight",
1848
- "aria-haspopup": "menu",
1849
- onKeyDown: (e) => {
1850
- if (e.key !== "ArrowDown" || e.defaultPrevented || open) return;
1851
- e.preventDefault();
1852
- focusFirst.current = true;
1853
- setOpen(true);
1854
- },
1855
- children: /* @__PURE__ */ jsx(InkIcon, { icon: ChevronDown })
1856
- })
1857
- })
1858
- }), /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(Popover.Content, {
1859
- role: "menu",
1860
- "aria-label": "Highlights",
1861
- className: "ink-select-content ink-menu-content",
1862
- "data-ink-select-content": "",
1863
- "data-ink-menu": "highlight",
1864
- side: "bottom",
1865
- align: "start",
1866
- sideOffset: 4,
1867
- collisionPadding: 8,
1868
- onOpenAutoFocus: (e) => {
1869
- e.preventDefault();
1870
- const menu = e.currentTarget;
1871
- if (focusFirst.current) menuItems(menu)[0]?.focus({ preventScroll: true });
1872
- else focusInitialMenuItem(menu);
1873
- focusFirst.current = false;
1874
- },
1875
- onKeyDownCapture: (e) => {
1876
- if (e.currentTarget.contains(e.target)) handleMenuKeys(e.nativeEvent, e.currentTarget);
1877
- },
1851
+ return /* @__PURE__ */ jsx(Popover.Root, {
1852
+ open,
1853
+ onOpenChange: setOpen,
1854
+ children: /* @__PURE__ */ jsx(Popover.Anchor, {
1855
+ asChild: true,
1856
+ children: /* @__PURE__ */ jsxs("div", {
1857
+ role: "group",
1858
+ "aria-label": "Highlight",
1859
+ className: cx("ink-split-button ink-highlight-menu", className),
1860
+ "data-ink-highlight-menu": "",
1861
+ ...rest,
1878
1862
  children: [
1879
- /* @__PURE__ */ jsx("div", {
1880
- role: "group",
1881
- "aria-label": "Kinds",
1882
- className: "ink-highlight-kinds",
1883
- children: model.items.map((item) => /* @__PURE__ */ jsxs("button", {
1884
- type: "button",
1885
- role: "menuitemradio",
1886
- "aria-checked": item.checked,
1887
- tabIndex: -1,
1888
- className: "ink-select-item ink-menu-item ink-highlight-item",
1889
- "data-ink-select-item": "",
1890
- "data-key": item.kind,
1891
- "data-state": item.checked ? "checked" : "unchecked",
1892
- onClick: () => {
1893
- setOptions({ kind: item.kind });
1894
- setTool("highlight");
1895
- setOpen(false);
1896
- },
1897
- children: [/* @__PURE__ */ jsx(InkIcon, {
1898
- icon: MARKUP_ICONS[item.kind],
1899
- size: 16
1900
- }), item.label]
1901
- }, item.kind))
1863
+ /* @__PURE__ */ jsx(Toolbar.Button, {
1864
+ className: "ink-tool-button ink-highlight-button",
1865
+ "data-ink-tool-button": "",
1866
+ "data-ink-highlight-button": "",
1867
+ "data-tool": "highlight",
1868
+ "data-kind": model.kind,
1869
+ "data-state": active ? "on" : "off",
1870
+ "aria-pressed": active,
1871
+ "aria-label": model.label,
1872
+ title: model.label,
1873
+ onClick: () => setTool("highlight"),
1874
+ children: children ?? /* @__PURE__ */ jsx(InkIcon, { icon: MARKUP_ICONS[model.kind] })
1902
1875
  }),
1903
- /* @__PURE__ */ jsx("div", {
1904
- role: "separator",
1905
- className: "ink-select-separator"
1876
+ /* @__PURE__ */ jsx(Toolbar.Button, {
1877
+ asChild: true,
1878
+ children: /* @__PURE__ */ jsx(Popover.Trigger, {
1879
+ asChild: true,
1880
+ children: /* @__PURE__ */ jsx("button", {
1881
+ type: "button",
1882
+ className: "ink-menu-trigger ink-highlight-menu-trigger",
1883
+ "data-ink-highlight-menu-trigger": "",
1884
+ "data-state": open ? "open" : "closed",
1885
+ "aria-label": "Choose highlight",
1886
+ title: "Choose highlight",
1887
+ "aria-haspopup": "menu",
1888
+ onKeyDown: (e) => {
1889
+ if (e.key !== "ArrowDown" || e.defaultPrevented || open) return;
1890
+ e.preventDefault();
1891
+ focusFirst.current = true;
1892
+ setOpen(true);
1893
+ },
1894
+ children: /* @__PURE__ */ jsx(InkIcon, { icon: ChevronDown })
1895
+ })
1896
+ })
1906
1897
  }),
1907
- /* @__PURE__ */ jsxs("div", {
1908
- role: "group",
1909
- "aria-label": "Colour",
1910
- className: "ink-highlight-colour",
1911
- children: [/* @__PURE__ */ jsx("span", {
1912
- className: "ink-highlight-colour-label",
1913
- "aria-hidden": "true",
1914
- children: "Colour"
1915
- }), /* @__PURE__ */ jsx(InkColorMenu, {
1916
- property: "border",
1917
- group: "markup",
1918
- label: "Highlight colour",
1919
- standalone: true,
1920
- role: "menuitem",
1921
- tabIndex: -1
1922
- })]
1923
- })
1898
+ /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(Popover.Content, {
1899
+ role: "menu",
1900
+ "aria-label": "Highlights",
1901
+ className: "ink-select-content ink-menu-content",
1902
+ "data-ink-select-content": "",
1903
+ "data-ink-menu": "highlight",
1904
+ side: "bottom",
1905
+ align: "start",
1906
+ sideOffset: 4,
1907
+ collisionPadding: 8,
1908
+ onOpenAutoFocus: (e) => {
1909
+ e.preventDefault();
1910
+ const menu = e.currentTarget;
1911
+ if (focusFirst.current) menuItems(menu)[0]?.focus({ preventScroll: true });
1912
+ else focusInitialMenuItem(menu);
1913
+ focusFirst.current = false;
1914
+ },
1915
+ onKeyDownCapture: (e) => {
1916
+ if (e.currentTarget.contains(e.target)) handleMenuKeys(e.nativeEvent, e.currentTarget);
1917
+ },
1918
+ children: [
1919
+ /* @__PURE__ */ jsx("div", {
1920
+ role: "group",
1921
+ "aria-label": "Kinds",
1922
+ className: "ink-highlight-kinds",
1923
+ children: model.items.map((item) => /* @__PURE__ */ jsxs("button", {
1924
+ type: "button",
1925
+ role: "menuitemradio",
1926
+ "aria-checked": item.checked,
1927
+ tabIndex: -1,
1928
+ className: "ink-select-item ink-menu-item ink-highlight-item",
1929
+ "data-ink-select-item": "",
1930
+ "data-key": item.kind,
1931
+ "data-state": item.checked ? "checked" : "unchecked",
1932
+ onClick: () => {
1933
+ setOptions({ kind: item.kind });
1934
+ setTool("highlight");
1935
+ setOpen(false);
1936
+ },
1937
+ children: [/* @__PURE__ */ jsx(InkIcon, {
1938
+ icon: MARKUP_ICONS[item.kind],
1939
+ size: 16
1940
+ }), item.label]
1941
+ }, item.kind))
1942
+ }),
1943
+ /* @__PURE__ */ jsx("div", {
1944
+ role: "separator",
1945
+ className: "ink-select-separator"
1946
+ }),
1947
+ /* @__PURE__ */ jsxs("div", {
1948
+ role: "group",
1949
+ "aria-label": "Colour",
1950
+ className: "ink-highlight-colour",
1951
+ children: [/* @__PURE__ */ jsx("span", {
1952
+ className: "ink-highlight-colour-label",
1953
+ "aria-hidden": "true",
1954
+ children: "Colour"
1955
+ }), /* @__PURE__ */ jsx(InkColorMenu, {
1956
+ property: "border",
1957
+ group: "markup",
1958
+ label: "Highlight colour",
1959
+ standalone: true,
1960
+ fallback: doc?.annotations.defaults.color(model.kind),
1961
+ role: "menuitem",
1962
+ tabIndex: -1
1963
+ })]
1964
+ })
1965
+ ]
1966
+ }) })
1924
1967
  ]
1925
- }) })]
1926
- })]
1968
+ })
1969
+ })
1927
1970
  });
1928
1971
  }
1929
1972
  //#endregion
@@ -2429,84 +2472,6 @@ function ThreadForm({ editingRoot, locked, deleteLabel, onSubmit, onRemove, onCl
2429
2472
  });
2430
2473
  }
2431
2474
  //#endregion
2432
- //#region src/components/InkSuggestionCard.tsx
2433
- function InkSuggestionCard({ children }) {
2434
- const ctx = useInkContext("InkSuggestionCard");
2435
- const { annotations, selection, accept: acceptId, dismiss: dismissId, select } = useAnnotations();
2436
- function suggestion(id) {
2437
- const a = id ? annotations.find((x) => x.id === id) : void 0;
2438
- return a?.type === "redact" && a.origin === "suggested" ? a : null;
2439
- }
2440
- const target = suggestion(ctx.activated) ?? (selection.length === 1 ? suggestion(selection[0]) : null);
2441
- const anchor = useAnnotationElement(ctx.rootEl, target?.id ?? null);
2442
- const anchorRef = useMemo(() => ({ current: anchor }), [anchor]);
2443
- const focusReturn = useFocusReturn(ctx);
2444
- const open = target !== null && anchor !== null;
2445
- const bucket = target?.suggestion ? confidenceBucket(target.suggestion.confidence) : void 0;
2446
- function close() {
2447
- ctx.setActivated(null);
2448
- select([]);
2449
- }
2450
- function accept() {
2451
- if (target) acceptId(target.id);
2452
- close();
2453
- }
2454
- /** Locked annotations cannot be removed: dismissing one does nothing and keeps the card. */
2455
- function dismiss() {
2456
- if (!target || target.locked) return;
2457
- focusReturn.beforeRemove(anchor, "[data-origin=\"suggested\"]");
2458
- dismissId(target.id);
2459
- close();
2460
- }
2461
- return /* @__PURE__ */ jsxs(Popover.Root, {
2462
- open,
2463
- onOpenChange: (next) => !next && close(),
2464
- children: [/* @__PURE__ */ jsx(Popover.Anchor, { virtualRef: anchorRef }), /* @__PURE__ */ jsx(Popover.Portal, { children: target && anchor ? /* @__PURE__ */ jsx(Popover.Content, {
2465
- className: "ink-suggestion-card",
2466
- "data-ink-suggestion-card": "",
2467
- side: "bottom",
2468
- sideOffset: 6,
2469
- collisionPadding: 8,
2470
- "aria-label": "Suggested redaction",
2471
- onInteractOutside: keepOpenOnAnnotation,
2472
- onCloseAutoFocus: (e) => focusReturn.onCloseAutoFocus(e, anchor),
2473
- children: children ? children({
2474
- annotation: target,
2475
- suggestion: target.suggestion,
2476
- bucket,
2477
- accept,
2478
- dismiss,
2479
- close
2480
- }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
2481
- /* @__PURE__ */ jsxs("p", {
2482
- className: "ink-suggestion-reason",
2483
- children: [/* @__PURE__ */ jsx("strong", { children: target.suggestion?.reason ?? "Suggested redaction" }), bucket ? /* @__PURE__ */ jsxs("span", {
2484
- className: "ink-suggestion-confidence",
2485
- "data-confidence": bucket,
2486
- children: [bucket, " confidence"]
2487
- }) : null]
2488
- }),
2489
- target.suggestion?.explanation ? /* @__PURE__ */ jsx("p", {
2490
- className: "ink-suggestion-explanation",
2491
- children: target.suggestion.explanation
2492
- }) : null,
2493
- /* @__PURE__ */ jsxs("div", {
2494
- className: "ink-suggestion-actions",
2495
- children: [/* @__PURE__ */ jsx("button", {
2496
- type: "button",
2497
- onClick: accept,
2498
- children: "Accept"
2499
- }), !target.locked ? /* @__PURE__ */ jsx("button", {
2500
- type: "button",
2501
- onClick: dismiss,
2502
- children: "Dismiss"
2503
- }) : null]
2504
- })
2505
- ] })
2506
- }) : null })]
2507
- });
2508
- }
2509
- //#endregion
2510
- export { InkAnnotation, InkColorMenu, InkHighlightMenu, InkIcon, InkLineStyleMenu, InkNextPage, InkPage, InkPageCount, InkPageInput, InkPrevPage, InkRedo, InkRoot, InkShapeMenu, InkSignatureDialog, InkSignatureMenu, InkSuggestionCard, InkTextStyleMenu, InkThreadPopover, InkToolButton, InkToolbar, InkToolbarSeparator, InkUndo, InkViewport, InkZoomIn, InkZoomOut, InkZoomSelect, useAnnotations, useDocument, useEmbedded, useHistory, useInkContext, usePage, useReadable, useSelection, useTool, useToolOptions, useToolStyle, useZoom };
2475
+ export { InkAnnotation, InkColorMenu, InkHighlightMenu, InkIcon, InkLineStyleMenu, InkNextPage, InkPage, InkPageCount, InkPageInput, InkPrevPage, InkRedo, InkRoot, InkShapeMenu, InkSignatureDialog, InkSignatureMenu, InkTextStyleMenu, InkThreadPopover, InkToolButton, InkToolbar, InkToolbarSeparator, InkUndo, InkViewport, InkZoomIn, InkZoomOut, InkZoomSelect, useAnnotations, useDocument, useEmbedded, useHistory, useInkContext, usePage, useReadable, useSelection, useTool, useToolOptions, useToolStyle, useZoom };
2511
2476
 
2512
2477
  //# sourceMappingURL=index.mjs.map