@inkbar/react 0.11.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 +97 -15
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +284 -64
- 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(() => {
|
|
@@ -1611,7 +1624,7 @@ function InkViewport({ mode = "continuous", rotation = 0, gap = 16, buffer = 2,
|
|
|
1611
1624
|
customAnnotations: cu,
|
|
1612
1625
|
...c.formHighlight === void 0 ? {} : { formHighlight: c.formHighlight },
|
|
1613
1626
|
onSignField: (req) => setSignRequest((open) => open?.widget === req.widget ? null : req),
|
|
1614
|
-
|
|
1627
|
+
onAction: (a) => latest.current.ctx.reportAction(a),
|
|
1615
1628
|
onFormAlert: (message) => setAlert((prev) => ({
|
|
1616
1629
|
message,
|
|
1617
1630
|
shown: (prev?.shown ?? 0) + 1
|
|
@@ -1665,12 +1678,14 @@ function InkViewport({ mode = "continuous", rotation = 0, gap = 16, buffer = 2,
|
|
|
1665
1678
|
} : p))
|
|
1666
1679
|
});
|
|
1667
1680
|
engine.current = e;
|
|
1681
|
+
c.setNavigation(e.navigation);
|
|
1668
1682
|
return () => {
|
|
1669
1683
|
for (const stop of stops) stop();
|
|
1670
1684
|
e.destroy();
|
|
1671
1685
|
engine.current = null;
|
|
1672
1686
|
builtWith.current = null;
|
|
1673
1687
|
c.setViewport(null, null);
|
|
1688
|
+
c.setNavigation(null);
|
|
1674
1689
|
c.setOpenedToolIds(null);
|
|
1675
1690
|
setPages((prev) => prev.length === 0 ? prev : []);
|
|
1676
1691
|
setSignRequest(null);
|
|
@@ -2415,6 +2430,182 @@ function InkNextPage({ asChild = false, className, children, disabled, onClick,
|
|
|
2415
2430
|
});
|
|
2416
2431
|
}
|
|
2417
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
|
|
2418
2609
|
//#region src/components/InkColorMenu.tsx
|
|
2419
2610
|
function InkColorMenu({ property, label, className, children, standalone = false, group, fallback, disabled, ...rest }) {
|
|
2420
2611
|
const Wrap = standalone ? Fragment : Toolbar.Button;
|
|
@@ -3425,21 +3616,6 @@ function ThreadForm({ editingRoot, locked, deleteLabel, onSubmit, onRemove, onCl
|
|
|
3425
3616
|
});
|
|
3426
3617
|
}
|
|
3427
3618
|
//#endregion
|
|
3428
|
-
//#region src/dom-attrs.ts
|
|
3429
|
-
/**
|
|
3430
|
-
* Core's attributes (`rootAttrs()`, `triggerAttrs(id)`, `panelAttrs(id)` and the like) as React
|
|
3431
|
-
* props. Core names them as the DOM does; React wants `hidden` as a boolean and `tabindex` as
|
|
3432
|
-
* `tabIndex`. `aria-*`, `data-*`, `id`, `role`, `type` and `title` pass through as they are.
|
|
3433
|
-
* Every component that spreads core's attributes goes through this, so the mapping lives once.
|
|
3434
|
-
*/
|
|
3435
|
-
function domAttrs(attrs) {
|
|
3436
|
-
const out = {};
|
|
3437
|
-
for (const [name, value] of Object.entries(attrs)) if (name === "hidden") out.hidden = true;
|
|
3438
|
-
else if (name === "tabindex") out.tabIndex = Number(value);
|
|
3439
|
-
else out[name] = value;
|
|
3440
|
-
return out;
|
|
3441
|
-
}
|
|
3442
|
-
//#endregion
|
|
3443
3619
|
//#region src/components/sidebar-context.ts
|
|
3444
3620
|
const SidebarContextObject = createContext(null);
|
|
3445
3621
|
/** The sidebar context: throws a readable error outside `InkSidebar`. */
|
|
@@ -3483,6 +3659,16 @@ function SidebarTrigger({ panel, rail }) {
|
|
|
3483
3659
|
}
|
|
3484
3660
|
//#endregion
|
|
3485
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
|
+
}
|
|
3486
3672
|
/** Sorts the panels by where their elements sit in the DOM. */
|
|
3487
3673
|
function inDomOrder(entries) {
|
|
3488
3674
|
return [...entries].sort((a, b) => {
|
|
@@ -3556,17 +3742,30 @@ function createRegistry(controller) {
|
|
|
3556
3742
|
*
|
|
3557
3743
|
* `open` with `onOpenChange` controls it; `defaultOpen` starts it uncontrolled; with neither,
|
|
3558
3744
|
* the first panel starts open. It needs no document, so it works outside `InkRoot`. The server
|
|
3559
|
-
* renders the root, the panels (the open one shown)
|
|
3560
|
-
* 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.
|
|
3561
3752
|
*/
|
|
3562
|
-
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 }) {
|
|
3563
3754
|
const controlled = open !== void 0;
|
|
3564
3755
|
const [inner, setInner] = useState(defaultOpen);
|
|
3565
3756
|
const value = controlled ? open : inner;
|
|
3566
3757
|
const latest = useLatest({
|
|
3567
3758
|
controlled,
|
|
3568
|
-
onOpenChange
|
|
3759
|
+
onOpenChange,
|
|
3760
|
+
onWidthChange
|
|
3761
|
+
});
|
|
3762
|
+
const widths = widthOptions({
|
|
3763
|
+
defaultWidth,
|
|
3764
|
+
minWidth,
|
|
3765
|
+
maxWidth,
|
|
3766
|
+
width
|
|
3569
3767
|
});
|
|
3768
|
+
const inherited = useContext(InkContextObject)?.storage;
|
|
3570
3769
|
const idPrefix = useId();
|
|
3571
3770
|
const [{ context, mount }] = useState(() => createRegistry(createSidebarController({
|
|
3572
3771
|
layout,
|
|
@@ -3576,6 +3775,10 @@ function InkSidebar({ side = "left", layout = "rail", visible = true, open, defa
|
|
|
3576
3775
|
...value !== void 0 && { open: value },
|
|
3577
3776
|
pending: true,
|
|
3578
3777
|
idPrefix,
|
|
3778
|
+
...(storageProp ?? inherited) && { storage: storageProp ?? inherited },
|
|
3779
|
+
...name !== void 0 && { name },
|
|
3780
|
+
...widths,
|
|
3781
|
+
onWidthChange: (next) => latest.current.onWidthChange?.(next),
|
|
3579
3782
|
onOpenChange: (next) => {
|
|
3580
3783
|
if (!latest.current.controlled) setInner(next);
|
|
3581
3784
|
latest.current.onOpenChange?.(next);
|
|
@@ -3588,40 +3791,72 @@ function InkSidebar({ side = "left", layout = "rail", visible = true, open, defa
|
|
|
3588
3791
|
layout,
|
|
3589
3792
|
side,
|
|
3590
3793
|
visible,
|
|
3591
|
-
...value !== void 0 && { open: value }
|
|
3794
|
+
...value !== void 0 && { open: value },
|
|
3795
|
+
...widths
|
|
3592
3796
|
});
|
|
3593
3797
|
}, [
|
|
3594
3798
|
controller,
|
|
3595
3799
|
layout,
|
|
3596
3800
|
side,
|
|
3597
3801
|
visible,
|
|
3598
|
-
value
|
|
3802
|
+
value,
|
|
3803
|
+
defaultWidth,
|
|
3804
|
+
minWidth,
|
|
3805
|
+
maxWidth,
|
|
3806
|
+
width
|
|
3599
3807
|
]);
|
|
3600
3808
|
const root = useRef(null);
|
|
3601
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;
|
|
3602
3822
|
const rail = state.layout === "rail";
|
|
3603
3823
|
return /* @__PURE__ */ jsxs("div", {
|
|
3604
3824
|
...rest,
|
|
3605
3825
|
ref: root,
|
|
3606
3826
|
className: cx("ink-sidebar", className),
|
|
3827
|
+
style: {
|
|
3828
|
+
...style,
|
|
3829
|
+
...controller.rootStyle()
|
|
3830
|
+
},
|
|
3831
|
+
suppressHydrationWarning: true,
|
|
3607
3832
|
...domAttrs(controller.rootAttrs()),
|
|
3608
|
-
children: [
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
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
|
|
3616
3851
|
})
|
|
3617
|
-
},
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3852
|
+
}),
|
|
3853
|
+
/* @__PURE__ */ jsx("div", {
|
|
3854
|
+
ref: handle,
|
|
3855
|
+
className: "ink-sidebar-handle",
|
|
3856
|
+
suppressHydrationWarning: true,
|
|
3857
|
+
...domAttrs(handleAttrs)
|
|
3623
3858
|
})
|
|
3624
|
-
|
|
3859
|
+
]
|
|
3625
3860
|
});
|
|
3626
3861
|
}
|
|
3627
3862
|
//#endregion
|
|
@@ -3687,21 +3922,6 @@ function InkPanel({ id, label, icon, badge, children }) {
|
|
|
3687
3922
|
});
|
|
3688
3923
|
}
|
|
3689
3924
|
//#endregion
|
|
3690
|
-
//#region src/to-readable.ts
|
|
3691
|
-
/**
|
|
3692
|
-
* A core `Readable` that follows a React value, for the core controllers and painters that
|
|
3693
|
-
* components build on. The same readable for the component's life; it takes each new value in
|
|
3694
|
-
* a layout effect, so declare it before the effects that hand it to core.
|
|
3695
|
-
*/
|
|
3696
|
-
function useToReadable(value) {
|
|
3697
|
-
const [store] = useState(() => writable(value));
|
|
3698
|
-
useLayoutEffect(() => {
|
|
3699
|
-
store.set(value);
|
|
3700
|
-
}, [store, value]);
|
|
3701
|
-
const [view] = useState(() => readonly(store));
|
|
3702
|
-
return view;
|
|
3703
|
-
}
|
|
3704
|
-
//#endregion
|
|
3705
3925
|
//#region src/components/InkThumbnail.tsx
|
|
3706
3926
|
/**
|
|
3707
3927
|
* One page as a static image, with its live annotations and plugin marks: core's thumbnail
|
|
@@ -4125,6 +4345,6 @@ function InkSearchResults({ field = true, className, ...rest }) {
|
|
|
4125
4345
|
});
|
|
4126
4346
|
}
|
|
4127
4347
|
//#endregion
|
|
4128
|
-
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 };
|
|
4129
4349
|
|
|
4130
4350
|
//# sourceMappingURL=index.mjs.map
|