@opentrace/components 0.1.1-rc.43 → 0.1.1-rc.44

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.
@@ -1385,6 +1385,28 @@
1385
1385
  .graph-badge-sep {
1386
1386
  margin: 0 3px;
1387
1387
  }
1388
+
1389
+ /* ── Compact badge (1100px–1300px) ──────────── */
1390
+ @media (max-width: 1300px) and (min-width: 1100px) {
1391
+ .graph-badge-total,
1392
+ .graph-badge-label {
1393
+ display: none;
1394
+ }
1395
+
1396
+ .graph-badge {
1397
+ gap: 4px;
1398
+ padding: 0 10px;
1399
+ }
1400
+ }
1401
+
1402
+ /* ── Hidden badge (1025px–1099px) ───────────── */
1403
+ /* Below 1024px the toolbar collapses to burger dropdown where the
1404
+ badge reappears as a full-width menu row, so we stop hiding at 1025px. */
1405
+ @media (max-width: 1099px) and (min-width: 1025px) {
1406
+ .graph-badge {
1407
+ display: none;
1408
+ }
1409
+ }
1388
1410
  /*
1389
1411
  * Copyright 2026 OpenTrace Contributors
1390
1412
  *
@@ -1504,6 +1526,427 @@
1504
1526
  * limitations under the License.
1505
1527
  */
1506
1528
 
