@inkbar/react 0.10.0 → 0.12.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 +59 -11
- package/dist/index.d.mts +100 -16
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +293 -67
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
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,
|
|
4
|
-
import { COLOR_COLUMNS, FONT_FAMILIES, FORM_LABELS, MARKUP_ICONS, MARKUP_KINDS, SHAPE_COLUMNS, SHAPE_ICONS, SHAPE_KINDS, SIGNATURE_FONTS, SIGNATURE_LABELS, SIGNATURE_TABS, THUMBNAIL_WIDTH, TOOL_LABELS, ZOOM_LEVELS, attachFileKeys, attachHistoryKeys, colorMenuModel, createFocusReturn, createPluginHost, createRecordListController, createSearchController, createSidebarController, createSignatureDraft, createThumbnailPainter, createThumbnailsController, createToolOptions, cssVariableDefaults, downloadDocument, findAnnouncer, findCountText, focusInitialMenuItem, fontFamilyValue, handleFindKey, handleMenuKeys, handleRadioKeys, handleResultsFieldKey, handleTabKeys, highlightMenuModel, isBlankQuery, keepHistoryFocus, lineStyleMenuModel, menuItems, mountViewer, observeAnnotationElement, pageSelectionText, printDocument, recordsSource, searchSource, shapeMenuModel, shouldKeepOpenOnAnnotation, sidebarBadge, signatureMenuModel, signaturePreview, textStyleMenuModel, threadDeleteLabel, threadPopoverLabel, trackToolStyle, unknownCommand, unknownTool, viewerSearchOf, watchDetached, withHostTools } from "@inkbar/core/dom";
|
|
3
|
+
import { InkError, createMemoryStorage, createSignatureLibrary, createSnapshotHistory, createStorageSignatureStore, isAbandonedNote, openDocument, readonly, repliesTo, signField, threadOf, threadRoot, writable } from "@inkbar/core";
|
|
4
|
+
import { COLOR_COLUMNS, FONT_FAMILIES, FORM_LABELS, MARKUP_ICONS, MARKUP_KINDS, SHAPE_COLUMNS, SHAPE_ICONS, SHAPE_KINDS, SIGNATURE_FONTS, SIGNATURE_LABELS, SIGNATURE_TABS, THUMBNAIL_WIDTH, TOOL_LABELS, ZOOM_LEVELS, attachFileKeys, attachHistoryKeys, colorMenuModel, createFocusReturn, createOutlineController, createPluginHost, createRecordListController, createSearchController, createSidebarController, createSignatureDraft, createThumbnailPainter, createThumbnailsController, createToolOptions, cssVariableDefaults, downloadDocument, findAnnouncer, findCountText, focusInitialMenuItem, fontFamilyValue, handleFindKey, handleMenuKeys, handleRadioKeys, handleResultsFieldKey, handleTabKeys, highlightMenuModel, isBlankQuery, keepHistoryFocus, lineStyleMenuModel, menuItems, mountViewer, observeAnnotationElement, outlineTreeAttrs, pageSelectionText, printDocument, recordsSource, searchSource, shapeMenuModel, shouldKeepOpenOnAnnotation, sidebarBadge, signatureMenuModel, signaturePreview, textStyleMenuModel, threadDeleteLabel, threadPopoverLabel, trackToolStyle, unknownCommand, unknownTool, viewerSearchOf, watchDetached, withHostTools } from "@inkbar/core/dom";
|
|
5
5
|
import { Dialog, Popover, Select, Slot, Toolbar } from "radix-ui";
|
|
6
6
|
import { createPortal, flushSync } from "react-dom";
|
|
7
7
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
-
import { ALargeSmall, AlignCenter, AlignJustify, AlignLeft, AlignRight, Bold, CaseSensitive, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Download, ICON_ATTRIBUTES, Italic, Minus, Plus, Printer, Redo2, Search, Signature, SquareDashedMousePointer, TextCursor, Trash2, Underline, Undo2, X, ZoomIn, ZoomOut } from "@inkbar/icons";
|
|
8
|
+
import { ALargeSmall, AlignCenter, AlignJustify, AlignLeft, AlignRight, ArrowLeft, ArrowRight, Bold, CaseSensitive, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Download, ICON_ATTRIBUTES, Italic, Minus, Plus, Printer, Redo2, Search, Signature, SquareDashedMousePointer, TextCursor, Trash2, Underline, Undo2, X, ZoomIn, ZoomOut } from "@inkbar/icons";
|
|
9
9
|
//#region src/context.ts
|
|
10
10
|
const InkContextObject = createContext(null);
|
|
11
11
|
/**
|
|
@@ -395,7 +395,7 @@ function isDevelopment$1() {
|
|
|
395
395
|
function setTestHook(el, doc) {
|
|
396
396
|
if (el && isDevelopment$1()) el.__inkDocument = doc;
|
|
397
397
|
}
|
|
398
|
-
function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsChange, onChange, fields, onFieldsChange, onFormAction, formHighlight, tool, onToolChange, tools: hostTools, plugins: pluginsProp, decorateAnnotation, fonts: fontsProp, signatures: signatureStore, signatureFonts: signatureFontsProp, page, onPageChange, zoom, onZoomChange, history, asChild = false, onReady, onError, onActivate, children, ref, ...rest }) {
|
|
398
|
+
function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsChange, onChange, fields, onFieldsChange, onAction, onFormAction, formHighlight, tool, onToolChange, tools: hostTools, plugins: pluginsProp, decorateAnnotation, fonts: fontsProp, storage: storageProp, signatures: signatureStore, signatureFonts: signatureFontsProp, page, onPageChange, zoom, onZoomChange, history, asChild = false, onReady, onError, onActivate, children, ref, ...rest }) {
|
|
399
399
|
const rootElRef = useRef(null);
|
|
400
400
|
const [rootEl, setRootElState] = useState(null);
|
|
401
401
|
const setRootEl = useCallback((el) => {
|
|
@@ -427,6 +427,7 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
|
|
|
427
427
|
controlled: controlledProp,
|
|
428
428
|
fields,
|
|
429
429
|
onFieldsChange,
|
|
430
|
+
onAction,
|
|
430
431
|
onFormAction,
|
|
431
432
|
history,
|
|
432
433
|
historyEnabled,
|
|
@@ -445,7 +446,7 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
|
|
|
445
446
|
tools
|
|
446
447
|
});
|
|
447
448
|
/**
|
|
448
|
-
* Hands `e` to `onError` one microtask later, as `onFieldsChange` and `
|
|
449
|
+
* Hands `e` to `onError` one microtask later, as `onFieldsChange` and `onAction` are: a
|
|
449
450
|
* script or a press reports from inside its own work. Dropped once `doc` is no longer open.
|
|
450
451
|
*/
|
|
451
452
|
const reportErrorFor = useCallback((doc, e) => {
|
|
@@ -492,6 +493,7 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
|
|
|
492
493
|
react: (fn) => active()?.react(fn) ?? noop
|
|
493
494
|
};
|
|
494
495
|
}, [snapshotHistory]);
|
|
496
|
+
const [storage] = useState(() => storageProp ?? createMemoryStorage());
|
|
495
497
|
const hostRef = useRef(null);
|
|
496
498
|
const [pluginHost, setPluginHost] = useState(null);
|
|
497
499
|
const [search, setSearch] = useState(null);
|
|
@@ -514,7 +516,8 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
|
|
|
514
516
|
root: readonly(plugins.root),
|
|
515
517
|
decorate: () => latest.current.decorateAnnotation,
|
|
516
518
|
viewport: () => viewportRef.current,
|
|
517
|
-
search: viewerSearchOf(search)
|
|
519
|
+
search: viewerSearchOf(search),
|
|
520
|
+
storage
|
|
518
521
|
});
|
|
519
522
|
hostRef.current = {
|
|
520
523
|
host,
|
|
@@ -701,16 +704,20 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
|
|
|
701
704
|
]);
|
|
702
705
|
const reportZoom = useCallback((z) => latest.current.onZoomChange?.(z), [latest]);
|
|
703
706
|
const reportPage = useCallback((p) => latest.current.onPageChange?.(p), [latest]);
|
|
704
|
-
const
|
|
707
|
+
const reportAction = useCallback((a) => {
|
|
705
708
|
const doc = documentRef.current;
|
|
706
709
|
queueMicrotask(() => {
|
|
707
710
|
if (documentRef.current !== doc) return;
|
|
708
|
-
flushSync(() =>
|
|
711
|
+
flushSync(() => {
|
|
712
|
+
const { onAction, onFormAction } = latest.current;
|
|
713
|
+
(onAction ?? onFormAction)?.(a);
|
|
714
|
+
});
|
|
709
715
|
});
|
|
710
716
|
}, [latest]);
|
|
711
717
|
const reportError = useCallback((e) => {
|
|
712
718
|
if (documentRef.current) reportErrorFor(documentRef.current, e);
|
|
713
719
|
}, [reportErrorFor]);
|
|
720
|
+
const [navigation, setNavigation] = useState(null);
|
|
714
721
|
const setViewport = useCallback((vp, tc) => {
|
|
715
722
|
viewportRef.current = vp;
|
|
716
723
|
setViewportState(vp);
|
|
@@ -799,7 +806,8 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
|
|
|
799
806
|
]);
|
|
800
807
|
const fonts = useMemo(() => fontsProp ?? FONT_FAMILIES, [fontsProp]);
|
|
801
808
|
const signatureFonts = useMemo(() => signatureFontsProp ?? SIGNATURE_FONTS, [signatureFontsProp]);
|
|
802
|
-
const
|
|
809
|
+
const [storageSignatures] = useState(() => createStorageSignatureStore(storage));
|
|
810
|
+
const signatures = useMemo(() => createSignatureLibrary(signatureStore ?? storageSignatures), [signatureStore, storageSignatures]);
|
|
803
811
|
useEffect(() => {
|
|
804
812
|
signatures.refresh();
|
|
805
813
|
}, [signatures]);
|
|
@@ -829,6 +837,8 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
|
|
|
829
837
|
selection,
|
|
830
838
|
viewport,
|
|
831
839
|
tools,
|
|
840
|
+
navigation,
|
|
841
|
+
setNavigation,
|
|
832
842
|
tool: internalTool,
|
|
833
843
|
setTool,
|
|
834
844
|
hostTools,
|
|
@@ -838,6 +848,7 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
|
|
|
838
848
|
onDecorateAnnotationChange,
|
|
839
849
|
fonts,
|
|
840
850
|
toolOptions,
|
|
851
|
+
storage,
|
|
841
852
|
signatures,
|
|
842
853
|
signatureFonts,
|
|
843
854
|
toolStyle: styleTracker?.toolStyle ?? null,
|
|
@@ -854,7 +865,7 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
|
|
|
854
865
|
rootEl,
|
|
855
866
|
setViewport,
|
|
856
867
|
formHighlight,
|
|
857
|
-
|
|
868
|
+
reportAction,
|
|
858
869
|
reportError
|
|
859
870
|
}), [
|
|
860
871
|
assets,
|
|
@@ -864,6 +875,7 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
|
|
|
864
875
|
selection,
|
|
865
876
|
viewport,
|
|
866
877
|
tools,
|
|
878
|
+
navigation,
|
|
867
879
|
internalTool,
|
|
868
880
|
setTool,
|
|
869
881
|
hostTools,
|
|
@@ -872,6 +884,7 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
|
|
|
872
884
|
onDecorateAnnotationChange,
|
|
873
885
|
fonts,
|
|
874
886
|
toolOptions,
|
|
887
|
+
storage,
|
|
875
888
|
signatures,
|
|
876
889
|
signatureFonts,
|
|
877
890
|
styleTracker,
|
|
@@ -888,7 +901,7 @@ function InkRoot({ src, assets, password, defaults, annotations, onAnnotationsCh
|
|
|
888
901
|
rootEl,
|
|
889
902
|
setViewport,
|
|
890
903
|
formHighlight,
|
|
891
|
-
|
|
904
|
+
reportAction,
|
|
892
905
|
reportError
|
|
893
906
|
]);
|
|
894
907
|
useEffect(() => {
|
|
@@ -1540,7 +1553,7 @@ function documentKey(doc) {
|
|
|
1540
1553
|
}
|
|
1541
1554
|
return key;
|
|
1542
1555
|
}
|
|
1543
|
-
function InkViewport({ mode = "continuous", rotation = 0, gap = 16, buffer = 2, loading, empty, error, renderAnnotation, renderPageError, className, ...rest }) {
|
|
1556
|
+
function InkViewport({ mode = "continuous", rotation = 0, gap = 16, buffer = 2, pinchZoom = true, loading, empty, error, renderAnnotation, renderPageError, className, ...rest }) {
|
|
1544
1557
|
const ctx = useInkContext("InkViewport");
|
|
1545
1558
|
const scroll = useRef(null);
|
|
1546
1559
|
const custom = !!renderAnnotation;
|
|
@@ -1550,6 +1563,7 @@ function InkViewport({ mode = "continuous", rotation = 0, gap = 16, buffer = 2,
|
|
|
1550
1563
|
rotation,
|
|
1551
1564
|
gap,
|
|
1552
1565
|
buffer,
|
|
1566
|
+
pinchZoom,
|
|
1553
1567
|
custom
|
|
1554
1568
|
});
|
|
1555
1569
|
const engine = useRef(null);
|
|
@@ -1571,7 +1585,7 @@ function InkViewport({ mode = "continuous", rotation = 0, gap = 16, buffer = 2,
|
|
|
1571
1585
|
/** The form script's message on show, and how many have been shown. */
|
|
1572
1586
|
const [alert, setAlert] = useState(null);
|
|
1573
1587
|
useEffect(() => {
|
|
1574
|
-
const { ctx: c, mode: m, rotation: r, gap: g, buffer: b, custom: cu } = latest.current;
|
|
1588
|
+
const { ctx: c, mode: m, rotation: r, gap: g, buffer: b, pinchZoom: pz, custom: cu } = latest.current;
|
|
1575
1589
|
const doc = c.document;
|
|
1576
1590
|
const el = scroll.current;
|
|
1577
1591
|
lastReportedZoom.current = void 0;
|
|
@@ -1583,6 +1597,7 @@ function InkViewport({ mode = "continuous", rotation = 0, gap = 16, buffer = 2,
|
|
|
1583
1597
|
builtWith.current = {
|
|
1584
1598
|
gap: g,
|
|
1585
1599
|
buffer: b,
|
|
1600
|
+
pinchZoom: pz,
|
|
1586
1601
|
custom: cu
|
|
1587
1602
|
};
|
|
1588
1603
|
c.setOpenedToolIds(toolIdsOf(c.hostTools, c.pluginHost));
|
|
@@ -1595,6 +1610,7 @@ function InkViewport({ mode = "continuous", rotation = 0, gap = 16, buffer = 2,
|
|
|
1595
1610
|
rotation: r,
|
|
1596
1611
|
gap: g,
|
|
1597
1612
|
buffer: b,
|
|
1613
|
+
pinchZoom: pz,
|
|
1598
1614
|
tool: c.tool,
|
|
1599
1615
|
...c.hostTools ? { tools: c.hostTools } : {},
|
|
1600
1616
|
...c.pluginHost ? { plugins: c.pluginHost } : {},
|
|
@@ -1608,7 +1624,7 @@ function InkViewport({ mode = "continuous", rotation = 0, gap = 16, buffer = 2,
|
|
|
1608
1624
|
customAnnotations: cu,
|
|
1609
1625
|
...c.formHighlight === void 0 ? {} : { formHighlight: c.formHighlight },
|
|
1610
1626
|
onSignField: (req) => setSignRequest((open) => open?.widget === req.widget ? null : req),
|
|
1611
|
-
|
|
1627
|
+
onAction: (a) => latest.current.ctx.reportAction(a),
|
|
1612
1628
|
onFormAlert: (message) => setAlert((prev) => ({
|
|
1613
1629
|
message,
|
|
1614
1630
|
shown: (prev?.shown ?? 0) + 1
|
|
@@ -1662,12 +1678,14 @@ function InkViewport({ mode = "continuous", rotation = 0, gap = 16, buffer = 2,
|
|
|
1662
1678
|
} : p))
|
|
1663
1679
|
});
|
|
1664
1680
|
engine.current = e;
|
|
1681
|
+
c.setNavigation(e.navigation);
|
|
1665
1682
|
return () => {
|
|
1666
1683
|
for (const stop of stops) stop();
|
|
1667
1684
|
e.destroy();
|
|
1668
1685
|
engine.current = null;
|
|
1669
1686
|
builtWith.current = null;
|
|
1670
1687
|
c.setViewport(null, null);
|
|
1688
|
+
c.setNavigation(null);
|
|
1671
1689
|
c.setOpenedToolIds(null);
|
|
1672
1690
|
setPages((prev) => prev.length === 0 ? prev : []);
|
|
1673
1691
|
setSignRequest(null);
|
|
@@ -1693,21 +1711,24 @@ function InkViewport({ mode = "continuous", rotation = 0, gap = 16, buffer = 2,
|
|
|
1693
1711
|
useEffect(() => {
|
|
1694
1712
|
const built = builtWith.current;
|
|
1695
1713
|
if (!engine.current || !built) return;
|
|
1696
|
-
if (built.gap === gap && built.buffer === buffer && built.custom === custom) return;
|
|
1714
|
+
if (built.gap === gap && built.buffer === buffer && built.pinchZoom === pinchZoom && built.custom === custom) return;
|
|
1697
1715
|
buildCount.current += 1;
|
|
1698
1716
|
builtWith.current = {
|
|
1699
1717
|
gap,
|
|
1700
1718
|
buffer,
|
|
1719
|
+
pinchZoom,
|
|
1701
1720
|
custom
|
|
1702
1721
|
};
|
|
1703
1722
|
engine.current.rebuild({
|
|
1704
1723
|
gap,
|
|
1705
1724
|
buffer,
|
|
1725
|
+
pinchZoom,
|
|
1706
1726
|
customAnnotations: custom
|
|
1707
1727
|
});
|
|
1708
1728
|
}, [
|
|
1709
1729
|
gap,
|
|
1710
1730
|
buffer,
|
|
1731
|
+
pinchZoom,
|
|
1711
1732
|
custom
|
|
1712
1733
|
]);
|
|
1713
1734
|
useEffect(() => {
|
|
@@ -2409,6 +2430,182 @@ function InkNextPage({ asChild = false, className, children, disabled, onClick,
|
|
|
2409
2430
|
});
|
|
2410
2431
|
}
|
|
2411
2432
|
//#endregion
|
|
2433
|
+
//#region src/components/InkBack.tsx
|
|
2434
|
+
/** Returns to where the view was before the last jump; disabled while there is nowhere to go. */
|
|
2435
|
+
function InkBack({ asChild = false, className, children, disabled, onClick, ...rest }) {
|
|
2436
|
+
const ctx = useInkContext("InkBack");
|
|
2437
|
+
const canGoBack = useReadable(ctx.navigation?.canGoBack, false);
|
|
2438
|
+
return /* @__PURE__ */ jsx(Toolbar.Button, {
|
|
2439
|
+
asChild,
|
|
2440
|
+
className: cx("ink-back", className),
|
|
2441
|
+
"data-ink-back": "",
|
|
2442
|
+
"aria-label": "Back",
|
|
2443
|
+
title: "Back",
|
|
2444
|
+
disabled: disabled === true || !canGoBack,
|
|
2445
|
+
...rest,
|
|
2446
|
+
onClick: (e) => {
|
|
2447
|
+
onClick?.(e);
|
|
2448
|
+
if (!e.defaultPrevented) ctx.navigation?.back();
|
|
2449
|
+
},
|
|
2450
|
+
children: children ?? /* @__PURE__ */ jsx(InkIcon, { icon: ArrowLeft })
|
|
2451
|
+
});
|
|
2452
|
+
}
|
|
2453
|
+
//#endregion
|
|
2454
|
+
//#region src/components/InkForward.tsx
|
|
2455
|
+
/** Goes forward again after Back; disabled until Back is used. */
|
|
2456
|
+
function InkForward({ asChild = false, className, children, disabled, onClick, ...rest }) {
|
|
2457
|
+
const ctx = useInkContext("InkForward");
|
|
2458
|
+
const canGoForward = useReadable(ctx.navigation?.canGoForward, false);
|
|
2459
|
+
return /* @__PURE__ */ jsx(Toolbar.Button, {
|
|
2460
|
+
asChild,
|
|
2461
|
+
className: cx("ink-forward", className),
|
|
2462
|
+
"data-ink-forward": "",
|
|
2463
|
+
"aria-label": "Forward",
|
|
2464
|
+
title: "Forward",
|
|
2465
|
+
disabled: disabled === true || !canGoForward,
|
|
2466
|
+
...rest,
|
|
2467
|
+
onClick: (e) => {
|
|
2468
|
+
onClick?.(e);
|
|
2469
|
+
if (!e.defaultPrevented) ctx.navigation?.forward();
|
|
2470
|
+
},
|
|
2471
|
+
children: children ?? /* @__PURE__ */ jsx(InkIcon, { icon: ArrowRight })
|
|
2472
|
+
});
|
|
2473
|
+
}
|
|
2474
|
+
//#endregion
|
|
2475
|
+
//#region src/dom-attrs.ts
|
|
2476
|
+
/**
|
|
2477
|
+
* Core's attributes (`rootAttrs()`, `triggerAttrs(id)`, `panelAttrs(id)` and the like) as React
|
|
2478
|
+
* props. Core names them as the DOM does; React wants `hidden` as a boolean and `tabindex` as
|
|
2479
|
+
* `tabIndex`. `aria-*`, `data-*`, `id`, `role`, `type` and `title` pass through as they are.
|
|
2480
|
+
* Every component that spreads core's attributes goes through this, so the mapping lives once.
|
|
2481
|
+
*/
|
|
2482
|
+
function domAttrs(attrs) {
|
|
2483
|
+
const out = {};
|
|
2484
|
+
for (const [name, value] of Object.entries(attrs)) if (name === "hidden") out.hidden = true;
|
|
2485
|
+
else if (name === "tabindex") out.tabIndex = Number(value);
|
|
2486
|
+
else out[name] = value;
|
|
2487
|
+
return out;
|
|
2488
|
+
}
|
|
2489
|
+
//#endregion
|
|
2490
|
+
//#region src/to-readable.ts
|
|
2491
|
+
/**
|
|
2492
|
+
* A core `Readable` that follows a React value, for the core controllers and painters that
|
|
2493
|
+
* components build on. The same readable for the component's life; it takes each new value in
|
|
2494
|
+
* a layout effect, so declare it before the effects that hand it to core.
|
|
2495
|
+
*/
|
|
2496
|
+
function useToReadable(value) {
|
|
2497
|
+
const [store] = useState(() => writable(value));
|
|
2498
|
+
useLayoutEffect(() => {
|
|
2499
|
+
store.set(value);
|
|
2500
|
+
}, [store, value]);
|
|
2501
|
+
const [view] = useState(() => readonly(store));
|
|
2502
|
+
return view;
|
|
2503
|
+
}
|
|
2504
|
+
//#endregion
|
|
2505
|
+
//#region src/components/InkOutline.tsx
|
|
2506
|
+
const NO_ITEMS = [];
|
|
2507
|
+
const NO_EXPANDED = /* @__PURE__ */ new Set();
|
|
2508
|
+
/**
|
|
2509
|
+
* The open document's outline as a tree: `createOutline`'s markup on core's outline
|
|
2510
|
+
* controller, which holds what is expanded, the Tab stop, the keys, the current item and
|
|
2511
|
+
* Back's history. Clicking an item, or Enter on it, follows it; its chevron expands and
|
|
2512
|
+
* collapses it. It fills its parent's height and scrolls, and keeps the item the reader has
|
|
2513
|
+
* reached in view. `renderItem` replaces an item's title. Inside `InkRoot`; the tree is empty
|
|
2514
|
+
* on the server.
|
|
2515
|
+
*/
|
|
2516
|
+
function InkOutline({ emptyText = "This document has no outline", renderItem, className, ...rest }) {
|
|
2517
|
+
const ctx = useInkContext("InkOutline");
|
|
2518
|
+
const document = useToReadable(ctx.document);
|
|
2519
|
+
const viewport = useToReadable(ctx.viewport);
|
|
2520
|
+
const navigation = useToReadable(ctx.navigation);
|
|
2521
|
+
const root = useRef(null);
|
|
2522
|
+
const [controller, setController] = useState(null);
|
|
2523
|
+
useLayoutEffect(() => {
|
|
2524
|
+
const c = createOutlineController({
|
|
2525
|
+
document,
|
|
2526
|
+
viewport,
|
|
2527
|
+
navigation
|
|
2528
|
+
});
|
|
2529
|
+
setController(c);
|
|
2530
|
+
const unbind = c.bindScroll(root.current);
|
|
2531
|
+
return () => {
|
|
2532
|
+
unbind();
|
|
2533
|
+
c.destroy();
|
|
2534
|
+
setController(null);
|
|
2535
|
+
};
|
|
2536
|
+
}, [
|
|
2537
|
+
document,
|
|
2538
|
+
viewport,
|
|
2539
|
+
navigation
|
|
2540
|
+
]);
|
|
2541
|
+
const items = useReadable(controller?.items, NO_ITEMS);
|
|
2542
|
+
const loading = useReadable(controller?.loading, false);
|
|
2543
|
+
const expanded = useReadable(controller?.expanded, NO_EXPANDED);
|
|
2544
|
+
const current = useReadable(controller?.current, null);
|
|
2545
|
+
useReadable(controller?.focused, null);
|
|
2546
|
+
const level = (id) => id.split(".").length - 1;
|
|
2547
|
+
const renderLevel = (list) => list.map((item) => {
|
|
2548
|
+
const c = controller;
|
|
2549
|
+
const open = expanded.has(item.id);
|
|
2550
|
+
const attrs = {};
|
|
2551
|
+
for (const [name, value] of Object.entries(c.itemAttrs(item.id))) if (value !== void 0) attrs[name] = value;
|
|
2552
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
2553
|
+
className: "ink-outline-item",
|
|
2554
|
+
"data-ink-outline-item": item.id,
|
|
2555
|
+
"data-bold": item.bold ? "" : void 0,
|
|
2556
|
+
"data-italic": item.italic ? "" : void 0,
|
|
2557
|
+
style: { "--ink-outline-level": level(item.id) },
|
|
2558
|
+
...domAttrs(attrs),
|
|
2559
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
2560
|
+
className: "ink-outline-row",
|
|
2561
|
+
...c.rowAttrs(item.id),
|
|
2562
|
+
onClick: () => c.activate(item.id),
|
|
2563
|
+
children: [item.children.length > 0 ? /* @__PURE__ */ jsx("span", {
|
|
2564
|
+
className: "ink-outline-toggle",
|
|
2565
|
+
"aria-hidden": "true",
|
|
2566
|
+
onClick: (e) => {
|
|
2567
|
+
e.stopPropagation();
|
|
2568
|
+
c.toggle(item.id);
|
|
2569
|
+
},
|
|
2570
|
+
children: /* @__PURE__ */ jsx(InkIcon, { icon: ChevronRight })
|
|
2571
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
2572
|
+
className: "ink-outline-spacer",
|
|
2573
|
+
"aria-hidden": "true"
|
|
2574
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
2575
|
+
className: "ink-outline-title",
|
|
2576
|
+
...c.titleAttrs(item.id),
|
|
2577
|
+
children: renderItem ? renderItem(item, {
|
|
2578
|
+
current: current === item.id,
|
|
2579
|
+
expanded: open
|
|
2580
|
+
}) : item.title
|
|
2581
|
+
})]
|
|
2582
|
+
}), item.children.length > 0 ? /* @__PURE__ */ jsx("ul", {
|
|
2583
|
+
className: "ink-outline-group",
|
|
2584
|
+
role: "group",
|
|
2585
|
+
hidden: !open,
|
|
2586
|
+
children: renderLevel(item.children)
|
|
2587
|
+
}) : null]
|
|
2588
|
+
}, item.id);
|
|
2589
|
+
});
|
|
2590
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
2591
|
+
...rest,
|
|
2592
|
+
ref: root,
|
|
2593
|
+
className: cx("ink-outline", className),
|
|
2594
|
+
"data-ink-outline": "",
|
|
2595
|
+
"aria-busy": loading ? "true" : void 0,
|
|
2596
|
+
children: [/* @__PURE__ */ jsx("ul", {
|
|
2597
|
+
className: "ink-outline-tree",
|
|
2598
|
+
...outlineTreeAttrs(),
|
|
2599
|
+
hidden: items.length === 0,
|
|
2600
|
+
onKeyDown: (e) => controller?.onKeydown(e.nativeEvent),
|
|
2601
|
+
children: controller ? renderLevel(items) : null
|
|
2602
|
+
}), controller && !loading && items.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
2603
|
+
className: "ink-outline-empty",
|
|
2604
|
+
children: emptyText
|
|
2605
|
+
}) : null]
|
|
2606
|
+
});
|
|
2607
|
+
}
|
|
2608
|
+
//#endregion
|
|
2412
2609
|
//#region src/components/InkColorMenu.tsx
|
|
2413
2610
|
function InkColorMenu({ property, label, className, children, standalone = false, group, fallback, disabled, ...rest }) {
|
|
2414
2611
|
const Wrap = standalone ? Fragment : Toolbar.Button;
|
|
@@ -3419,21 +3616,6 @@ function ThreadForm({ editingRoot, locked, deleteLabel, onSubmit, onRemove, onCl
|
|
|
3419
3616
|
});
|
|
3420
3617
|
}
|
|
3421
3618
|
//#endregion
|
|
3422
|
-
//#region src/dom-attrs.ts
|
|
3423
|
-
/**
|
|
3424
|
-
* Core's attributes (`rootAttrs()`, `triggerAttrs(id)`, `panelAttrs(id)` and the like) as React
|
|
3425
|
-
* props. Core names them as the DOM does; React wants `hidden` as a boolean and `tabindex` as
|
|
3426
|
-
* `tabIndex`. `aria-*`, `data-*`, `id`, `role`, `type` and `title` pass through as they are.
|
|
3427
|
-
* Every component that spreads core's attributes goes through this, so the mapping lives once.
|
|
3428
|
-
*/
|
|
3429
|
-
function domAttrs(attrs) {
|
|
3430
|
-
const out = {};
|
|
3431
|
-
for (const [name, value] of Object.entries(attrs)) if (name === "hidden") out.hidden = true;
|
|
3432
|
-
else if (name === "tabindex") out.tabIndex = Number(value);
|
|
3433
|
-
else out[name] = value;
|
|
3434
|
-
return out;
|
|
3435
|
-
}
|
|
3436
|
-
//#endregion
|
|
3437
3619
|
//#region src/components/sidebar-context.ts
|
|
3438
3620
|
const SidebarContextObject = createContext(null);
|
|
3439
3621
|
/** The sidebar context: throws a readable error outside `InkSidebar`. */
|
|
@@ -3477,6 +3659,16 @@ function SidebarTrigger({ panel, rail }) {
|
|
|
3477
3659
|
}
|
|
3478
3660
|
//#endregion
|
|
3479
3661
|
//#region src/components/InkSidebar.tsx
|
|
3662
|
+
/** The width props the host gave; an undefined one keeps the controller's. */
|
|
3663
|
+
function widthOptions(props) {
|
|
3664
|
+
const { defaultWidth, minWidth, maxWidth, width } = props;
|
|
3665
|
+
return {
|
|
3666
|
+
...defaultWidth !== void 0 && { defaultWidth },
|
|
3667
|
+
...minWidth !== void 0 && { minWidth },
|
|
3668
|
+
...maxWidth !== void 0 && { maxWidth },
|
|
3669
|
+
...width !== void 0 && { width }
|
|
3670
|
+
};
|
|
3671
|
+
}
|
|
3480
3672
|
/** Sorts the panels by where their elements sit in the DOM. */
|
|
3481
3673
|
function inDomOrder(entries) {
|
|
3482
3674
|
return [...entries].sort((a, b) => {
|
|
@@ -3550,17 +3742,30 @@ function createRegistry(controller) {
|
|
|
3550
3742
|
*
|
|
3551
3743
|
* `open` with `onOpenChange` controls it; `defaultOpen` starts it uncontrolled; with neither,
|
|
3552
3744
|
* the first panel starts open. It needs no document, so it works outside `InkRoot`. The server
|
|
3553
|
-
* renders the root, the panels (the open one shown)
|
|
3554
|
-
* buttons follow once mounted.
|
|
3745
|
+
* renders the root, the panels (the open one shown), the stack headers and the resize handle;
|
|
3746
|
+
* rail and tab buttons follow once mounted.
|
|
3747
|
+
*
|
|
3748
|
+
* The handle on the inner edge resizes the sidebar. Its width is saved in `storage`, under
|
|
3749
|
+
* `sidebar.<name>.width`; inside `InkRoot` the root's storage is the default. `width` with
|
|
3750
|
+
* `onWidthChange` makes the width the host's: drags and keys then only report, and storage is
|
|
3751
|
+
* not read or written.
|
|
3555
3752
|
*/
|
|
3556
|
-
function InkSidebar({ side = "left", layout = "rail", visible = true, open, defaultOpen, onOpenChange, className, children, ...rest }) {
|
|
3753
|
+
function InkSidebar({ side = "left", layout = "rail", visible = true, open, defaultOpen, onOpenChange, storage: storageProp, name, defaultWidth, minWidth, maxWidth, width, onWidthChange, className, style, children, ...rest }) {
|
|
3557
3754
|
const controlled = open !== void 0;
|
|
3558
3755
|
const [inner, setInner] = useState(defaultOpen);
|
|
3559
3756
|
const value = controlled ? open : inner;
|
|
3560
3757
|
const latest = useLatest({
|
|
3561
3758
|
controlled,
|
|
3562
|
-
onOpenChange
|
|
3759
|
+
onOpenChange,
|
|
3760
|
+
onWidthChange
|
|
3761
|
+
});
|
|
3762
|
+
const widths = widthOptions({
|
|
3763
|
+
defaultWidth,
|
|
3764
|
+
minWidth,
|
|
3765
|
+
maxWidth,
|
|
3766
|
+
width
|
|
3563
3767
|
});
|
|
3768
|
+
const inherited = useContext(InkContextObject)?.storage;
|
|
3564
3769
|
const idPrefix = useId();
|
|
3565
3770
|
const [{ context, mount }] = useState(() => createRegistry(createSidebarController({
|
|
3566
3771
|
layout,
|
|
@@ -3570,6 +3775,10 @@ function InkSidebar({ side = "left", layout = "rail", visible = true, open, defa
|
|
|
3570
3775
|
...value !== void 0 && { open: value },
|
|
3571
3776
|
pending: true,
|
|
3572
3777
|
idPrefix,
|
|
3778
|
+
...(storageProp ?? inherited) && { storage: storageProp ?? inherited },
|
|
3779
|
+
...name !== void 0 && { name },
|
|
3780
|
+
...widths,
|
|
3781
|
+
onWidthChange: (next) => latest.current.onWidthChange?.(next),
|
|
3573
3782
|
onOpenChange: (next) => {
|
|
3574
3783
|
if (!latest.current.controlled) setInner(next);
|
|
3575
3784
|
latest.current.onOpenChange?.(next);
|
|
@@ -3582,40 +3791,72 @@ function InkSidebar({ side = "left", layout = "rail", visible = true, open, defa
|
|
|
3582
3791
|
layout,
|
|
3583
3792
|
side,
|
|
3584
3793
|
visible,
|
|
3585
|
-
...value !== void 0 && { open: value }
|
|
3794
|
+
...value !== void 0 && { open: value },
|
|
3795
|
+
...widths
|
|
3586
3796
|
});
|
|
3587
3797
|
}, [
|
|
3588
3798
|
controller,
|
|
3589
3799
|
layout,
|
|
3590
3800
|
side,
|
|
3591
3801
|
visible,
|
|
3592
|
-
value
|
|
3802
|
+
value,
|
|
3803
|
+
defaultWidth,
|
|
3804
|
+
minWidth,
|
|
3805
|
+
maxWidth,
|
|
3806
|
+
width
|
|
3593
3807
|
]);
|
|
3594
3808
|
const root = useRef(null);
|
|
3595
3809
|
useLayoutEffect(() => mount(root.current), [mount]);
|
|
3810
|
+
const handle = useRef(null);
|
|
3811
|
+
const [mounted, setMounted] = useState(false);
|
|
3812
|
+
useLayoutEffect(() => {
|
|
3813
|
+
setMounted(true);
|
|
3814
|
+
const el = handle.current;
|
|
3815
|
+
const unbind = controller.bindHandle(el);
|
|
3816
|
+
for (const [prop, value] of Object.entries(controller.rootStyle())) root.current.style.setProperty(prop, value);
|
|
3817
|
+
for (const [attr, value] of Object.entries(controller.handleAttrs())) if (attr.startsWith("aria-value")) el.setAttribute(attr, value);
|
|
3818
|
+
return unbind;
|
|
3819
|
+
}, [controller]);
|
|
3820
|
+
const handleAttrs = controller.handleAttrs();
|
|
3821
|
+
if (!mounted) delete handleAttrs.hidden;
|
|
3596
3822
|
const rail = state.layout === "rail";
|
|
3597
3823
|
return /* @__PURE__ */ jsxs("div", {
|
|
3598
3824
|
...rest,
|
|
3599
3825
|
ref: root,
|
|
3600
3826
|
className: cx("ink-sidebar", className),
|
|
3827
|
+
style: {
|
|
3828
|
+
...style,
|
|
3829
|
+
...controller.rootStyle()
|
|
3830
|
+
},
|
|
3831
|
+
suppressHydrationWarning: true,
|
|
3601
3832
|
...domAttrs(controller.rootAttrs()),
|
|
3602
|
-
children: [
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3833
|
+
children: [
|
|
3834
|
+
state.layout !== "stack" ? /* @__PURE__ */ jsx("div", {
|
|
3835
|
+
className: rail ? "ink-sidebar-rail" : "ink-sidebar-tabs",
|
|
3836
|
+
...domAttrs(controller.tablistAttrs()),
|
|
3837
|
+
children: state.panels.map((panel) => /* @__PURE__ */ jsx("button", {
|
|
3838
|
+
...domAttrs(controller.triggerAttrs(panel.id)),
|
|
3839
|
+
children: /* @__PURE__ */ jsx(SidebarTrigger, {
|
|
3840
|
+
panel,
|
|
3841
|
+
rail
|
|
3842
|
+
})
|
|
3843
|
+
}, panel.id))
|
|
3844
|
+
}) : null,
|
|
3845
|
+
/* @__PURE__ */ jsx("div", {
|
|
3846
|
+
className: state.layout !== "stack" ? "ink-sidebar-panels" : void 0,
|
|
3847
|
+
...state.layout !== "stack" && domAttrs(controller.panelsAttrs()),
|
|
3848
|
+
children: /* @__PURE__ */ jsx(SidebarContextObject.Provider, {
|
|
3849
|
+
value: context,
|
|
3850
|
+
children
|
|
3610
3851
|
})
|
|
3611
|
-
},
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3852
|
+
}),
|
|
3853
|
+
/* @__PURE__ */ jsx("div", {
|
|
3854
|
+
ref: handle,
|
|
3855
|
+
className: "ink-sidebar-handle",
|
|
3856
|
+
suppressHydrationWarning: true,
|
|
3857
|
+
...domAttrs(handleAttrs)
|
|
3617
3858
|
})
|
|
3618
|
-
|
|
3859
|
+
]
|
|
3619
3860
|
});
|
|
3620
3861
|
}
|
|
3621
3862
|
//#endregion
|
|
@@ -3681,21 +3922,6 @@ function InkPanel({ id, label, icon, badge, children }) {
|
|
|
3681
3922
|
});
|
|
3682
3923
|
}
|
|
3683
3924
|
//#endregion
|
|
3684
|
-
//#region src/to-readable.ts
|
|
3685
|
-
/**
|
|
3686
|
-
* A core `Readable` that follows a React value, for the core controllers and painters that
|
|
3687
|
-
* components build on. The same readable for the component's life; it takes each new value in
|
|
3688
|
-
* a layout effect, so declare it before the effects that hand it to core.
|
|
3689
|
-
*/
|
|
3690
|
-
function useToReadable(value) {
|
|
3691
|
-
const [store] = useState(() => writable(value));
|
|
3692
|
-
useLayoutEffect(() => {
|
|
3693
|
-
store.set(value);
|
|
3694
|
-
}, [store, value]);
|
|
3695
|
-
const [view] = useState(() => readonly(store));
|
|
3696
|
-
return view;
|
|
3697
|
-
}
|
|
3698
|
-
//#endregion
|
|
3699
3925
|
//#region src/components/InkThumbnail.tsx
|
|
3700
3926
|
/**
|
|
3701
3927
|
* One page as a static image, with its live annotations and plugin marks: core's thumbnail
|
|
@@ -4119,6 +4345,6 @@ function InkSearchResults({ field = true, className, ...rest }) {
|
|
|
4119
4345
|
});
|
|
4120
4346
|
}
|
|
4121
4347
|
//#endregion
|
|
4122
|
-
export { InkAnnotation, InkColorMenu, InkCommand, InkDownloadButton, InkFindBar, InkHighlightMenu, InkIcon, InkLineStyleMenu, InkNextPage, InkPage, InkPageCount, InkPageInput, InkPanel, InkPrevPage, InkPrintButton, InkRecordList, InkRedo, InkRoot, InkSearchButton, InkSearchResults, InkShapeMenu, InkSidebar, InkSignatureDialog, InkSignatureMenu, InkTextStyleMenu, InkThreadPopover, InkThumbnail, InkThumbnails, InkToolButton, InkToolbar, InkToolbarButton, InkToolbarSeparator, InkUndo, InkViewport, InkZoomIn, InkZoomOut, InkZoomSelect, useAnnotations, useCommand, useDocument, useEmbedded, useForm, useHistory, useInkContext, usePage, useReadable, useRecordSelection, useRecords, useSearch, useSelection, useTool, useToolOptions, useToolStyle, useZoom };
|
|
4348
|
+
export { InkAnnotation, InkBack, InkColorMenu, InkCommand, InkDownloadButton, InkFindBar, InkForward, InkHighlightMenu, InkIcon, InkLineStyleMenu, InkNextPage, InkOutline, InkPage, InkPageCount, InkPageInput, InkPanel, InkPrevPage, InkPrintButton, InkRecordList, InkRedo, InkRoot, InkSearchButton, InkSearchResults, InkShapeMenu, InkSidebar, InkSignatureDialog, InkSignatureMenu, InkTextStyleMenu, InkThreadPopover, InkThumbnail, InkThumbnails, InkToolButton, InkToolbar, InkToolbarButton, InkToolbarSeparator, InkUndo, InkViewport, InkZoomIn, InkZoomOut, InkZoomSelect, useAnnotations, useCommand, useDocument, useEmbedded, useForm, useHistory, useInkContext, usePage, useReadable, useRecordSelection, useRecords, useSearch, useSelection, useTool, useToolOptions, useToolStyle, useZoom };
|
|
4123
4349
|
|
|
4124
4350
|
//# sourceMappingURL=index.mjs.map
|