@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 CHANGED
@@ -192,6 +192,12 @@ Rules the component cannot enforce for you:
192
192
  - **Dimming is not a signal.** `dimmedNodeIds` must be accompanied by text that says what is dimmed and why.
193
193
  - **Localise everything.** Every visible and announced string comes from `labels`; the English defaults live in `DEFAULT_RELATIONSHIP_GRAPH_LABELS`.
194
194
 
195
+ **Map controls (`controls`, `initialView`).** The default `controls="full"` is the labelled toolbar above the map. `controls="compact"` is the map convention: an icon cluster in the map's bottom-right corner (zoom in, zoom out, fit, reset, full screen, each with a tooltip) and the zoom level beside it; drag pans, Ctrl/⌘ + wheel or a pinch zooms around the pointer, and a plain wheel keeps scrolling the page and briefly says how to zoom. The map itself takes keyboard focus: arrow keys pan (on an item they still move between items), `+` and `−` zoom, `0` resets and Escape leaves full screen. Full screen covers the page (the page behind does not scroll) and there a plain wheel zooms. `controls="none"` draws nothing; drag, pinch and Ctrl/⌘ + wheel still work. `initialView="fit"` opens with every item in view (down to the 40 % minimum) instead of the 75 % readability floor, and Reset returns to it.
196
+
197
+ ```tsx
198
+ <RelationshipGraph layout="layered" controls="compact" initialView="fit" height="clamp(24rem, 62vh, 44rem)" … />
199
+ ```
200
+
195
201
  Radial mode still shortens long labels to fit its ring, but every node carries its full label in a `<title>`, and the `viewBox` grows to contain every node, including nodes you position yourself. Use `layout="layered"` when the labels matter more than the ring.
196
202
 
197
203
  ### Conversations, save feedback and kept tabs