1529
+ /* ── Toolbar layout ─────────────────────────── */
1530
+
1531
+ .ot-toolbar {
1532
+ position: absolute;
1533
+ top: 0;
1534
+ left: 0;
1535
+ right: 0;
1536
+ z-index: 10;
1537
+ display: flex;
1538
+ align-items: center;
1539
+ gap: 12px;
1540
+ padding: 16px 24px;
1541
+ pointer-events: none;
1542
+ }
1543
+
1544
+ .ot-toolbar h1 {
1545
+ margin: 0;
1546
+ font-size: 1.25rem;
1547
+ font-weight: 600;
1548
+ color: var(--foreground);
1549
+ letter-spacing: -0.02em;
1550
+ pointer-events: auto;
1551
+ }
1552
+
1553
+ /* ── Nav (inline on desktop, dropdown on mobile) */
1554
+
1555
+ .ot-toolbar-nav {
1556
+ display: flex;
1557
+ align-items: center;
1558
+ gap: 12px;
1559
+ flex: 1;
1560
+ pointer-events: auto;
1561
+ }
1562
+
1563
+ /* Hidden on desktop */
1564
+ .ot-toolbar .ot-menu-label {
1565
+ display: none;
1566
+ }
1567
+
1568
+ .ot-toolbar .ot-mobile-panel-btn,
1569
+ .ot-toolbar .ot-menu-divider {
1570
+ display: none;
1571
+ }
1572
+
1573
+ /* ── Search placement ──────────────────────── */
1574
+ /* Desktop: search inside nav is visible, tablet search is hidden */
1575
+ .ot-toolbar .ot-search-tablet {
1576
+ display: none;
1577
+ }
1578
+
1579
+ .ot-toolbar .ot-search-nav {
1580
+ display: contents;
1581
+ }
1582
+
1583
+ /* ── Persistent actions ─────────────────────── */
1584
+ /* On desktop: hidden here, shown inside nav via .ot-persistent-desktop */
1585
+ .ot-toolbar .ot-persistent-mobile {
1586
+ display: none;
1587
+ pointer-events: auto;
1588
+ }
1589
+
1590
+ .ot-toolbar .ot-persistent-desktop {
1591
+ display: contents;
1592
+ }
1593
+
1594
+ /* ── Burger button ──────────────────────────── */
1595
+
1596
+ .ot-toolbar .ot-burger-btn {
1597
+ display: none;
1598
+ background: var(--card);
1599
+ border: 1px solid var(--border);
1600
+ border-radius: 8px;
1601
+ padding: 6px;
1602
+ cursor: pointer;
1603
+ color: var(--foreground);
1604
+ pointer-events: auto;
1605
+ flex-shrink: 0;
1606
+ margin-left: auto;
1607
+ }
1608
+
1609
+ .ot-toolbar .ot-burger-btn:hover {
1610
+ background: var(--accent);
1611
+ }
1612
+
1613
+ /* ── Search ─────────────────────────────────── */
1614
+
1615
+ .ot-toolbar .ot-search-container {
1616
+ position: relative;
1617
+ flex: 1;
1618
+ max-width: 460px;
1619
+ margin: 0 0.5rem;
1620
+ pointer-events: auto;
1621
+ display: flex;
1622
+ align-items: center;
1623
+ }
1624
+
1625
+ .ot-toolbar .ot-search-input {
1626
+ width: 100%;
1627
+ height: 36px;
1628
+ padding: 0 12px;
1629
+ padding-right: 155px;
1630
+ background: color-mix(in oklch, var(--card) 80%, transparent);
1631
+ border: 1px solid color-mix(in oklch, var(--border) 30%, transparent);
1632
+ border-radius: calc(var(--radius) + 2px);
1633
+ color: var(--foreground);
1634
+ font-size: 0.8rem;
1635
+ transition: all 0.2s;
1636
+ }
1637
+
1638
+ .ot-toolbar .ot-search-input:focus {
1639
+ outline: none;
1640
+ border-color: color-mix(in oklch, var(--primary) 50%, transparent);
1641
+ box-shadow: 0 0 0 2px color-mix(in oklch, var(--primary) 12%, transparent);
1642
+ }
1643
+
1644
+ .ot-toolbar .ot-search-input::placeholder {
1645
+ color: var(--muted-foreground);
1646
+ }
1647
+
1648
+ .ot-toolbar .ot-search-params {
1649
+ position: absolute;
1650
+ right: 56px;
1651
+ display: flex;
1652
+ align-items: center;
1653
+ gap: 6px;
1654
+ font-size: 0.7rem;
1655
+ color: var(--muted-foreground);
1656
+ border-left: 1px solid color-mix(in oklch, var(--border) 30%, transparent);
1657
+ padding-left: 8px;
1658
+ }
1659
+
1660
+ .ot-toolbar .ot-hops-input {
1661
+ width: 32px;
1662
+ height: 22px;
1663
+ background: color-mix(in oklch, var(--background) 60%, transparent);
1664
+ border: 1px solid color-mix(in oklch, var(--border) 25%, transparent);
1665
+ border-radius: calc(var(--radius) - 2px);
1666
+ color: var(--foreground);
1667
+ font-size: 0.7rem;
1668
+ padding: 0 4px;
1669
+ text-align: center;
1670
+ }
1671
+
1672
+ .ot-toolbar .ot-hops-input:focus {
1673
+ outline: none;
1674
+ border-color: var(--primary);
1675
+ }
1676
+
1677
+ .ot-toolbar .ot-hops-input::-webkit-inner-spin-button,
1678
+ .ot-toolbar .ot-hops-input::-webkit-outer-spin-button {
1679
+ -webkit-appearance: none;
1680
+ margin: 0;
1681
+ }
1682
+
1683
+ .ot-toolbar .ot-search-actions {
1684
+ position: absolute;
1685
+ right: 6px;
1686
+ top: 50%;
1687
+ transform: translateY(-50%);
1688
+ display: flex;
1689
+ align-items: center;
1690
+ gap: 2px;
1691
+ }
1692
+
1693
+ .ot-toolbar .ot-clear-search {
1694
+ background: none;
1695
+ border: none;
1696
+ color: var(--muted-foreground);
1697
+ font-size: 1rem;
1698
+ cursor: pointer;
1699
+ padding: 2px;
1700
+ line-height: 1;
1701
+ display: flex;
1702
+ align-items: center;
1703
+ justify-content: center;
1704
+ }
1705
+
1706
+ .ot-toolbar .ot-clear-search:hover {
1707
+ color: var(--foreground);
1708
+ }
1709
+
1710
+ .ot-toolbar .ot-search-btn {
1711
+ background: var(--primary);
1712
+ border: none;
1713
+ border-radius: calc(var(--radius) - 2px);
1714
+ color: var(--primary-foreground);
1715
+ width: 24px;
1716
+ height: 24px;
1717
+ cursor: pointer;
1718
+ display: flex;
1719
+ align-items: center;
1720
+ justify-content: center;
1721
+ transition: background 0.15s;
1722
+ }
1723
+
1724
+ .ot-toolbar .ot-search-btn:hover:not(:disabled) {
1725
+ background: color-mix(in oklch, var(--primary) 85%, black);
1726
+ }
1727
+
1728
+ .ot-toolbar .ot-search-btn:disabled {
1729
+ background: color-mix(in oklch, var(--secondary) 60%, transparent);
1730
+ color: var(--muted-foreground);
1731
+ cursor: not-allowed;
1732
+ }
1733
+
1734
+ /* ── Reset / Show All button ────────────────── */
1735
+
1736
+ .ot-toolbar .ot-reset-btn {
1737
+ pointer-events: auto;
1738
+ background: color-mix(in oklch, var(--card) 80%, transparent);
1739
+ border: 1px solid color-mix(in oklch, var(--border) 30%, transparent);
1740
+ color: var(--muted-foreground);
1741
+ height: 36px;
1742
+ padding: 0 12px;
1743
+ border-radius: calc(var(--radius) + 2px);
1744
+ font-size: 0.75rem;
1745
+ cursor: pointer;
1746
+ transition: all 0.2s;
1747
+ }
1748
+
1749
+ .ot-toolbar .ot-reset-btn:hover {
1750
+ background: color-mix(in oklch, var(--primary) 10%, transparent);
1751
+ color: var(--primary);
1752
+ border-color: color-mix(in oklch, var(--primary) 30%, transparent);
1753
+ }
1754
+
1755
+ /* ── Tablet + Mobile (≤ 1024px): burger dropdown ── */
1756
+
1757
+ @media (max-width: 1024px) {
1758
+ .ot-toolbar {
1759
+ flex-wrap: wrap;
1760
+ padding: max(12px, env(safe-area-inset-top))
1761
+ max(16px, env(safe-area-inset-right)) 12px
1762
+ max(16px, env(safe-area-inset-left));
1763
+ gap: 0;
1764
+ }
1765
+
1766
+ /* Tablet search: visible outside the nav at 600–1024px */
1767
+ .ot-toolbar .ot-search-tablet {
1768
+ display: flex;
1769
+ flex: 1;
1770
+ min-width: 0;
1771
+ pointer-events: auto;
1772
+ }
1773
+
1774
+ .ot-toolbar .ot-search-tablet .ot-search-container {
1775
+ flex: 1;
1776
+ max-width: none;
1777
+ margin: 0 8px;
1778
+ }
1779
+
1780
+ /* Hide the in-nav copy of search */
1781
+ .ot-toolbar .ot-search-nav {
1782
+ display: none;
1783
+ }
1784
+
1785
+ .ot-toolbar .ot-persistent-mobile {
1786
+ display: flex;
1787
+ align-items: center;
1788
+ gap: 8px;
1789
+ margin-left: 0;
1790
+ flex-shrink: 0;
1791
+ }
1792
+
1793
+ .ot-toolbar .ot-persistent-desktop {
1794
+ display: none;
1795
+ }
1796
+
1797
+ .ot-toolbar .ot-burger-btn {
1798
+ display: flex;
1799
+ align-items: center;
1800
+ justify-content: center;
1801
+ margin-left: 8px;
1802
+ }
1803
+
1804
+ .ot-toolbar-nav {
1805
+ display: none;
1806
+ flex-basis: 100%;
1807
+ flex-direction: column;
1808
+ align-items: stretch;
1809
+ gap: 0;
1810
+ background: var(--card);
1811
+ border: 1px solid var(--border);
1812
+ border-radius: calc(var(--radius) + 2px);
1813
+ padding: 6px 0;
1814
+ margin-top: 8px;
1815
+ pointer-events: auto;
1816
+ }
1817
+
1818
+ .ot-toolbar-nav.open {
1819
+ display: flex;
1820
+ }
1821
+
1822
+ /* Show panel shortcuts and dividers */
1823
+ .ot-toolbar .ot-mobile-panel-btn {
1824
+ display: flex;
1825
+ align-items: center;
1826
+ gap: 10px;
1827
+ padding: 10px 16px;
1828
+ background: transparent;
1829
+ border: none;
1830
+ color: var(--foreground);
1831
+ cursor: pointer;
1832
+ font-size: 14px;
1833
+ font-weight: 500;
1834
+ pointer-events: auto;
1835
+ }
1836
+
1837
+ .ot-toolbar .ot-mobile-panel-btn:hover {
1838
+ background: var(--accent);
1839
+ }
1840
+
1841
+ .ot-toolbar .ot-menu-divider {
1842
+ display: block;
1843
+ height: 1px;
1844
+ background: var(--border);
1845
+ margin: 4px 0;
1846
+ }
1847
+
1848
+ .ot-toolbar .ot-menu-label {
1849
+ display: inline;
1850
+ font-size: 14px;
1851
+ font-weight: 500;
1852
+ }
1853
+
1854
+ /* Search full width in dropdown */
1855
+ .ot-toolbar-nav .ot-search-container {
1856
+ width: auto;
1857
+ max-width: none;
1858
+ min-width: 0;
1859
+ margin: 4px 10px;
1860
+ }
1861
+
1862
+ /* Reset button as menu row */
1863
+ .ot-toolbar-nav .ot-reset-btn {
1864
+ border: none;
1865
+ border-radius: 0;
1866
+ background: transparent;
1867
+ height: auto;
1868
+ padding: 10px 16px;
1869
+ font-size: 14px;
1870
+ font-weight: 500;
1871
+ color: var(--foreground);
1872
+ }
1873
+
1874
+ .ot-toolbar-nav .ot-reset-btn:hover {
1875
+ background: var(--accent);
1876
+ border-color: transparent;
1877
+ }
1878
+
1879
+ /* Badge as menu row */
1880
+ .ot-toolbar-nav .graph-badge {
1881
+ border: none;
1882
+ border-radius: 0;
1883
+ background: transparent;
1884
+ backdrop-filter: none;
1885
+ height: auto;
1886
+ padding: 10px 16px;
1887
+ font-size: 13px;
1888
+ }
1889
+ }
1890
+
1891
+ /* ── Small mobile (≤ 600px): search goes back into burger ── */
1892
+
1893
+ @media (max-width: 600px) {
1894
+ .ot-toolbar .ot-search-tablet {
1895
+ display: none;
1896
+ }
1897
+
1898
+ .ot-toolbar .ot-search-nav {
1899
+ display: contents;
1900
+ }
1901
+
1902
+ .ot-toolbar .ot-persistent-mobile {
1903
+ margin-left: auto;
1904
+ }
1905
+ }
1906
+
1907
+ /* ── Extra small (≤ 640px) ──────────────────── */
1908
+
1909
+ @media (max-width: 640px) {
1910
+ .ot-toolbar {
1911
+ padding: max(10px, env(safe-area-inset-top))
1912
+ max(12px, env(safe-area-inset-right)) 10px
1913
+ max(12px, env(safe-area-inset-left));
1914
+ }
1915
+
1916
+ .ot-toolbar h1 {
1917
+ display: none;
1918
+ }
1919
+
1920
+ .ot-toolbar-nav .ot-search-container {
1921
+ margin: 4px 8px;
1922
+ }
1923
+
1924
+ .ot-toolbar .ot-search-btn {
1925
+ width: 32px;
1926
+ height: 32px;
1927
+ }
1928
+
1929
+ .ot-toolbar .ot-hops-input {
1930
+ width: 40px;
1931
+ height: 28px;
1932
+ }
1933
+ }
1934
+ /*
1935
+ * Copyright 2026 OpenTrace Contributors
1936
+ *
1937
+ * Licensed under the Apache License, Version 2.0 (the "License");
1938
+ * you may not use this file except in compliance with the License.
1939
+ * You may obtain a copy of the License at
1940
+ *
1941
+ * http://www.apache.org/licenses/LICENSE-2.0
1942
+ *
1943
+ * Unless required by applicable law or agreed to in writing, software
1944
+ * distributed under the License is distributed on an "AS IS" BASIS,
1945
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1946
+ * See the License for the specific language governing permissions and
1947
+ * limitations under the License.
1948
+ */
1949
+
1507
1950
  /* Discover Panel — directory tree view */
