@pipelex/mthds-ui 0.8.0 → 0.10.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.
@@ -5,6 +5,7 @@ import {
5
5
  FOLD_MODE,
6
6
  GRAPH_DIRECTION,
7
7
  GRAPH_THEME,
8
+ GRAPH_THEME_MODE,
8
9
  MAX_VISIBLE_CONTROLLER_CHILDREN,
9
10
  applyControllers,
10
11
  applyFolds,
@@ -15,8 +16,10 @@ import {
15
16
  getPipeBlueprint,
16
17
  resolveConceptRef,
17
18
  stuffDigestFromId,
19
+ toolbarOrientation,
20
+ toolbarSide,
18
21
  validateGraphSpec
19
- } from "../../chunk-7VQUZ35P.js";
22
+ } from "../../chunk-D2ID5Z3Y.js";
20
23
  import {
21
24
  __spreadProps,
22
25
  __spreadValues
@@ -29,7 +32,7 @@ import "./stuff/StuffViewer.css";
29
32
  import "./viewer/GraphToolbar.css";
30
33
 
31
34
  // src/graph/react/viewer/GraphViewer.tsx
32
- import React8 from "react";
35
+ import React9 from "react";
33
36
  import {
34
37
  ReactFlow,
35
38
  useNodesState,
@@ -38,6 +41,51 @@ import {
38
41
  BackgroundVariant
39
42
  } from "@xyflow/react";
40
43
 
44
+ // src/graph/react/viewer/useSystemTheme.ts
45
+ import React from "react";
46
+ var PREFERS_DARK_QUERY = "(prefers-color-scheme: dark)";
47
+ function prefersDarkToTheme(prefersDark) {
48
+ return prefersDark ? GRAPH_THEME.DARK : GRAPH_THEME.LIGHT;
49
+ }
50
+ function detectSystemTheme() {
51
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
52
+ return GRAPH_THEME.DARK;
53
+ }
54
+ return prefersDarkToTheme(window.matchMedia(PREFERS_DARK_QUERY).matches);
55
+ }
56
+ function subscribeToSystemTheme(onChange) {
57
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
58
+ return () => {
59
+ };
60
+ }
61
+ const mql = window.matchMedia(PREFERS_DARK_QUERY);
62
+ if (typeof mql.addEventListener === "function") {
63
+ mql.addEventListener("change", onChange);
64
+ return () => mql.removeEventListener("change", onChange);
65
+ }
66
+ mql.addListener(onChange);
67
+ return () => mql.removeListener(onChange);
68
+ }
69
+ function systemThemeStore(injected) {
70
+ if (injected !== void 0) {
71
+ return {
72
+ subscribe: () => () => {
73
+ },
74
+ getSnapshot: () => injected,
75
+ getServerSnapshot: () => injected
76
+ };
77
+ }
78
+ return {
79
+ subscribe: subscribeToSystemTheme,
80
+ getSnapshot: detectSystemTheme,
81
+ getServerSnapshot: () => GRAPH_THEME.DARK
82
+ };
83
+ }
84
+ function useSystemTheme(injected) {
85
+ const store = React.useMemo(() => systemThemeStore(injected), [injected]);
86
+ return React.useSyncExternalStore(store.subscribe, store.getSnapshot, store.getServerSnapshot);
87
+ }
88
+
41
89
  // src/graph/react/stuff/stuffViewerUtils.ts
42
90
  function isSafeDisplayUrl(url) {
43
91
  if (!url || typeof url !== "string") return false;
@@ -155,7 +203,7 @@ function findStuffDataByDigest(graphspec, digest) {
155
203
  }
156
204
 
157
205
  // src/graph/react/stuff/StuffViewer.tsx
158
- import React from "react";
206
+ import React2 from "react";
159
207
  import DOMPurify from "dompurify";
160
208
  import { jsx, jsxs } from "react/jsx-runtime";
161
209
  var ICON_COPY = /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { d: "M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" }) });