@@ -26,6 +26,13 @@ interface RelationshipGraphLabels {
26
26
  fit: string;
27
27
  reset: string;
28
28
  zoomLevel: (percent: number) => string;
29
+ /** Layered `controls="compact"`: the full-screen toggle, entering and leaving. */
30
+ fullscreen: string;
31
+ exitFullscreen: string;
32
+ /** Layered `controls="compact"`: how to move the map; `modifier` is "Ctrl" or "⌘" for the viewer's platform. */
33
+ navigationHint: (modifier: string) => string;
34
+ /** Layered `controls="compact"`: the map's keyboard, read when the map itself has focus. */
35
+ viewportKeyboardHint: string;
29
36
  bounded: (shown: number, omitted: number) => string;
30
37
  graphSummary: (nodes: number, edges: number) => string;
31
38
  relationship: string;
@@ -95,6 +102,21 @@ interface RelationshipGraphProps {
95
102
  showList?: boolean;
96
103
  /** Layered: CSS length for the viewport height. */
97
104
  height?: string;
105
+ /**
106
+ * Layered: the view controls. `full` (default) is the labelled toolbar above the map.
107
+ * `compact` is a map-style icon cluster in the map's corner (+, −, fit, reset, full screen,
108
+ * each with a tooltip) with the zoom level beside it; the map itself takes keyboard focus
109
+ * (arrows pan, + and − zoom, 0 resets, Escape leaves full screen), a plain wheel scrolls the
110
+ * page and says how to zoom, and Ctrl/⌘ + wheel or a pinch zooms (a plain wheel too, in full
111
+ * screen). `none` draws no controls: drag, pinch and Ctrl/⌘ + wheel still work.
112
+ */
113
+ controls?: 'full' | 'compact' | 'none';
114
+ /**
115
+ * Layered: the first view, and the one Reset returns to. `readable` (default) fits the graph
116
+ * but never below 75 %, starting at the top-left when it does not fit (ADR-0003). `fit` shows
117
+ * every item on load, down to the minimum zoom.
118
+ */
119
+ initialView?: 'readable' | 'fit';
98
120
  /** Layered: controlled roving focus. */
99
121
  focusId?: string;
100
122
  onFocusChange?: (id: string) => void;
@@ -24,6 +24,10 @@ const DEFAULT_RELATIONSHIP_GRAPH_LABELS = {
24
24
  fit: "Fit",
25
25
  reset: "Reset view",
26
26
  zoomLevel: (percent) => `Zoom ${percent}%`,
27
+ fullscreen: "Full screen",
28
+ exitFullscreen: "Exit full screen",
29
+ navigationHint: (modifier) => `Drag to move \xB7 ${modifier} + scroll to zoom`,
30
+ viewportKeyboardHint: "Arrow keys move the map, + and \u2212 zoom, 0 resets the view, Escape leaves full screen.",
27
31
  bounded: (shown, omitted) => `Showing ${shown} nodes; ${omitted} outside this bounded neighborhood.`,
28
32
  graphSummary: (nodes, edges) => `Graph with ${nodes} nodes and ${edges} relationships`,
29
33
  relationship: "Relationship",
@@ -3,6 +3,6 @@ import { ResolvedRelationshipGraphProps } from './RelationshipGraph.js';
3
3
  import '../relationship-graph-model.js';
4
4
 
5
5
  /** `RelationshipGraph layout="layered"` (ADR-0003). Internal — reached through RelationshipGraph. */
6
- declare function LayeredRelationshipGraph({ nodes, edges, selectedId, onSelect, onExpandNeighbors, onOpenDetails, maxNodes, density, highlightedNodeIds, conflictedNodeIds, highlightedEdgeIds, conflictedEdgeIds, legend, className, labels, rootId, renderNode, nodeAriaLabel, renderCluster, clusterThreshold, expandedClusterIds, onToggleCluster, dimmedNodeIds, edgeLabels, showList, height, focusId, onFocusChange, }: ResolvedRelationshipGraphProps): react.JSX.Element;
6
+ declare function LayeredRelationshipGraph({ nodes, edges, selectedId, onSelect, onExpandNeighbors, onOpenDetails, maxNodes, density, highlightedNodeIds, conflictedNodeIds, highlightedEdgeIds, conflictedEdgeIds, legend, className, labels, rootId, renderNode, nodeAriaLabel, renderCluster, clusterThreshold, expandedClusterIds, onToggleCluster, dimmedNodeIds, edgeLabels, showList, height, focusId, onFocusChange, controls, initialView: initialViewMode, }: ResolvedRelationshipGraphProps): react.JSX.Element;
7
7
 
8
8
  export { LayeredRelationshipGraph };
@@ -3,7 +3,10 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
4
4
  import { boundRelationshipGraph, layeredNeighbor, layoutLayeredGraph } from "../relationship-graph-model.js";
5
5
  import { cx } from "../cx.js";
6
+ import { Maximize2Icon, Minimize2Icon, MinusIcon, PlusIcon, RotateCcwIcon, ScanIcon } from "../icons/components.js";
7
+ import { useKbdPlatform } from "./Kbd.js";
6
8
  import { EquivalentRelationshipList } from "./RelationshipGraphList.js";
9
+ import { Tooltip } from "./Tooltip.js";
7
10
  const EMPTY_IDS = /* @__PURE__ */ new Set();
8
11
  const MIN_ZOOM = 0.4;
9
12
  const MAX_ZOOM = 1.5;
@@ -11,6 +14,7 @@ const READABLE_ZOOM = 0.75;
11
14
  const ZOOM_STEP = 1.2;
12
15
  const PAN_STEP = 64;
13
16
  const FOCUS_MARGIN = 24;
17
+ const HINT_MS = 1600;
14
18
  const NAV_KEYS = ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Home", "End"];
15
19
  const clampZoom = (zoom) => Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, zoom));
16
20
  function initialView(layout, size) {
@@ -54,9 +58,13 @@ function LayeredRelationshipGraph({
54
58
  showList = true,
55
59
  height,
56
60
  focusId,
57
- onFocusChange
61
+ onFocusChange,
62
+ controls = "full",
63
+ initialView: initialViewMode = "readable"
58
64
  }) {
59
65
  const hintId = useId();
66
+ const viewportHintId = useId();
67
+ const compact = controls === "compact";
60
68
  const bounded = useMemo(() => boundRelationshipGraph(nodes, edges, maxNodes), [nodes, edges, maxNodes]);
61
69
  const [localExpanded, setLocalExpanded] = useState(EMPTY_IDS);
62
70
  const expanded = expandedClusterIds ?? localExpanded;
@@ -70,19 +78,33 @@ function LayeredRelationshipGraph({
70
78
  [bounded, rootId, clusterThreshold, expanded, density]
71
79
  );
72
80
  const itemById = useMemo(() => new Map(layout.items.map((item) => [item.id, item])), [layout]);
81
+ const startView = useCallback(
82
+ (forLayout, forSize) => initialViewMode === "fit" ? fitView(forLayout, forSize) : initialView(forLayout, forSize),
83
+ [initialViewMode]
84
+ );
73
85
  const viewportRef = useRef(null);
74
86
  const itemRefs = useRef(/* @__PURE__ */ new Map());
87
+ const fullscreenButtonRef = useRef(null);
75
88
  const [size, setSize] = useState({ width: 0, height: 0 });
76
89
  const [view, setView] = useState({ x: 0, y: 0, zoom: 1 });
77
90
  const [animate, setAnimate] = useState(false);
78
91
  const [localFocus, setLocalFocus] = useState(void 0);
79
92
  const [hoverId, setHoverId] = useState(void 0);
93
+ const [fullscreen, setFullscreen] = useState(false);
94
+ const [wheelHint, setWheelHint] = useState(false);
80
95
  const viewRef = useRef(view);
81
96
  viewRef.current = view;
82
97
  const layoutRef = useRef(layout);
83
98
  layoutRef.current = layout;
99
+ const fullscreenRef = useRef(fullscreen);
100
+ fullscreenRef.current = fullscreen;
101
+ const compactRef = useRef(compact);
102
+ compactRef.current = compact;
84
103
  const pendingFocus = useRef(void 0);
85
104
  const initialisedFor = useRef(void 0);
105
+ const refitOnResize = useRef(false);
106
+ const hintTimer = useRef(void 0);
107
+ const modifier = useKbdPlatform() === "mac" ? "\u2318" : "Ctrl";
86
108
  const rootItemId = layout.rootId !== void 0 ? layout.itemOf[layout.rootId] : layout.items[0]?.id;
87
109
  const requestedFocus = focusId !== void 0 ? layout.itemOf[focusId] ?? focusId : localFocus;
88
110
  const focusedId = requestedFocus !== void 0 && itemById.has(requestedFocus) ? requestedFocus : rootItemId;
@@ -106,8 +128,24 @@ function LayeredRelationshipGraph({
106
128
  const key = `${layout.rootId ?? ""}`;
107
129
  if (initialisedFor.current === key) return;
108
130
  initialisedFor.current = key;
109
- setView(initialView(layout, size));
110
- }, [layout, size]);
131
+ setView(startView(layout, size));
132
+ }, [layout, size, startView]);
133
+ useEffect(() => {
134
+ if (!refitOnResize.current || size.width === 0) return;
135
+ refitOnResize.current = false;
136
+ setAnimate(false);
137
+ setView(startView(layoutRef.current, size));
138
+ }, [size, startView]);
139
+ useEffect(() => {
140
+ if (!fullscreen) return;
141
+ const root = document.documentElement;
142
+ const previous = root.style.overflow;
143
+ root.style.overflow = "hidden";
144
+ return () => {
145
+ root.style.overflow = previous;
146
+ };
147
+ }, [fullscreen]);
148
+ useEffect(() => () => clearTimeout(hintTimer.current), []);
111
149
  const moveView = useCallback((next, smooth) => {
112
150
  setAnimate(smooth);
113
151
  setView(next);
@@ -163,7 +201,14 @@ function LayeredRelationshipGraph({
163
201
  const element = viewportRef.current;
164
202
  if (!element) return;
165
203
  const onWheel = (event) => {
166
- if (!event.ctrlKey && !event.metaKey) return;
204
+ if (!event.ctrlKey && !event.metaKey && !fullscreenRef.current) {
205
+ if (compactRef.current) {
206
+ setWheelHint(true);
207
+ clearTimeout(hintTimer.current);
208
+ hintTimer.current = setTimeout(() => setWheelHint(false), HINT_MS);
209
+ }
210
+ return;
211
+ }
167
212
  event.preventDefault();
168
213
  const rect = element.getBoundingClientRect();
169
214
  const px = event.clientX - rect.left;
@@ -224,6 +269,27 @@ function LayeredRelationshipGraph({
224
269
  moveView({ zoom, x: cx0 - (cx0 - current.x) * ratio, y: cy0 - (cy0 - current.y) * ratio }, true);
225
270
  };
226
271
  const panBy = (dx, dy) => moveView({ ...viewRef.current, x: viewRef.current.x + dx, y: viewRef.current.y + dy }, true);
272
+ const resetView = () => moveView(startView(layout, size), true);
273
+ const toggleFullscreen = () => {
274
+ const next = !fullscreenRef.current;
275
+ refitOnResize.current = true;
276
+ setFullscreen(next);
277
+ requestAnimationFrame(() => (next ? viewportRef.current : fullscreenButtonRef.current)?.focus({ preventScroll: true }));
278
+ };
279
+ const onViewportKeyDown = (event) => {
280
+ if (!compact || event.altKey || event.ctrlKey || event.metaKey) return;
281
+ const onMap = event.target === event.currentTarget;
282
+ if (onMap && event.key === "ArrowLeft") panBy(PAN_STEP, 0);
283
+ else if (onMap && event.key === "ArrowRight") panBy(-PAN_STEP, 0);
284
+ else if (onMap && event.key === "ArrowUp") panBy(0, PAN_STEP);
285
+ else if (onMap && event.key === "ArrowDown") panBy(0, -PAN_STEP);
286
+ else if (event.key === "+" || event.key === "=") zoomBy(ZOOM_STEP);
287
+ else if (event.key === "-" || event.key === "_") zoomBy(1 / ZOOM_STEP);
288
+ else if (event.key === "0") resetView();
289
+ else if (event.key === "Escape" && fullscreen) toggleFullscreen();
290
+ else return;
291
+ event.preventDefault();
292
+ };
227
293
  const toggleCluster = (clusterId, focusAfter) => {
228
294
  const isExpanded = expanded.has(clusterId);
229
295
  pendingFocus.current = focusAfter;
@@ -276,144 +342,189 @@ function LayeredRelationshipGraph({
276
342
  height: layout.height,
277
343
  transform: `translate(${view.x}px, ${view.y}px) scale(${view.zoom})`
278
344
  };
279
- return /* @__PURE__ */ jsxs("section", { className: cx("uix-relationship-graph", "uix-relationship-graph--layered", density === "compact" && "uix-relationship-graph--compact", className), "aria-label": labels.graph, children: [
280
- /* @__PURE__ */ jsxs("div", { className: "uix-relationship-graph__toolbar", role: "group", "aria-label": labels.controls, children: [
281
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => zoomBy(ZOOM_STEP), disabled: view.zoom >= MAX_ZOOM, children: labels.zoomIn }),
282
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => zoomBy(1 / ZOOM_STEP), disabled: view.zoom <= MIN_ZOOM, children: labels.zoomOut }),
283
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => moveView(fitView(layout, size), true), children: labels.fit }),
284
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => moveView(initialView(layout, size), true), children: labels.reset }),
285
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => panBy(PAN_STEP, 0), "aria-label": labels.panLeft, children: labels.left }),
286
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => panBy(0, PAN_STEP), "aria-label": labels.panUp, children: labels.up }),
287
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => panBy(0, -PAN_STEP), "aria-label": labels.panDown, children: labels.down }),
288
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => panBy(-PAN_STEP, 0), "aria-label": labels.panRight, children: labels.right }),
289
- /* @__PURE__ */ jsx("span", { "aria-live": "polite", children: labels.zoomLevel(Math.round(view.zoom * 100)) })
290
- ] }),
291
- bounded.omittedNodeCount > 0 && /* @__PURE__ */ jsx("p", { className: "uix-relationship-graph__bounded", role: "status", children: labels.bounded(bounded.nodes.length, bounded.omittedNodeCount) }),
292
- /* @__PURE__ */ jsx("p", { id: hintId, className: "uix-visually-hidden", children: labels.keyboardHint }),
293
- /* @__PURE__ */ jsx(
294
- "div",
295
- {
296
- ref: viewportRef,
297
- className: "uix-relationship-graph__viewport",
298
- style: viewportStyle,
299
- onPointerDown,
300
- onPointerMove,
301
- onPointerUp: onPointerEnd,
302
- onPointerCancel: onPointerEnd,
303
- children: /* @__PURE__ */ jsxs("div", { className: "uix-relationship-graph__stage", style: stageStyle, "data-animate": animate || void 0, onTransitionEnd: () => setAnimate(false), children: [
304
- /* @__PURE__ */ jsx("svg", { className: "uix-relationship-graph__edges", width: layout.width, height: layout.height, "aria-hidden": "true", focusable: "false", children: layout.edges.map((edge) => {
305
- const active = activeIds.has(edge.source) || activeIds.has(edge.target) || edge.edgeIds.some((id) => highlightedEdgeIds.has(id));
306
- const angle = edge.arrowAngle * 180 / Math.PI;
307
- return /* @__PURE__ */ jsxs(
308
- "g",
309
- {
310
- className: "uix-relationship-graph__link",
311
- "data-kind": edge.kind,
312
- "data-active": active || void 0,
313
- "data-emphasis": edge.emphasis || void 0,
314
- "data-conflicted": edge.edgeIds.some((id) => conflictedEdgeIds.has(id)) || void 0,
315
- "data-dimmed": dimmedNodeIds.has(edge.source) && dimmedNodeIds.has(edge.target) || void 0,
316
- children: [
317
- /* @__PURE__ */ jsx("path", { d: edge.path }),
318
- edge.arrow !== "none" && /* @__PURE__ */ jsx("polygon", { points: arrowPoints, transform: `translate(${edge.arrowX} ${edge.arrowY}) rotate(${angle})` }),
319
- showLabel(edge) && /* @__PURE__ */ 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__ */ jsx("tspan", { x: edge.labelX, dy: index === 0 ? `${-(lines.length - 1) * 0.55}em` : "1.1em", children: line }, index)) })
320
- ]
321
- },
322
- edge.id
323
- );
324
- }) }),
325
- layout.columns.map((column) => /* @__PURE__ */ jsx(
326
- "div",
327
- {
328
- className: "uix-relationship-graph__column",
329
- "aria-hidden": "true",
330
- style: { left: column.x, width: layout.nodeWidth },
331
- children: labels.column(column.depth, column.count)
345
+ const zoomPercent = Math.round(view.zoom * 100);
346
+ const control = (label, icon, onClick, { disabled = false, keys, ref } = {}) => /* @__PURE__ */ jsx(Tooltip, { label, placement: "top", ...keys ? { shortcut: keys } : {}, children: /* @__PURE__ */ jsx("button", { ref, type: "button", className: "uix-relationship-graph__control", "aria-label": label, onClick, disabled, children: icon }) });
347
+ return /* @__PURE__ */ jsxs(
348
+ "section",
349
+ {
350
+ className: cx(
351
+ "uix-relationship-graph",
352
+ "uix-relationship-graph--layered",
353
+ compact && "uix-relationship-graph--map",
354
+ fullscreen && "uix-relationship-graph--fullscreen",
355
+ density === "compact" && "uix-relationship-graph--compact",
356
+ className
357
+ ),
358
+ "aria-label": labels.graph,
359
+ children: [
360
+ controls === "full" && /* @__PURE__ */ jsxs("div", { className: "uix-relationship-graph__toolbar", role: "group", "aria-label": labels.controls, children: [
361
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => zoomBy(ZOOM_STEP), disabled: view.zoom >= MAX_ZOOM, children: labels.zoomIn }),
362
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => zoomBy(1 / ZOOM_STEP), disabled: view.zoom <= MIN_ZOOM, children: labels.zoomOut }),
363
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => moveView(fitView(layout, size), true), children: labels.fit }),
364
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: resetView, children: labels.reset }),
365
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => panBy(PAN_STEP, 0), "aria-label": labels.panLeft, children: labels.left }),
366
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => panBy(0, PAN_STEP), "aria-label": labels.panUp, children: labels.up }),
367
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => panBy(0, -PAN_STEP), "aria-label": labels.panDown, children: labels.down }),
368
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => panBy(-PAN_STEP, 0), "aria-label": labels.panRight, children: labels.right }),
369
+ /* @__PURE__ */ jsx("span", { "aria-live": "polite", children: labels.zoomLevel(zoomPercent) })
370
+ ] }),
371
+ bounded.omittedNodeCount > 0 && /* @__PURE__ */ jsx("p", { className: "uix-relationship-graph__bounded", role: "status", children: labels.bounded(bounded.nodes.length, bounded.omittedNodeCount) }),
372
+ /* @__PURE__ */ jsx("p", { id: hintId, className: "uix-visually-hidden", children: labels.keyboardHint }),
373
+ compact && /* @__PURE__ */ jsx("p", { id: viewportHintId, className: "uix-visually-hidden", children: labels.viewportKeyboardHint }),
374
+ /* @__PURE__ */ jsxs(
375
+ "div",
376
+ {
377
+ ref: viewportRef,
378
+ className: "uix-relationship-graph__viewport",
379
+ style: viewportStyle,
380
+ onPointerDown,
381
+ onPointerMove,
382
+ onPointerUp: onPointerEnd,
383
+ onPointerCancel: onPointerEnd,
384
+ ...compact ? {
385
+ tabIndex: 0,
386
+ role: "group",
387
+ "aria-label": labels.graph,
388
+ "aria-describedby": viewportHintId,
389
+ onKeyDown: onViewportKeyDown
390
+ } : {},
391
+ children: [
392
+ /* @__PURE__ */ jsxs("div", { className: "uix-relationship-graph__stage", style: stageStyle, "data-animate": animate || void 0, onTransitionEnd: () => setAnimate(false), children: [
393
+ /* @__PURE__ */ jsx("svg", { className: "uix-relationship-graph__edges", width: layout.width, height: layout.height, "aria-hidden": "true", focusable: "false", children: layout.edges.map((edge) => {
394
+ const active = activeIds.has(edge.source) || activeIds.has(edge.target) || edge.edgeIds.some((id) => highlightedEdgeIds.has(id));
395
+ const angle = edge.arrowAngle * 180 / Math.PI;
396
+ return /* @__PURE__ */ jsxs(
397
+ "g",
398
+ {
399
+ className: "uix-relationship-graph__link",
400
+ "data-kind": edge.kind,
401
+ "data-active": active || void 0,
402
+ "data-emphasis": edge.emphasis || void 0,
403
+ "data-conflicted": edge.edgeIds.some((id) => conflictedEdgeIds.has(id)) || void 0,
404
+ "data-dimmed": dimmedNodeIds.has(edge.source) && dimmedNodeIds.has(edge.target) || void 0,
405
+ children: [
406
+ /* @__PURE__ */ jsx("path", { d: edge.path }),
407
+ edge.arrow !== "none" && /* @__PURE__ */ jsx("polygon", { points: arrowPoints, transform: `translate(${edge.arrowX} ${edge.arrowY}) rotate(${angle})` }),
408
+ showLabel(edge) && /* @__PURE__ */ 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__ */ jsx("tspan", { x: edge.labelX, dy: index === 0 ? `${-(lines.length - 1) * 0.55}em` : "1.1em", children: line }, index)) })
409
+ ]
410
+ },
411
+ edge.id
412
+ );
413
+ }) }),
414
+ layout.columns.map((column) => /* @__PURE__ */ jsx(
415
+ "div",
416
+ {
417
+ className: "uix-relationship-graph__column",
418
+ "aria-hidden": "true",
419
+ style: { left: column.x, width: layout.nodeWidth },
420
+ children: labels.column(column.depth, column.count)
421
+ },
422
+ column.depth
423
+ )),
424
+ /* @__PURE__ */ 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) => {
425
+ const selected = item.id === selectedItemId;
426
+ const dimmed = item.node ? dimmedNodeIds.has(item.node.id) : item.cluster.members.every((member) => dimmedNodeIds.has(member.id));
427
+ const body = item.cluster ? renderCluster?.(item.cluster) ?? /* @__PURE__ */ jsxs(Fragment, { children: [
428
+ /* @__PURE__ */ jsx("span", { className: "uix-relationship-graph__item-label", children: labels.cluster(item.cluster.members.length, item.cluster.type, item.cluster.edgeLabel) }),
429
+ /* @__PURE__ */ jsx("span", { className: "uix-relationship-graph__item-meta", children: labels.expandCluster })
430
+ ] }) : renderNode?.(item.node, { selected, dimmed }) ?? /* @__PURE__ */ jsxs(Fragment, { children: [
431
+ /* @__PURE__ */ jsx("span", { className: "uix-relationship-graph__item-label", children: item.node.label }),
432
+ (item.node.type || item.node.description) && /* @__PURE__ */ jsx("span", { className: "uix-relationship-graph__item-meta", children: [item.node.type, item.node.description].filter(Boolean).join(" \xB7 ") })
433
+ ] });
434
+ return /* @__PURE__ */ jsxs(
435
+ "button",
436
+ {
437
+ ref: (element) => {
438
+ if (element) itemRefs.current.set(item.id, element);
439
+ else itemRefs.current.delete(item.id);
440
+ },
441
+ type: "button",
442
+ className: "uix-relationship-graph__item",
443
+ "data-kind": item.kind,
444
+ "data-node-id": item.id,
445
+ "data-selected": selected || void 0,
446
+ "data-dimmed": dimmed || void 0,
447
+ "data-highlighted": item.node && highlightedNodeIds.has(item.node.id) || void 0,
448
+ "data-conflicted": item.node && conflictedNodeIds.has(item.node.id) || void 0,
449
+ "data-root": item.id === rootItemId || void 0,
450
+ style: { left: item.x, top: item.y, width: item.width, height: item.height },
451
+ tabIndex: item.id === focusedId ? 0 : -1,
452
+ "aria-label": labelFor(item),
453
+ ...item.cluster ? { "aria-expanded": false } : { "aria-pressed": selected },
454
+ onClick: () => activate(item),
455
+ onKeyDown: (event) => onItemKeyDown(event, item),
456
+ onFocus: () => {
457
+ if (item.id === focusedId) return;
458
+ setLocalFocus(item.id);
459
+ onFocusChange?.(item.id);
460
+ },
461
+ onPointerEnter: () => setHoverId(item.id),
462
+ onPointerLeave: () => setHoverId((current) => current === item.id ? void 0 : current),
463
+ children: [
464
+ body,
465
+ item.inCycle && /* @__PURE__ */ jsx("span", { className: "uix-relationship-graph__item-flag", "aria-hidden": "true", children: labels.cycle })
466
+ ]
467
+ },
468
+ item.id
469
+ );
470
+ }) }),
471
+ layout.items.filter((item) => item.expandedGroup).map((item) => {
472
+ const group = item.expandedGroup;
473
+ return /* @__PURE__ */ jsx(
474
+ "button",
475
+ {
476
+ type: "button",
477
+ className: "uix-relationship-graph__collapse",
478
+ "aria-expanded": "true",
479
+ style: { left: item.x, top: item.y - 26, width: item.width },
480
+ onClick: () => toggleCluster(group.id, group.id),
481
+ children: labels.collapseCluster(group.members.length, group.type)
482
+ },
483
+ `collapse:${group.id}`
484
+ );
485
+ })
486
+ ] }),
487
+ compact && /* @__PURE__ */ jsxs(Fragment, { children: [
488
+ /* @__PURE__ */ jsx("p", { className: "uix-relationship-graph__hint", "aria-hidden": "true", children: labels.navigationHint(modifier) }),
489
+ wheelHint && /* @__PURE__ */ jsx("p", { className: "uix-relationship-graph__toast", role: "status", children: labels.navigationHint(modifier) }),
490
+ /* @__PURE__ */ jsxs("div", { className: "uix-relationship-graph__controls", role: "group", "aria-label": labels.controls, children: [
491
+ /* @__PURE__ */ jsx("span", { className: "uix-relationship-graph__zoom-level", "aria-live": "polite", children: labels.zoomLevel(zoomPercent) }),
492
+ /* @__PURE__ */ jsxs("div", { className: "uix-relationship-graph__control-cluster", children: [
493
+ control(labels.zoomIn, /* @__PURE__ */ jsx(PlusIcon, { "aria-hidden": "true" }), () => zoomBy(ZOOM_STEP), { disabled: view.zoom >= MAX_ZOOM, keys: ["+"] }),
494
+ control(labels.zoomOut, /* @__PURE__ */ jsx(MinusIcon, { "aria-hidden": "true" }), () => zoomBy(1 / ZOOM_STEP), { disabled: view.zoom <= MIN_ZOOM, keys: ["\u2212"] }),
495
+ control(labels.fit, /* @__PURE__ */ jsx(ScanIcon, { "aria-hidden": "true" }), () => moveView(fitView(layout, size), true)),
496
+ control(labels.reset, /* @__PURE__ */ jsx(RotateCcwIcon, { "aria-hidden": "true" }), resetView, { keys: ["0"] }),
497
+ control(
498
+ fullscreen ? labels.exitFullscreen : labels.fullscreen,
499
+ fullscreen ? /* @__PURE__ */ jsx(Minimize2Icon, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Maximize2Icon, { "aria-hidden": "true" }),
500
+ toggleFullscreen,
501
+ { ref: fullscreenButtonRef, ...fullscreen ? { keys: ["Esc"] } : {} }
502
+ )
503
+ ] })
504
+ ] })
505
+ ] })
506
+ ]
507
+ }
508
+ ),
509
+ legend.length > 0 && /* @__PURE__ */ jsx("ul", { className: "uix-relationship-graph__legend", "aria-label": labels.legend, children: legend.map((entry) => /* @__PURE__ */ jsx("li", { "data-type": entry.id, children: entry.label }, entry.id)) }),
510
+ showList && /* @__PURE__ */ jsx(
511
+ EquivalentRelationshipList,
512
+ {
513
+ nodes: bounded.nodes,
514
+ edges: bounded.edges,
515
+ selectedId,
516
+ labels,
517
+ onSelect: (id) => {
518
+ const node = bounded.nodes.find((candidate) => candidate.id === id);
519
+ if (node) onSelect?.(node);
332
520
  },
333
- column.depth
334
- )),
335
- /* @__PURE__ */ 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) => {
336
- const selected = item.id === selectedItemId;
337
- const dimmed = item.node ? dimmedNodeIds.has(item.node.id) : item.cluster.members.every((member) => dimmedNodeIds.has(member.id));
338
- const body = item.cluster ? renderCluster?.(item.cluster) ?? /* @__PURE__ */ jsxs(Fragment, { children: [
339
- /* @__PURE__ */ jsx("span", { className: "uix-relationship-graph__item-label", children: labels.cluster(item.cluster.members.length, item.cluster.type, item.cluster.edgeLabel) }),
340
- /* @__PURE__ */ jsx("span", { className: "uix-relationship-graph__item-meta", children: labels.expandCluster })
341
- ] }) : renderNode?.(item.node, { selected, dimmed }) ?? /* @__PURE__ */ jsxs(Fragment, { children: [
342
- /* @__PURE__ */ jsx("span", { className: "uix-relationship-graph__item-label", children: item.node.label }),
343
- (item.node.type || item.node.description) && /* @__PURE__ */ jsx("span", { className: "uix-relationship-graph__item-meta", children: [item.node.type, item.node.description].filter(Boolean).join(" \xB7 ") })
344
- ] });
345
- return /* @__PURE__ */ jsxs(
346
- "button",
347
- {
348
- ref: (element) => {
349
- if (element) itemRefs.current.set(item.id, element);
350
- else itemRefs.current.delete(item.id);
351
- },
352
- type: "button",
353
- className: "uix-relationship-graph__item",
354
- "data-kind": item.kind,
355
- "data-node-id": item.id,
356
- "data-selected": selected || void 0,
357
- "data-dimmed": dimmed || void 0,
358
- "data-highlighted": item.node && highlightedNodeIds.has(item.node.id) || void 0,
359
- "data-conflicted": item.node && conflictedNodeIds.has(item.node.id) || void 0,
360
- "data-root": item.id === rootItemId || void 0,
361
- style: { left: item.x, top: item.y, width: item.width, height: item.height },
362
- tabIndex: item.id === focusedId ? 0 : -1,
363
- "aria-label": labelFor(item),
364
- ...item.cluster ? { "aria-expanded": false } : { "aria-pressed": selected },
365
- onClick: () => activate(item),
366
- onKeyDown: (event) => onItemKeyDown(event, item),
367
- onFocus: () => {
368
- if (item.id === focusedId) return;
369
- setLocalFocus(item.id);
370
- onFocusChange?.(item.id);
371
- },
372
- onPointerEnter: () => setHoverId(item.id),
373
- onPointerLeave: () => setHoverId((current) => current === item.id ? void 0 : current),
374
- children: [
375
- body,
376
- item.inCycle && /* @__PURE__ */ jsx("span", { className: "uix-relationship-graph__item-flag", "aria-hidden": "true", children: labels.cycle })
377
- ]
378
- },
379
- item.id
380
- );
381
- }) }),
382
- layout.items.filter((item) => item.expandedGroup).map((item) => {
383
- const group = item.expandedGroup;
384
- return /* @__PURE__ */ jsx(
385
- "button",
386
- {
387
- type: "button",
388
- className: "uix-relationship-graph__collapse",
389
- "aria-expanded": "true",
390
- style: { left: item.x, top: item.y - 26, width: item.width },
391
- onClick: () => toggleCluster(group.id, group.id),
392
- children: labels.collapseCluster(group.members.length, group.type)
393
- },
394
- `collapse:${group.id}`
395
- );
396
- })
397
- ] })
398
- }
399
- ),
400
- legend.length > 0 && /* @__PURE__ */ jsx("ul", { className: "uix-relationship-graph__legend", "aria-label": labels.legend, children: legend.map((entry) => /* @__PURE__ */ jsx("li", { "data-type": entry.id, children: entry.label }, entry.id)) }),
401
- showList && /* @__PURE__ */ jsx(
402
- EquivalentRelationshipList,
403
- {
404
- nodes: bounded.nodes,
405
- edges: bounded.edges,
406
- selectedId,
407
- labels,
408
- onSelect: (id) => {
409
- const node = bounded.nodes.find((candidate) => candidate.id === id);
410
- if (node) onSelect?.(node);
411
- },
412
- onExpandNeighbors,
413
- onOpenDetails
414
- }
415
- )
416
- ] });
521
+ onExpandNeighbors,
522
+ onOpenDetails
523
+ }
524
+ )
525
+ ]
526
+ }
527
+ );
417
528
  }
