@usefidel/design-system 0.24.0 → 0.25.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/dist/index.js CHANGED
@@ -1637,21 +1637,66 @@ import {
1637
1637
  useRef as useRef7,
1638
1638
  useState as useState8
1639
1639
  } from "react";
1640
+ import { Check, Search } from "lucide-react";
1640
1641
  import { jsx as jsx34, jsxs as jsxs29 } from "react/jsx-runtime";
1641
- function Menu({ trigger, items, align = "end", className }) {
1642
+ var isItem = (e) => !("type" in e);
1643
+ function searchText(it) {
1644
+ if (it.keywords) return it.keywords;
1645
+ return typeof it.label === "string" ? it.label : "";
1646
+ }
1647
+ function visibleEntries(items, query) {
1648
+ const q = query.trim().toLowerCase();
1649
+ if (!q) return items.map((_, i) => i);
1650
+ const matches = (i) => {
1651
+ const e = items[i];
1652
+ return isItem(e) && searchText(e).toLowerCase().includes(q);
1653
+ };
1654
+ const out = [];
1655
+ items.forEach((e, i) => {
1656
+ if (isItem(e)) {
1657
+ if (matches(i)) out.push(i);
1658
+ } else if (e.type === "label") {
1659
+ for (let j = i + 1; j < items.length && isItem(items[j]); j++) {
1660
+ if (matches(j)) {
1661
+ out.push(i);
1662
+ break;
1663
+ }
1664
+ }
1665
+ }
1666
+ });
1667
+ return out;
1668
+ }
1669
+ function Menu({
1670
+ trigger,
1671
+ items,
1672
+ align = "end",
1673
+ placement = "bottom",
1674
+ search,
1675
+ width = "auto",
1676
+ block = false,
1677
+ className
1678
+ }) {
1642
1679
  const listId = useId12();
1643
1680
  const rootRef = useRef7(null);
1644
1681
  const listRef = useRef7(null);
1682
+ const searchRef = useRef7(null);
1645
1683
  const [open, setOpen] = useState8(false);
1646
- const [active, setActive] = useState8(0);
1647
- const enabled = items.map((it, i) => it.disabled ? -1 : i).filter((i) => i >= 0);
1684
+ const [query, setQuery] = useState8("");
1685
+ const [active, setActive] = useState8(-1);
1686
+ const shown = visibleEntries(items, query);
1687
+ const enabled = shown.filter((i) => {
1688
+ const e = items[i];
1689
+ return isItem(e) && !e.disabled;
1690
+ });
1648
1691
  useEffect6(() => {
1649
1692
  if (!open) return;
1650
1693
  const onDown = (e) => {
1651
1694
  if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false);
1652
1695
  };
1653
1696
  document.addEventListener("mousedown", onDown);
1654
- const raf = requestAnimationFrame(() => listRef.current?.focus());
1697
+ const raf = requestAnimationFrame(
1698
+ () => (searchRef.current && !searchRef.current.disabled ? searchRef.current : listRef.current)?.focus()
1699
+ );
1655
1700
  return () => {
1656
1701
  document.removeEventListener("mousedown", onDown);
1657
1702
  cancelAnimationFrame(raf);
@@ -1662,20 +1707,26 @@ function Menu({ trigger, items, align = "end", className }) {
1662
1707
  setOpen(false);
1663
1708
  triggerEl()?.focus();
1664
1709
  };
1665
- const openAt = (index) => {
1666
- setActive(index);
1710
+ const openAt = (which) => {
1711
+ setQuery("");
1712
+ const all = visibleEntries(items, "").filter((i) => {
1713
+ const e = items[i];
1714
+ return isItem(e) && !e.disabled;
1715
+ });
1716
+ setActive((which === "first" ? all[0] : all[all.length - 1]) ?? -1);
1667
1717
  setOpen(true);
1668
1718
  };
1669
1719
  const choose = (i) => {
1670
- const it = items[i];
1671
- if (!it || it.disabled) return;
1720
+ const e = items[i];
1721
+ if (!e || !isItem(e) || e.disabled) return;
1672
1722
  close();
1673
- it.onSelect();
1723
+ e.onSelect();
1674
1724
  };
1675
1725
  const step = (dir) => {
1676
1726
  if (enabled.length === 0) return;
1677
1727
  const at = enabled.indexOf(active);
1678
- setActive(enabled[(at + dir + enabled.length) % enabled.length]);
1728
+ const next = at === -1 ? dir === 1 ? 0 : enabled.length - 1 : (at + dir + enabled.length) % enabled.length;
1729
+ setActive(enabled[next]);
1679
1730
  };
1680
1731
  const onListKeyDown = (e) => {
1681
1732
  if (e.key === "ArrowDown") {
@@ -1684,13 +1735,13 @@ function Menu({ trigger, items, align = "end", className }) {
1684
1735
  } else if (e.key === "ArrowUp") {
1685
1736
  e.preventDefault();
1686
1737
  step(-1);
1687
- } else if (e.key === "Home") {
1738
+ } else if (e.key === "Home" && !search) {
1688
1739
  e.preventDefault();
1689
- setActive(enabled[0] ?? 0);
1690
- } else if (e.key === "End") {
1740
+ setActive(enabled[0] ?? -1);
1741
+ } else if (e.key === "End" && !search) {
1691
1742
  e.preventDefault();
1692
- setActive(enabled[enabled.length - 1] ?? 0);
1693
- } else if (e.key === "Enter" || e.key === " ") {
1743
+ setActive(enabled[enabled.length - 1] ?? -1);
1744
+ } else if (e.key === "Enter" || e.key === " " && !search) {
1694
1745
  e.preventDefault();
1695
1746
  choose(active);
1696
1747
  } else if (e.key === "Escape") {
@@ -1698,6 +1749,14 @@ function Menu({ trigger, items, align = "end", className }) {
1698
1749
  close();
1699
1750
  } else if (e.key === "Tab") setOpen(false);
1700
1751
  };
1752
+ const onQuery = (value) => {
1753
+ setQuery(value);
1754
+ const first = visibleEntries(items, value).find((i) => {
1755
+ const e = items[i];
1756
+ return isItem(e) && !e.disabled;
1757
+ });
1758
+ setActive(first ?? -1);
1759
+ };
1701
1760
  const own = trigger.props;
1702
1761
  const wired = cloneElement(trigger, {
1703
1762
  "aria-haspopup": "menu",
@@ -1706,56 +1765,103 @@ function Menu({ trigger, items, align = "end", className }) {
1706
1765
  onClick: (e) => {
1707
1766
  own.onClick?.(e);
1708
1767
  if (open) setOpen(false);
1709
- else openAt(enabled[0] ?? 0);
1768
+ else openAt("first");
1710
1769
  },
1711
1770
  onKeyDown: (e) => {
1712
1771
  own.onKeyDown?.(e);
1713
1772
  if (!open && (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ")) {
1714
1773
  e.preventDefault();
1715
- openAt(enabled[0] ?? 0);
1774
+ openAt("first");
1716
1775
  } else if (!open && e.key === "ArrowUp") {
1717
1776
  e.preventDefault();
1718
- openAt(enabled[enabled.length - 1] ?? 0);
1777
+ openAt("last");
1719
1778
  }
1720
1779
  }
1721
1780
  });
1722
- return /* @__PURE__ */ jsxs29("div", { ref: rootRef, className: ["fds-menu", className].filter(Boolean).join(" "), children: [
1723
- wired,
1724
- open && /* @__PURE__ */ jsx34(
1725
- "div",
1726
- {
1727
- ref: listRef,
1728
- id: listId,
1729
- role: "menu",
1730
- tabIndex: -1,
1731
- className: `fds-menu__list fds-menu__list--${align}`,
1732
- "aria-activedescendant": `${listId}-item-${active}`,
1733
- onKeyDown: onListKeyDown,
1734
- children: items.map((it, i) => /* @__PURE__ */ jsxs29(
1735
- "div",
1736
- {
1737
- id: `${listId}-item-${i}`,
1738
- role: "menuitem",
1739
- "aria-disabled": it.disabled || void 0,
1740
- className: [
1741
- "fds-menu__item",
1742
- it.tone === "danger" ? "fds-menu__item--danger" : "",
1743
- i === active ? "fds-menu__item--active" : "",
1744
- it.disabled ? "fds-menu__item--disabled" : ""
1745
- ].filter(Boolean).join(" "),
1746
- onMouseEnter: () => !it.disabled && setActive(i),
1747
- onMouseDown: (e) => e.preventDefault(),
1748
- onClick: () => choose(i),
1749
- children: [
1750
- it.icon != null && /* @__PURE__ */ jsx34("span", { className: "fds-menu__icon", "aria-hidden": "true", children: it.icon }),
1751
- it.label
1752
- ]
1753
- },
1754
- i
1755
- ))
1756
- }
1757
- )
1758
- ] });
1781
+ const listClasses = [
1782
+ "fds-menu__list",
1783
+ `fds-menu__list--${placement}`,
1784
+ placement === "right" ? "" : `fds-menu__list--${align}`,
1785
+ width === "wide" ? "fds-menu__list--wide" : ""
1786
+ ].filter(Boolean).join(" ");
1787
+ return /* @__PURE__ */ jsxs29(
1788
+ "div",
1789
+ {
1790
+ ref: rootRef,
1791
+ className: ["fds-menu", block ? "fds-menu--block" : "", className].filter(Boolean).join(" "),
1792
+ children: [
1793
+ wired,
1794
+ open && /* @__PURE__ */ jsxs29("div", { className: listClasses, onKeyDown: onListKeyDown, children: [
1795
+ search && /* @__PURE__ */ jsxs29("div", { className: "fds-menu__search", children: [
1796
+ /* @__PURE__ */ jsx34(Search, { "aria-hidden": "true" }),
1797
+ /* @__PURE__ */ jsx34(
1798
+ "input",
1799
+ {
1800
+ ref: searchRef,
1801
+ type: "text",
1802
+ value: query,
1803
+ placeholder: search.placeholder,
1804
+ disabled: search.disabled,
1805
+ "aria-label": search.placeholder,
1806
+ "aria-controls": listId,
1807
+ "aria-activedescendant": active >= 0 ? `${listId}-item-${active}` : void 0,
1808
+ onChange: (e) => onQuery(e.target.value)
1809
+ }
1810
+ )
1811
+ ] }),
1812
+ /* @__PURE__ */ jsxs29(
1813
+ "div",
1814
+ {
1815
+ ref: listRef,
1816
+ id: listId,
1817
+ role: "menu",
1818
+ tabIndex: -1,
1819
+ className: "fds-menu__items",
1820
+ "aria-activedescendant": (!search || search.disabled) && active >= 0 ? `${listId}-item-${active}` : void 0,
1821
+ children: [
1822
+ shown.length === 0 && search && /* @__PURE__ */ jsx34("div", { className: "fds-menu__empty", children: search.emptyLabel }),
1823
+ shown.map((i) => {
1824
+ const e = items[i];
1825
+ if (!isItem(e)) {
1826
+ return e.type === "label" ? /* @__PURE__ */ jsx34("div", { className: "fds-menu__label", role: "presentation", children: e.label }, i) : /* @__PURE__ */ jsx34("div", { className: "fds-menu__divider", role: "separator" }, i);
1827
+ }
1828
+ return /* @__PURE__ */ jsxs29(
1829
+ "div",
1830
+ {
1831
+ id: `${listId}-item-${i}`,
1832
+ role: "menuitem",
1833
+ "aria-disabled": e.disabled || void 0,
1834
+ "aria-current": e.selected || void 0,
1835
+ className: [
1836
+ "fds-menu__item",
1837
+ e.tone === "danger" ? "fds-menu__item--danger" : "",
1838
+ i === active ? "fds-menu__item--active" : "",
1839
+ e.disabled ? "fds-menu__item--disabled" : ""
1840
+ ].filter(Boolean).join(" "),
1841
+ onMouseEnter: () => !e.disabled && setActive(i),
1842
+ onMouseDown: (ev) => ev.preventDefault(),
1843
+ onClick: () => choose(i),
1844
+ children: [
1845
+ e.avatar != null && /* @__PURE__ */ jsx34("span", { className: "fds-menu__avatar", "aria-hidden": "true", children: e.avatar }),
1846
+ e.icon != null && /* @__PURE__ */ jsx34("span", { className: "fds-menu__icon", "aria-hidden": "true", children: e.icon }),
1847
+ /* @__PURE__ */ jsxs29("span", { className: "fds-menu__text", children: [
1848
+ /* @__PURE__ */ jsx34("span", { className: "fds-menu__title", children: e.label }),
1849
+ e.description != null && /* @__PURE__ */ jsx34("span", { className: "fds-menu__description", children: e.description })
1850
+ ] }),
1851
+ e.trailing != null && /* @__PURE__ */ jsx34("span", { className: "fds-menu__trailing", children: e.trailing }),
1852
+ e.selected && /* @__PURE__ */ jsx34(Check, { className: "fds-menu__check", "aria-hidden": "true" })
1853
+ ]
1854
+ },
1855
+ i
1856
+ );
1857
+ })
1858
+ ]
1859
+ }
1860
+ )
1861
+ ] })
1862
+ ]
1863
+ }
1864
+ );
1759
1865
  }
1760
1866
 
1761
1867
  // src/components/Table/Table.tsx
@@ -1824,11 +1930,402 @@ function PricingCard({
1824
1930
  ] })
1825
1931
  ] });
1826
1932
  }
1933
+
1934
+ // src/components/StatusDot/StatusDot.tsx
1935
+ import { jsx as jsx37 } from "react/jsx-runtime";
1936
+ function StatusDot({ status, label, className, ...rest }) {
1937
+ return /* @__PURE__ */ jsx37(
1938
+ "span",
1939
+ {
1940
+ className: ["fds-status-dot", `fds-status-dot--${status}`, className].filter(Boolean).join(" "),
1941
+ role: label ? "img" : void 0,
1942
+ "aria-label": label,
1943
+ "aria-hidden": label ? void 0 : true,
1944
+ ...rest
1945
+ }
1946
+ );
1947
+ }
1948
+
1949
+ // src/components/ListLabel/ListLabel.tsx
1950
+ import { jsx as jsx38 } from "react/jsx-runtime";
1951
+ function ListLabel({ className, children, ...rest }) {
1952
+ return /* @__PURE__ */ jsx38("div", { className: ["fds-list-label", className].filter(Boolean).join(" "), ...rest, children });
1953
+ }
1954
+
1955
+ // src/components/Divider/Divider.tsx
1956
+ import { jsx as jsx39 } from "react/jsx-runtime";
1957
+ function Divider({ orientation = "horizontal", className, ...rest }) {
1958
+ return /* @__PURE__ */ jsx39(
1959
+ "hr",
1960
+ {
1961
+ className: ["fds-divider", `fds-divider--${orientation}`, className].filter(Boolean).join(" "),
1962
+ "aria-orientation": orientation,
1963
+ ...rest
1964
+ }
1965
+ );
1966
+ }
1967
+
1968
+ // src/components/Tooltip/Tooltip.tsx
1969
+ import {
1970
+ cloneElement as cloneElement2,
1971
+ useEffect as useEffect7,
1972
+ useId as useId13,
1973
+ useRef as useRef8,
1974
+ useState as useState9
1975
+ } from "react";
1976
+ import { createPortal as createPortal2 } from "react-dom";
1977
+ import { Fragment as Fragment2, jsx as jsx40, jsxs as jsxs32 } from "react/jsx-runtime";
1978
+ var GAP = 8;
1979
+ function place(rect, side) {
1980
+ switch (side) {
1981
+ case "right":
1982
+ return { top: rect.top + rect.height / 2, left: rect.right + GAP };
1983
+ case "left":
1984
+ return { top: rect.top + rect.height / 2, left: rect.left - GAP };
1985
+ case "top":
1986
+ return { top: rect.top - GAP, left: rect.left + rect.width / 2 };
1987
+ case "bottom":
1988
+ return { top: rect.bottom + GAP, left: rect.left + rect.width / 2 };
1989
+ }
1990
+ }
1991
+ function Tooltip({ content, children, side = "right", delay = 400, disabled = false }) {
1992
+ const id = useId13();
1993
+ const timer = useRef8();
1994
+ const [pos, setPos] = useState9(null);
1995
+ useEffect7(() => () => window.clearTimeout(timer.current), []);
1996
+ useEffect7(() => {
1997
+ if (disabled) setPos(null);
1998
+ }, [disabled]);
1999
+ const show = (el, wait) => {
2000
+ window.clearTimeout(timer.current);
2001
+ timer.current = window.setTimeout(() => setPos(place(el.getBoundingClientRect(), side)), wait);
2002
+ };
2003
+ const hide = () => {
2004
+ window.clearTimeout(timer.current);
2005
+ setPos(null);
2006
+ };
2007
+ if (disabled) return children;
2008
+ const own = children.props;
2009
+ const trigger = cloneElement2(children, {
2010
+ "aria-describedby": pos ? id : own["aria-describedby"],
2011
+ onMouseEnter: (e) => {
2012
+ own.onMouseEnter?.(e);
2013
+ show(e.currentTarget, delay);
2014
+ },
2015
+ onMouseLeave: (e) => {
2016
+ own.onMouseLeave?.(e);
2017
+ hide();
2018
+ },
2019
+ onFocus: (e) => {
2020
+ own.onFocus?.(e);
2021
+ if (e.currentTarget.matches(":focus-visible")) show(e.currentTarget, 0);
2022
+ },
2023
+ onBlur: (e) => {
2024
+ own.onBlur?.(e);
2025
+ hide();
2026
+ }
2027
+ });
2028
+ return /* @__PURE__ */ jsxs32(Fragment2, { children: [
2029
+ trigger,
2030
+ pos && createPortal2(
2031
+ /* @__PURE__ */ jsx40(
2032
+ "div",
2033
+ {
2034
+ id,
2035
+ role: "tooltip",
2036
+ className: `fds-tooltip fds-tooltip--${side}`,
2037
+ style: { top: pos.top, left: pos.left },
2038
+ children: content
2039
+ }
2040
+ ),
2041
+ document.body
2042
+ )
2043
+ ] });
2044
+ }
2045
+
2046
+ // src/components/BrandButton/BrandButton.tsx
2047
+ import { PanelLeftOpen } from "lucide-react";
2048
+ import { jsx as jsx41, jsxs as jsxs33 } from "react/jsx-runtime";
2049
+ function BrandButton({ mark, hoverIcon, type = "button", className, ...rest }) {
2050
+ return /* @__PURE__ */ jsxs33("button", { type, className: ["fds-brand-button", className].filter(Boolean).join(" "), ...rest, children: [
2051
+ /* @__PURE__ */ jsx41("span", { className: "fds-brand-button__mark", "aria-hidden": "true", children: mark }),
2052
+ /* @__PURE__ */ jsx41("span", { className: "fds-brand-button__hover", "aria-hidden": "true", children: hoverIcon ?? /* @__PURE__ */ jsx41(PanelLeftOpen, {}) })
2053
+ ] });
2054
+ }
2055
+
2056
+ // src/components/Sidebar/SidebarContext.ts
2057
+ import { createContext, useContext } from "react";
2058
+ var SidebarContext = createContext(null);
2059
+ function useSidebar() {
2060
+ return useContext(SidebarContext);
2061
+ }
2062
+
2063
+ // src/components/SidebarItem/SidebarItem.tsx
2064
+ import { jsx as jsx42, jsxs as jsxs34 } from "react/jsx-runtime";
2065
+ function SidebarItem({
2066
+ as,
2067
+ icon,
2068
+ leading,
2069
+ active = false,
2070
+ iconOnly,
2071
+ className,
2072
+ children,
2073
+ ...rest
2074
+ }) {
2075
+ const sidebar = useSidebar();
2076
+ const compact = iconOnly ?? sidebar?.collapsed ?? false;
2077
+ const Component = as ?? "a";
2078
+ const classes = [
2079
+ "fds-sidebar-item",
2080
+ active ? "fds-sidebar-item--active" : "",
2081
+ compact ? "fds-sidebar-item--icon-only" : "",
2082
+ className
2083
+ ].filter(Boolean).join(" ");
2084
+ return /* @__PURE__ */ jsx42(Tooltip, { content: children, disabled: !compact, children: /* @__PURE__ */ jsxs34(Component, { className: classes, "aria-current": active ? "page" : void 0, ...rest, children: [
2085
+ (leading ?? icon) != null && /* @__PURE__ */ jsx42("span", { className: leading != null ? "fds-sidebar-item__leading" : "fds-sidebar-item__icon", "aria-hidden": "true", children: leading ?? icon }),
2086
+ /* @__PURE__ */ jsx42("span", { className: "fds-sidebar-item__label", children })
2087
+ ] }) });
2088
+ }
2089
+
2090
+ // src/components/Sidebar/Sidebar.tsx
2091
+ import {
2092
+ useCallback,
2093
+ useEffect as useEffect8,
2094
+ useMemo as useMemo2,
2095
+ useRef as useRef9,
2096
+ useState as useState10
2097
+ } from "react";
2098
+ import { PanelLeftClose } from "lucide-react";
2099
+ import { jsx as jsx43, jsxs as jsxs35 } from "react/jsx-runtime";
2100
+ function SidebarRoot({
2101
+ collapsed: controlled,
2102
+ defaultCollapsed = false,
2103
+ onCollapsedChange,
2104
+ shortcut = true,
2105
+ className,
2106
+ children,
2107
+ "aria-label": ariaLabel = "Main",
2108
+ ...rest
2109
+ }) {
2110
+ const [own, setOwn] = useState10(defaultCollapsed);
2111
+ const collapsed = controlled ?? own;
2112
+ const setCollapsed = useCallback(
2113
+ (next) => {
2114
+ if (controlled === void 0) setOwn(next);
2115
+ onCollapsedChange?.(next);
2116
+ },
2117
+ [controlled, onCollapsedChange]
2118
+ );
2119
+ const toggle = useCallback(() => setCollapsed(!collapsed), [collapsed, setCollapsed]);
2120
+ useEffect8(() => {
2121
+ if (!shortcut) return;
2122
+ const onKey = (e) => {
2123
+ if ((e.metaKey || e.ctrlKey) && e.key === "\\") {
2124
+ e.preventDefault();
2125
+ toggle();
2126
+ }
2127
+ };
2128
+ window.addEventListener("keydown", onKey);
2129
+ return () => window.removeEventListener("keydown", onKey);
2130
+ }, [shortcut, toggle]);
2131
+ const state = useMemo2(() => ({ collapsed, setCollapsed, toggle }), [collapsed, setCollapsed, toggle]);
2132
+ return /* @__PURE__ */ jsx43(SidebarContext.Provider, { value: state, children: /* @__PURE__ */ jsx43(
2133
+ "nav",
2134
+ {
2135
+ className: ["fds-sidebar", collapsed ? "fds-sidebar--collapsed" : "", className].filter(Boolean).join(" "),
2136
+ "aria-label": ariaLabel,
2137
+ "data-collapsed": collapsed || void 0,
2138
+ ...rest,
2139
+ children
2140
+ }
2141
+ ) });
2142
+ }
2143
+ function useInert(on) {
2144
+ const ref = useRef9(null);
2145
+ useEffect8(() => {
2146
+ if (ref.current) ref.current.inert = on;
2147
+ }, [on]);
2148
+ return ref;
2149
+ }
2150
+ function SidebarBrand({
2151
+ logo,
2152
+ mark,
2153
+ collapseLabel = "Collapse sidebar",
2154
+ expandLabel = "Expand sidebar"
2155
+ }) {
2156
+ const sidebar = useSidebar();
2157
+ const collapsed = sidebar?.collapsed ?? false;
2158
+ const collapseRef = useInert(collapsed);
2159
+ const expandRef = useInert(!collapsed);
2160
+ return /* @__PURE__ */ jsxs35("div", { className: "fds-sidebar__brand", children: [
2161
+ /* @__PURE__ */ jsx43("span", { className: "fds-sidebar__logo", "aria-hidden": collapsed || void 0, children: logo }),
2162
+ /* @__PURE__ */ jsx43("span", { ref: collapseRef, className: "fds-sidebar__collapse", children: /* @__PURE__ */ jsx43(Tooltip, { content: collapseLabel, side: "bottom", children: /* @__PURE__ */ jsx43(
2163
+ IconButton,
2164
+ {
2165
+ variant: "ghost",
2166
+ size: "small",
2167
+ icon: /* @__PURE__ */ jsx43(PanelLeftClose, {}),
2168
+ "aria-label": collapseLabel,
2169
+ "aria-keyshortcuts": "Meta+Backslash Control+Backslash",
2170
+ onClick: () => sidebar?.setCollapsed(true)
2171
+ }
2172
+ ) }) }),
2173
+ /* @__PURE__ */ jsx43("span", { ref: expandRef, className: "fds-sidebar__expand", children: /* @__PURE__ */ jsx43(Tooltip, { content: expandLabel, children: /* @__PURE__ */ jsx43(BrandButton, { mark, "aria-label": expandLabel, onClick: () => sidebar?.setCollapsed(false) }) }) })
2174
+ ] });
2175
+ }
2176
+ function SidebarAction({ icon, label, type = "button", className, ...rest }) {
2177
+ const sidebar = useSidebar();
2178
+ const collapsed = sidebar?.collapsed ?? false;
2179
+ return /* @__PURE__ */ jsx43(Tooltip, { content: label, disabled: !collapsed, children: /* @__PURE__ */ jsxs35(
2180
+ "button",
2181
+ {
2182
+ type,
2183
+ className: ["fds-sidebar__action", className].filter(Boolean).join(" "),
2184
+ "aria-label": collapsed ? label : void 0,
2185
+ ...rest,
2186
+ children: [
2187
+ /* @__PURE__ */ jsx43("span", { className: "fds-sidebar__action-icon", "aria-hidden": "true", children: icon }),
2188
+ /* @__PURE__ */ jsx43("span", { className: "fds-sidebar__action-label", children: label })
2189
+ ]
2190
+ }
2191
+ ) });
2192
+ }
2193
+ function SidebarSection({ hideWhenCollapsed = false, className, children, ...rest }) {
2194
+ const sidebar = useSidebar();
2195
+ const hidden = hideWhenCollapsed && (sidebar?.collapsed ?? false);
2196
+ const ref = useInert(hidden);
2197
+ return /* @__PURE__ */ jsx43(
2198
+ "div",
2199
+ {
2200
+ ref,
2201
+ className: ["fds-sidebar__section", hidden ? "fds-sidebar__section--hidden" : "", className].filter(Boolean).join(" "),
2202
+ "aria-hidden": hidden || void 0,
2203
+ ...rest,
2204
+ children
2205
+ }
2206
+ );
2207
+ }
2208
+ function SidebarHeader({ className, children, ...rest }) {
2209
+ return /* @__PURE__ */ jsx43("div", { className: ["fds-sidebar__header", className].filter(Boolean).join(" "), ...rest, children });
2210
+ }
2211
+ function SidebarFooter({ className, children, ...rest }) {
2212
+ return /* @__PURE__ */ jsx43("div", { className: ["fds-sidebar__footer", className].filter(Boolean).join(" "), ...rest, children });
2213
+ }
2214
+ var Sidebar = Object.assign(SidebarRoot, {
2215
+ Header: SidebarHeader,
2216
+ Brand: SidebarBrand,
2217
+ Action: SidebarAction,
2218
+ Section: SidebarSection,
2219
+ Item: SidebarItem,
2220
+ Footer: SidebarFooter
2221
+ });
2222
+
2223
+ // src/components/WorkspaceSwitcher/WorkspaceSwitcher.tsx
2224
+ import { forwardRef as forwardRef8 } from "react";
2225
+ import { ChevronDown } from "lucide-react";
2226
+ import { jsx as jsx44, jsxs as jsxs36 } from "react/jsx-runtime";
2227
+ function WorkspaceAvatar({ name }) {
2228
+ return /* @__PURE__ */ jsx44("span", { className: "fds-workspace-avatar", "aria-hidden": "true", children: name.trim().charAt(0).toUpperCase() || "?" });
2229
+ }
2230
+ var WorkspaceSwitcher = forwardRef8(function WorkspaceSwitcher2({ name, plan, avatar, compact, type = "button", className, ...rest }, ref) {
2231
+ const sidebar = useSidebar();
2232
+ const iconOnly = compact ?? sidebar?.collapsed ?? false;
2233
+ return /* @__PURE__ */ jsxs36(
2234
+ "button",
2235
+ {
2236
+ ref,
2237
+ type,
2238
+ className: ["fds-workspace-switcher", iconOnly ? "fds-workspace-switcher--compact" : "", className].filter(Boolean).join(" "),
2239
+ "aria-label": iconOnly ? `Workspace: ${name}` : void 0,
2240
+ ...rest,
2241
+ children: [
2242
+ avatar ?? /* @__PURE__ */ jsx44(WorkspaceAvatar, { name }),
2243
+ /* @__PURE__ */ jsxs36("span", { className: "fds-workspace-switcher__text", "aria-hidden": iconOnly || void 0, children: [
2244
+ /* @__PURE__ */ jsx44("span", { className: "fds-workspace-switcher__name", children: name }),
2245
+ plan && /* @__PURE__ */ jsx44("span", { className: "fds-workspace-switcher__plan", children: plan }),
2246
+ /* @__PURE__ */ jsx44(ChevronDown, { className: "fds-workspace-switcher__chevron", "aria-hidden": "true" })
2247
+ ] })
2248
+ ]
2249
+ }
2250
+ );
2251
+ });
2252
+
2253
+ // src/components/AvatarLabelGroup/AvatarLabelGroup.tsx
2254
+ import { forwardRef as forwardRef9 } from "react";
2255
+ import { jsx as jsx45, jsxs as jsxs37 } from "react/jsx-runtime";
2256
+ var AvatarLabelGroup = forwardRef9(function AvatarLabelGroup2({ name, detail, src, compact = false, type = "button", className, ...rest }, ref) {
2257
+ return /* @__PURE__ */ jsxs37(
2258
+ "button",
2259
+ {
2260
+ ref,
2261
+ type,
2262
+ className: ["fds-avatar-label-group", compact ? "fds-avatar-label-group--compact" : "", className].filter(Boolean).join(" "),
2263
+ "aria-label": compact ? name : void 0,
2264
+ ...rest,
2265
+ children: [
2266
+ /* @__PURE__ */ jsx45(Avatar, { name, src, size: "small" }),
2267
+ /* @__PURE__ */ jsxs37("span", { className: "fds-avatar-label-group__text", "aria-hidden": compact || void 0, children: [
2268
+ /* @__PURE__ */ jsx45("span", { className: "fds-avatar-label-group__name", children: name }),
2269
+ detail && /* @__PURE__ */ jsx45("span", { className: "fds-avatar-label-group__detail", children: detail })
2270
+ ] })
2271
+ ]
2272
+ }
2273
+ );
2274
+ });
2275
+
2276
+ // src/components/AppLayout/AppLayout.tsx
2277
+ import { jsx as jsx46 } from "react/jsx-runtime";
2278
+ function AppLayoutRoot({ className, children, ...rest }) {
2279
+ return /* @__PURE__ */ jsx46("div", { className: ["fds-app-layout", className].filter(Boolean).join(" "), ...rest, children });
2280
+ }
2281
+ function AppLayoutPanel({ className, children, ...rest }) {
2282
+ return /* @__PURE__ */ jsx46("main", { className: ["fds-app-layout__panel", className].filter(Boolean).join(" "), ...rest, children });
2283
+ }
2284
+ var AppLayout = Object.assign(AppLayoutRoot, { Panel: AppLayoutPanel });
2285
+
2286
+ // src/components/PageHeader/PageHeader.tsx
2287
+ import { jsx as jsx47, jsxs as jsxs38 } from "react/jsx-runtime";
2288
+ function PageHeader({ title, description, breadcrumb, actions, className, children, ...rest }) {
2289
+ return /* @__PURE__ */ jsxs38("header", { className: ["fds-page-header", className].filter(Boolean).join(" "), ...rest, children: [
2290
+ /* @__PURE__ */ jsxs38("div", { className: "fds-page-header__row", children: [
2291
+ /* @__PURE__ */ jsxs38("div", { className: "fds-page-header__text", children: [
2292
+ breadcrumb != null && /* @__PURE__ */ jsx47("div", { className: "fds-page-header__breadcrumb", children: breadcrumb }),
2293
+ /* @__PURE__ */ jsx47("h1", { className: "fds-page-header__title", children: title }),
2294
+ description != null && /* @__PURE__ */ jsx47("p", { className: "fds-page-header__description", children: description })
2295
+ ] }),
2296
+ actions != null && /* @__PURE__ */ jsx47("div", { className: "fds-page-header__actions", children: actions })
2297
+ ] }),
2298
+ children
2299
+ ] });
2300
+ }
2301
+
2302
+ // src/components/Toast/Toast.tsx
2303
+ import { useEffect as useEffect9 } from "react";
2304
+ import { X } from "lucide-react";
2305
+ import { jsx as jsx48, jsxs as jsxs39 } from "react/jsx-runtime";
2306
+ function ToastRegion({ className, children, ...rest }) {
2307
+ return /* @__PURE__ */ jsx48("div", { className: ["fds-toast-region", className].filter(Boolean).join(" "), "aria-live": "polite", ...rest, children });
2308
+ }
2309
+ function Toast({ children, action, onDismiss, duration, className, ...rest }) {
2310
+ useEffect9(() => {
2311
+ if (!duration || !onDismiss) return;
2312
+ const t = window.setTimeout(onDismiss, duration);
2313
+ return () => window.clearTimeout(t);
2314
+ }, [duration, onDismiss]);
2315
+ return /* @__PURE__ */ jsxs39("div", { role: "status", className: ["fds-toast", className].filter(Boolean).join(" "), ...rest, children: [
2316
+ /* @__PURE__ */ jsx48("span", { className: "fds-toast__message", children }),
2317
+ action && /* @__PURE__ */ jsx48("button", { type: "button", className: "fds-toast__action", onClick: action.onClick, children: action.label }),
2318
+ onDismiss && /* @__PURE__ */ jsx48("button", { type: "button", className: "fds-toast__close", "aria-label": "Dismiss", onClick: onDismiss, children: /* @__PURE__ */ jsx48(X, { "aria-hidden": "true" }) })
2319
+ ] });
2320
+ }
1827
2321
  export {
1828
2322
  Accordion,
2323
+ AppLayout,
1829
2324
  AppNav,
1830
2325
  Avatar,
2326
+ AvatarLabelGroup,
1831
2327
  Badge,
2328
+ BrandButton,
1832
2329
  Button,
1833
2330
  ButtonLink,
1834
2331
  Callout,
@@ -1836,13 +2333,16 @@ export {
1836
2333
  Checkbox,
1837
2334
  DiffPropertyList,
1838
2335
  DiffSection,
2336
+ Divider,
1839
2337
  EmptyState,
1840
2338
  IconButton,
1841
2339
  Input,
2340
+ ListLabel,
1842
2341
  Menu,
1843
2342
  MismatchCard,
1844
2343
  Modal,
1845
2344
  MultiSelect,
2345
+ PageHeader,
1846
2346
  Pagination,
1847
2347
  PricingCard,
1848
2348
  Radio,
@@ -1852,17 +2352,26 @@ export {
1852
2352
  SegmentedControl,
1853
2353
  Select,
1854
2354
  SettingsSection,
2355
+ Sidebar,
2356
+ SidebarItem,
1855
2357
  Skeleton,
1856
2358
  SkeletonGroup,
1857
2359
  Spinner,
1858
2360
  Split,
1859
2361
  StackedCardsIllustration,
1860
2362
  Stat,
2363
+ StatusDot,
1861
2364
  StepList,
1862
2365
  Swatch,
1863
2366
  TabNav,
1864
2367
  Table,
1865
2368
  Tag,
2369
+ Toast,
2370
+ ToastRegion,
1866
2371
  Toggle,
1867
- breakpoints
2372
+ Tooltip,
2373
+ WorkspaceAvatar,
2374
+ WorkspaceSwitcher,
2375
+ breakpoints,
2376
+ useSidebar
1868
2377
  };