@@ -190,15 +238,15 @@ function StuffViewer({
190
238
  onOpenExternally
191
239
  }) {
192
240
  var _a, _b;
193
- const [activeTab, setActiveTab] = React.useState("html");
194
- const [copied, setCopied] = React.useState(false);
195
- const contentRef = React.useRef(null);
196
- const httpInlineUrl = React.useMemo(() => extractInlineUrl(stuff.data), [stuff.data]);
197
- const httpExternalUrl = React.useMemo(() => extractUrl(stuff.data), [stuff.data]);
198
- const storageUri = React.useMemo(() => extractStorageUri(stuff.data), [stuff.data]);
199
- const filename = React.useMemo(() => extractFilename(stuff.data), [stuff.data]);
200
- const [resolvedStorageUrl, setResolvedStorageUrl] = React.useState(null);
201
- React.useEffect(() => {
241
+ const [activeTab, setActiveTab] = React2.useState("html");
242
+ const [copied, setCopied] = React2.useState(false);
243
+ const contentRef = React2.useRef(null);
244
+ const httpInlineUrl = React2.useMemo(() => extractInlineUrl(stuff.data), [stuff.data]);
245
+ const httpExternalUrl = React2.useMemo(() => extractUrl(stuff.data), [stuff.data]);
246
+ const storageUri = React2.useMemo(() => extractStorageUri(stuff.data), [stuff.data]);
247
+ const filename = React2.useMemo(() => extractFilename(stuff.data), [stuff.data]);
248
+ const [resolvedStorageUrl, setResolvedStorageUrl] = React2.useState(null);
249
+ React2.useEffect(() => {
202
250
  setResolvedStorageUrl(null);
203
251
  if (!storageUri || !resolveStorageUrl || httpInlineUrl) {
204
252
  return;
@@ -216,14 +264,14 @@ function StuffViewer({
216
264
  }, [storageUri, resolveStorageUrl, httpInlineUrl]);
217
265
  const inlineUrl = httpInlineUrl != null ? httpInlineUrl : resolvedStorageUrl;
218
266
  const externalUrl = httpExternalUrl != null ? httpExternalUrl : resolvedStorageUrl;
219
- const effectiveMime = React.useMemo(
267
+ const effectiveMime = React2.useMemo(
220
268
  () => resolveMimeType(stuff.data, stuff.contentType, externalUrl != null ? externalUrl : storageUri),
221
269
  [stuff.data, stuff.contentType, externalUrl, storageUri]
222
270
  );
223
271
  const isPdf = effectiveMime === "application/pdf";
224
272
  const isImage = (_a = effectiveMime == null ? void 0 : effectiveMime.startsWith("image/")) != null ? _a : false;
225
273
  const htmlTabLabel = getHtmlTabLabel(effectiveMime != null ? effectiveMime : stuff.contentType);
226
- const { jsonString, jsonError } = React.useMemo(() => {
274
+ const { jsonString, jsonError } = React2.useMemo(() => {
227
275
  if (stuff.data == null) return { jsonString: null, jsonError: null };
228
276
  try {
229
277
  return { jsonString: JSON.stringify(stuff.data, null, 2), jsonError: null };
@@ -231,7 +279,7 @@ function StuffViewer({
231
279
  return { jsonString: null, jsonError: err instanceof Error ? err.message : String(err) };
232
280
  }
233
281
  }, [stuff.data]);
234
- React.useEffect(() => {
282
+ React2.useEffect(() => {
235
283
  if (activeTab !== "html" || !contentRef.current) return;
236
284
  contentRef.current.querySelectorAll("a").forEach((link) => {
237
285
  link.setAttribute("target", "_blank");
@@ -461,7 +509,7 @@ function StuffViewer({
461
509
  }
462
510
 
463
511
  // src/graph/react/detail/DetailPanel.tsx
464
- import React2 from "react";
512
+ import React3 from "react";
465
513
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
466
514
  function DetailPanel({
467
515
  isOpen,
@@ -472,7 +520,7 @@ function DetailPanel({
472
520
  onResizeHandleMouseDown,
473
521
  closeOnEscape = true
474
522
  }) {
475
- React2.useEffect(() => {
523
+ React3.useEffect(() => {
476
524
  if (!isOpen || !closeOnEscape) return;
477
525
  const onKeyDown = (e) => {
478
526
  if (e.key === "Escape") onClose();
@@ -504,7 +552,7 @@ function DetailPanel({
504
552
  }
505
553
 
506
554
  // src/graph/react/detail/useResizable.ts
507
- import React3 from "react";
555
+ import React4 from "react";
508
556
  var MAX_WIDTH_RATIO = 0.6;
509
557
  function useResizable({
510
558
  defaultWidth,
@@ -512,11 +560,11 @@ function useResizable({
512
560
  maxWidth,
513
561
  containerRef
514
562
  }) {
515
- const [width, setWidth] = React3.useState(defaultWidth);
516
- const [isDragging, setIsDragging] = React3.useState(false);
517
- const dragRef = React3.useRef({ startX: 0, startWidth: 0, maxAllowed: maxWidth });
518
- const rafRef = React3.useRef(null);
519
- const handleMouseDown = React3.useCallback(
563
+ const [width, setWidth] = React4.useState(defaultWidth);
564
+ const [isDragging, setIsDragging] = React4.useState(false);
565
+ const dragRef = React4.useRef({ startX: 0, startWidth: 0, maxAllowed: maxWidth });
566
+ const rafRef = React4.useRef(null);
567
+ const handleMouseDown = React4.useCallback(
520
568
  (e) => {
521
569
  var _a;
522
570
  e.preventDefault();
@@ -530,7 +578,7 @@ function useResizable({
530
578
  },
531
579
  [width, maxWidth, containerRef]
532
580
  );
533
- React3.useEffect(() => {
581
+ React4.useEffect(() => {
534
582
  if (!isDragging) return;
535
583
  const onMouseMove = (e) => {
536
584
  if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
@@ -568,7 +616,7 @@ function useResizable({
568
616
  }
569
617
 
570
618
  // src/graph/react/detail/PipeDetailPanel.tsx
571
- import React5 from "react";
619
+ import React6 from "react";
572
620
 
573
621
  // src/graph/react/detail/sections/shared.tsx
574
622
  import { useState } from "react";
@@ -1160,7 +1208,7 @@ function PipeDetailPanel({ node, spec, onConceptClick }) {
1160
1208
  const badge = PIPE_TYPE_BADGES[pipeType];
1161
1209
  const status = node.status;
1162
1210
  const statusColor = (_a = STATUS_COLORS[status]) != null ? _a : "#6272a4";
1163
- const blueprint = React5.useMemo(() => {
1211
+ const blueprint = React6.useMemo(() => {
1164
1212
  var _a2, _b2;
1165
1213
  if (!node.pipe_code || !spec.pipe_registry) return void 0;
1166
1214
  const directKey = `${(_b2 = (_a2 = spec.pipeline_ref) == null ? void 0 : _a2.domain) != null ? _b2 : ""}.${node.pipe_code}`;
@@ -1331,7 +1379,7 @@ function GenericExecutionData({ data }) {
1331
1379
  }
1332
1380
 
1333
1381
  // src/graph/react/detail/ConceptDetailPanel.tsx
1334
- import React6 from "react";
1382
+ import React7 from "react";
1335
1383
  import { Fragment as Fragment10, jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
1336
1384
  function ConceptDetailPanel({
1337
1385
  concept,
@@ -1376,8 +1424,8 @@ function ConceptBody({
1376
1424
  onOpenExternally
1377
1425
  }) {
1378
1426
  const hasData = Boolean(ioData) && !isDryRun;
1379
- const [activeTab, setActiveTab] = React6.useState(hasData ? "data" : "structure");
1380
- const baseId = React6.useId();
1427
+ const [activeTab, setActiveTab] = React7.useState(hasData ? "data" : "structure");
1428
+ const baseId = React7.useId();
1381
1429
  const tabId = (tab) => `${baseId}-tab-${tab}`;
1382
1430
  const panelId = (tab) => `${baseId}-tabpanel-${tab}`;
1383
1431
  const structure = concept.json_schema ? /* @__PURE__ */ jsxs14("div", { children: [
@@ -1469,18 +1517,19 @@ function SchemaTable({
1469
1517
  }
1470
1518
  function extractType(schema) {
1471
1519
  var _a;
1472
- if (schema.type) return String(schema.type);
1520
+ if (typeof schema.type === "string") return schema.type;
1521
+ if (Array.isArray(schema.type)) return schema.type.join(" | ");
1473
1522
  if (schema.anyOf) return "union";
1474
1523
  if (schema.allOf) return "all";
1475
- if (schema.$ref) {
1476
- const ref = String(schema.$ref);
1524
+ if (typeof schema.$ref === "string") {
1525
+ const ref = schema.$ref;
1477
1526
  return (_a = ref.split("/").pop()) != null ? _a : "(unresolved type)";
1478
1527
  }
1479
1528
  return "(unresolved type)";
1480
1529
  }
1481
1530
  function toStuffViewerData(ioData) {
1482
1531
  var _a;
1483
- if ("digest" in ioData) return ioData;
1532
+ if (isStuffViewerData(ioData)) return ioData;
1484
1533
  return {
1485
1534
  digest: (_a = ioData.digest) != null ? _a : "",
1486
1535
  name: ioData.name,
@@ -1491,6 +1540,9 @@ function toStuffViewerData(ioData) {
1491
1540
  dataHtml: ioData.data_html
1492
1541
  };
1493
1542
  }
1543
+ function isStuffViewerData(ioData) {
1544
+ return "contentType" in ioData || "dataText" in ioData || "dataHtml" in ioData;
1545
+ }
1494
1546
 
1495
1547
  // src/graph/react/rfTypes.ts
1496
1548
  function toAppNodes(nodes) {
@@ -1623,7 +1675,9 @@ function hydrateLabels(nodes) {
1623
1675
  }
1624
1676
 
1625
1677
  // src/graph/react/viewer/GraphToolbar.tsx
1678
+ import { Panel } from "@xyflow/react";
1626
1679
  import { Fragment as Fragment11, jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
1680
+ var REACTFLOW_PANEL_MARGIN = 15;
1627
1681
  var ARROW_RIGHT_ICON = /* @__PURE__ */ jsxs16(
1628
1682
  "svg",
1629
1683
  {
@@ -1813,6 +1867,47 @@ var MOON_ICON = /* @__PURE__ */ jsx16(
1813
1867
  children: /* @__PURE__ */ jsx16("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" })
1814
1868
  }
1815
1869
  );
1870
+ var MONITOR_ICON = /* @__PURE__ */ jsxs16(
1871
+ "svg",
1872
+ {
1873
+ viewBox: "0 0 24 24",
1874
+ width: "14",
1875
+ height: "14",
1876
+ fill: "none",
1877
+ stroke: "currentColor",
1878
+ strokeWidth: "2",
1879
+ strokeLinecap: "round",
1880
+ strokeLinejoin: "round",
1881
+ children: [
1882
+ /* @__PURE__ */ jsx16("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2" }),
1883
+ /* @__PURE__ */ jsx16("line", { x1: "8", y1: "21", x2: "16", y2: "21" }),
1884
+ /* @__PURE__ */ jsx16("line", { x1: "12", y1: "17", x2: "12", y2: "21" })
1885
+ ]
1886
+ }
1887
+ );
1888
+ var THEME_MODE_CYCLE = [
1889
+ GRAPH_THEME_MODE.SYSTEM,
1890
+ GRAPH_THEME_MODE.LIGHT,
1891
+ GRAPH_THEME_MODE.DARK
1892
+ ];
1893
+ function nextThemeMode(current) {
1894
+ const idx = THEME_MODE_CYCLE.indexOf(current);
1895
+ return THEME_MODE_CYCLE[(idx + 1) % THEME_MODE_CYCLE.length];
1896
+ }
1897
+ function themeModeIcon(mode) {
1898
+ if (mode === GRAPH_THEME_MODE.LIGHT) return SUN_ICON;
1899
+ if (mode === GRAPH_THEME_MODE.DARK) return MOON_ICON;
1900
+ return MONITOR_ICON;
1901
+ }
1902
+ function themeModeLabel(mode) {
1903
+ const names = {
1904
+ [GRAPH_THEME_MODE.SYSTEM]: "system",
1905
+ [GRAPH_THEME_MODE.LIGHT]: "light",
1906
+ [GRAPH_THEME_MODE.DARK]: "dark"
1907
+ };
1908
+ const next = nextThemeMode(mode);
1909
+ return `Theme: ${names[mode]} \u2014 switch to ${names[next]}`;
1910
+ }
1816
1911
  function GraphToolbar({
1817
1912
  direction,
1818
1913
  onDirectionChange,
@@ -1825,19 +1920,22 @@ function GraphToolbar({
1825
1920
  onExpandAll,
1826
1921
  foldAllDisabled = false,
1827
1922
  expandAllDisabled = false,
1828
- theme,
1829
- onThemeChange,
1830
- rightOffset = 0
1923
+ themeMode,
1924
+ onThemeModeChange,
1925
+ rightOffset = 0,
1926
+ position
1831
1927
  }) {
1832
- const themeToggleEnabled = theme !== void 0 && onThemeChange !== void 0;
1833
- const themeLabel = theme === GRAPH_THEME.LIGHT ? "Switch to dark theme" : "Switch to light theme";
1928
+ const themeToggleEnabled = themeMode !== void 0 && onThemeModeChange !== void 0;
1929
+ const orientation = toolbarOrientation(position);
1930
+ const dodgesDetailPanel = toolbarSide(position) === "right" && rightOffset > 0;
1931
+ const panelStyle = dodgesDetailPanel ? { marginRight: REACTFLOW_PANEL_MARGIN + rightOffset } : void 0;
1834
1932
  const isVertical = direction === GRAPH_DIRECTION.TB || direction === GRAPH_DIRECTION.BT;
1835
1933
  const directionLabel = isVertical ? "Switch to horizontal layout" : "Switch to vertical layout";
1836
1934
  const controllersLabel = showControllers ? "Hide pipe controllers" : "Show pipe controllers \u2014 groups pipes by their controlling pipe";
1837
1935
  const foldAllSection = onFoldAll || onExpandAll;
1838
1936
  const foldAllTitle = foldAllDisabled ? "Fold all controllers (nothing to fold)" : "Fold all controllers";
1839
1937
  const expandAllTitle = expandAllDisabled ? "Expand all controllers (nothing to expand)" : "Expand all controllers";
1840
- return /* @__PURE__ */ jsxs16("div", { className: "graph-toolbar", style: { right: `${rightOffset + 8}px` }, children: [
1938
+ return /* @__PURE__ */ jsx16(Panel, { position, className: "graph-toolbar-panel", style: panelStyle, children: /* @__PURE__ */ jsxs16("div", { className: `graph-toolbar graph-toolbar--${orientation}`, children: [
1841
1939
  onFoldAll && /* @__PURE__ */ jsx16(
1842
1940
  "button",
1843
1941
  {
@@ -1926,14 +2024,14 @@ function GraphToolbar({
1926
2024
  {
1927
2025
  type: "button",
1928
2026
  className: "graph-toolbar-btn",
1929
- onClick: () => onThemeChange(theme === GRAPH_THEME.LIGHT ? GRAPH_THEME.DARK : GRAPH_THEME.LIGHT),
1930
- title: themeLabel,
1931
- "aria-label": themeLabel,
1932
- children: theme === GRAPH_THEME.LIGHT ? MOON_ICON : SUN_ICON
2027
+ onClick: () => onThemeModeChange(nextThemeMode(themeMode)),
2028
+ title: themeModeLabel(themeMode),
2029
+ "aria-label": themeModeLabel(themeMode),
2030
+ children: themeModeIcon(themeMode)
1933
2031
  }
1934
2032
  )
1935
2033
  ] })
1936
- ] });
2034
+ ] }) });
1937
2035
  }
1938
2036
 
1939
2037
  // src/graph/react/nodes/controller/ControllerGroupNode.tsx
@@ -2213,9 +2311,16 @@ function seedFoldedControllers(mode, controllerIds) {
2213
2311
  if (mode === FOLD_MODE.FOLDED) return new Set(controllerIds);
2214
2312
  return /* @__PURE__ */ new Set();
2215
2313
  }
2216
- function resolveExternalTheme(themeProp, configTheme) {
2314
+ function resolveExternalThemeMode(themeProp, configTheme) {
2217
2315
  var _a, _b;
2218
- return (_b = (_a = themeProp != null ? themeProp : configTheme) != null ? _a : DEFAULT_GRAPH_CONFIG.theme) != null ? _b : GRAPH_THEME.DARK;
2316
+ return (_b = (_a = themeProp != null ? themeProp : configTheme) != null ? _a : DEFAULT_GRAPH_CONFIG.theme) != null ? _b : GRAPH_THEME_MODE.SYSTEM;
2317
+ }
2318
+ function resolveActiveTheme(mode, systemTheme) {
2319
+ return mode === GRAPH_THEME_MODE.SYSTEM ? systemTheme : mode;
2320
+ }
2321
+ function resolveToolbarPosition(positionProp, configPosition) {
2322
+ var _a;
2323
+ return (_a = positionProp != null ? positionProp : configPosition) != null ? _a : DEFAULT_GRAPH_CONFIG.toolbarPosition;
2219
2324
  }
2220
2325
  function cloneCachedNodes(nodes) {
2221
2326
  return nodes.map((n) => __spreadProps(__spreadValues({}, n), {
@@ -2250,6 +2355,8 @@ function GraphViewer(props) {
2250
2355
  initialFoldMode,
2251
2356
  hideToolbar = false,
2252
2357
  theme: themeProp,
2358
+ toolbarPosition: toolbarPositionProp,
2359
+ systemTheme: systemThemeProp,
2253
2360
  showThemeToggle = true,
2254
2361
  onThemeChange,
2255
2362
  onNavigateToPipe,
@@ -2263,59 +2370,65 @@ function GraphViewer(props) {
2263
2370
  canEmbedPdf,
2264
2371
  onOpenExternally
2265
2372
  } = props;
2266
- const graphspec = React8.useMemo(
2373
+ const graphspec = React9.useMemo(
2267
2374
  () => graphspecProp === null ? null : validateGraphSpec(graphspecProp),
2268
2375
  [graphspecProp]
2269
2376
  );
2270
- const [direction, setDirection] = React8.useState(
2377
+ const [direction, setDirection] = React9.useState(
2271
2378
  () => {
2272
2379
  var _a2, _b2;
2273
2380
  return (_b2 = (_a2 = initialDirection != null ? initialDirection : config.direction) != null ? _a2 : DEFAULT_GRAPH_CONFIG.direction) != null ? _b2 : GRAPH_DIRECTION.TB;
2274
2381
  }
2275
2382
  );
2276
- const externalTheme = resolveExternalTheme(themeProp, config.theme);
2277
- const [theme, setTheme] = React8.useState(externalTheme);
2278
- const prevExternalThemeRef = React8.useRef(externalTheme);
2279
- React8.useEffect(() => {
2280
- if (externalTheme !== prevExternalThemeRef.current) {
2281
- prevExternalThemeRef.current = externalTheme;
2282
- setTheme(externalTheme);
2383
+ const externalMode = resolveExternalThemeMode(themeProp, config.theme);
2384
+ const [mode, setMode] = React9.useState(externalMode);
2385
+ const prevExternalModeRef = React9.useRef(externalMode);
2386
+ React9.useEffect(() => {
2387
+ if (externalMode !== prevExternalModeRef.current) {
2388
+ prevExternalModeRef.current = externalMode;
2389
+ setMode(externalMode);
2283
2390
  }
2284
- }, [externalTheme]);
2285
- const onThemeChangeRef = React8.useRef(onThemeChange);
2391
+ }, [externalMode]);
2392
+ const systemTheme = useSystemTheme(systemThemeProp);
2393
+ const resolvedTheme = resolveActiveTheme(mode, systemTheme);
2394
+ const onThemeChangeRef = React9.useRef(onThemeChange);
2286
2395
  onThemeChangeRef.current = onThemeChange;
2287
- const prevReportedThemeRef = React8.useRef(theme);
2288
- React8.useEffect(() => {
2396
+ const prevReportedRef = React9.useRef({
2397
+ mode,
2398
+ resolvedTheme
2399
+ });
2400
+ React9.useEffect(() => {
2289
2401
  var _a2;
2290
- if (theme !== prevReportedThemeRef.current) {
2291
- prevReportedThemeRef.current = theme;
2292
- (_a2 = onThemeChangeRef.current) == null ? void 0 : _a2.call(onThemeChangeRef, theme);
2402
+ const prev = prevReportedRef.current;
2403
+ if (prev.mode !== mode || prev.resolvedTheme !== resolvedTheme) {
2404
+ prevReportedRef.current = { mode, resolvedTheme };
2405
+ (_a2 = onThemeChangeRef.current) == null ? void 0 : _a2.call(onThemeChangeRef, mode, resolvedTheme);
2293
2406
  }
2294
- }, [theme]);
2407
+ }, [mode, resolvedTheme]);
2295
2408
  const effectiveFoldMode = (_b = (_a = initialFoldMode != null ? initialFoldMode : config.foldMode) != null ? _a : DEFAULT_GRAPH_CONFIG.foldMode) != null ? _b : FOLD_MODE.EXPANDED;
2296
- const [showControllers, setShowControllers] = React8.useState(() => {
2409
+ const [showControllers, setShowControllers] = React9.useState(() => {
2297
2410
  var _a2, _b2;
2298
2411
  if (effectiveFoldMode === FOLD_MODE.FOLDED) return true;
2299
2412
  return (_b2 = (_a2 = initialShowControllers != null ? initialShowControllers : config.showControllers) != null ? _a2 : DEFAULT_GRAPH_CONFIG.showControllers) != null ? _b2 : false;
2300
2413
  });
2301
- const foldModeRef = React8.useRef(effectiveFoldMode);
2414
+ const foldModeRef = React9.useRef(effectiveFoldMode);
2302
2415
  foldModeRef.current = effectiveFoldMode;
2303
- const containerRef = React8.useRef(null);
2304
- const [detailSelection, setDetailSelection] = React8.useState(null);
2305
- const [conceptOverride, setConceptOverride] = React8.useState(null);
2416
+ const containerRef = React9.useRef(null);
2417
+ const [detailSelection, setDetailSelection] = React9.useState(null);
2418
+ const [conceptOverride, setConceptOverride] = React9.useState(null);
2306
2419
  const {
2307
2420
  width: panelWidth,
2308
2421
  isDragging: isPanelDragging,
2309
2422
  handleMouseDown: onResizeMouseDown
2310
2423
  } = useResizable({ defaultWidth: 380, minWidth: 280, maxWidth: 800, containerRef });
2311
- React8.useEffect(() => {
2424
+ React9.useEffect(() => {
2312
2425
  setDetailSelection(null);
2313
2426
  setConceptOverride(null);
2314
2427
  }, [graphspec]);
2315
- React8.useEffect(() => {
2428
+ React9.useEffect(() => {
2316
2429
  const el = containerRef.current;
2317
2430
  if (!el) return;
2318
- const themePalette = getPaletteForTheme(theme);
2431
+ const themePalette = getPaletteForTheme(resolvedTheme);
2319
2432
  const overrides = config.paletteColors;
2320
2433
  const palette = overrides ? __spreadValues(__spreadValues({}, themePalette), overrides) : themePalette;
2321
2434
  for (const [cssVar, value] of Object.entries(palette)) {
@@ -2326,15 +2439,15 @@ function GraphViewer(props) {
2326
2439
  el.style.removeProperty(cssVar);
2327
2440
  }
2328
2441
  };
2329
- }, [config.paletteColors, theme]);
2442
+ }, [config.paletteColors, resolvedTheme]);
2330
2443
  const [nodes, setNodes, onNodesChange] = useNodesState([]);
2331
2444
  const [edges, setEdges, onEdgesChange] = useEdgesState([]);
2332
- const reactFlowRef = React8.useRef(null);
2333
- const initialDataRef = React8.useRef(null);
2334
- const rawGraphDataRef = React8.useRef(null);
2335
- const layoutCacheRef = React8.useRef(null);
2336
- const [expandedControllers, setExpandedControllers] = React8.useState(/* @__PURE__ */ new Set());
2337
- const toggleCollapse = React8.useCallback((controllerId) => {
2445
+ const reactFlowRef = React9.useRef(null);
2446
+ const initialDataRef = React9.useRef(null);
2447
+ const rawGraphDataRef = React9.useRef(null);
2448
+ const layoutCacheRef = React9.useRef(null);
2449
+ const [expandedControllers, setExpandedControllers] = React9.useState(/* @__PURE__ */ new Set());
2450
+ const toggleCollapse = React9.useCallback((controllerId) => {
2338
2451
  setExpandedControllers((prev) => {
2339
2452
  const next = new Set(prev);
2340
2453
  if (next.has(controllerId)) next.delete(controllerId);
@@ -2342,8 +2455,8 @@ function GraphViewer(props) {
2342
2455
  return next;
2343
2456
  });
2344
2457
  }, []);
2345
- const [foldedControllers, setFoldedControllers] = React8.useState(/* @__PURE__ */ new Set());
2346
- const toggleFold = React8.useCallback((controllerId, options) => {
2458
+ const [foldedControllers, setFoldedControllers] = React9.useState(/* @__PURE__ */ new Set());
2459
+ const toggleFold = React9.useCallback((controllerId, options) => {
2347
2460
  setFoldedControllers((prev) => {
2348
2461
  const next = new Set(prev);
2349
2462
  const shouldFold = !next.has(controllerId);
@@ -2357,37 +2470,37 @@ function GraphViewer(props) {
2357
2470
  });
2358
2471
  }, []);
2359
2472
  const edgeType = config.edgeType || EDGE_TYPE.DEFAULT;
2360
- const layoutConfig = React8.useMemo(
2473
+ const layoutConfig = React9.useMemo(
2361
2474
  () => ({ nodesep: config.nodesep, ranksep: config.ranksep }),
2362
2475
  [config.nodesep, config.ranksep]
2363
2476
  );
2364
- const showControllersRef = React8.useRef(showControllers);
2477
+ const showControllersRef = React9.useRef(showControllers);
2365
2478
  showControllersRef.current = showControllers;
2366
- const directionRef = React8.useRef(direction);
2479
+ const directionRef = React9.useRef(direction);
2367
2480
  directionRef.current = direction;
2368
- const layoutConfigRef = React8.useRef(layoutConfig);
2481
+ const layoutConfigRef = React9.useRef(layoutConfig);
2369
2482
  layoutConfigRef.current = layoutConfig;
2370
- const initialZoomRef = React8.useRef(config.initialZoom);
2483
+ const initialZoomRef = React9.useRef(config.initialZoom);
2371
2484
  initialZoomRef.current = config.initialZoom;
2372
- const panToTopRef = React8.useRef(config.panToTop);
2485
+ const panToTopRef = React9.useRef(config.panToTop);
2373
2486
  panToTopRef.current = config.panToTop;
2374
- const expandedRef = React8.useRef(expandedControllers);
2487
+ const expandedRef = React9.useRef(expandedControllers);
2375
2488
  expandedRef.current = expandedControllers;
2376
- const toggleCollapseRef = React8.useRef(toggleCollapse);
2489
+ const toggleCollapseRef = React9.useRef(toggleCollapse);
2377
2490
  toggleCollapseRef.current = toggleCollapse;
2378
- const foldedRef = React8.useRef(foldedControllers);
2491
+ const foldedRef = React9.useRef(foldedControllers);
2379
2492
  foldedRef.current = foldedControllers;
2380
- const toggleFoldRef = React8.useRef(toggleFold);
2493
+ const toggleFoldRef = React9.useRef(toggleFold);
2381
2494
  toggleFoldRef.current = toggleFold;
2382
- const isFirstFoldEffect = React8.useRef(true);
2383
- const prevFoldSizeRef = React8.useRef(0);
2384
- const skipNextFoldEffectRef = React8.useRef(false);
2385
- const statusMapRef = React8.useRef(statusMap);
2495
+ const isFirstFoldEffect = React9.useRef(true);
2496
+ const prevFoldSizeRef = React9.useRef(0);
2497
+ const skipNextFoldEffectRef = React9.useRef(false);
2498
+ const statusMapRef = React9.useRef(statusMap);
2386
2499
  statusMapRef.current = statusMap;
2387
- React8.useEffect(() => {
2500
+ React9.useEffect(() => {
2388
2501
  if (!initialDataRef.current) return;
2389
2502
  let cancelled = false;
2390
- (async () => {
2503
+ void (async () => {
2391
2504
  try {
2392
2505
  const data = initialDataRef.current;
2393
2506
  if (!data) return;
@@ -2425,7 +2538,7 @@ function GraphViewer(props) {
2425
2538
  setEdges(toAppEdges(withControllers.edges));
2426
2539
  setTimeout(() => {
2427
2540
  if (!cancelled && reactFlowRef.current) {
2428
- reactFlowRef.current.fitView({ padding: 0.1 });
2541
+ void reactFlowRef.current.fitView({ padding: 0.1 });
2429
2542
  }
2430
2543
  }, 50);
2431
2544
  } catch (err) {
@@ -2436,7 +2549,7 @@ function GraphViewer(props) {
2436
2549
  cancelled = true;
2437
2550
  };
2438
2551
  }, [direction, layoutConfig]);
2439
- React8.useEffect(() => {
2552
+ React9.useEffect(() => {
2440
2553
  if (!layoutCacheRef.current || !initialDataRef.current) return;
2441
2554
  const cachedNodes = cloneCachedNodes(layoutCacheRef.current.nodes);
2442
2555
  const cachedEdges = layoutCacheRef.current.edges;
@@ -2456,7 +2569,7 @@ function GraphViewer(props) {
2456
2569
  );
2457
2570
  setEdges(toAppEdges(withControllers.edges));
2458
2571
  }, [showControllers, expandedControllers, toggleCollapse, toggleFold]);
2459
- React8.useEffect(() => {
2572
+ React9.useEffect(() => {
2460
2573
  if (!graphspec) {
2461
2574
  initialDataRef.current = null;
2462
2575
  rawGraphDataRef.current = null;
@@ -2497,7 +2610,7 @@ function GraphViewer(props) {
2497
2610
  _analysis: folded.analysis,
2498
2611
  _graphspec: graphspec
2499
2612
  };
2500
- (async () => {
2613
+ void (async () => {
2501
2614
  try {
2502
2615
  const currentDirection = directionRef.current;
2503
2616
  const currentLayoutConfig = layoutConfigRef.current;
@@ -2542,13 +2655,13 @@ function GraphViewer(props) {
2542
2655
  setEdges(toAppEdges(withControllers.edges));
2543
2656
  setTimeout(() => {
2544
2657
  if (!cancelled && reactFlowRef.current) {
2545
- reactFlowRef.current.fitView({ padding: 0.1 });
2658
+ void reactFlowRef.current.fitView({ padding: 0.1 });
2546
2659
  if (initialZoomRef.current !== void 0 && initialZoomRef.current !== null) {
2547
- reactFlowRef.current.zoomTo(initialZoomRef.current);
2660
+ void reactFlowRef.current.zoomTo(initialZoomRef.current);
2548
2661
  }
2549
2662
  if (panToTopRef.current) {
2550
2663
  const vp = reactFlowRef.current.getViewport();
2551
- reactFlowRef.current.setViewport({ x: vp.x, y: 20, zoom: vp.zoom });
2664
+ void reactFlowRef.current.setViewport({ x: vp.x, y: 20, zoom: vp.zoom });
2552
2665
  }
2553
2666
  }
2554
2667
  }, 100);
@@ -2560,7 +2673,7 @@ function GraphViewer(props) {
2560
2673
  cancelled = true;
2561
2674
  };
2562
2675
  }, [graphspec, edgeType]);
2563
- React8.useEffect(() => {
2676
+ React9.useEffect(() => {
2564
2677
  if (isFirstFoldEffect.current) {
2565
2678
  isFirstFoldEffect.current = false;
2566
2679
  prevFoldSizeRef.current = foldedControllers.size;
@@ -2593,7 +2706,7 @@ function GraphViewer(props) {
2593
2706
  _analysis: folded.analysis,
2594
2707
  _graphspec: currentGraphspec
2595
2708
  };
2596
- (async () => {
2709
+ void (async () => {
2597
2710
  try {
2598
2711
  const layouted = await getLayoutedElements(
2599
2712
  folded.nodes,
@@ -2629,7 +2742,7 @@ function GraphViewer(props) {
2629
2742
  setEdges(toAppEdges(withControllers.edges));
2630
2743
  setTimeout(() => {
2631
2744
  if (!cancelled && reactFlowRef.current) {
2632
- reactFlowRef.current.fitView({ padding: 0.1 });
2745
+ void reactFlowRef.current.fitView({ padding: 0.1 });
2633
2746
  }
2634
2747
  }, 50);
2635
2748
  } catch (err) {
@@ -2640,7 +2753,7 @@ function GraphViewer(props) {
2640
2753
  cancelled = true;
2641
2754
  };
2642
2755
  }, [foldedControllers, toggleFold]);
2643
- React8.useEffect(() => {
2756
+ React9.useEffect(() => {
2644
2757
  if (!layoutCacheRef.current || !initialDataRef.current) return;
2645
2758
  const cachedNodes = cloneCachedNodes(layoutCacheRef.current.nodes);
2646
2759
  const cachedEdges = layoutCacheRef.current.edges;
@@ -2658,7 +2771,7 @@ function GraphViewer(props) {
2658
2771
  setNodes(applyStatusOverrides(toAppNodes(hydrateLabels(withControllers.nodes)), statusMap));
2659
2772
  setEdges(toAppEdges(withControllers.edges));
2660
2773
  }, [statusMap]);
2661
- const onNodeClick = React8.useCallback(
2774
+ const onNodeClick = React9.useCallback(
2662
2775
  (event, node) => {
2663
2776
  var _a2;
2664
2777
  const nodeData = node.data;
@@ -2700,7 +2813,7 @@ function GraphViewer(props) {
2700
2813
  conceptOverride
2701
2814
  ]
2702
2815
  );
2703
- const onInit = React8.useCallback(
2816
+ const onInit = React9.useCallback(
2704
2817
  (reactFlowInstance) => {
2705
2818
  reactFlowRef.current = reactFlowInstance;
2706
2819
  if (onReactFlowInit) {
@@ -2709,12 +2822,12 @@ function GraphViewer(props) {
2709
2822
  },
2710
2823
  [onReactFlowInit]
2711
2824
  );
2712
- const handlePaneClick = React8.useCallback(() => {
2825
+ const handlePaneClick = React9.useCallback(() => {
2713
2826
  setDetailSelection(null);
2714
2827
  setConceptOverride(null);
2715
2828
  onPaneClick == null ? void 0 : onPaneClick();
2716
2829
  }, [onPaneClick]);
2717
- const handleConceptClick = React8.useCallback(
2830
+ const handleConceptClick = React9.useCallback(
2718
2831
  (conceptCode) => {
2719
2832
  if (!graphspec) return;
2720
2833
  const info = resolveConceptRef(graphspec, conceptCode);
@@ -2724,9 +2837,13 @@ function GraphViewer(props) {
2724
2837
  );
2725
2838
  const selectedSpecNode = (detailSelection == null ? void 0 : detailSelection.kind) === "pipe" && graphspec ? graphspec.nodes.find((n) => n.pipe_code === detailSelection.nodeData.pipeCode) : void 0;
2726
2839
  const detailOpen = detailSelection !== null || conceptOverride !== null;
2840
+ const effectiveToolbarPosition = resolveToolbarPosition(
2841
+ toolbarPositionProp,
2842
+ config.toolbarPosition
2843
+ );
2727
2844
  const rawAnalysis = (_c = rawGraphDataRef.current) == null ? void 0 : _c.analysis;
2728
2845
  const allControllerIds = rawAnalysis == null ? void 0 : rawAnalysis.controllerNodeIds;
2729
- const foldAllProps = React8.useMemo(() => {
2846
+ const foldAllProps = React9.useMemo(() => {
2730
2847
  if (!showControllers || !allControllerIds || allControllerIds.size === 0) {
2731
2848
  return {
2732
2849
  onFoldAll: void 0,
@@ -2742,96 +2859,106 @@ function GraphViewer(props) {
2742
2859
  expandAllDisabled: foldedControllers.size === 0
2743
2860
  };
2744
2861
  }, [showControllers, allControllerIds, foldedControllers]);
2745
- return /* @__PURE__ */ jsxs20("div", { ref: containerRef, className: `react-flow-container react-flow-container--theme-${theme}`, children: [
2746
- /* @__PURE__ */ jsx20(
2747
- ReactFlow,
2748
- {
2749
- nodes,
2750
- edges,
2751
- nodeTypes,
2752
- onNodesChange,
2753
- onEdgesChange,
2754
- onNodeClick,
2755
- onPaneClick: handlePaneClick,
2756
- onInit,
2757
- fitView: true,
2758
- fitViewOptions: { padding: 0.1 },
2759
- defaultEdgeOptions: { type: edgeType },
2760
- panOnScroll: true,
2761
- minZoom: 0.1,
2762
- proOptions: { hideAttribution: true },
2763
- panActivationKeyCode: null,
2764
- children: /* @__PURE__ */ jsx20(
2765
- Background,
2862
+ return /* @__PURE__ */ jsxs20(
2863
+ "div",
2864
+ {
2865
+ ref: containerRef,
2866
+ className: `react-flow-container react-flow-container--theme-${resolvedTheme} react-flow-container--mode-${mode}`,
2867
+ children: [
2868
+ /* @__PURE__ */ jsxs20(
2869
+ ReactFlow,
2766
2870
  {
2767
- variant: BackgroundVariant.Dots,
2768
- gap: 20,
2769
- size: 1,
2770
- color: "var(--color-bg-dots)"
2871
+ nodes,
2872
+ edges,
2873
+ nodeTypes,
2874
+ onNodesChange,
2875
+ onEdgesChange,
2876
+ onNodeClick,
2877
+ onPaneClick: handlePaneClick,
2878
+ onInit,
2879
+ fitView: true,
2880
+ fitViewOptions: { padding: 0.1 },
2881
+ defaultEdgeOptions: { type: edgeType },
2882
+ panOnScroll: true,
2883
+ minZoom: 0.1,
2884
+ proOptions: { hideAttribution: true },
2885
+ panActivationKeyCode: null,
2886
+ children: [
2887
+ /* @__PURE__ */ jsx20(
2888
+ Background,
2889
+ {
2890
+ variant: BackgroundVariant.Dots,
2891
+ gap: 20,
2892
+ size: 1,
2893
+ color: "var(--color-bg-dots)"
2894
+ }
2895
+ ),
2896
+ !hideToolbar && /* @__PURE__ */ jsx20(
2897
+ GraphToolbar,
2898
+ {
2899
+ direction,
2900
+ onDirectionChange: setDirection,
2901
+ showControllers,
2902
+ onShowControllersChange: setShowControllers,
2903
+ onZoomIn: () => {
2904
+ var _a2;
2905
+ void ((_a2 = reactFlowRef.current) == null ? void 0 : _a2.zoomIn());
2906
+ },
2907
+ onZoomOut: () => {
2908
+ var _a2;
2909
+ void ((_a2 = reactFlowRef.current) == null ? void 0 : _a2.zoomOut());
2910
+ },
2911
+ onFitView: () => {
2912
+ var _a2;
2913
+ void ((_a2 = reactFlowRef.current) == null ? void 0 : _a2.fitView({ padding: 0.1 }));
2914
+ },
2915
+ onFoldAll: foldAllProps.onFoldAll,
2916
+ onExpandAll: foldAllProps.onExpandAll,
2917
+ foldAllDisabled: foldAllProps.foldAllDisabled,
2918
+ expandAllDisabled: foldAllProps.expandAllDisabled,
2919
+ themeMode: showThemeToggle ? mode : void 0,
2920
+ onThemeModeChange: showThemeToggle ? setMode : void 0,
2921
+ rightOffset: detailOpen ? panelWidth : 0,
2922
+ position: effectiveToolbarPosition
2923
+ }
2924
+ )
2925
+ ]
2926
+ }
2927
+ ),
2928
+ /* @__PURE__ */ jsxs20(
2929
+ DetailPanel,
2930
+ {
2931
+ isOpen: detailOpen,
2932
+ onClose: handlePaneClick,
2933
+ width: panelWidth,
2934
+ isDragging: isPanelDragging,
2935
+ onResizeHandleMouseDown: onResizeMouseDown,
2936
+ children: [
2937
+ conceptOverride ? /* @__PURE__ */ jsx20(ConceptDetailPanel, { concept: conceptOverride }) : selectedSpecNode && graphspec ? /* @__PURE__ */ jsx20(
2938
+ PipeDetailPanel,
2939
+ {
2940
+ node: selectedSpecNode,
2941
+ spec: graphspec,
2942
+ onConceptClick: handleConceptClick
2943
+ }
2944
+ ) : (detailSelection == null ? void 0 : detailSelection.stuffData) ? /* @__PURE__ */ jsx20(
2945
+ StuffNodeDetail,
2946
+ {
2947
+ nodeId: detailSelection.nodeId,
2948
+ stuffData: detailSelection.stuffData,
2949
+ graphspec,
2950
+ resolveStorageUrl,
2951
+ canEmbedPdf,
2952
+ onOpenExternally
2953
+ }
2954
+ ) : null,
2955
+ renderDetailExtra && detailSelection && !conceptOverride && renderDetailExtra(detailSelection.nodeId, detailSelection.nodeData)
2956
+ ]
2771
2957
  }
2772
2958
  )
2773
- }
2774
- ),
2775
- /* @__PURE__ */ jsxs20(
2776
- DetailPanel,
2777
- {
2778
- isOpen: detailOpen,
2779
- onClose: handlePaneClick,
2780
- width: panelWidth,
2781
- isDragging: isPanelDragging,
2782
- onResizeHandleMouseDown: onResizeMouseDown,
2783
- children: [
2784
- conceptOverride ? /* @__PURE__ */ jsx20(ConceptDetailPanel, { concept: conceptOverride }) : selectedSpecNode && graphspec ? /* @__PURE__ */ jsx20(
2785
- PipeDetailPanel,
2786
- {
2787
- node: selectedSpecNode,
2788
- spec: graphspec,
2789
- onConceptClick: handleConceptClick
2790
- }
2791
- ) : (detailSelection == null ? void 0 : detailSelection.stuffData) ? /* @__PURE__ */ jsx20(
2792
- StuffNodeDetail,
2793
- {
2794
- nodeId: detailSelection.nodeId,
2795
- stuffData: detailSelection.stuffData,
2796
- graphspec,
2797
- resolveStorageUrl,
2798
- canEmbedPdf,
2799
- onOpenExternally
2800
- }
2801
- ) : null,
2802
- renderDetailExtra && detailSelection && !conceptOverride && renderDetailExtra(detailSelection.nodeId, detailSelection.nodeData)
2803
- ]
2804
- }
2805
- ),
2806
- !hideToolbar && /* @__PURE__ */ jsx20(
2807
- GraphToolbar,
2808
- {
2809
- direction,
2810
- onDirectionChange: setDirection,
2811
- showControllers,
2812
- onShowControllersChange: setShowControllers,
2813
- onZoomIn: () => {
2814
- var _a2;
2815
- return (_a2 = reactFlowRef.current) == null ? void 0 : _a2.zoomIn();
2816
- },
2817
- onZoomOut: () => {
2818
- var _a2;
2819
- return (_a2 = reactFlowRef.current) == null ? void 0 : _a2.zoomOut();
2820
- },
2821
- onFitView: () => {
2822
- var _a2;
2823
- return (_a2 = reactFlowRef.current) == null ? void 0 : _a2.fitView({ padding: 0.1 });
2824
- },
2825
- onFoldAll: foldAllProps.onFoldAll,
2826
- onExpandAll: foldAllProps.onExpandAll,
2827
- foldAllDisabled: foldAllProps.foldAllDisabled,
2828
- expandAllDisabled: foldAllProps.expandAllDisabled,
2829
- theme: showThemeToggle ? theme : void 0,
2830
- onThemeChange: showThemeToggle ? setTheme : void 0,
2831
- rightOffset: detailOpen ? panelWidth : 0
2832
- }
2833
- )
2834
- ] });
2959
+ ]
2960
+ }
2961
+ );
2835
2962
  }
2836
2963
  export {
2837
2964
  ConceptDetailPanel,
@@ -2844,6 +2971,7 @@ export {
2844
2971
  StuffViewer,
2845
2972
  applyStatusOverrides,
2846
2973
  controllerNodeTypes,
2974
+ detectSystemTheme,
2847
2975
  extractFilename,
2848
2976
  extractInlineUrl,
2849
2977
  extractStorageUri,
@@ -2857,6 +2985,7 @@ export {
2857
2985
  resolveMimeType,
2858
2986
  toAppEdges,
2859
2987
  toAppNodes,
2860
- useResizable
2988
+ useResizable,
2989
+ useSystemTheme
2861
2990
  };
2862
2991
  //# sourceMappingURL=index.js.map