1508
1951
 
1509
1952
  .discover-panel {
@@ -7799,7 +7799,7 @@ function GraphBadge({
7799
7799
  totalNodes,
7800
7800
  ")"
7801
7801
  ] }),
7802
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "nodes" }),
7802
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "graph-badge-label", children: "nodes" }),
7803
7803
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "graph-badge-sep", children: "·" }),
7804
7804
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "graph-badge-rendered", children: edgeCount }),
7805
7805
  totalEdges != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "graph-badge-total", children: [
@@ -7807,7 +7807,7 @@ function GraphBadge({
7807
7807
  totalEdges,
7808
7808
  ")"
7809
7809
  ] }),
7810
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "edges" })
7810
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "graph-badge-label", children: "edges" })
7811
7811
  ] });
7812
7812
  }
7813
7813
  const DEFAULT_MAX_VISIBLE = 5;
@@ -7877,6 +7877,198 @@ function GraphLegend({
7877
7877
  ] })
7878
7878
  ] });
7879
7879
  }
7880
+ function GraphToolbar({
7881
+ logo,
7882
+ searchQuery,
7883
+ onSearchQueryChange,
7884
+ onSearch,
7885
+ onReset,
7886
+ searchDisabled,
7887
+ showResetButton,
7888
+ hops,
7889
+ onHopsChange,
7890
+ maxHops = 5,
7891
+ nodeCount,
7892
+ edgeCount,
7893
+ totalNodes,
7894
+ totalEdges,
7895
+ mobilePanelTabs,
7896
+ onMobilePanelTab,
7897
+ actions,
7898
+ persistentActions,
7899
+ className
7900
+ }) {
7901
+ const [menuOpen, setMenuOpen] = t.useState(false);
7902
+ const navRef = t.useRef(null);
7903
+ const burgerRef = t.useRef(null);
7904
+ t.useEffect(() => {
7905
+ if (!menuOpen) return;
7906
+ const onClickOutside = (e2) => {
7907
+ if (navRef.current?.contains(e2.target)) return;
7908
+ if (burgerRef.current?.contains(e2.target)) return;
7909
+ setMenuOpen(false);
7910
+ };
7911
+ const onEscape = (e2) => {
7912
+ if (e2.key === "Escape") setMenuOpen(false);
7913
+ };
7914
+ document.addEventListener("mousedown", onClickOutside);
7915
+ document.addEventListener("keydown", onEscape);
7916
+ return () => {
7917
+ document.removeEventListener("mousedown", onClickOutside);
7918
+ document.removeEventListener("keydown", onEscape);
7919
+ };
7920
+ }, [menuOpen]);
7921
+ const handleNavClick = t.useCallback((e2) => {
7922
+ const target = e2.target;
7923
+ const clickable = target.closest("button, a");
7924
+ if (clickable && !clickable.classList.contains("ot-clear-search") && !clickable.classList.contains("ot-search-btn")) {
7925
+ setMenuOpen(false);
7926
+ }
7927
+ }, []);
7928
+ const visibleTabs = mobilePanelTabs?.filter((t2) => t2.visible !== false);
7929
+ const searchMarkup = (id) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ot-search-container", children: [
7930
+ /* @__PURE__ */ jsxRuntime.jsx(
7931
+ "input",
7932
+ {
7933
+ type: "text",
7934
+ placeholder: "Search nodes...",
7935
+ value: searchQuery,
7936
+ onChange: (e2) => onSearchQueryChange(e2.target.value),
7937
+ onKeyDown: (e2) => e2.key === "Enter" && onSearch(),
7938
+ className: "ot-search-input"
7939
+ }
7940
+ ),
7941
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ot-search-params", children: [
7942
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `ot-hops-input-${id}`, children: "Hops:" }),
7943
+ /* @__PURE__ */ jsxRuntime.jsx(
7944
+ "input",
7945
+ {
7946
+ id: `ot-hops-input-${id}`,
7947
+ type: "number",
7948
+ min: "0",
7949
+ max: maxHops,
7950
+ value: hops,
7951
+ onChange: (e2) => onHopsChange(
7952
+ Math.min(maxHops, Math.max(0, parseInt(e2.target.value) || 0))
7953
+ ),
7954
+ className: "ot-hops-input",
7955
+ title: `Number of connection hops to include (max ${maxHops})`
7956
+ }
7957
+ )
7958
+ ] }),
7959
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ot-search-actions", children: [
7960
+ searchQuery && /* @__PURE__ */ jsxRuntime.jsx(
7961
+ "button",
7962
+ {
7963
+ className: "ot-clear-search",
7964
+ onClick: onReset,
7965
+ title: "Clear search",
7966
+ children: "×"
7967
+ }
7968
+ ),
7969
+ /* @__PURE__ */ jsxRuntime.jsx(
7970
+ "button",
7971
+ {
7972
+ className: "ot-search-btn",
7973
+ onClick: onSearch,
7974
+ title: "Query API and rerender",
7975
+ disabled: searchDisabled,
7976
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
7977
+ "svg",
7978
+ {
7979
+ width: "14",
7980
+ height: "14",
7981
+ viewBox: "0 0 24 24",
7982
+ fill: "none",
7983
+ stroke: "currentColor",
7984
+ strokeWidth: "2.5",
7985
+ strokeLinecap: "round",
7986
+ strokeLinejoin: "round",
7987
+ children: [
7988
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "8" }),
7989
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" })
7990
+ ]
7991
+ }
7992
+ )
7993
+ }
7994
+ )
7995
+ ] })
7996
+ ] });
7997
+ return /* @__PURE__ */ jsxRuntime.jsxs("header", { className: `ot-toolbar${className ? ` ${className}` : ""}`, children: [
7998
+ logo,
7999
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ot-search-tablet", children: searchMarkup("tablet") }),
8000
+ persistentActions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ot-persistent-mobile", children: persistentActions }),
8001
+ /* @__PURE__ */ jsxRuntime.jsx(
8002
+ "button",
8003
+ {
8004
+ type: "button",
8005
+ className: "ot-burger-btn",
8006
+ ref: burgerRef,
8007
+ onClick: () => setMenuOpen((v2) => !v2),
8008
+ "aria-label": "Toggle menu",
8009
+ "aria-expanded": menuOpen,
8010
+ children: /* @__PURE__ */ jsxRuntime.jsx(
8011
+ "svg",
8012
+ {
8013
+ width: "22",
8014
+ height: "22",
8015
+ viewBox: "0 0 24 24",
8016
+ fill: "none",
8017
+ stroke: "currentColor",
8018
+ strokeWidth: "2",
8019
+ strokeLinecap: "round",
8020
+ strokeLinejoin: "round",
8021
+ children: menuOpen ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8022
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
8023
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
8024
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8025
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "6", x2: "21", y2: "6" }),
8026
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "12", x2: "21", y2: "12" }),
8027
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "18", x2: "21", y2: "18" })
8028
+ ] })
8029
+ }
8030
+ )
8031
+ }
8032
+ ),
8033
+ /* @__PURE__ */ jsxRuntime.jsxs(
8034
+ "nav",
8035
+ {
8036
+ className: `ot-toolbar-nav${menuOpen ? " open" : ""}`,
8037
+ ref: navRef,
8038
+ onClick: handleNavClick,
8039
+ children: [
8040
+ visibleTabs?.map((tab) => /* @__PURE__ */ jsxRuntime.jsxs(
8041
+ "button",
8042
+ {
8043
+ type: "button",
8044
+ className: "ot-mobile-panel-btn",
8045
+ onClick: () => onMobilePanelTab?.(tab.key),
8046
+ children: [
8047
+ tab.icon,
8048
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ot-menu-label", children: tab.label })
8049
+ ]
8050
+ },
8051
+ tab.key
8052
+ )),
8053
+ visibleTabs && visibleTabs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ot-menu-divider" }),
8054
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ot-search-nav", children: searchMarkup("nav") }),
8055
+ showResetButton && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "ot-reset-btn", onClick: onReset, children: "Show All" }),
8056
+ /* @__PURE__ */ jsxRuntime.jsx(
8057
+ GraphBadge,
8058
+ {
8059
+ nodeCount,
8060
+ edgeCount,
8061
+ totalNodes,
8062
+ totalEdges
8063
+ }
8064
+ ),
8065
+ persistentActions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ot-persistent-desktop", children: persistentActions }),
8066
+ actions
8067
+ ]
8068
+ }
8069
+ )
8070
+ ] });
8071
+ }
7880
8072
  const q = typeof window < "u" ? t.useLayoutEffect : t.useEffect;
7881
8073
  function ie(e2) {
7882
8074
  if (e2 !== void 0)
@@ -8805,6 +8997,7 @@ exports.Graph = GraphCanvas;
8805
8997
  exports.GraphBadge = GraphBadge;
8806
8998
  exports.GraphCanvas = GraphCanvas;
8807
8999
  exports.GraphLegend = GraphLegend;
9000
+ exports.GraphToolbar = GraphToolbar;
8808
9001
  exports.LABEL_COLOR = LABEL_COLOR;
8809
9002
  exports.LABEL_FONT = LABEL_FONT;
8810
9003
  exports.LABEL_RENDERED_SIZE_THRESHOLD = LABEL_RENDERED_SIZE_THRESHOLD;