@tensor_1/react 2.44.1 → 2.45.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 +6 -0
- package/dist/components/RelationshipGraph.d.ts +22 -0
- package/dist/components/RelationshipGraph.js +4 -0
- package/dist/components/RelationshipGraphLayered.d.ts +1 -1
- package/dist/components/RelationshipGraphLayered.js +252 -141
- package/dist/icons/components.d.ts +2 -1
- package/dist/icons/components.js +2 -0
- package/dist/icons/glyphs.d.ts +3 -1
- package/dist/icons/glyphs.js +3 -0
- package/dist/icons.cjs +5 -0
- package/dist/icons.d.cts +3 -1
- package/dist/icons.d.ts +1 -1
- package/dist/index.cjs +267 -145
- package/dist/index.d.cts +22 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2358,8 +2358,13 @@ var glyphCircleCheck = [["circle", { "cx": "12", "cy": "12", "r": "10" }], ["pat
|
|
|
2358
2358
|
var glyphCircleQuestionMark = [["circle", { "cx": "12", "cy": "12", "r": "10" }], ["path", { "d": "M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" }], ["path", { "d": "M12 17h.01" }]];
|
|
2359
2359
|
var glyphGripVertical = [["circle", { "cx": "9", "cy": "12", "r": "1" }], ["circle", { "cx": "9", "cy": "5", "r": "1" }], ["circle", { "cx": "9", "cy": "19", "r": "1" }], ["circle", { "cx": "15", "cy": "12", "r": "1" }], ["circle", { "cx": "15", "cy": "5", "r": "1" }], ["circle", { "cx": "15", "cy": "19", "r": "1" }]];
|
|
2360
2360
|
var glyphMaximize2 = [["path", { "d": "M15 3h6v6" }], ["path", { "d": "m21 3-7 7" }], ["path", { "d": "m3 21 7-7" }], ["path", { "d": "M9 21H3v-6" }]];
|
|
2361
|
+
var glyphMinimize2 = [["path", { "d": "m14 10 7-7" }], ["path", { "d": "M20 10h-6V4" }], ["path", { "d": "m3 21 7-7" }], ["path", { "d": "M4 14h6v6" }]];
|
|
2362
|
+
var glyphMinus = [["path", { "d": "M5 12h14" }]];
|
|
2361
2363
|
var glyphOctagonAlert = [["path", { "d": "M12 16h.01" }], ["path", { "d": "M12 8v4" }], ["path", { "d": "M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z" }]];
|
|
2362
2364
|
var glyphPencil = [["path", { "d": "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" }], ["path", { "d": "m15 5 4 4" }]];
|
|
2365
|
+
var glyphPlus = [["path", { "d": "M5 12h14" }], ["path", { "d": "M12 5v14" }]];
|
|
2366
|
+
var glyphRotateCcw = [["path", { "d": "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }], ["path", { "d": "M3 3v5h5" }]];
|
|
2367
|
+
var glyphScan = [["path", { "d": "M3 7V5a2 2 0 0 1 2-2h2" }], ["path", { "d": "M17 3h2a2 2 0 0 1 2 2v2" }], ["path", { "d": "M21 17v2a2 2 0 0 1-2 2h-2" }], ["path", { "d": "M7 21H5a2 2 0 0 1-2-2v-2" }]];
|
|
2363
2368
|
var glyphTriangleAlert = [["path", { "d": "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }], ["path", { "d": "M12 9v4" }], ["path", { "d": "M12 17h.01" }]];
|
|
2364
2369
|
var glyphX = [["path", { "d": "M18 6 6 18" }], ["path", { "d": "m6 6 12 12" }]];
|
|
2365
2370
|
|
|
@@ -2373,8 +2378,13 @@ var CircleCheckIcon = /* @__PURE__ */ createIcon("CircleCheckIcon", glyphCircleC
|
|
|
2373
2378
|
var CircleQuestionMarkIcon = /* @__PURE__ */ createIcon("CircleQuestionMarkIcon", glyphCircleQuestionMark);
|
|
2374
2379
|
var GripVerticalIcon = /* @__PURE__ */ createIcon("GripVerticalIcon", glyphGripVertical);
|
|
2375
2380
|
var Maximize2Icon = /* @__PURE__ */ createIcon("Maximize2Icon", glyphMaximize2);
|
|
2381
|
+
var Minimize2Icon = /* @__PURE__ */ createIcon("Minimize2Icon", glyphMinimize2);
|
|
2382
|
+
var MinusIcon = /* @__PURE__ */ createIcon("MinusIcon", glyphMinus);
|
|
2376
2383
|
var OctagonAlertIcon = /* @__PURE__ */ createIcon("OctagonAlertIcon", glyphOctagonAlert);
|
|
2377
2384
|
var PencilIcon = /* @__PURE__ */ createIcon("PencilIcon", glyphPencil);
|
|
2385
|
+
var PlusIcon = /* @__PURE__ */ createIcon("PlusIcon", glyphPlus);
|
|
2386
|
+
var RotateCcwIcon = /* @__PURE__ */ createIcon("RotateCcwIcon", glyphRotateCcw);
|
|
2387
|
+
var ScanIcon = /* @__PURE__ */ createIcon("ScanIcon", glyphScan);
|
|
2378
2388
|
var TriangleAlertIcon = /* @__PURE__ */ createIcon("TriangleAlertIcon", glyphTriangleAlert);
|
|
2379
2389
|
var XIcon = /* @__PURE__ */ createIcon("XIcon", glyphX);
|
|
2380
2390
|
|
|
@@ -9949,8 +9959,8 @@ var idRef = (chartId, nodeId, part) => {
|
|
|
9949
9959
|
};
|
|
9950
9960
|
var isExpandable = (node, known, lazy) => known ? known.length > 0 : lazy && (node.reportCount ?? 0) > 0;
|
|
9951
9961
|
var ChevronIcon3 = () => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("svg", { viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("path", { d: "M2 4l4 4 4-4" }) });
|
|
9952
|
-
var
|
|
9953
|
-
var
|
|
9962
|
+
var PlusIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("path", { d: "M8 3v10M3 8h10" }) });
|
|
9963
|
+
var MinusIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("path", { d: "M3 8h10" }) });
|
|
9954
9964
|
var FitIcon = () => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("path", { d: "M2 6V2h4M14 6V2h-4M2 10v4h4M14 10v4h-4" }) });
|
|
9955
9965
|
var useIsoLayoutEffect = typeof window === "undefined" ? import_react64.useEffect : import_react64.useLayoutEffect;
|
|
9956
9966
|
var Ring2 = () => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "uix-spinner uix-spinner--sm", "aria-hidden": "true" });
|
|
@@ -10495,7 +10505,7 @@ function OrgChart({
|
|
|
10495
10505
|
zoomTo(orgChartZoomStep(zoom, -1));
|
|
10496
10506
|
}
|
|
10497
10507
|
},
|
|
10498
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
10508
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(MinusIcon2, {})
|
|
10499
10509
|
}
|
|
10500
10510
|
),
|
|
10501
10511
|
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
@@ -10529,7 +10539,7 @@ function OrgChart({
|
|
|
10529
10539
|
zoomTo(orgChartZoomStep(zoom, 1));
|
|
10530
10540
|
}
|
|
10531
10541
|
},
|
|
10532
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
10542
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(PlusIcon2, {})
|
|
10533
10543
|
}
|
|
10534
10544
|
),
|
|
10535
10545
|
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => {
|
|
@@ -15527,6 +15537,7 @@ var READABLE_ZOOM = 0.75;
|
|
|
15527
15537
|
var ZOOM_STEP = 1.2;
|
|
15528
15538
|
var PAN_STEP = 64;
|
|
15529
15539
|
var FOCUS_MARGIN = 24;
|
|
15540
|
+
var HINT_MS = 1600;
|
|
15530
15541
|
var NAV_KEYS = ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Home", "End"];
|
|
15531
15542
|
var clampZoom2 = (zoom) => Math.min(MAX_ZOOM2, Math.max(MIN_ZOOM2, zoom));
|
|
15532
15543
|
function initialView(layout, size) {
|
|
@@ -15570,9 +15581,13 @@ function LayeredRelationshipGraph({
|
|
|
15570
15581
|
showList = true,
|
|
15571
15582
|
height,
|
|
15572
15583
|
focusId,
|
|
15573
|
-
onFocusChange
|
|
15584
|
+
onFocusChange,
|
|
15585
|
+
controls = "full",
|
|
15586
|
+
initialView: initialViewMode = "readable"
|
|
15574
15587
|
}) {
|
|
15575
15588
|
const hintId = (0, import_react74.useId)();
|
|
15589
|
+
const viewportHintId = (0, import_react74.useId)();
|
|
15590
|
+
const compact = controls === "compact";
|
|
15576
15591
|
const bounded = (0, import_react74.useMemo)(() => boundRelationshipGraph(nodes, edges, maxNodes), [nodes, edges, maxNodes]);
|
|
15577
15592
|
const [localExpanded, setLocalExpanded] = (0, import_react74.useState)(EMPTY_IDS2);
|
|
15578
15593
|
const expanded = expandedClusterIds ?? localExpanded;
|
|
@@ -15586,19 +15601,33 @@ function LayeredRelationshipGraph({
|
|
|
15586
15601
|
[bounded, rootId, clusterThreshold, expanded, density]
|
|
15587
15602
|
);
|
|
15588
15603
|
const itemById = (0, import_react74.useMemo)(() => new Map(layout.items.map((item) => [item.id, item])), [layout]);
|
|
15604
|
+
const startView = (0, import_react74.useCallback)(
|
|
15605
|
+
(forLayout, forSize) => initialViewMode === "fit" ? fitView(forLayout, forSize) : initialView(forLayout, forSize),
|
|
15606
|
+
[initialViewMode]
|
|
15607
|
+
);
|
|
15589
15608
|
const viewportRef = (0, import_react74.useRef)(null);
|
|
15590
15609
|
const itemRefs = (0, import_react74.useRef)(/* @__PURE__ */ new Map());
|
|
15610
|
+
const fullscreenButtonRef = (0, import_react74.useRef)(null);
|
|
15591
15611
|
const [size, setSize] = (0, import_react74.useState)({ width: 0, height: 0 });
|
|
15592
15612
|
const [view, setView] = (0, import_react74.useState)({ x: 0, y: 0, zoom: 1 });
|
|
15593
15613
|
const [animate, setAnimate] = (0, import_react74.useState)(false);
|
|
15594
15614
|
const [localFocus, setLocalFocus] = (0, import_react74.useState)(void 0);
|
|
15595
15615
|
const [hoverId, setHoverId] = (0, import_react74.useState)(void 0);
|
|
15616
|
+
const [fullscreen, setFullscreen] = (0, import_react74.useState)(false);
|
|
15617
|
+
const [wheelHint, setWheelHint] = (0, import_react74.useState)(false);
|
|
15596
15618
|
const viewRef = (0, import_react74.useRef)(view);
|
|
15597
15619
|
viewRef.current = view;
|
|
15598
15620
|
const layoutRef = (0, import_react74.useRef)(layout);
|
|
15599
15621
|
layoutRef.current = layout;
|
|
15622
|
+
const fullscreenRef = (0, import_react74.useRef)(fullscreen);
|
|
15623
|
+
fullscreenRef.current = fullscreen;
|
|
15624
|
+
const compactRef = (0, import_react74.useRef)(compact);
|
|
15625
|
+
compactRef.current = compact;
|
|
15600
15626
|
const pendingFocus = (0, import_react74.useRef)(void 0);
|
|
15601
15627
|
const initialisedFor = (0, import_react74.useRef)(void 0);
|
|
15628
|
+
const refitOnResize = (0, import_react74.useRef)(false);
|
|
15629
|
+
const hintTimer = (0, import_react74.useRef)(void 0);
|
|
15630
|
+
const modifier = useKbdPlatform() === "mac" ? "\u2318" : "Ctrl";
|
|
15602
15631
|
const rootItemId = layout.rootId !== void 0 ? layout.itemOf[layout.rootId] : layout.items[0]?.id;
|
|
15603
15632
|
const requestedFocus = focusId !== void 0 ? layout.itemOf[focusId] ?? focusId : localFocus;
|
|
15604
15633
|
const focusedId = requestedFocus !== void 0 && itemById.has(requestedFocus) ? requestedFocus : rootItemId;
|
|
@@ -15622,8 +15651,24 @@ function LayeredRelationshipGraph({
|
|
|
15622
15651
|
const key = `${layout.rootId ?? ""}`;
|
|
15623
15652
|
if (initialisedFor.current === key) return;
|
|
15624
15653
|
initialisedFor.current = key;
|
|
15625
|
-
setView(
|
|
15626
|
-
}, [layout, size]);
|
|
15654
|
+
setView(startView(layout, size));
|
|
15655
|
+
}, [layout, size, startView]);
|
|
15656
|
+
(0, import_react74.useEffect)(() => {
|
|
15657
|
+
if (!refitOnResize.current || size.width === 0) return;
|
|
15658
|
+
refitOnResize.current = false;
|
|
15659
|
+
setAnimate(false);
|
|
15660
|
+
setView(startView(layoutRef.current, size));
|
|
15661
|
+
}, [size, startView]);
|
|
15662
|
+
(0, import_react74.useEffect)(() => {
|
|
15663
|
+
if (!fullscreen) return;
|
|
15664
|
+
const root = document.documentElement;
|
|
15665
|
+
const previous = root.style.overflow;
|
|
15666
|
+
root.style.overflow = "hidden";
|
|
15667
|
+
return () => {
|
|
15668
|
+
root.style.overflow = previous;
|
|
15669
|
+
};
|
|
15670
|
+
}, [fullscreen]);
|
|
15671
|
+
(0, import_react74.useEffect)(() => () => clearTimeout(hintTimer.current), []);
|
|
15627
15672
|
const moveView = (0, import_react74.useCallback)((next, smooth) => {
|
|
15628
15673
|
setAnimate(smooth);
|
|
15629
15674
|
setView(next);
|
|
@@ -15679,7 +15724,14 @@ function LayeredRelationshipGraph({
|
|
|
15679
15724
|
const element = viewportRef.current;
|
|
15680
15725
|
if (!element) return;
|
|
15681
15726
|
const onWheel = (event) => {
|
|
15682
|
-
if (!event.ctrlKey && !event.metaKey)
|
|
15727
|
+
if (!event.ctrlKey && !event.metaKey && !fullscreenRef.current) {
|
|
15728
|
+
if (compactRef.current) {
|
|
15729
|
+
setWheelHint(true);
|
|
15730
|
+
clearTimeout(hintTimer.current);
|
|
15731
|
+
hintTimer.current = setTimeout(() => setWheelHint(false), HINT_MS);
|
|
15732
|
+
}
|
|
15733
|
+
return;
|
|
15734
|
+
}
|
|
15683
15735
|
event.preventDefault();
|
|
15684
15736
|
const rect = element.getBoundingClientRect();
|
|
15685
15737
|
const px = event.clientX - rect.left;
|
|
@@ -15740,6 +15792,27 @@ function LayeredRelationshipGraph({
|
|
|
15740
15792
|
moveView({ zoom, x: cx0 - (cx0 - current.x) * ratio, y: cy0 - (cy0 - current.y) * ratio }, true);
|
|
15741
15793
|
};
|
|
15742
15794
|
const panBy = (dx, dy) => moveView({ ...viewRef.current, x: viewRef.current.x + dx, y: viewRef.current.y + dy }, true);
|
|
15795
|
+
const resetView = () => moveView(startView(layout, size), true);
|
|
15796
|
+
const toggleFullscreen = () => {
|
|
15797
|
+
const next = !fullscreenRef.current;
|
|
15798
|
+
refitOnResize.current = true;
|
|
15799
|
+
setFullscreen(next);
|
|
15800
|
+
requestAnimationFrame(() => (next ? viewportRef.current : fullscreenButtonRef.current)?.focus({ preventScroll: true }));
|
|
15801
|
+
};
|
|
15802
|
+
const onViewportKeyDown = (event) => {
|
|
15803
|
+
if (!compact || event.altKey || event.ctrlKey || event.metaKey) return;
|
|
15804
|
+
const onMap = event.target === event.currentTarget;
|
|
15805
|
+
if (onMap && event.key === "ArrowLeft") panBy(PAN_STEP, 0);
|
|
15806
|
+
else if (onMap && event.key === "ArrowRight") panBy(-PAN_STEP, 0);
|
|
15807
|
+
else if (onMap && event.key === "ArrowUp") panBy(0, PAN_STEP);
|
|
15808
|
+
else if (onMap && event.key === "ArrowDown") panBy(0, -PAN_STEP);
|
|
15809
|
+
else if (event.key === "+" || event.key === "=") zoomBy(ZOOM_STEP);
|
|
15810
|
+
else if (event.key === "-" || event.key === "_") zoomBy(1 / ZOOM_STEP);
|
|
15811
|
+
else if (event.key === "0") resetView();
|
|
15812
|
+
else if (event.key === "Escape" && fullscreen) toggleFullscreen();
|
|
15813
|
+
else return;
|
|
15814
|
+
event.preventDefault();
|
|
15815
|
+
};
|
|
15743
15816
|
const toggleCluster = (clusterId, focusAfter) => {
|
|
15744
15817
|
const isExpanded = expanded.has(clusterId);
|
|
15745
15818
|
pendingFocus.current = focusAfter;
|
|
@@ -15792,144 +15865,189 @@ function LayeredRelationshipGraph({
|
|
|
15792
15865
|
height: layout.height,
|
|
15793
15866
|
transform: `translate(${view.x}px, ${view.y}px) scale(${view.zoom})`
|
|
15794
15867
|
};
|
|
15795
|
-
|
|
15796
|
-
|
|
15797
|
-
|
|
15798
|
-
|
|
15799
|
-
|
|
15800
|
-
|
|
15801
|
-
|
|
15802
|
-
|
|
15803
|
-
|
|
15804
|
-
|
|
15805
|
-
|
|
15806
|
-
|
|
15807
|
-
|
|
15808
|
-
|
|
15809
|
-
|
|
15810
|
-
|
|
15811
|
-
|
|
15812
|
-
|
|
15813
|
-
|
|
15814
|
-
|
|
15815
|
-
|
|
15816
|
-
|
|
15817
|
-
|
|
15818
|
-
|
|
15819
|
-
|
|
15820
|
-
|
|
15821
|
-
|
|
15822
|
-
|
|
15823
|
-
|
|
15824
|
-
|
|
15825
|
-
|
|
15826
|
-
|
|
15827
|
-
|
|
15828
|
-
|
|
15829
|
-
|
|
15830
|
-
|
|
15831
|
-
|
|
15832
|
-
|
|
15833
|
-
|
|
15834
|
-
|
|
15835
|
-
|
|
15836
|
-
|
|
15837
|
-
|
|
15838
|
-
|
|
15839
|
-
|
|
15840
|
-
|
|
15841
|
-
|
|
15842
|
-
|
|
15843
|
-
|
|
15844
|
-
|
|
15845
|
-
|
|
15846
|
-
|
|
15847
|
-
|
|
15868
|
+
const zoomPercent = Math.round(view.zoom * 100);
|
|
15869
|
+
const control = (label, icon, onClick, { disabled = false, keys, ref } = {}) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Tooltip, { label, placement: "top", ...keys ? { shortcut: keys } : {}, children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("button", { ref, type: "button", className: "uix-relationship-graph__control", "aria-label": label, onClick, disabled, children: icon }) });
|
|
15870
|
+
return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(
|
|
15871
|
+
"section",
|
|
15872
|
+
{
|
|
15873
|
+
className: cx(
|
|
15874
|
+
"uix-relationship-graph",
|
|
15875
|
+
"uix-relationship-graph--layered",
|
|
15876
|
+
compact && "uix-relationship-graph--map",
|
|
15877
|
+
fullscreen && "uix-relationship-graph--fullscreen",
|
|
15878
|
+
density === "compact" && "uix-relationship-graph--compact",
|
|
15879
|
+
className
|
|
15880
|
+
),
|
|
15881
|
+
"aria-label": labels.graph,
|
|
15882
|
+
children: [
|
|
15883
|
+
controls === "full" && /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "uix-relationship-graph__toolbar", role: "group", "aria-label": labels.controls, children: [
|
|
15884
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("button", { type: "button", onClick: () => zoomBy(ZOOM_STEP), disabled: view.zoom >= MAX_ZOOM2, children: labels.zoomIn }),
|
|
15885
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("button", { type: "button", onClick: () => zoomBy(1 / ZOOM_STEP), disabled: view.zoom <= MIN_ZOOM2, children: labels.zoomOut }),
|
|
15886
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("button", { type: "button", onClick: () => moveView(fitView(layout, size), true), children: labels.fit }),
|
|
15887
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("button", { type: "button", onClick: resetView, children: labels.reset }),
|
|
15888
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("button", { type: "button", onClick: () => panBy(PAN_STEP, 0), "aria-label": labels.panLeft, children: labels.left }),
|
|
15889
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("button", { type: "button", onClick: () => panBy(0, PAN_STEP), "aria-label": labels.panUp, children: labels.up }),
|
|
15890
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("button", { type: "button", onClick: () => panBy(0, -PAN_STEP), "aria-label": labels.panDown, children: labels.down }),
|
|
15891
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("button", { type: "button", onClick: () => panBy(-PAN_STEP, 0), "aria-label": labels.panRight, children: labels.right }),
|
|
15892
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { "aria-live": "polite", children: labels.zoomLevel(zoomPercent) })
|
|
15893
|
+
] }),
|
|
15894
|
+
bounded.omittedNodeCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("p", { className: "uix-relationship-graph__bounded", role: "status", children: labels.bounded(bounded.nodes.length, bounded.omittedNodeCount) }),
|
|
15895
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("p", { id: hintId, className: "uix-visually-hidden", children: labels.keyboardHint }),
|
|
15896
|
+
compact && /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("p", { id: viewportHintId, className: "uix-visually-hidden", children: labels.viewportKeyboardHint }),
|
|
15897
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(
|
|
15898
|
+
"div",
|
|
15899
|
+
{
|
|
15900
|
+
ref: viewportRef,
|
|
15901
|
+
className: "uix-relationship-graph__viewport",
|
|
15902
|
+
style: viewportStyle,
|
|
15903
|
+
onPointerDown,
|
|
15904
|
+
onPointerMove,
|
|
15905
|
+
onPointerUp: onPointerEnd,
|
|
15906
|
+
onPointerCancel: onPointerEnd,
|
|
15907
|
+
...compact ? {
|
|
15908
|
+
tabIndex: 0,
|
|
15909
|
+
role: "group",
|
|
15910
|
+
"aria-label": labels.graph,
|
|
15911
|
+
"aria-describedby": viewportHintId,
|
|
15912
|
+
onKeyDown: onViewportKeyDown
|
|
15913
|
+
} : {},
|
|
15914
|
+
children: [
|
|
15915
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "uix-relationship-graph__stage", style: stageStyle, "data-animate": animate || void 0, onTransitionEnd: () => setAnimate(false), children: [
|
|
15916
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("svg", { className: "uix-relationship-graph__edges", width: layout.width, height: layout.height, "aria-hidden": "true", focusable: "false", children: layout.edges.map((edge) => {
|
|
15917
|
+
const active = activeIds.has(edge.source) || activeIds.has(edge.target) || edge.edgeIds.some((id) => highlightedEdgeIds.has(id));
|
|
15918
|
+
const angle = edge.arrowAngle * 180 / Math.PI;
|
|
15919
|
+
return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(
|
|
15920
|
+
"g",
|
|
15921
|
+
{
|
|
15922
|
+
className: "uix-relationship-graph__link",
|
|
15923
|
+
"data-kind": edge.kind,
|
|
15924
|
+
"data-active": active || void 0,
|
|
15925
|
+
"data-emphasis": edge.emphasis || void 0,
|
|
15926
|
+
"data-conflicted": edge.edgeIds.some((id) => conflictedEdgeIds.has(id)) || void 0,
|
|
15927
|
+
"data-dimmed": dimmedNodeIds.has(edge.source) && dimmedNodeIds.has(edge.target) || void 0,
|
|
15928
|
+
children: [
|
|
15929
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("path", { d: edge.path }),
|
|
15930
|
+
edge.arrow !== "none" && /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("polygon", { points: arrowPoints, transform: `translate(${edge.arrowX} ${edge.arrowY}) rotate(${angle})` }),
|
|
15931
|
+
showLabel(edge) && /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("text", { x: edge.labelX, y: edge.labelY, textAnchor: "middle", dominantBaseline: "middle", children: (edge.kind === "cycle" ? [...edge.labelLines, labels.cycle] : edge.labelLines).map((line, index, lines) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("tspan", { x: edge.labelX, dy: index === 0 ? `${-(lines.length - 1) * 0.55}em` : "1.1em", children: line }, index)) })
|
|
15932
|
+
]
|
|
15933
|
+
},
|
|
15934
|
+
edge.id
|
|
15935
|
+
);
|
|
15936
|
+
}) }),
|
|
15937
|
+
layout.columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
|
|
15938
|
+
"div",
|
|
15939
|
+
{
|
|
15940
|
+
className: "uix-relationship-graph__column",
|
|
15941
|
+
"aria-hidden": "true",
|
|
15942
|
+
style: { left: column.x, width: layout.nodeWidth },
|
|
15943
|
+
children: labels.column(column.depth, column.count)
|
|
15944
|
+
},
|
|
15945
|
+
column.depth
|
|
15946
|
+
)),
|
|
15947
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { role: "group", "aria-roledescription": labels.roleDescription, "aria-label": labels.graphSummary(bounded.nodes.length, bounded.edges.length), "aria-describedby": hintId, children: layout.items.map((item) => {
|
|
15948
|
+
const selected = item.id === selectedItemId;
|
|
15949
|
+
const dimmed = item.node ? dimmedNodeIds.has(item.node.id) : item.cluster.members.every((member) => dimmedNodeIds.has(member.id));
|
|
15950
|
+
const body = item.cluster ? renderCluster?.(item.cluster) ?? /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(import_jsx_runtime100.Fragment, { children: [
|
|
15951
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "uix-relationship-graph__item-label", children: labels.cluster(item.cluster.members.length, item.cluster.type, item.cluster.edgeLabel) }),
|
|
15952
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "uix-relationship-graph__item-meta", children: labels.expandCluster })
|
|
15953
|
+
] }) : renderNode?.(item.node, { selected, dimmed }) ?? /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(import_jsx_runtime100.Fragment, { children: [
|
|
15954
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "uix-relationship-graph__item-label", children: item.node.label }),
|
|
15955
|
+
(item.node.type || item.node.description) && /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "uix-relationship-graph__item-meta", children: [item.node.type, item.node.description].filter(Boolean).join(" \xB7 ") })
|
|
15956
|
+
] });
|
|
15957
|
+
return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(
|
|
15958
|
+
"button",
|
|
15959
|
+
{
|
|
15960
|
+
ref: (element) => {
|
|
15961
|
+
if (element) itemRefs.current.set(item.id, element);
|
|
15962
|
+
else itemRefs.current.delete(item.id);
|
|
15963
|
+
},
|
|
15964
|
+
type: "button",
|
|
15965
|
+
className: "uix-relationship-graph__item",
|
|
15966
|
+
"data-kind": item.kind,
|
|
15967
|
+
"data-node-id": item.id,
|
|
15968
|
+
"data-selected": selected || void 0,
|
|
15969
|
+
"data-dimmed": dimmed || void 0,
|
|
15970
|
+
"data-highlighted": item.node && highlightedNodeIds.has(item.node.id) || void 0,
|
|
15971
|
+
"data-conflicted": item.node && conflictedNodeIds.has(item.node.id) || void 0,
|
|
15972
|
+
"data-root": item.id === rootItemId || void 0,
|
|
15973
|
+
style: { left: item.x, top: item.y, width: item.width, height: item.height },
|
|
15974
|
+
tabIndex: item.id === focusedId ? 0 : -1,
|
|
15975
|
+
"aria-label": labelFor(item),
|
|
15976
|
+
...item.cluster ? { "aria-expanded": false } : { "aria-pressed": selected },
|
|
15977
|
+
onClick: () => activate(item),
|
|
15978
|
+
onKeyDown: (event) => onItemKeyDown(event, item),
|
|
15979
|
+
onFocus: () => {
|
|
15980
|
+
if (item.id === focusedId) return;
|
|
15981
|
+
setLocalFocus(item.id);
|
|
15982
|
+
onFocusChange?.(item.id);
|
|
15983
|
+
},
|
|
15984
|
+
onPointerEnter: () => setHoverId(item.id),
|
|
15985
|
+
onPointerLeave: () => setHoverId((current) => current === item.id ? void 0 : current),
|
|
15986
|
+
children: [
|
|
15987
|
+
body,
|
|
15988
|
+
item.inCycle && /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "uix-relationship-graph__item-flag", "aria-hidden": "true", children: labels.cycle })
|
|
15989
|
+
]
|
|
15990
|
+
},
|
|
15991
|
+
item.id
|
|
15992
|
+
);
|
|
15993
|
+
}) }),
|
|
15994
|
+
layout.items.filter((item) => item.expandedGroup).map((item) => {
|
|
15995
|
+
const group = item.expandedGroup;
|
|
15996
|
+
return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
|
|
15997
|
+
"button",
|
|
15998
|
+
{
|
|
15999
|
+
type: "button",
|
|
16000
|
+
className: "uix-relationship-graph__collapse",
|
|
16001
|
+
"aria-expanded": "true",
|
|
16002
|
+
style: { left: item.x, top: item.y - 26, width: item.width },
|
|
16003
|
+
onClick: () => toggleCluster(group.id, group.id),
|
|
16004
|
+
children: labels.collapseCluster(group.members.length, group.type)
|
|
16005
|
+
},
|
|
16006
|
+
`collapse:${group.id}`
|
|
16007
|
+
);
|
|
16008
|
+
})
|
|
16009
|
+
] }),
|
|
16010
|
+
compact && /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(import_jsx_runtime100.Fragment, { children: [
|
|
16011
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("p", { className: "uix-relationship-graph__hint", "aria-hidden": "true", children: labels.navigationHint(modifier) }),
|
|
16012
|
+
wheelHint && /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("p", { className: "uix-relationship-graph__toast", role: "status", children: labels.navigationHint(modifier) }),
|
|
16013
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "uix-relationship-graph__controls", role: "group", "aria-label": labels.controls, children: [
|
|
16014
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "uix-relationship-graph__zoom-level", "aria-live": "polite", children: labels.zoomLevel(zoomPercent) }),
|
|
16015
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "uix-relationship-graph__control-cluster", children: [
|
|
16016
|
+
control(labels.zoomIn, /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(PlusIcon, { "aria-hidden": "true" }), () => zoomBy(ZOOM_STEP), { disabled: view.zoom >= MAX_ZOOM2, keys: ["+"] }),
|
|
16017
|
+
control(labels.zoomOut, /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(MinusIcon, { "aria-hidden": "true" }), () => zoomBy(1 / ZOOM_STEP), { disabled: view.zoom <= MIN_ZOOM2, keys: ["\u2212"] }),
|
|
16018
|
+
control(labels.fit, /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(ScanIcon, { "aria-hidden": "true" }), () => moveView(fitView(layout, size), true)),
|
|
16019
|
+
control(labels.reset, /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(RotateCcwIcon, { "aria-hidden": "true" }), resetView, { keys: ["0"] }),
|
|
16020
|
+
control(
|
|
16021
|
+
fullscreen ? labels.exitFullscreen : labels.fullscreen,
|
|
16022
|
+
fullscreen ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Minimize2Icon, { "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Maximize2Icon, { "aria-hidden": "true" }),
|
|
16023
|
+
toggleFullscreen,
|
|
16024
|
+
{ ref: fullscreenButtonRef, ...fullscreen ? { keys: ["Esc"] } : {} }
|
|
16025
|
+
)
|
|
16026
|
+
] })
|
|
16027
|
+
] })
|
|
16028
|
+
] })
|
|
16029
|
+
]
|
|
16030
|
+
}
|
|
16031
|
+
),
|
|
16032
|
+
legend.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("ul", { className: "uix-relationship-graph__legend", "aria-label": labels.legend, children: legend.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("li", { "data-type": entry.id, children: entry.label }, entry.id)) }),
|
|
16033
|
+
showList && /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
|
|
16034
|
+
EquivalentRelationshipList,
|
|
16035
|
+
{
|
|
16036
|
+
nodes: bounded.nodes,
|
|
16037
|
+
edges: bounded.edges,
|
|
16038
|
+
selectedId,
|
|
16039
|
+
labels,
|
|
16040
|
+
onSelect: (id) => {
|
|
16041
|
+
const node = bounded.nodes.find((candidate) => candidate.id === id);
|
|
16042
|
+
if (node) onSelect?.(node);
|
|
15848
16043
|
},
|
|
15849
|
-
|
|
15850
|
-
|
|
15851
|
-
|
|
15852
|
-
|
|
15853
|
-
|
|
15854
|
-
|
|
15855
|
-
|
|
15856
|
-
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "uix-relationship-graph__item-meta", children: labels.expandCluster })
|
|
15857
|
-
] }) : renderNode?.(item.node, { selected, dimmed }) ?? /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(import_jsx_runtime100.Fragment, { children: [
|
|
15858
|
-
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "uix-relationship-graph__item-label", children: item.node.label }),
|
|
15859
|
-
(item.node.type || item.node.description) && /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "uix-relationship-graph__item-meta", children: [item.node.type, item.node.description].filter(Boolean).join(" \xB7 ") })
|
|
15860
|
-
] });
|
|
15861
|
-
return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(
|
|
15862
|
-
"button",
|
|
15863
|
-
{
|
|
15864
|
-
ref: (element) => {
|
|
15865
|
-
if (element) itemRefs.current.set(item.id, element);
|
|
15866
|
-
else itemRefs.current.delete(item.id);
|
|
15867
|
-
},
|
|
15868
|
-
type: "button",
|
|
15869
|
-
className: "uix-relationship-graph__item",
|
|
15870
|
-
"data-kind": item.kind,
|
|
15871
|
-
"data-node-id": item.id,
|
|
15872
|
-
"data-selected": selected || void 0,
|
|
15873
|
-
"data-dimmed": dimmed || void 0,
|
|
15874
|
-
"data-highlighted": item.node && highlightedNodeIds.has(item.node.id) || void 0,
|
|
15875
|
-
"data-conflicted": item.node && conflictedNodeIds.has(item.node.id) || void 0,
|
|
15876
|
-
"data-root": item.id === rootItemId || void 0,
|
|
15877
|
-
style: { left: item.x, top: item.y, width: item.width, height: item.height },
|
|
15878
|
-
tabIndex: item.id === focusedId ? 0 : -1,
|
|
15879
|
-
"aria-label": labelFor(item),
|
|
15880
|
-
...item.cluster ? { "aria-expanded": false } : { "aria-pressed": selected },
|
|
15881
|
-
onClick: () => activate(item),
|
|
15882
|
-
onKeyDown: (event) => onItemKeyDown(event, item),
|
|
15883
|
-
onFocus: () => {
|
|
15884
|
-
if (item.id === focusedId) return;
|
|
15885
|
-
setLocalFocus(item.id);
|
|
15886
|
-
onFocusChange?.(item.id);
|
|
15887
|
-
},
|
|
15888
|
-
onPointerEnter: () => setHoverId(item.id),
|
|
15889
|
-
onPointerLeave: () => setHoverId((current) => current === item.id ? void 0 : current),
|
|
15890
|
-
children: [
|
|
15891
|
-
body,
|
|
15892
|
-
item.inCycle && /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "uix-relationship-graph__item-flag", "aria-hidden": "true", children: labels.cycle })
|
|
15893
|
-
]
|
|
15894
|
-
},
|
|
15895
|
-
item.id
|
|
15896
|
-
);
|
|
15897
|
-
}) }),
|
|
15898
|
-
layout.items.filter((item) => item.expandedGroup).map((item) => {
|
|
15899
|
-
const group = item.expandedGroup;
|
|
15900
|
-
return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
|
|
15901
|
-
"button",
|
|
15902
|
-
{
|
|
15903
|
-
type: "button",
|
|
15904
|
-
className: "uix-relationship-graph__collapse",
|
|
15905
|
-
"aria-expanded": "true",
|
|
15906
|
-
style: { left: item.x, top: item.y - 26, width: item.width },
|
|
15907
|
-
onClick: () => toggleCluster(group.id, group.id),
|
|
15908
|
-
children: labels.collapseCluster(group.members.length, group.type)
|
|
15909
|
-
},
|
|
15910
|
-
`collapse:${group.id}`
|
|
15911
|
-
);
|
|
15912
|
-
})
|
|
15913
|
-
] })
|
|
15914
|
-
}
|
|
15915
|
-
),
|
|
15916
|
-
legend.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("ul", { className: "uix-relationship-graph__legend", "aria-label": labels.legend, children: legend.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("li", { "data-type": entry.id, children: entry.label }, entry.id)) }),
|
|
15917
|
-
showList && /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
|
|
15918
|
-
EquivalentRelationshipList,
|
|
15919
|
-
{
|
|
15920
|
-
nodes: bounded.nodes,
|
|
15921
|
-
edges: bounded.edges,
|
|
15922
|
-
selectedId,
|
|
15923
|
-
labels,
|
|
15924
|
-
onSelect: (id) => {
|
|
15925
|
-
const node = bounded.nodes.find((candidate) => candidate.id === id);
|
|
15926
|
-
if (node) onSelect?.(node);
|
|
15927
|
-
},
|
|
15928
|
-
onExpandNeighbors,
|
|
15929
|
-
onOpenDetails
|
|
15930
|
-
}
|
|
15931
|
-
)
|
|
15932
|
-
] });
|
|
16044
|
+
onExpandNeighbors,
|
|
16045
|
+
onOpenDetails
|
|
16046
|
+
}
|
|
16047
|
+
)
|
|
16048
|
+
]
|
|
16049
|
+
}
|
|
16050
|
+
);
|
|
15933
16051
|
}
|
|
15934
16052
|
|
|
15935
16053
|
// src/components/RelationshipGraph.tsx
|
|
@@ -15953,6 +16071,10 @@ var DEFAULT_RELATIONSHIP_GRAPH_LABELS = {
|
|
|
15953
16071
|
fit: "Fit",
|
|
15954
16072
|
reset: "Reset view",
|
|
15955
16073
|
zoomLevel: (percent) => `Zoom ${percent}%`,
|
|
16074
|
+
fullscreen: "Full screen",
|
|
16075
|
+
exitFullscreen: "Exit full screen",
|
|
16076
|
+
navigationHint: (modifier) => `Drag to move \xB7 ${modifier} + scroll to zoom`,
|
|
16077
|
+
viewportKeyboardHint: "Arrow keys move the map, + and \u2212 zoom, 0 resets the view, Escape leaves full screen.",
|
|
15956
16078
|
bounded: (shown, omitted) => `Showing ${shown} nodes; ${omitted} outside this bounded neighborhood.`,
|
|
15957
16079
|
graphSummary: (nodes, edges) => `Graph with ${nodes} nodes and ${edges} relationships`,
|
|
15958
16080
|
relationship: "Relationship",
|
package/dist/index.d.cts
CHANGED
|
@@ -6053,6 +6053,13 @@ interface RelationshipGraphLabels {
|
|
|
6053
6053
|
fit: string;
|
|
6054
6054
|
reset: string;
|
|
6055
6055
|
zoomLevel: (percent: number) => string;
|
|
6056
|
+
/** Layered `controls="compact"`: the full-screen toggle, entering and leaving. */
|
|
6057
|
+
fullscreen: string;
|
|
6058
|
+
exitFullscreen: string;
|
|
6059
|
+
/** Layered `controls="compact"`: how to move the map; `modifier` is "Ctrl" or "⌘" for the viewer's platform. */
|
|
6060
|
+
navigationHint: (modifier: string) => string;
|
|
6061
|
+
/** Layered `controls="compact"`: the map's keyboard, read when the map itself has focus. */
|
|
6062
|
+
viewportKeyboardHint: string;
|
|
6056
6063
|
bounded: (shown: number, omitted: number) => string;
|
|
6057
6064
|
graphSummary: (nodes: number, edges: number) => string;
|
|
6058
6065
|
relationship: string;
|
|
@@ -6122,6 +6129,21 @@ interface RelationshipGraphProps {
|
|
|
6122
6129
|
showList?: boolean;
|
|
6123
6130
|
/** Layered: CSS length for the viewport height. */
|
|
6124
6131
|
height?: string;
|
|
6132
|
+
/**
|
|
6133
|
+
* Layered: the view controls. `full` (default) is the labelled toolbar above the map.
|
|
6134
|
+
* `compact` is a map-style icon cluster in the map's corner (+, −, fit, reset, full screen,
|
|
6135
|
+
* each with a tooltip) with the zoom level beside it; the map itself takes keyboard focus
|
|
6136
|
+
* (arrows pan, + and − zoom, 0 resets, Escape leaves full screen), a plain wheel scrolls the
|
|
6137
|
+
* page and says how to zoom, and Ctrl/⌘ + wheel or a pinch zooms (a plain wheel too, in full
|
|
6138
|
+
* screen). `none` draws no controls: drag, pinch and Ctrl/⌘ + wheel still work.
|
|
6139
|
+
*/
|
|
6140
|
+
controls?: 'full' | 'compact' | 'none';
|
|
6141
|
+
/**
|
|
6142
|
+
* Layered: the first view, and the one Reset returns to. `readable` (default) fits the graph
|
|
6143
|
+
* but never below 75 %, starting at the top-left when it does not fit (ADR-0003). `fit` shows
|
|
6144
|
+
* every item on load, down to the minimum zoom.
|
|
6145
|
+
*/
|
|
6146
|
+
initialView?: 'readable' | 'fit';
|
|
6125
6147
|
/** Layered: controlled roving focus. */
|
|
6126
6148
|
focusId?: string;
|
|
6127
6149
|
onFocusChange?: (id: string) => void;
|