418
529
  export {
419
530
  LayeredRelationshipGraph
@@ -175,6 +175,7 @@ declare const Rows3Icon: UixIcon;
175
175
  declare const Rows4Icon: UixIcon;
176
176
  declare const SaveIcon: UixIcon;
177
177
  declare const ScaleIcon: UixIcon;
178
+ declare const ScanIcon: UixIcon;
178
179
  declare const ScanBarcodeIcon: UixIcon;
179
180
  declare const ScanSearchIcon: UixIcon;
180
181
  declare const ScrollTextIcon: UixIcon;
@@ -254,4 +255,4 @@ declare const PlayCircleIcon: UixIcon;
254
255
  declare const SmileIcon: UixIcon;
255
256
  declare const XCircleIcon: UixIcon;
256
257
 
257
- export { AccessibilityIcon, ActivityIcon, AlertCircleIcon, AlertOctagonIcon, AlertTriangleIcon, ArchiveIcon, ArrowDownIcon, ArrowLeftIcon, ArrowLeftRightIcon, ArrowRightIcon, ArrowUpDownIcon, ArrowUpIcon, ArrowUpRightIcon, AwardIcon, BadgeCheckIcon, BanknoteIcon, BarChart3Icon, BellIcon, BellOffIcon, BellRingIcon, BookOpenIcon, BookmarkIcon, BotIcon, BoxesIcon, BriefcaseIcon, Building2Icon, CalendarCheckIcon, CalendarClockIcon, CalendarDaysIcon, CalendarIcon, CalendarOffIcon, CalendarXIcon, CameraIcon, ChartColumnIcon, CheckCheckIcon, CheckCircle2Icon, CheckCircleIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronsDownUpIcon, ChevronsLeftIcon, ChevronsRightIcon, ChevronsUpDownIcon, CircleAlertIcon, CircleCheckBigIcon, CircleCheckIcon, CircleDotIcon, CircleHelpIcon, CircleIcon, CirclePauseIcon, CirclePlayIcon, CircleQuestionMarkIcon, CircleXIcon, ClipboardCheckIcon, ClipboardListIcon, ClockIcon, CloudIcon, CloudOffIcon, CoinsIcon, Columns3Icon, CommandIcon, ComponentIcon, CopyIcon, CornerUpLeftIcon, CreditCardIcon, DatabaseBackupIcon, DatabaseIcon, DoorOpenIcon, DownloadIcon, EllipsisIcon, EllipsisVerticalIcon, ExternalLinkIcon, EyeIcon, EyeOffIcon, FaceSlightlySmilingIcon, FileArchiveIcon, FileBarChartIcon, FileChartColumnIncreasingIcon, FileCheck2Icon, FileCheckCornerIcon, FileCheckIcon, FileDownIcon, FileIcon, FileImageIcon, FileInputIcon, FileQuestionIcon, FileQuestionMarkIcon, FileSearchIcon, FileSpreadsheetIcon, FileTextIcon, FileUpIcon, FilterIcon, FlagIcon, FolderCheckIcon, FolderKanbanIcon, FolderTreeIcon, FunnelIcon, GanttChartSquareIcon, GaugeIcon, GitBranchIcon, GitBranchPlusIcon, GitCompareArrowsIcon, GitMergeIcon, GitPullRequestArrowIcon, GitPullRequestClosedIcon, GlobeIcon, GraduationCapIcon, Grid3x3Icon, GripVerticalIcon, HandHeartIcon, HeartIcon, HeartPulseIcon, HexagonIcon, HistoryIcon, HourglassIcon, HouseIcon, IdCardIcon, ImageIcon, InboxIcon, InfoIcon, KeyIcon, KeyRoundIcon, LanguagesIcon, LaptopIcon, LayersIcon, LayoutDashboardIcon, LayoutTemplateIcon, LibraryIcon, LifeBuoyIcon, LightbulbIcon, Link2Icon, Link2OffIcon, LinkIcon, ListChecksIcon, ListFilterIcon, ListTreeIcon, Loader2Icon, LoaderCircleIcon, LockIcon, LogInIcon, LogOutIcon, MailIcon, MapPinIcon, Maximize2Icon, MegaphoneIcon, MenuIcon, MessageCircleIcon, MessageSquareIcon, Minimize2Icon, MinusIcon, MonitorCogIcon, MonitorIcon, MoonIcon, MoreHorizontalIcon, NewspaperIcon, NotebookPenIcon, OctagonAlertIcon, PackageIcon, PackageOpenIcon, PackageSearchIcon, PaletteIcon, PanelLeftIcon, PaperclipIcon, PartyPopperIcon, PauseCircleIcon, PauseIcon, PenLineIcon, PencilIcon, PhoneIcon, PlaneIcon, PlayCircleIcon, PlayIcon, PlugIcon, PlusIcon, PrinterIcon, QrCodeIcon, RadioIcon, RadioTowerIcon, ReceiptIcon, RefreshCwIcon, RotateCcwClockIcon, RotateCcwIcon, RouteIcon, Rows2Icon, Rows3Icon, Rows4Icon, SaveIcon, ScaleIcon, ScanBarcodeIcon, ScanSearchIcon, ScrollTextIcon, SearchIcon, SearchXIcon, SendIcon, ServerIcon, Settings2Icon, SettingsIcon, ShapesIcon, Share2Icon, ShieldAlertIcon, ShieldCheckIcon, ShieldHalfIcon, ShieldIcon, ShieldOffIcon, ShieldXIcon, ShoppingCartIcon, SignpostIcon, SirenIcon, SlidersHorizontalIcon, SmileIcon, SparklesIcon, SquareChartGanttIcon, SquareIcon, StampIcon, StarIcon, StarOffIcon, StoreIcon, SunIcon, TagIcon, TagsIcon, ThumbsDownIcon, ThumbsUpIcon, TicketIcon, TimerIcon, TimerOffIcon, Trash2Icon, TrendingDownIcon, TrendingUpIcon, TriangleAlertIcon, UnlinkIcon, UploadIcon, UserCheckIcon, UserCogIcon, UserIcon, UserPlusIcon, UserRoundIcon, UserXIcon, UsersIcon, UsersRoundIcon, WalletIcon, WaypointsIcon, WebhookIcon, WifiIcon, WifiOffIcon, WorkflowIcon, WrenchIcon, XCircleIcon, XIcon, ZapIcon };
258
+ export { AccessibilityIcon, ActivityIcon, AlertCircleIcon, AlertOctagonIcon, AlertTriangleIcon, ArchiveIcon, ArrowDownIcon, ArrowLeftIcon, ArrowLeftRightIcon, ArrowRightIcon, ArrowUpDownIcon, ArrowUpIcon, ArrowUpRightIcon, AwardIcon, BadgeCheckIcon, BanknoteIcon, BarChart3Icon, BellIcon, BellOffIcon, BellRingIcon, BookOpenIcon, BookmarkIcon, BotIcon, BoxesIcon, BriefcaseIcon, Building2Icon, CalendarCheckIcon, CalendarClockIcon, CalendarDaysIcon, CalendarIcon, CalendarOffIcon, CalendarXIcon, CameraIcon, ChartColumnIcon, CheckCheckIcon, CheckCircle2Icon, CheckCircleIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronsDownUpIcon, ChevronsLeftIcon, ChevronsRightIcon, ChevronsUpDownIcon, CircleAlertIcon, CircleCheckBigIcon, CircleCheckIcon, CircleDotIcon, CircleHelpIcon, CircleIcon, CirclePauseIcon, CirclePlayIcon, CircleQuestionMarkIcon, CircleXIcon, ClipboardCheckIcon, ClipboardListIcon, ClockIcon, CloudIcon, CloudOffIcon, CoinsIcon, Columns3Icon, CommandIcon, ComponentIcon, CopyIcon, CornerUpLeftIcon, CreditCardIcon, DatabaseBackupIcon, DatabaseIcon, DoorOpenIcon, DownloadIcon, EllipsisIcon, EllipsisVerticalIcon, ExternalLinkIcon, EyeIcon, EyeOffIcon, FaceSlightlySmilingIcon, FileArchiveIcon, FileBarChartIcon, FileChartColumnIncreasingIcon, FileCheck2Icon, FileCheckCornerIcon, FileCheckIcon, FileDownIcon, FileIcon, FileImageIcon, FileInputIcon, FileQuestionIcon, FileQuestionMarkIcon, FileSearchIcon, FileSpreadsheetIcon, FileTextIcon, FileUpIcon, FilterIcon, FlagIcon, FolderCheckIcon, FolderKanbanIcon, FolderTreeIcon, FunnelIcon, GanttChartSquareIcon, GaugeIcon, GitBranchIcon, GitBranchPlusIcon, GitCompareArrowsIcon, GitMergeIcon, GitPullRequestArrowIcon, GitPullRequestClosedIcon, GlobeIcon, GraduationCapIcon, Grid3x3Icon, GripVerticalIcon, HandHeartIcon, HeartIcon, HeartPulseIcon, HexagonIcon, HistoryIcon, HourglassIcon, HouseIcon, IdCardIcon, ImageIcon, InboxIcon, InfoIcon, KeyIcon, KeyRoundIcon, LanguagesIcon, LaptopIcon, LayersIcon, LayoutDashboardIcon, LayoutTemplateIcon, LibraryIcon, LifeBuoyIcon, LightbulbIcon, Link2Icon, Link2OffIcon, LinkIcon, ListChecksIcon, ListFilterIcon, ListTreeIcon, Loader2Icon, LoaderCircleIcon, LockIcon, LogInIcon, LogOutIcon, MailIcon, MapPinIcon, Maximize2Icon, MegaphoneIcon, MenuIcon, MessageCircleIcon, MessageSquareIcon, Minimize2Icon, MinusIcon, MonitorCogIcon, MonitorIcon, MoonIcon, MoreHorizontalIcon, NewspaperIcon, NotebookPenIcon, OctagonAlertIcon, PackageIcon, PackageOpenIcon, PackageSearchIcon, PaletteIcon, PanelLeftIcon, PaperclipIcon, PartyPopperIcon, PauseCircleIcon, PauseIcon, PenLineIcon, PencilIcon, PhoneIcon, PlaneIcon, PlayCircleIcon, PlayIcon, PlugIcon, PlusIcon, PrinterIcon, QrCodeIcon, RadioIcon, RadioTowerIcon, ReceiptIcon, RefreshCwIcon, RotateCcwClockIcon, RotateCcwIcon, RouteIcon, Rows2Icon, Rows3Icon, Rows4Icon, SaveIcon, ScaleIcon, ScanBarcodeIcon, ScanIcon, ScanSearchIcon, ScrollTextIcon, SearchIcon, SearchXIcon, SendIcon, ServerIcon, Settings2Icon, SettingsIcon, ShapesIcon, Share2Icon, ShieldAlertIcon, ShieldCheckIcon, ShieldHalfIcon, ShieldIcon, ShieldOffIcon, ShieldXIcon, ShoppingCartIcon, SignpostIcon, SirenIcon, SlidersHorizontalIcon, SmileIcon, SparklesIcon, SquareChartGanttIcon, SquareIcon, StampIcon, StarIcon, StarOffIcon, StoreIcon, SunIcon, TagIcon, TagsIcon, ThumbsDownIcon, ThumbsUpIcon, TicketIcon, TimerIcon, TimerOffIcon, Trash2Icon, TrendingDownIcon, TrendingUpIcon, TriangleAlertIcon, UnlinkIcon, UploadIcon, UserCheckIcon, UserCogIcon, UserIcon, UserPlusIcon, UserRoundIcon, UserXIcon, UsersIcon, UsersRoundIcon, WalletIcon, WaypointsIcon, WebhookIcon, WifiIcon, WifiOffIcon, WorkflowIcon, WrenchIcon, XCircleIcon, XIcon, ZapIcon };
@@ -174,6 +174,7 @@ const Rows3Icon = /* @__PURE__ */ createIcon("Rows3Icon", g.glyphRows3);
174
174
  const Rows4Icon = /* @__PURE__ */ createIcon("Rows4Icon", g.glyphRows4);
175
175
  const SaveIcon = /* @__PURE__ */ createIcon("SaveIcon", g.glyphSave);
176
176
  const ScaleIcon = /* @__PURE__ */ createIcon("ScaleIcon", g.glyphScale);
177
+ const ScanIcon = /* @__PURE__ */ createIcon("ScanIcon", g.glyphScan);
177
178
  const ScanBarcodeIcon = /* @__PURE__ */ createIcon("ScanBarcodeIcon", g.glyphScanBarcode);
178
179
  const ScanSearchIcon = /* @__PURE__ */ createIcon("ScanSearchIcon", g.glyphScanSearch);
179
180
  const ScrollTextIcon = /* @__PURE__ */ createIcon("ScrollTextIcon", g.glyphScrollText);
@@ -445,6 +446,7 @@ export {
445
446
  SaveIcon,
446
447
  ScaleIcon,
447
448
  ScanBarcodeIcon,
449
+ ScanIcon,
448
450
  ScanSearchIcon,
449
451
  ScrollTextIcon,
450
452
  SearchIcon,
@@ -175,6 +175,7 @@ declare const glyphRows3: IconNode;
175
175
  declare const glyphRows4: IconNode;
176
176
  declare const glyphSave: IconNode;
177
177
  declare const glyphScale: IconNode;
178
+ declare const glyphScan: IconNode;
178
179
  declare const glyphScanBarcode: IconNode;
179
180
  declare const glyphScanSearch: IconNode;
180
181
  declare const glyphScrollText: IconNode;
@@ -410,6 +411,7 @@ declare const ICON_GLYPHS: {
410
411
  readonly 'rows-4': IconNode;
411
412
  readonly save: IconNode;
412
413
  readonly scale: IconNode;
414
+ readonly scan: IconNode;
413
415
  readonly 'scan-barcode': IconNode;
414
416
  readonly 'scan-search': IconNode;
415
417
  readonly 'scroll-text': IconNode;
@@ -473,4 +475,4 @@ declare const ICON_GLYPHS: {
473
475
  /** A glyph name for `<Icon name>`. */
474
476
  type IconName = keyof typeof ICON_GLYPHS;
475
477
 
476
- export { ICON_GLYPHS, type IconName, glyphAccessibility, glyphActivity, glyphArchive, glyphArrowDown, glyphArrowLeft, glyphArrowLeftRight, glyphArrowRight, glyphArrowUp, glyphArrowUpDown, glyphArrowUpRight, glyphAward, glyphBadgeCheck, glyphBanknote, glyphBell, glyphBellOff, glyphBellRing, glyphBookOpen, glyphBookmark, glyphBot, glyphBoxes, glyphBriefcase, glyphBuilding2, glyphCalendar, glyphCalendarCheck, glyphCalendarClock, glyphCalendarDays, glyphCalendarOff, glyphCalendarX, glyphCamera, glyphChartColumn, glyphCheck, glyphCheckCheck, glyphChevronDown, glyphChevronLeft, glyphChevronRight, glyphChevronUp, glyphChevronsDownUp, glyphChevronsLeft, glyphChevronsRight, glyphChevronsUpDown, glyphCircle, glyphCircleAlert, glyphCircleCheck, glyphCircleCheckBig, glyphCircleDot, glyphCirclePause, glyphCirclePlay, glyphCircleQuestionMark, glyphCircleX, glyphClipboardCheck, glyphClipboardList, glyphClock, glyphCloud, glyphCloudOff, glyphCoins, glyphColumns3, glyphCommand, glyphComponent, glyphCopy, glyphCornerUpLeft, glyphCreditCard, glyphDatabase, glyphDatabaseBackup, glyphDoorOpen, glyphDownload, glyphEllipsis, glyphEllipsisVertical, glyphExternalLink, glyphEye, glyphEyeOff, glyphFaceSlightlySmiling, glyphFile, glyphFileArchive, glyphFileChartColumnIncreasing, glyphFileCheck, glyphFileCheckCorner, glyphFileDown, glyphFileImage, glyphFileInput, glyphFileQuestionMark, glyphFileSearch, glyphFileSpreadsheet, glyphFileText, glyphFileUp, glyphFlag, glyphFolderCheck, glyphFolderKanban, glyphFolderTree, glyphFunnel, glyphGauge, glyphGitBranch, glyphGitBranchPlus, glyphGitCompareArrows, glyphGitMerge, glyphGitPullRequestArrow, glyphGitPullRequestClosed, glyphGlobe, glyphGraduationCap, glyphGrid3x3, glyphGripVertical, glyphHandHeart, glyphHeart, glyphHeartPulse, glyphHexagon, glyphHourglass, glyphHouse, glyphIdCard, glyphImage, glyphInbox, glyphInfo, glyphKey, glyphKeyRound, glyphLanguages, glyphLaptop, glyphLayers, glyphLayoutDashboard, glyphLayoutTemplate, glyphLibrary, glyphLifeBuoy, glyphLightbulb, glyphLink, glyphLink2, glyphLink2Off, glyphListChecks, glyphListFilter, glyphListTree, glyphLoaderCircle, glyphLock, glyphLogIn, glyphLogOut, glyphMail, glyphMapPin, glyphMaximize2, glyphMegaphone, glyphMenu, glyphMessageCircle, glyphMessageSquare, glyphMinimize2, glyphMinus, glyphMonitor, glyphMonitorCog, glyphMoon, glyphNewspaper, glyphNotebookPen, glyphOctagonAlert, glyphPackage, glyphPackageOpen, glyphPackageSearch, glyphPalette, glyphPanelLeft, glyphPaperclip, glyphPartyPopper, glyphPause, glyphPenLine, glyphPencil, glyphPhone, glyphPlane, glyphPlay, glyphPlug, glyphPlus, glyphPrinter, glyphQrCode, glyphRadio, glyphRadioTower, glyphReceipt, glyphRefreshCw, glyphRotateCcw, glyphRotateCcwClock, glyphRoute, glyphRows2, glyphRows3, glyphRows4, glyphSave, glyphScale, glyphScanBarcode, glyphScanSearch, glyphScrollText, glyphSearch, glyphSearchX, glyphSend, glyphServer, glyphSettings, glyphSettings2, glyphShapes, glyphShare2, glyphShield, glyphShieldAlert, glyphShieldCheck, glyphShieldHalf, glyphShieldOff, glyphShieldX, glyphShoppingCart, glyphSignpost, glyphSiren, glyphSlidersHorizontal, glyphSparkles, glyphSquare, glyphSquareChartGantt, glyphStamp, glyphStar, glyphStarOff, glyphStore, glyphSun, glyphTag, glyphTags, glyphThumbsDown, glyphThumbsUp, glyphTicket, glyphTimer, glyphTimerOff, glyphTrash2, glyphTrendingDown, glyphTrendingUp, glyphTriangleAlert, glyphUnlink, glyphUpload, glyphUser, glyphUserCheck, glyphUserCog, glyphUserPlus, glyphUserRound, glyphUserX, glyphUsers, glyphUsersRound, glyphWallet, glyphWaypoints, glyphWebhook, glyphWifi, glyphWifiOff, glyphWorkflow, glyphWrench, glyphX, glyphZap };
478
+ export { ICON_GLYPHS, type IconName, glyphAccessibility, glyphActivity, glyphArchive, glyphArrowDown, glyphArrowLeft, glyphArrowLeftRight, glyphArrowRight, glyphArrowUp, glyphArrowUpDown, glyphArrowUpRight, glyphAward, glyphBadgeCheck, glyphBanknote, glyphBell, glyphBellOff, glyphBellRing, glyphBookOpen, glyphBookmark, glyphBot, glyphBoxes, glyphBriefcase, glyphBuilding2, glyphCalendar, glyphCalendarCheck, glyphCalendarClock, glyphCalendarDays, glyphCalendarOff, glyphCalendarX, glyphCamera, glyphChartColumn, glyphCheck, glyphCheckCheck, glyphChevronDown, glyphChevronLeft, glyphChevronRight, glyphChevronUp, glyphChevronsDownUp, glyphChevronsLeft, glyphChevronsRight, glyphChevronsUpDown, glyphCircle, glyphCircleAlert, glyphCircleCheck, glyphCircleCheckBig, glyphCircleDot, glyphCirclePause, glyphCirclePlay, glyphCircleQuestionMark, glyphCircleX, glyphClipboardCheck, glyphClipboardList, glyphClock, glyphCloud, glyphCloudOff, glyphCoins, glyphColumns3, glyphCommand, glyphComponent, glyphCopy, glyphCornerUpLeft, glyphCreditCard, glyphDatabase, glyphDatabaseBackup, glyphDoorOpen, glyphDownload, glyphEllipsis, glyphEllipsisVertical, glyphExternalLink, glyphEye, glyphEyeOff, glyphFaceSlightlySmiling, glyphFile, glyphFileArchive, glyphFileChartColumnIncreasing, glyphFileCheck, glyphFileCheckCorner, glyphFileDown, glyphFileImage, glyphFileInput, glyphFileQuestionMark, glyphFileSearch, glyphFileSpreadsheet, glyphFileText, glyphFileUp, glyphFlag, glyphFolderCheck, glyphFolderKanban, glyphFolderTree, glyphFunnel, glyphGauge, glyphGitBranch, glyphGitBranchPlus, glyphGitCompareArrows, glyphGitMerge, glyphGitPullRequestArrow, glyphGitPullRequestClosed, glyphGlobe, glyphGraduationCap, glyphGrid3x3, glyphGripVertical, glyphHandHeart, glyphHeart, glyphHeartPulse, glyphHexagon, glyphHourglass, glyphHouse, glyphIdCard, glyphImage, glyphInbox, glyphInfo, glyphKey, glyphKeyRound, glyphLanguages, glyphLaptop, glyphLayers, glyphLayoutDashboard, glyphLayoutTemplate, glyphLibrary, glyphLifeBuoy, glyphLightbulb, glyphLink, glyphLink2, glyphLink2Off, glyphListChecks, glyphListFilter, glyphListTree, glyphLoaderCircle, glyphLock, glyphLogIn, glyphLogOut, glyphMail, glyphMapPin, glyphMaximize2, glyphMegaphone, glyphMenu, glyphMessageCircle, glyphMessageSquare, glyphMinimize2, glyphMinus, glyphMonitor, glyphMonitorCog, glyphMoon, glyphNewspaper, glyphNotebookPen, glyphOctagonAlert, glyphPackage, glyphPackageOpen, glyphPackageSearch, glyphPalette, glyphPanelLeft, glyphPaperclip, glyphPartyPopper, glyphPause, glyphPenLine, glyphPencil, glyphPhone, glyphPlane, glyphPlay, glyphPlug, glyphPlus, glyphPrinter, glyphQrCode, glyphRadio, glyphRadioTower, glyphReceipt, glyphRefreshCw, glyphRotateCcw, glyphRotateCcwClock, glyphRoute, glyphRows2, glyphRows3, glyphRows4, glyphSave, glyphScale, glyphScan, glyphScanBarcode, glyphScanSearch, glyphScrollText, glyphSearch, glyphSearchX, glyphSend, glyphServer, glyphSettings, glyphSettings2, glyphShapes, glyphShare2, glyphShield, glyphShieldAlert, glyphShieldCheck, glyphShieldHalf, glyphShieldOff, glyphShieldX, glyphShoppingCart, glyphSignpost, glyphSiren, glyphSlidersHorizontal, glyphSparkles, glyphSquare, glyphSquareChartGantt, glyphStamp, glyphStar, glyphStarOff, glyphStore, glyphSun, glyphTag, glyphTags, glyphThumbsDown, glyphThumbsUp, glyphTicket, glyphTimer, glyphTimerOff, glyphTrash2, glyphTrendingDown, glyphTrendingUp, glyphTriangleAlert, glyphUnlink, glyphUpload, glyphUser, glyphUserCheck, glyphUserCog, glyphUserPlus, glyphUserRound, glyphUserX, glyphUsers, glyphUsersRound, glyphWallet, glyphWaypoints, glyphWebhook, glyphWifi, glyphWifiOff, glyphWorkflow, glyphWrench, glyphX, glyphZap };