aidos-ui 5.0.11 → 5.0.12

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
@@ -1,6 +1,7 @@
1
- import React35, { useState, Children, useId, useContext, useMemo, cloneElement, useRef, useEffect, useCallback, useSyncExternalStore, createContext, startTransition } from 'react';
1
+ import React35, { useState, Children, useId, useContext, useMemo, cloneElement, useRef, createContext, useCallback, useEffect, useSyncExternalStore, startTransition } from 'react';
2
2
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
3
  import { Icon as Icon$1 } from '@iconify/react';
4
+ import { createPortal } from 'react-dom';
4
5
 
5
6
  // src/Avatar.tsx
6
7
 
@@ -28,50 +29,32 @@ function hash(source, modulus) {
28
29
  function isServer() {
29
30
  return typeof window === "undefined" || window.document == null;
30
31
  }
31
- var aliases = {
32
- margin: (value) => {
33
- if (value == null) {
34
- return [];
35
- }
36
- const matches = typeof value === "string" ? Array.from(value.matchAll(/(.+) (.+)$/g))[0] : null;
37
- if (matches) {
38
- return [
39
- ["margin-top", matches[1]],
40
- ["margin-bottom", matches[1]],
41
- ["margin-left", matches[2]],
42
- ["margin-right", matches[2]]
43
- ];
44
- } else {
45
- return [
46
- ["margin-top", value],
47
- ["margin-bottom", value],
48
- ["margin-left", value],
49
- ["margin-right", value]
50
- ];
51
- }
52
- },
53
- padding: (value) => {
54
- if (value == null) {
55
- return [];
56
- }
57
- const matches = typeof value === "string" ? Array.from(value.matchAll(/(.+) (.+)$/g))[0] : null;
58
- if (matches) {
59
- return [
60
- ["padding-top", matches[1]],
61
- ["padding-bottom", matches[1]],
62
- ["padding-left", matches[2]],
63
- ["padding-right", matches[2]]
64
- ];
65
- } else {
66
- return [
67
- ["padding-top", value],
68
- ["padding-bottom", value],
69
- ["padding-left", value],
70
- ["padding-right", value]
71
- ];
72
- }
32
+ function spacingEntries(key, value) {
33
+ const values = [];
34
+ let token = "";
35
+ let depth = 0;
36
+ let quote = "";
37
+ for (const char of String(value)) {
38
+ if (quote) {
39
+ if (char === quote && !token.endsWith("\\")) quote = "";
40
+ } else if (char === '"' || char === "'") quote = char;
41
+ else if (char === "(") depth++;
42
+ else if (char === ")") depth--;
43
+ if (/\s/.test(char) && depth === 0 && !quote) {
44
+ if (token) values.push(token);
45
+ token = "";
46
+ } else token += char;
73
47
  }
74
- };
48
+ if (token) values.push(token);
49
+ if (values.length < 1 || values.length > 4) return [[key, value]];
50
+ const [top, right = top, bottom = top, left = right] = values;
51
+ return [
52
+ [`${key}Top`, top],
53
+ [`${key}Right`, right],
54
+ [`${key}Bottom`, bottom],
55
+ [`${key}Left`, left]
56
+ ];
57
+ }
75
58
  var rawHashMap = /* @__PURE__ */ new Map();
76
59
  function createStyleNode(content) {
77
60
  if (isServer()) {
@@ -108,7 +91,41 @@ var pixelStyles = /* @__PURE__ */ new Set([
108
91
  "outline-offset",
109
92
  "gap",
110
93
  "row-gap",
111
- "column-gap"
94
+ "column-gap",
95
+ "padding-inline",
96
+ "padding-block",
97
+ "padding-inline-start",
98
+ "padding-inline-end",
99
+ "padding-block-start",
100
+ "padding-block-end",
101
+ "margin-inline",
102
+ "margin-block",
103
+ "margin-inline-start",
104
+ "margin-inline-end",
105
+ "margin-block-start",
106
+ "margin-block-end",
107
+ "inline-size",
108
+ "block-size",
109
+ "min-inline-size",
110
+ "min-block-size",
111
+ "max-inline-size",
112
+ "max-block-size",
113
+ "inset",
114
+ "inset-inline",
115
+ "inset-block",
116
+ "inset-inline-start",
117
+ "inset-inline-end",
118
+ "inset-block-start",
119
+ "inset-block-end",
120
+ "border-width",
121
+ "border-top-width",
122
+ "border-right-width",
123
+ "border-bottom-width",
124
+ "border-left-width",
125
+ "outline-width",
126
+ "flex-basis",
127
+ "letter-spacing",
128
+ "text-indent"
112
129
  ]);
113
130
  var toPixelValue = (key, value) => {
114
131
  const stringValue = value.toString();
@@ -126,11 +143,12 @@ var flattenJSS = (jss) => {
126
143
  } else if (Array.isArray(jss)) {
127
144
  const result = {};
128
145
  for (const item of jss) {
129
- const styles15 = flattenJSS(item);
130
- for (const [key, value] of Object.entries(styles15)) {
146
+ const styles12 = flattenJSS(item);
147
+ for (const [key, value] of Object.entries(styles12)) {
131
148
  const current = result[key];
149
+ delete result[key];
132
150
  if (typeof current === "object" && current != null && typeof value === "object" && value != null) {
133
- result[key] = { ...current, ...value };
151
+ result[key] = flattenJSS([current, value]);
134
152
  } else {
135
153
  result[key] = value;
136
154
  }
@@ -138,22 +156,33 @@ var flattenJSS = (jss) => {
138
156
  }
139
157
  return result;
140
158
  } else {
141
- return jss;
159
+ const result = {};
160
+ for (const [key, value] of Object.entries(jss)) {
161
+ if (value == null) continue;
162
+ const entries = key === "padding" || key === "margin" ? spacingEntries(key, value) : [[key, typeof value === "object" ? flattenJSS(value) : value]];
163
+ for (const [property, entry] of entries) {
164
+ delete result[property];
165
+ result[property] = entry;
166
+ }
167
+ }
168
+ return result;
142
169
  }
143
170
  };
144
171
  var toClassnames = (jss, componentName) => {
145
172
  jss = flattenJSS(jss);
146
- const stylesStack = Object.entries(jss);
173
+ const spacing = {};
174
+ const stylesStack = Object.entries(jss).filter(([key, value]) => {
175
+ if (!/^(padding|margin)([A-Z-]|$)/.test(key)) return true;
176
+ spacing[key] = value;
177
+ return false;
178
+ });
179
+ if (Object.keys(spacing).length) stylesStack.push(["", spacing]);
147
180
  const classNames = [];
148
181
  if (componentName) {
149
182
  classNames.push(componentName);
150
183
  }
151
184
  while (stylesStack.length) {
152
185
  const [key, value] = stylesStack.pop();
153
- if (aliases[key]) {
154
- stylesStack.push(...aliases[key](value));
155
- continue;
156
- }
157
186
  const inputKey = (key.startsWith("@media") ? "specific:" : "") + key + JSON.stringify(value);
158
187
  const rawHash = hash(inputKey).toString(32);
159
188
  const cached = rawHashMap.get(rawHash);
@@ -194,15 +223,15 @@ function JSSProvider({
194
223
  themes,
195
224
  children
196
225
  }) {
197
- const [styles15] = useState(() => getBaseStyles(themes));
226
+ const [styles12] = useState(() => getBaseStyles(themes));
198
227
  return /* @__PURE__ */ jsxs(Fragment, { children: [
199
- styles15.map((style, i) => /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: style } }, i)),
228
+ styles12.map((style, i) => /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: style } }, i)),
200
229
  children
201
230
  ] });
202
231
  }
203
232
  function JSServerStyles() {
204
- const [styles15] = useState(() => serverStyles);
205
- return /* @__PURE__ */ jsx(Fragment, { children: styles15.map((style, i) => /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: style } }, i)) });
233
+ const [styles12] = useState(() => serverStyles);
234
+ return /* @__PURE__ */ jsx(Fragment, { children: styles12.map((style, i) => /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: style } }, i)) });
206
235
  }
207
236
  function cssVar(string) {
208
237
  return `var(${string})`;
@@ -303,7 +332,7 @@ var lightTheme = {
303
332
  /* Effects */
304
333
  ["--warning"]: "rgb(166, 107, 0)",
305
334
  ["--highlight"]: "rgb(0, 122, 255)",
306
- ["--outline"]: "rgb(103, 176, 255)",
335
+ ["--outline"]: "rgb(112, 140, 170)",
307
336
  ["--light-highlight"]: "rgb(220, 232, 245)",
308
337
  ["--light-highlight-hovered"]: "rgb(209, 226, 244)",
309
338
  ["--light-highlight-pressed"]: "rgb(197, 218, 240)",
@@ -367,7 +396,7 @@ var darkTheme = {
367
396
  /* Effects */
368
397
  ["--warning"]: "rgb(255, 204, 0)",
369
398
  ["--highlight"]: "rgb(50, 140, 220)",
370
- ["--outline"]: "rgb(91, 170, 255)",
399
+ ["--outline"]: "rgb(125, 170, 220)",
371
400
  ["--light-highlight"]: "rgba(49, 57, 63)",
372
401
  ["--light-highlight-hovered"]: "rgb(54, 68, 80)",
373
402
  ["--light-highlight-pressed"]: "rgb(60, 78, 96)",
@@ -422,10 +451,6 @@ var baseStyles = `
422
451
  -moz-osx-font-smoothing: grayscale;
423
452
  }
424
453
 
425
- *:focus {
426
- outline-color: ${cssVar("--highlight")};
427
- }
428
-
429
454
  button,
430
455
  input,
431
456
  textarea,
@@ -443,6 +468,7 @@ html {
443
468
  }
444
469
 
445
470
  body {
471
+ color: ${cssVar("--primary-text")};
446
472
  margin: 0;
447
473
  min-height: 100%;
448
474
  width: 100%;
@@ -481,6 +507,17 @@ body {
481
507
  }
482
508
  }
483
509
 
510
+ @media (prefers-reduced-motion: reduce) {
511
+ @keyframes dialogFadeIn { from { opacity: 1; } to { opacity: 1; } }
512
+ @keyframes popoverFadeIn { from { opacity: 1; } to { opacity: 1; } }
513
+ @keyframes backdropFadeIn { from { opacity: 1; } to { opacity: 1; } }
514
+ }
515
+
516
+ [data-aidos-action-scope]:is(:hover, :focus-within) [data-aidos-actions] {
517
+ opacity: 1;
518
+ pointer-events: auto;
519
+ }
520
+
484
521
  `;
485
522
  var backgroundStyles = {
486
523
  highlight: {
@@ -1039,8 +1076,7 @@ var styles3 = {
1039
1076
  backgroundColor: cssVar("--background-button-secondary")
1040
1077
  },
1041
1078
  ":focus-visible": {
1042
- outlineWidth: "2px",
1043
- outlineStyle: "solid",
1079
+ outline: `2px solid ${cssVar("--outline")}`,
1044
1080
  outlineOffset: 2
1045
1081
  }
1046
1082
  },
@@ -1101,6 +1137,7 @@ function getInteractableJSS({
1101
1137
  }) {
1102
1138
  return [
1103
1139
  styles3.root,
1140
+ getTextColor(getGlyphColor(color, disabled, bare)),
1104
1141
  color === "primary" && styles3.primary,
1105
1142
  color === "secondary" && styles3.secondary,
1106
1143
  color === "negative" && styles3.negative,
@@ -1252,6 +1289,7 @@ var BaseButton = React35.forwardRef(function BaseButton2({
1252
1289
  ref,
1253
1290
  onClick: (event) => {
1254
1291
  if (disabled) {
1292
+ event.preventDefault();
1255
1293
  return;
1256
1294
  }
1257
1295
  onClick?.(event);
@@ -1330,6 +1368,7 @@ var BaseLink = React35.forwardRef(function BaseLink2({
1330
1368
  ref,
1331
1369
  onClick: (event) => {
1332
1370
  if (disabled) {
1371
+ event.preventDefault();
1333
1372
  return;
1334
1373
  }
1335
1374
  onClick?.(event);
@@ -1480,7 +1519,11 @@ var BaseListItem = React35.forwardRef(function BaseListItem2({
1480
1519
  children,
1481
1520
  jss,
1482
1521
  headline,
1483
- headlineSize = "medium",
1522
+ size = "medium",
1523
+ indent,
1524
+ jssPrimary,
1525
+ jssAddOn,
1526
+ headlineSize = size === "small" || size === "xsmall" ? "small" : "medium",
1484
1527
  headlineColor = "primary",
1485
1528
  headlineAddOn,
1486
1529
  body,
@@ -1493,7 +1536,7 @@ var BaseListItem = React35.forwardRef(function BaseListItem2({
1493
1536
  iconJss,
1494
1537
  addOn,
1495
1538
  disabled = false,
1496
- padding = "medium",
1539
+ padding = size === "medium" || size === "large" ? "medium" : "small",
1497
1540
  gap = "medium",
1498
1541
  selected,
1499
1542
  headlineBold,
@@ -1525,7 +1568,8 @@ var BaseListItem = React35.forwardRef(function BaseListItem2({
1525
1568
  bodyColor: disabled || selected ? contentColor : bodyColor,
1526
1569
  bodyEllipsis,
1527
1570
  grow: true,
1528
- shrink: false
1571
+ shrink: false,
1572
+ jss: jssPrimary
1529
1573
  }
1530
1574
  );
1531
1575
  return /* @__PURE__ */ jsxs(
@@ -1534,9 +1578,15 @@ var BaseListItem = React35.forwardRef(function BaseListItem2({
1534
1578
  ...otherProps,
1535
1579
  ref,
1536
1580
  relative: true,
1581
+ "data-aidos-action-scope": true,
1537
1582
  tag: "li",
1538
1583
  role: "row",
1539
- jss: [getTextColor(contentColor), jss],
1584
+ jss: [
1585
+ getTextColor(contentColor),
1586
+ { minHeight: { xsmall: 28, small: 32, medium: 36, large: 44 }[size] },
1587
+ indent != null && { paddingInlineStart: indent },
1588
+ jss
1589
+ ],
1540
1590
  children: [
1541
1591
  /* @__PURE__ */ jsx(
1542
1592
  Row,
@@ -1549,7 +1599,17 @@ var BaseListItem = React35.forwardRef(function BaseListItem2({
1549
1599
  children: children({ content })
1550
1600
  }
1551
1601
  ),
1552
- addOn && /* @__PURE__ */ jsx(BaseListAddOn, { role: "gridcell", children: addOn })
1602
+ addOn && /* @__PURE__ */ jsx(
1603
+ BaseListAddOn,
1604
+ {
1605
+ role: "gridcell",
1606
+ jss: [
1607
+ { minWidth: 24, height: "auto", alignSelf: "stretch" },
1608
+ jssAddOn
1609
+ ],
1610
+ children: addOn
1611
+ }
1612
+ )
1553
1613
  ]
1554
1614
  }
1555
1615
  );
@@ -1570,6 +1630,14 @@ function Box({
1570
1630
  }
1571
1631
  );
1572
1632
  }
1633
+
1634
+ // src/controlSize.ts
1635
+ var controlSizes = {
1636
+ xsmall: { height: 24, icon: 12, padding: 6, text: "small" },
1637
+ small: { height: 28, icon: 14, padding: 8, text: "small" },
1638
+ medium: { height: 34, icon: 18, padding: 14, text: "medium" },
1639
+ large: { height: 40, icon: 20, padding: 16, text: "large" }
1640
+ };
1573
1641
  var Button = React35.forwardRef(function Button2({
1574
1642
  children,
1575
1643
  color,
@@ -1577,12 +1645,18 @@ var Button = React35.forwardRef(function Button2({
1577
1645
  disabled,
1578
1646
  icon,
1579
1647
  iconPosition = "left",
1648
+ size = "medium",
1649
+ leading,
1650
+ trailing,
1651
+ rowProps,
1580
1652
  align = "center",
1581
1653
  gap = "medium",
1582
1654
  justify = "center",
1583
1655
  jss,
1584
1656
  ...otherProps
1585
1657
  }, ref) {
1658
+ const metrics = controlSizes[size];
1659
+ const glyph = getGlyphColor(color, disabled, bare);
1586
1660
  return /* @__PURE__ */ jsx(
1587
1661
  BaseButton,
1588
1662
  {
@@ -1594,69 +1668,86 @@ var Button = React35.forwardRef(function Button2({
1594
1668
  padding: "none",
1595
1669
  jss: [
1596
1670
  {
1597
- height: 34,
1598
- padding: "0 14px",
1671
+ height: metrics.height,
1672
+ minWidth: 0,
1673
+ maxWidth: "100%",
1674
+ padding: `0 ${metrics.padding}px`,
1599
1675
  borderRadius: cssVar("--border-radius-l"),
1600
1676
  justifyContent: "center",
1601
1677
  userSelect: "none"
1602
1678
  },
1603
1679
  jss
1604
1680
  ],
1605
- children: /* @__PURE__ */ jsxs(Row, { grow: true, align, gap, justify, children: [
1606
- icon && iconPosition === "left" && /* @__PURE__ */ jsx(
1607
- Icon,
1608
- {
1609
- icon,
1610
- size: "medium",
1611
- color: getGlyphColor(color, disabled, bare)
1612
- }
1613
- ),
1614
- /* @__PURE__ */ jsx(
1615
- Text,
1616
- {
1617
- size: "medium",
1618
- color: getGlyphColor(color, disabled, bare),
1619
- jss: {
1620
- fontWeight: 600,
1621
- letterSpacing: "-0.01em"
1622
- },
1623
- children
1624
- }
1625
- ),
1626
- icon && iconPosition === "right" && /* @__PURE__ */ jsx(
1627
- Icon,
1628
- {
1629
- icon,
1630
- size: "medium",
1631
- color: getGlyphColor(color, disabled, bare)
1632
- }
1633
- )
1634
- ] })
1681
+ children: /* @__PURE__ */ jsxs(
1682
+ Row,
1683
+ {
1684
+ ...rowProps,
1685
+ direction: "row",
1686
+ grow: true,
1687
+ align,
1688
+ gap,
1689
+ justify,
1690
+ jss: [{ minWidth: 0 }, rowProps?.jss],
1691
+ children: [
1692
+ leading,
1693
+ icon && iconPosition === "left" && /* @__PURE__ */ jsx(
1694
+ Icon,
1695
+ {
1696
+ icon,
1697
+ size: "medium",
1698
+ jss: { width: metrics.icon, height: metrics.icon, flexShrink: 0 },
1699
+ color: glyph
1700
+ }
1701
+ ),
1702
+ /* @__PURE__ */ jsx(
1703
+ Text,
1704
+ {
1705
+ size: metrics.text,
1706
+ color: glyph,
1707
+ jss: {
1708
+ minWidth: 0,
1709
+ fontWeight: 600,
1710
+ letterSpacing: "-0.01em"
1711
+ },
1712
+ children
1713
+ }
1714
+ ),
1715
+ icon && iconPosition === "right" && /* @__PURE__ */ jsx(
1716
+ Icon,
1717
+ {
1718
+ icon,
1719
+ size: "medium",
1720
+ jss: { width: metrics.icon, height: metrics.icon, flexShrink: 0 },
1721
+ color: glyph
1722
+ }
1723
+ ),
1724
+ trailing
1725
+ ]
1726
+ }
1727
+ )
1635
1728
  }
1636
1729
  );
1637
1730
  });
1638
1731
 
1639
1732
  // src/aria.ts
1640
1733
  function queryFocusables(root) {
1641
- const focusables = Array.from(
1734
+ return Array.from(
1642
1735
  root.querySelectorAll(
1643
- "button,input,textarea,a,[tabindex='0'],[tabindex='-1']"
1736
+ 'button, input, textarea, select, a[href], [tabindex], [contenteditable="true"]'
1644
1737
  )
1738
+ ).filter(
1739
+ (element) => !element.matches(':disabled, input[type="hidden"]') && !element.closest("[inert], [hidden]") && element.getClientRects().length > 0 && getComputedStyle(element).visibility !== "hidden"
1645
1740
  );
1646
- return focusables.filter((element) => !element["disabled"]);
1647
1741
  }
1648
- var normalizeElements = (focusables, index) => {
1649
- for (const element2 of focusables) {
1650
- element2.tabIndex = -1;
1651
- }
1652
- const element = focusables[index] ?? focusables[focusables.length - 1];
1653
- element.tabIndex = 0;
1654
- };
1655
- var focusElement = (focusables, index) => {
1656
- normalizeElements(focusables, index);
1657
- const element = focusables[index] ?? focusables[focusables.length - 1];
1658
- element.focus();
1659
- };
1742
+ function normalizeElements(elements, index) {
1743
+ const selected = elements[Math.max(0, Math.min(index, elements.length - 1))];
1744
+ for (const element of elements)
1745
+ element.tabIndex = element === selected ? 0 : -1;
1746
+ }
1747
+ function focusElement(elements, index) {
1748
+ normalizeElements(elements, index);
1749
+ elements.find((element) => element.tabIndex === 0)?.focus();
1750
+ }
1660
1751
  function useRefEffect(callback) {
1661
1752
  const unsubscribeRef = useRef(null);
1662
1753
  return useCallback(
@@ -1680,81 +1771,74 @@ function useNavigation({
1680
1771
  autofocus = false,
1681
1772
  rowLength = 1,
1682
1773
  enabled = true,
1683
- initialIndex = 0
1774
+ initialIndex = 0,
1775
+ orientation = "both"
1684
1776
  } = {}) {
1685
1777
  return useRefEffect(
1686
1778
  useCallback(
1687
1779
  (root) => {
1688
- if (!enabled) {
1689
- return;
1690
- }
1691
- let index = Math.max(
1692
- 0,
1693
- Math.min(initialIndex, queryFocusables(root).length - 1)
1694
- );
1695
- const elements = queryFocusables(root);
1696
- if (elements.length === 0) {
1697
- return;
1698
- }
1699
- if (elements.length !== 0 && autofocus) {
1700
- focusElement(elements, index);
1701
- } else {
1780
+ if (!enabled) return;
1781
+ let current;
1782
+ const normalize = () => {
1783
+ const elements = queryFocusables(root);
1784
+ const activeIndex = elements.indexOf(
1785
+ document.activeElement
1786
+ );
1787
+ const previousIndex = elements.indexOf(current);
1788
+ const index = activeIndex >= 0 ? activeIndex : previousIndex >= 0 ? previousIndex : initialIndex;
1702
1789
  normalizeElements(elements, index);
1703
- }
1704
- const onKeyDown = (e) => {
1705
- const elements2 = queryFocusables(root);
1706
- if (elements2.length === 0) {
1790
+ current = elements.find((element) => element.tabIndex === 0);
1791
+ };
1792
+ normalize();
1793
+ if (autofocus) current?.focus();
1794
+ const focusin = () => normalize();
1795
+ const keydown = (event) => {
1796
+ if (event.defaultPrevented || event.isComposing || event.altKey || event.metaKey || event.ctrlKey)
1707
1797
  return;
1708
- }
1709
- let newIndex = -1;
1710
- if (e.code === "ArrowUp") {
1711
- if (index - rowLength < 0) {
1712
- newIndex = elements2.length - elements2.length % rowLength + index;
1713
- } else {
1714
- newIndex = index - rowLength;
1715
- }
1716
- } else if (e.code === "ArrowLeft") {
1717
- if (index <= 0) {
1718
- newIndex = elements2.length - 1;
1719
- } else {
1720
- newIndex = index - 1;
1721
- }
1722
- } else if (e.code === "ArrowRight") {
1723
- if (index >= elements2.length - 1) {
1724
- newIndex = 0;
1725
- } else {
1726
- newIndex = index + 1;
1727
- }
1728
- } else if (e.code === "ArrowDown") {
1729
- if (index + rowLength > elements2.length - 1) {
1730
- newIndex = (index + rowLength) % rowLength;
1731
- } else {
1732
- newIndex = index + rowLength;
1733
- }
1734
- }
1735
- if (newIndex !== -1 && index !== newIndex) {
1736
- index = newIndex;
1737
- focusElement(elements2, index);
1738
- e.preventDefault();
1739
- e.stopPropagation();
1740
- }
1798
+ const target = event.target;
1799
+ if (target.matches('input, textarea, select, [contenteditable="true"]'))
1800
+ return;
1801
+ const elements = queryFocusables(root);
1802
+ if (!elements.length) return;
1803
+ const index = Math.max(
1804
+ 0,
1805
+ elements.indexOf(document.activeElement)
1806
+ );
1807
+ let next;
1808
+ if (event.key === "Home") next = 0;
1809
+ else if (event.key === "End") next = elements.length - 1;
1810
+ else if (orientation !== "horizontal" && event.key === "ArrowDown")
1811
+ next = index + rowLength;
1812
+ else if (orientation !== "horizontal" && event.key === "ArrowUp")
1813
+ next = index - rowLength;
1814
+ else if (orientation !== "vertical" && event.key === "ArrowRight")
1815
+ next = index + 1;
1816
+ else if (orientation !== "vertical" && event.key === "ArrowLeft")
1817
+ next = index - 1;
1818
+ else return;
1819
+ event.preventDefault();
1820
+ event.stopPropagation();
1821
+ focusElement(
1822
+ elements,
1823
+ (next % elements.length + elements.length) % elements.length
1824
+ );
1741
1825
  };
1742
- root.addEventListener("keydown", onKeyDown);
1743
- const observer = new MutationObserver((mutationList) => {
1744
- if (mutationList.filter((m) => m.type === "childList").length > 0) {
1745
- const elements2 = queryFocusables(root);
1746
- if (elements2.length > 0) {
1747
- normalizeElements(elements2, index);
1748
- }
1749
- }
1826
+ root.addEventListener("focusin", focusin);
1827
+ root.addEventListener("keydown", keydown);
1828
+ const observer = new MutationObserver(normalize);
1829
+ observer.observe(root, {
1830
+ childList: true,
1831
+ subtree: true,
1832
+ attributes: true,
1833
+ attributeFilter: ["disabled", "aria-disabled", "hidden", "inert"]
1750
1834
  });
1751
- observer.observe(root, { childList: true });
1752
1835
  return () => {
1753
- root.removeEventListener("keydown", onKeyDown);
1754
1836
  observer.disconnect();
1837
+ root.removeEventListener("focusin", focusin);
1838
+ root.removeEventListener("keydown", keydown);
1755
1839
  };
1756
1840
  },
1757
- [autofocus, enabled, initialIndex, rowLength]
1841
+ [autofocus, rowLength, enabled, initialIndex, orientation]
1758
1842
  )
1759
1843
  );
1760
1844
  }
@@ -2099,7 +2183,17 @@ function Circle({
2099
2183
  }
2100
2184
  );
2101
2185
  }
2102
- var IconButton = React35.forwardRef(function IconButton2({ icon, color, bare, disabled, jss, label, ...buttonProps }, ref) {
2186
+ var IconButton = React35.forwardRef(function IconButton2({
2187
+ icon,
2188
+ color,
2189
+ bare,
2190
+ disabled,
2191
+ size = "medium",
2192
+ jss,
2193
+ label,
2194
+ ...buttonProps
2195
+ }, ref) {
2196
+ const metrics = controlSizes[size];
2103
2197
  return /* @__PURE__ */ jsxs(
2104
2198
  BaseButton,
2105
2199
  {
@@ -2111,9 +2205,12 @@ var IconButton = React35.forwardRef(function IconButton2({ icon, color, bare, di
2111
2205
  display: "flex",
2112
2206
  justifyContent: "center",
2113
2207
  alignItems: "center",
2114
- height: 34,
2115
- width: 34,
2116
- borderRadius: 17
2208
+ height: metrics.height,
2209
+ width: metrics.height,
2210
+ minWidth: metrics.height,
2211
+ flexShrink: 0,
2212
+ padding: 0,
2213
+ borderRadius: metrics.height / 2
2117
2214
  },
2118
2215
  jss
2119
2216
  ],
@@ -2125,6 +2222,7 @@ var IconButton = React35.forwardRef(function IconButton2({ icon, color, bare, di
2125
2222
  Icon,
2126
2223
  {
2127
2224
  size: "medium",
2225
+ jss: { width: metrics.icon, height: metrics.icon },
2128
2226
  icon,
2129
2227
  color: getGlyphColor(color, disabled, bare)
2130
2228
  }
@@ -2239,19 +2337,19 @@ var InputFrame = React35.forwardRef(function InputFrame2({ children, jss, ...row
2239
2337
  ":hover": {
2240
2338
  borderColor: cssVar("--strong-divider")
2241
2339
  },
2242
- ":has(:focus-visible)": {
2340
+ ":has(:is(input, textarea, select):focus-visible)": {
2243
2341
  borderColor: cssVar("--outline"),
2244
2342
  outline: `2px solid ${cssVar("--outline")}`,
2245
- outlineOffset: 1
2343
+ outlineOffset: -2
2246
2344
  },
2247
- ":has(:disabled)": {
2345
+ ":has(:is(input, textarea, select):disabled)": {
2248
2346
  backgroundColor: cssVar("--secondary-background"),
2249
2347
  borderColor: cssVar("--divider")
2250
2348
  },
2251
- ":has([aria-invalid=true])": {
2349
+ ":has(:is(input, textarea, select)[aria-invalid=true])": {
2252
2350
  borderColor: cssVar("--negative-text")
2253
2351
  },
2254
- ":has([aria-invalid=true]:focus-visible)": {
2352
+ ":has(:is(input, textarea, select)[aria-invalid=true]:focus-visible)": {
2255
2353
  outline: `2px solid ${cssVar("--negative-text")}`,
2256
2354
  outlineColor: cssVar("--negative-text")
2257
2355
  }
@@ -2333,97 +2431,185 @@ var NumericInputSegment = React35.forwardRef(
2333
2431
  );
2334
2432
  }
2335
2433
  );
2336
- var styles5 = {
2337
- popover: {
2338
- padding: 0,
2339
- zIndex: 1e3,
2340
- top: `calc(100% + ${cssVar("--spacing-xs")})`,
2341
- right: "auto",
2342
- left: 0,
2343
- margin: 0,
2344
- border: 0,
2345
- overflow: "visible",
2346
- background: "transparent",
2347
- animation: "popoverFadeIn 0.15s ease-out"
2348
- },
2349
- card: {
2350
- minWidth: 220,
2351
- maxWidth: "calc(100vw - 32px)",
2352
- overflow: "hidden"
2353
- }
2354
- };
2355
- function Popover({
2356
- children,
2357
- close
2358
- }) {
2359
- const activeElementRef = useRef(null);
2360
- const focusTrapRoot = useRefEffect(
2434
+ function useFloatingPosition(anchor, placement, align, onClose) {
2435
+ const reference = useRef(anchor);
2436
+ reference.current = anchor;
2437
+ const close = useRef(onClose);
2438
+ close.current = onClose;
2439
+ return useRefEffect(
2361
2440
  useCallback(
2362
- (root) => {
2363
- activeElementRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
2364
- const selectedElement = root.querySelector(
2365
- '[aria-selected="true"]'
2366
- );
2367
- const autofocusElement = root.querySelector(
2368
- '[data-autofocus="true"]'
2369
- );
2370
- const [firstElement] = queryFocusables(root);
2371
- const element = selectedElement ?? autofocusElement ?? firstElement;
2372
- if (element) {
2373
- element.focus();
2374
- } else {
2375
- root.focus();
2376
- }
2377
- const keydown = (e) => {
2378
- if (e.key === "Escape") {
2379
- close();
2380
- } else if (e.key === "Tab") {
2381
- const focusables = queryFocusables(root).filter(
2382
- (element2) => element2.tabIndex !== -1
2441
+ (element) => {
2442
+ const toggle = () => {
2443
+ if (!element.matches(":popover-open")) close.current();
2444
+ };
2445
+ element.addEventListener("toggle", toggle);
2446
+ element.showPopover?.();
2447
+ const update = () => {
2448
+ if (!reference.current.current) return;
2449
+ const rect = reference.current.current.getBoundingClientRect();
2450
+ const viewport = window.visualViewport;
2451
+ const left = viewport?.offsetLeft ?? 0;
2452
+ const top = viewport?.offsetTop ?? 0;
2453
+ const width = viewport?.width ?? window.innerWidth;
2454
+ const height = viewport?.height ?? window.innerHeight;
2455
+ const gap = 8;
2456
+ const edge = 12;
2457
+ element.style.setProperty(
2458
+ "--aidos-overlay-width",
2459
+ `${Math.max(0, width - edge * 2)}px`
2460
+ );
2461
+ element.style.setProperty(
2462
+ "--aidos-overlay-height",
2463
+ `${Math.max(0, height - edge * 2)}px`
2464
+ );
2465
+ const box = element.getBoundingClientRect();
2466
+ const space = {
2467
+ top: rect.top - top,
2468
+ bottom: top + height - rect.bottom,
2469
+ left: rect.left - left,
2470
+ right: left + width - rect.right
2471
+ };
2472
+ const opposite = {
2473
+ top: "bottom",
2474
+ bottom: "top",
2475
+ left: "right",
2476
+ right: "left"
2477
+ };
2478
+ const vertical = placement === "top" || placement === "bottom";
2479
+ const required = (vertical ? box.height : box.width) + gap + edge;
2480
+ const side = space[placement] < required && space[opposite[placement]] > space[placement] ? opposite[placement] : placement;
2481
+ const cross = (start, size, own) => align === "start" ? start : align === "end" ? start + size - own : start + (size - own) / 2;
2482
+ const available = Math.max(0, space[side] - gap - edge);
2483
+ const boxHeight = vertical ? Math.min(box.height, available) : box.height;
2484
+ const boxWidth = vertical ? box.width : Math.min(box.width, available);
2485
+ const x = vertical ? cross(rect.left, rect.width, boxWidth) : side === "left" ? rect.left - boxWidth - gap : rect.right + gap;
2486
+ const y = vertical ? side === "top" ? rect.top - boxHeight - gap : rect.bottom + gap : cross(rect.top, rect.height, boxHeight);
2487
+ element.style.left = `${Math.max(left + edge, Math.min(x, left + width - boxWidth - edge))}px`;
2488
+ element.style.top = `${Math.max(top + edge, Math.min(y, top + height - boxHeight - edge))}px`;
2489
+ if (vertical)
2490
+ element.style.setProperty(
2491
+ "--aidos-overlay-height",
2492
+ `${available}px`
2383
2493
  );
2384
- if (focusables.length === 0) {
2385
- e.stopPropagation();
2386
- e.preventDefault();
2387
- }
2388
- const focusedIndex = focusables.findIndex(
2389
- (x) => x === document.activeElement
2494
+ else
2495
+ element.style.setProperty(
2496
+ "--aidos-overlay-width",
2497
+ `${available}px`
2390
2498
  );
2391
- if (focusables.length === 0) {
2392
- e.stopPropagation();
2393
- e.preventDefault();
2394
- } else if (e.shiftKey && focusedIndex === 0) {
2395
- focusables[focusables.length - 1].focus();
2396
- e.stopPropagation();
2397
- e.preventDefault();
2398
- } else if (!e.shiftKey && focusedIndex === focusables.length - 1) {
2399
- focusables[0].focus();
2400
- e.stopPropagation();
2401
- e.preventDefault();
2402
- } else ;
2403
- }
2499
+ element.dataset.placement = side;
2404
2500
  };
2405
- const click = () => {
2406
- close();
2407
- };
2408
- const timeout = window.setTimeout(() => {
2409
- window.addEventListener("keydown", keydown);
2410
- window.addEventListener("click", click);
2411
- }, 0);
2501
+ update();
2502
+ const observer = new ResizeObserver(update);
2503
+ observer.observe(element);
2504
+ if (reference.current.current)
2505
+ observer.observe(reference.current.current);
2506
+ window.addEventListener("resize", update);
2507
+ window.addEventListener("scroll", update, true);
2508
+ window.visualViewport?.addEventListener("resize", update);
2509
+ window.visualViewport?.addEventListener("scroll", update);
2412
2510
  return () => {
2413
- window.clearTimeout(timeout);
2414
- activeElementRef.current?.focus();
2415
- window.removeEventListener("keydown", keydown);
2416
- window.removeEventListener("click", click);
2511
+ element.removeEventListener("toggle", toggle);
2512
+ observer.disconnect();
2513
+ window.removeEventListener("resize", update);
2514
+ window.removeEventListener("scroll", update, true);
2515
+ window.visualViewport?.removeEventListener("resize", update);
2516
+ window.visualViewport?.removeEventListener("scroll", update);
2417
2517
  };
2418
2518
  },
2419
- [close]
2519
+ [placement, align]
2420
2520
  )
2421
2521
  );
2422
- return /* @__PURE__ */ jsx(Card, { variant: "floating", padding: "small", gap: "none", jss: styles5.card, children: /* @__PURE__ */ jsx(BaseView, { ref: focusTrapRoot, jss: { width: "100%" }, children }) });
2522
+ }
2523
+ function Popover({
2524
+ children,
2525
+ close,
2526
+ initialFocus
2527
+ }) {
2528
+ const previous = useRef(null);
2529
+ const closeRef = useRef(close);
2530
+ closeRef.current = close;
2531
+ const initial = useRef(initialFocus);
2532
+ initial.current = initialFocus;
2533
+ const mount = useRefEffect(
2534
+ useCallback((root) => {
2535
+ previous.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
2536
+ let mounted = true;
2537
+ queueMicrotask(() => {
2538
+ if (!mounted || !root.getClientRects().length) return;
2539
+ const items = queryFocusables(root);
2540
+ const selected = root.querySelector(
2541
+ '[aria-selected="true"], [aria-checked="true"]'
2542
+ );
2543
+ (initial.current?.current ?? items.find(
2544
+ (item) => item.matches('[autofocus], [data-autofocus="true"]')
2545
+ ) ?? items.find((item) => item === selected || selected?.contains(item)) ?? items[0] ?? root).focus({ preventScroll: true });
2546
+ });
2547
+ const outside = (event) => {
2548
+ if (!root.contains(event.target) && !previous.current?.contains(event.target))
2549
+ closeRef.current();
2550
+ };
2551
+ const native = root.closest("[popover]");
2552
+ if (!native) document.addEventListener("pointerdown", outside);
2553
+ return () => {
2554
+ mounted = false;
2555
+ if (!native) document.removeEventListener("pointerdown", outside);
2556
+ if (root.contains(document.activeElement) && previous.current?.isConnected)
2557
+ previous.current.focus({ preventScroll: true });
2558
+ };
2559
+ }, [])
2560
+ );
2561
+ return /* @__PURE__ */ jsx(
2562
+ Card,
2563
+ {
2564
+ ref: mount,
2565
+ "data-aidos-popover": true,
2566
+ tabIndex: -1,
2567
+ variant: "floating",
2568
+ padding: "small",
2569
+ gap: "none",
2570
+ jss: {
2571
+ minWidth: "min(220px, calc(100vw - 24px))",
2572
+ maxWidth: "100%",
2573
+ borderRadius: "calc(var(--border-radius-s) + var(--spacing-s))",
2574
+ ":focus-visible": { outline: "none" }
2575
+ },
2576
+ onKeyDown: (event) => {
2577
+ if (event.defaultPrevented || event.nativeEvent.isComposing) return;
2578
+ if (event.key === "Escape") {
2579
+ event.stopPropagation();
2580
+ if (!event.currentTarget.closest("[popover]")?.showPopover) {
2581
+ event.preventDefault();
2582
+ close();
2583
+ }
2584
+ } else if (event.key === "Tab") {
2585
+ const items = queryFocusables(event.currentTarget).filter(
2586
+ (item) => item.tabIndex >= 0
2587
+ );
2588
+ const index = items.indexOf(document.activeElement);
2589
+ if (items.length && (event.shiftKey ? index > 0 : index >= 0 && index < items.length - 1))
2590
+ return;
2591
+ const outside = queryFocusables(document.body).filter(
2592
+ (item) => item.tabIndex >= 0 && !event.currentTarget.contains(item)
2593
+ );
2594
+ const next = outside[outside.indexOf(previous.current) + (event.shiftKey ? -1 : 1)];
2595
+ if (next) {
2596
+ event.preventDefault();
2597
+ next.focus();
2598
+ }
2599
+ close();
2600
+ }
2601
+ },
2602
+ children
2603
+ }
2604
+ );
2423
2605
  }
2424
2606
  function PopoverTrigger({
2425
2607
  PopoverComponent,
2608
+ content,
2426
2609
  ariaLabel,
2610
+ placement = "bottom",
2611
+ align = "start",
2612
+ role = "dialog",
2427
2613
  jss,
2428
2614
  jssDialog,
2429
2615
  grow,
@@ -2431,59 +2617,71 @@ function PopoverTrigger({
2431
2617
  tag,
2432
2618
  children
2433
2619
  }) {
2434
- const [popover, setPopover] = useState(null);
2435
- const dialogRef = useRef(null);
2436
- useEffect(() => {
2437
- if (popover == null) {
2438
- dialogRef.current?.close();
2439
- } else {
2440
- dialogRef.current?.show();
2441
- }
2442
- }, [popover]);
2620
+ const [open, setOpen] = useState(null);
2621
+ const anchor = useRef(null);
2622
+ const surface = useRef(null);
2623
+ const pointerOpen = useRef(false);
2624
+ const id = useId();
2625
+ const close = useCallback(() => setOpen(null), []);
2626
+ const position = useFloatingPosition(anchor, placement, align, close);
2443
2627
  const toggle = (input) => {
2444
- if (popover == null) {
2445
- setPopover(
2446
- /* @__PURE__ */ jsx(
2447
- PopoverComponent,
2448
- {
2449
- ...input,
2450
- close: () => {
2451
- setPopover(null);
2452
- }
2453
- }
2454
- )
2455
- );
2456
- } else {
2457
- setPopover(null);
2458
- }
2628
+ if (open || pointerOpen.current) close();
2629
+ else
2630
+ setOpen({
2631
+ element: PopoverComponent ? /* @__PURE__ */ jsx(PopoverComponent, { ...input, close }) : null
2632
+ });
2633
+ pointerOpen.current = false;
2459
2634
  };
2460
2635
  return /* @__PURE__ */ jsxs(
2461
2636
  BaseView,
2462
2637
  {
2638
+ ref: anchor,
2463
2639
  grow,
2464
2640
  shrink,
2465
2641
  tag,
2466
- relative: true,
2467
- jss: [jss, { position: "relative", display: "inline-block" }],
2642
+ jss: [{ display: "inline-block", minWidth: 0 }, jss],
2643
+ onPointerDown: (event) => {
2644
+ if (!surface.current?.contains(event.target))
2645
+ pointerOpen.current = Boolean(open);
2646
+ },
2468
2647
  children: [
2469
- children({ toggle, expanded: popover != null }),
2470
- /* @__PURE__ */ jsx(
2471
- "dialog",
2472
- {
2473
- "aria-label": ariaLabel,
2474
- ref: (ref) => {
2475
- dialogRef.current = ref;
2476
- },
2477
- className: toClassnames([styles5.popover, jssDialog]),
2478
- onClose: () => {
2479
- setPopover(null);
2480
- },
2481
- onClick: (e) => {
2482
- e.preventDefault();
2483
- e.stopPropagation();
2484
- },
2485
- children: popover
2486
- }
2648
+ children({ toggle, expanded: open != null, id }),
2649
+ open && createPortal(
2650
+ /* @__PURE__ */ jsx(
2651
+ "div",
2652
+ {
2653
+ id,
2654
+ role,
2655
+ "aria-label": ariaLabel,
2656
+ popover: "auto",
2657
+ ref: (element) => {
2658
+ surface.current = element;
2659
+ position(element);
2660
+ },
2661
+ className: toClassnames([
2662
+ {
2663
+ position: "fixed",
2664
+ inset: "auto",
2665
+ padding: 0,
2666
+ margin: 0,
2667
+ border: "1px solid var(--divider)",
2668
+ boxShadow: "var(--shadow-md)",
2669
+ zIndex: 1e3,
2670
+ width: "max-content",
2671
+ maxWidth: "var(--aidos-overlay-width, calc(100vw - 24px))",
2672
+ maxHeight: "var(--aidos-overlay-height, calc(100dvh - 24px))",
2673
+ overflow: "auto",
2674
+ background: "var(--overlay-background)",
2675
+ color: "var(--primary-text)",
2676
+ borderRadius: "calc(var(--border-radius-s) + var(--spacing-s) + 1px)",
2677
+ " [data-aidos-popover]": { boxShadow: "none" }
2678
+ },
2679
+ jssDialog
2680
+ ]),
2681
+ children: content != null ? /* @__PURE__ */ jsx(Popover, { close, children: typeof content === "function" ? content({ close }) : content }) : open.element
2682
+ }
2683
+ ),
2684
+ anchor.current.closest("dialog[open], [popover]") ?? document.body
2487
2685
  )
2488
2686
  ]
2489
2687
  }
@@ -2983,7 +3181,7 @@ var DateInput = React35.forwardRef(function DateInput2({
2983
3181
  field
2984
3182
  ] });
2985
3183
  });
2986
- var styles6 = {
3184
+ var styles5 = {
2987
3185
  root: {
2988
3186
  backgroundColor: "var(--primary-background)"
2989
3187
  },
@@ -2992,7 +3190,10 @@ var styles6 = {
2992
3190
  flexGrow: 1,
2993
3191
  backgroundColor: "var(--primary-background)",
2994
3192
  color: "var(--primary-text)",
2995
- outline: "none",
3193
+ ":focus-visible": {
3194
+ outline: "2px solid var(--outline)",
3195
+ outlineOffset: -2
3196
+ },
2996
3197
  border: "none",
2997
3198
  fontSize: 20,
2998
3199
  lineHeight: 24 / 20,
@@ -3005,7 +3206,7 @@ var styles6 = {
3005
3206
  }
3006
3207
  };
3007
3208
  var DatetimeInput = React35.forwardRef(function DatetimeInput2({ date, onDateChange, jss, icon, addOn, ...inputProps }, ref) {
3008
- return /* @__PURE__ */ jsxs(Row, { jss: styles6.root, children: [
3209
+ return /* @__PURE__ */ jsxs(Row, { jss: styles5.root, children: [
3009
3210
  icon && /* @__PURE__ */ jsx(Box, { padding: "medium", children: /* @__PURE__ */ jsx(Icon, { size: "medium", color: "secondary", icon }) }),
3010
3211
  /* @__PURE__ */ jsx(
3011
3212
  BaseInput,
@@ -3019,81 +3220,142 @@ var DatetimeInput = React35.forwardRef(function DatetimeInput2({ date, onDateCha
3019
3220
  onDateChange(parseDatetimeInputValue(e.target.value));
3020
3221
  }
3021
3222
  },
3022
- jss: [styles6.input, jss]
3223
+ jss: [styles5.input, jss]
3023
3224
  }
3024
3225
  ),
3025
3226
  addOn
3026
3227
  ] });
3027
3228
  });
3028
- var styles7 = {
3029
- root: {
3030
- width: "100%",
3031
- borderBottom: "1px solid var(--divider)"
3032
- }
3033
- };
3034
- function ListDivider() {
3035
- return /* @__PURE__ */ jsx(BaseView, { jss: styles7.root });
3229
+ var DialogTitleContext = createContext(void 0);
3230
+ function Modal({ open, ...props }) {
3231
+ return open ? /* @__PURE__ */ jsx(ModalSurface, { ...props }) : null;
3036
3232
  }
3037
- var styles8 = {
3038
- dialog: {
3039
- border: "1px solid var(--divider)",
3040
- borderRadius: "var(--border-radius-l)",
3041
- padding: 0,
3042
- boxShadow: "var(--shadow-lg)",
3043
- animation: "dialogFadeIn 0.2s ease-out",
3044
- "::backdrop": {
3045
- backgroundColor: "rgba(0, 0, 0, 0.4)",
3046
- animation: "backdropFadeIn 0.2s ease-out"
3047
- }
3048
- },
3049
- root: {
3050
- display: "grid",
3051
- width: "calc(100vw - 48px)",
3052
- gridTemplateAreas: `
3053
- "header"
3054
- "content"
3055
- `,
3056
- "@media (min-width: 750px)": {
3057
- maxWidth: 750
3058
- },
3059
- backgroundColor: "var(--secondary-background)"
3060
- },
3061
- header: {
3062
- gridArea: "header"
3063
- },
3064
- content: {
3065
- gridArea: "content"
3066
- }
3067
- };
3068
- var Dialog = ({
3233
+ function ModalSurface({
3069
3234
  label,
3070
3235
  children,
3071
- close
3072
- }) => {
3073
- return /* @__PURE__ */ jsxs(BaseView, { jss: styles8.root, children: [
3074
- /* @__PURE__ */ jsxs(Column, { jss: styles8.header, children: [
3075
- /* @__PURE__ */ jsxs(Row, { padding: "medium", justify: "space-between", align: "center", children: [
3076
- /* @__PURE__ */ jsx(Text, { size: "medium", color: "secondary", children: label }),
3077
- /* @__PURE__ */ jsx(
3078
- IconButton,
3079
- {
3080
- autoFocus: true,
3081
- bare: true,
3082
- icon: "x",
3083
- onClick: close,
3084
- color: "secondary"
3085
- }
3086
- )
3087
- ] }),
3088
- /* @__PURE__ */ jsx(ListDivider, {})
3089
- ] }),
3090
- /* @__PURE__ */ jsx(BaseView, { jss: styles8.content, children })
3091
- ] });
3092
- };
3093
- var DialogContext = React35.createContext({
3094
- setDialog: () => {
3095
- }
3096
- });
3236
+ onClose,
3237
+ onAfterClose,
3238
+ closeOnOutsideClick = true,
3239
+ initialFocus,
3240
+ jss
3241
+ }) {
3242
+ const titleId = useId();
3243
+ const afterClose = useRef(onAfterClose);
3244
+ afterClose.current = onAfterClose;
3245
+ const initial = useRef(initialFocus);
3246
+ initial.current = initialFocus;
3247
+ const mount = useRefEffect(
3248
+ useCallback((element) => {
3249
+ const previous = document.activeElement;
3250
+ element.showModal();
3251
+ initial.current?.current?.focus({ preventScroll: true });
3252
+ return () => {
3253
+ element.close();
3254
+ queueMicrotask(() => {
3255
+ if (element.isConnected && element.open) return;
3256
+ if (previous instanceof HTMLElement && previous.isConnected && (document.activeElement === document.body || element.contains(document.activeElement)))
3257
+ previous.focus({ preventScroll: true });
3258
+ afterClose.current?.();
3259
+ });
3260
+ };
3261
+ }, [])
3262
+ );
3263
+ return /* @__PURE__ */ jsx(
3264
+ "dialog",
3265
+ {
3266
+ ref: mount,
3267
+ "aria-label": label,
3268
+ "aria-labelledby": label ? void 0 : titleId,
3269
+ onCancel: (event) => {
3270
+ event.preventDefault();
3271
+ onClose();
3272
+ },
3273
+ onClose: (event) => {
3274
+ if (!event.currentTarget.open) onClose();
3275
+ },
3276
+ onClick: (event) => {
3277
+ if (!closeOnOutsideClick || event.target !== event.currentTarget)
3278
+ return;
3279
+ const box = event.currentTarget.getBoundingClientRect();
3280
+ if (event.clientX < box.left || event.clientX > box.right || event.clientY < box.top || event.clientY > box.bottom)
3281
+ onClose();
3282
+ },
3283
+ className: toClassnames([
3284
+ {
3285
+ padding: 0,
3286
+ border: "1px solid var(--divider)",
3287
+ borderRadius: "var(--border-radius-xl)",
3288
+ background: "var(--overlay-background)",
3289
+ color: "var(--primary-text)",
3290
+ maxWidth: "calc(100vw - 32px)",
3291
+ maxHeight: "calc(100dvh - 32px)",
3292
+ boxShadow: "var(--shadow-lg)",
3293
+ overflow: "auto",
3294
+ "::backdrop": { background: "rgba(0, 0, 0, 0.3)" }
3295
+ },
3296
+ jss
3297
+ ]),
3298
+ children: /* @__PURE__ */ jsx(DialogTitleContext.Provider, { value: titleId, children })
3299
+ }
3300
+ );
3301
+ }
3302
+ function Dialog({
3303
+ label,
3304
+ children,
3305
+ close,
3306
+ header,
3307
+ footer
3308
+ }) {
3309
+ const titleId = useContext(DialogTitleContext);
3310
+ return /* @__PURE__ */ jsxs(
3311
+ Column,
3312
+ {
3313
+ gap: "none",
3314
+ jss: {
3315
+ width: "min(640px, calc(100vw - 34px))",
3316
+ maxHeight: "calc(100dvh - 34px)"
3317
+ },
3318
+ children: [
3319
+ header === void 0 ? /* @__PURE__ */ jsxs(
3320
+ Row,
3321
+ {
3322
+ padding: "medium",
3323
+ align: "center",
3324
+ justify: "space-between",
3325
+ jss: { flexShrink: 0, borderBottom: "1px solid var(--divider)" },
3326
+ children: [
3327
+ /* @__PURE__ */ jsx(Text, { id: titleId, type: "h2", size: "medium", bold: true, children: label }),
3328
+ /* @__PURE__ */ jsx(
3329
+ IconButton,
3330
+ {
3331
+ "aria-label": "Close dialog",
3332
+ size: "small",
3333
+ bare: true,
3334
+ icon: "x",
3335
+ onClick: close,
3336
+ color: "secondary"
3337
+ }
3338
+ )
3339
+ ]
3340
+ }
3341
+ ) : header,
3342
+ /* @__PURE__ */ jsx(BaseView, { jss: { minHeight: 0, overflowY: "auto" }, children }),
3343
+ footer && /* @__PURE__ */ jsx(
3344
+ Row,
3345
+ {
3346
+ padding: "large",
3347
+ gap: "small",
3348
+ justify: "flex-end",
3349
+ jss: { flexShrink: 0, borderTop: "1px solid var(--divider)" },
3350
+ children: footer
3351
+ }
3352
+ )
3353
+ ]
3354
+ }
3355
+ );
3356
+ }
3357
+ var DialogContext = createContext({ setDialog: () => {
3358
+ } });
3097
3359
  function DialogProvider({ children }) {
3098
3360
  const [dialog, setDialog] = useState(null);
3099
3361
  const value = useMemo(() => ({ setDialog }), []);
@@ -3104,50 +3366,20 @@ function DialogProvider({ children }) {
3104
3366
  }
3105
3367
  function useDialog(DialogComponent, options) {
3106
3368
  const { setDialog } = useContext(DialogContext);
3107
- const dialogRef = useRef(null);
3108
- const activeElementRef = useRef(null);
3109
- const close = useCallback(() => {
3110
- dialogRef.current?.close();
3111
- activeElementRef.current?.focus();
3112
- dialogRef.current = null;
3113
- activeElementRef.current = null;
3114
- setDialog(null);
3115
- }, [setDialog]);
3116
- const open = (input) => {
3117
- activeElementRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
3118
- setDialog(
3119
- /* @__PURE__ */ jsx(
3120
- "dialog",
3121
- {
3122
- ref: (ref) => {
3123
- dialogRef.current = ref;
3124
- ref?.showModal();
3125
- },
3126
- className: toClassnames(styles8.dialog),
3127
- onClose: () => {
3128
- close();
3129
- },
3130
- onClick: (e) => {
3131
- if (dialogRef.current == null) {
3132
- return;
3133
- }
3134
- const dialogDimensions = dialogRef.current.getBoundingClientRect();
3135
- if (options.closeOnOutsideClick === false) {
3136
- return;
3137
- }
3138
- if (e.clientX < dialogDimensions.left || e.clientX > dialogDimensions.right || e.clientY > dialogDimensions.bottom || e.clientY < dialogDimensions.top) {
3139
- dialogRef.current.close();
3140
- }
3141
- },
3142
- children: /* @__PURE__ */ jsx(DialogComponent, { ...input, close })
3143
- }
3144
- )
3145
- );
3146
- };
3147
- return {
3148
- open,
3149
- close
3150
- };
3369
+ const close = useCallback(() => setDialog(null), [setDialog]);
3370
+ const open = (input) => setDialog(
3371
+ /* @__PURE__ */ jsx(
3372
+ Modal,
3373
+ {
3374
+ open: true,
3375
+ label: options.label,
3376
+ onClose: close,
3377
+ closeOnOutsideClick: options.closeOnOutsideClick,
3378
+ children: /* @__PURE__ */ jsx(DialogComponent, { ...input, close })
3379
+ }
3380
+ )
3381
+ );
3382
+ return { open, close };
3151
3383
  }
3152
3384
 
3153
3385
  // src/Emitter.ts
@@ -3177,7 +3409,16 @@ function guid() {
3177
3409
  return v.toString(16);
3178
3410
  });
3179
3411
  }
3180
- var IconLink = React35.forwardRef(function IconLink2({ icon, color, bare, disabled, jss, ...otherProps }, ref) {
3412
+ var IconLink = React35.forwardRef(function IconLink2({
3413
+ icon,
3414
+ color,
3415
+ bare,
3416
+ disabled,
3417
+ size = "medium",
3418
+ jss,
3419
+ ...otherProps
3420
+ }, ref) {
3421
+ const metrics = controlSizes[size];
3181
3422
  return /* @__PURE__ */ jsx(
3182
3423
  BaseLink,
3183
3424
  {
@@ -3188,9 +3429,12 @@ var IconLink = React35.forwardRef(function IconLink2({ icon, color, bare, disabl
3188
3429
  display: "flex",
3189
3430
  justifyContent: "center",
3190
3431
  alignItems: "center",
3191
- height: 34,
3192
- width: 34,
3193
- borderRadius: 17,
3432
+ height: metrics.height,
3433
+ width: metrics.height,
3434
+ minWidth: metrics.height,
3435
+ flexShrink: 0,
3436
+ padding: 0,
3437
+ borderRadius: metrics.height / 2,
3194
3438
  textDecoration: "none"
3195
3439
  },
3196
3440
  jss
@@ -3202,6 +3446,7 @@ var IconLink = React35.forwardRef(function IconLink2({ icon, color, bare, disabl
3202
3446
  Icon,
3203
3447
  {
3204
3448
  size: "medium",
3449
+ jss: { width: metrics.icon, height: metrics.icon },
3205
3450
  icon,
3206
3451
  color: getGlyphColor(color, disabled, bare)
3207
3452
  }
@@ -3217,6 +3462,10 @@ var Link = React35.forwardRef(function Link2({
3217
3462
  icon,
3218
3463
  underline,
3219
3464
  iconPosition = "left",
3465
+ size = "medium",
3466
+ leading,
3467
+ trailing,
3468
+ rowProps,
3220
3469
  align = "center",
3221
3470
  gap = "medium",
3222
3471
  justify = "center",
@@ -3224,6 +3473,8 @@ var Link = React35.forwardRef(function Link2({
3224
3473
  inline = true,
3225
3474
  ...otherProps
3226
3475
  }, ref) {
3476
+ const metrics = controlSizes[size];
3477
+ const glyph = getGlyphColor(color, disabled, bare);
3227
3478
  return /* @__PURE__ */ jsx(
3228
3479
  BaseLink,
3229
3480
  {
@@ -3235,8 +3486,10 @@ var Link = React35.forwardRef(function Link2({
3235
3486
  padding: "none",
3236
3487
  jss: [
3237
3488
  {
3238
- height: 34,
3239
- padding: "0 14px",
3489
+ height: metrics.height,
3490
+ minWidth: 0,
3491
+ maxWidth: "100%",
3492
+ padding: `0 ${metrics.padding}px`,
3240
3493
  borderRadius: cssVar("--border-radius-l"),
3241
3494
  justifyContent: "center",
3242
3495
  userSelect: "none",
@@ -3254,28 +3507,37 @@ var Link = React35.forwardRef(function Link2({
3254
3507
  children: /* @__PURE__ */ jsxs(
3255
3508
  Row,
3256
3509
  {
3257
- jss: {
3258
- display: inline ? "inline-flex" : "flex"
3259
- },
3510
+ ...rowProps,
3511
+ direction: "row",
3512
+ jss: [
3513
+ {
3514
+ display: inline ? "inline-flex" : "flex",
3515
+ minWidth: 0
3516
+ },
3517
+ rowProps?.jss
3518
+ ],
3260
3519
  grow: true,
3261
3520
  align,
3262
3521
  gap,
3263
3522
  justify,
3264
3523
  children: [
3524
+ leading,
3265
3525
  icon && iconPosition === "left" && /* @__PURE__ */ jsx(
3266
3526
  Icon,
3267
3527
  {
3268
3528
  icon,
3269
3529
  size: "medium",
3270
- color: getGlyphColor(color, disabled, bare)
3530
+ jss: { width: metrics.icon, height: metrics.icon, flexShrink: 0 },
3531
+ color: glyph
3271
3532
  }
3272
3533
  ),
3273
3534
  /* @__PURE__ */ jsx(
3274
3535
  Text,
3275
3536
  {
3276
- size: "medium",
3277
- color: getGlyphColor(color, disabled, bare),
3537
+ size: metrics.text,
3538
+ color: glyph,
3278
3539
  jss: {
3540
+ minWidth: 0,
3279
3541
  fontWeight: 600,
3280
3542
  letterSpacing: "-0.01em"
3281
3543
  },
@@ -3287,9 +3549,11 @@ var Link = React35.forwardRef(function Link2({
3287
3549
  {
3288
3550
  icon,
3289
3551
  size: "medium",
3290
- color: getGlyphColor(color, disabled, bare)
3552
+ jss: { width: metrics.icon, height: metrics.icon, flexShrink: 0 },
3553
+ color: glyph
3291
3554
  }
3292
- )
3555
+ ),
3556
+ trailing
3293
3557
  ]
3294
3558
  }
3295
3559
  )
@@ -3321,7 +3585,13 @@ var ListButtonItem = React35.forwardRef(function ListButtonItem2({
3321
3585
  onClick,
3322
3586
  color = "secondary",
3323
3587
  disabled = false,
3324
- padding = "medium",
3588
+ size = "medium",
3589
+ padding = size === "medium" || size === "large" ? "medium" : "small",
3590
+ jssPrimary,
3591
+ "aria-expanded": ariaExpanded,
3592
+ "aria-controls": ariaControls,
3593
+ "aria-haspopup": ariaHasPopup,
3594
+ "aria-label": ariaLabel,
3325
3595
  jss,
3326
3596
  gap,
3327
3597
  selected,
@@ -3331,6 +3601,7 @@ var ListButtonItem = React35.forwardRef(function ListButtonItem2({
3331
3601
  return /* @__PURE__ */ jsx(
3332
3602
  BaseListItem,
3333
3603
  {
3604
+ size,
3334
3605
  disabled,
3335
3606
  padding: "none",
3336
3607
  gap,
@@ -3357,7 +3628,17 @@ var ListButtonItem = React35.forwardRef(function ListButtonItem2({
3357
3628
  color,
3358
3629
  ref,
3359
3630
  "data-list-primary": true,
3360
- jss: interactableListItemContentJSS,
3631
+ "aria-expanded": ariaExpanded,
3632
+ "aria-controls": ariaControls,
3633
+ "aria-haspopup": ariaHasPopup,
3634
+ "aria-label": ariaLabel,
3635
+ jss: [
3636
+ interactableListItemContentJSS,
3637
+ {
3638
+ minHeight: { xsmall: 28, small: 32, medium: 36, large: 44 }[size]
3639
+ },
3640
+ jssPrimary
3641
+ ],
3361
3642
  onClick,
3362
3643
  children: content
3363
3644
  }
@@ -3365,6 +3646,15 @@ var ListButtonItem = React35.forwardRef(function ListButtonItem2({
3365
3646
  }
3366
3647
  );
3367
3648
  });
3649
+ var styles6 = {
3650
+ root: {
3651
+ width: "100%",
3652
+ borderBottom: "1px solid var(--divider)"
3653
+ }
3654
+ };
3655
+ function ListDivider() {
3656
+ return /* @__PURE__ */ jsx(BaseView, { jss: styles6.root });
3657
+ }
3368
3658
  function ListHeaderItem({
3369
3659
  highlight,
3370
3660
  headline,
@@ -3396,7 +3686,13 @@ var ListLinkItem = React35.forwardRef(function ListLinkItem2({
3396
3686
  onClick,
3397
3687
  href,
3398
3688
  disabled = false,
3399
- padding = "medium",
3689
+ size = "medium",
3690
+ padding = size === "medium" || size === "large" ? "medium" : "small",
3691
+ jssPrimary,
3692
+ "aria-expanded": ariaExpanded,
3693
+ "aria-controls": ariaControls,
3694
+ "aria-haspopup": ariaHasPopup,
3695
+ "aria-label": ariaLabel,
3400
3696
  jss,
3401
3697
  gap,
3402
3698
  selected,
@@ -3408,6 +3704,7 @@ var ListLinkItem = React35.forwardRef(function ListLinkItem2({
3408
3704
  return /* @__PURE__ */ jsx(
3409
3705
  BaseListItem,
3410
3706
  {
3707
+ size,
3411
3708
  disabled,
3412
3709
  "aria-selected": selected,
3413
3710
  padding: "none",
@@ -3437,7 +3734,17 @@ var ListLinkItem = React35.forwardRef(function ListLinkItem2({
3437
3734
  href,
3438
3735
  ref,
3439
3736
  "data-list-primary": true,
3440
- jss: interactableListItemContentJSS,
3737
+ "aria-expanded": ariaExpanded,
3738
+ "aria-controls": ariaControls,
3739
+ "aria-haspopup": ariaHasPopup,
3740
+ "aria-label": ariaLabel,
3741
+ jss: [
3742
+ interactableListItemContentJSS,
3743
+ {
3744
+ minHeight: { xsmall: 28, small: 32, medium: 36, large: 44 }[size]
3745
+ },
3746
+ jssPrimary
3747
+ ],
3441
3748
  onClick,
3442
3749
  children: content
3443
3750
  }
@@ -3445,7 +3752,7 @@ var ListLinkItem = React35.forwardRef(function ListLinkItem2({
3445
3752
  }
3446
3753
  );
3447
3754
  });
3448
- var styles9 = {
3755
+ var styles7 = {
3449
3756
  root: {
3450
3757
  height: "var(--spacing-xl)",
3451
3758
  backgroundColor: "var(--secondary-background)",
@@ -3453,7 +3760,7 @@ var styles9 = {
3453
3760
  }
3454
3761
  };
3455
3762
  function ListSpacer() {
3456
- return /* @__PURE__ */ jsx(BaseView, { jss: styles9.root });
3763
+ return /* @__PURE__ */ jsx(BaseView, { jss: styles7.root });
3457
3764
  }
3458
3765
  function MenuIcon({ open, color }) {
3459
3766
  return /* @__PURE__ */ jsxs(Column, { gap: "small", children: [
@@ -3754,7 +4061,7 @@ function OnVisible({
3754
4061
  }, [onVisible]);
3755
4062
  return children(refCallback);
3756
4063
  }
3757
- var styles10 = {
4064
+ var styles8 = {
3758
4065
  root: {
3759
4066
  width: "100%",
3760
4067
  position: "relative",
@@ -3798,18 +4105,18 @@ function ProgressBar({
3798
4105
  "aria-valuemin": 0,
3799
4106
  "aria-valuemax": 100,
3800
4107
  "aria-valuenow": Math.round(value * 100),
3801
- jss: [styles10.root, { height: sizes4[size] }, jss],
4108
+ jss: [styles8.root, { height: sizes4[size] }, jss],
3802
4109
  children: /* @__PURE__ */ jsx(
3803
4110
  BaseView,
3804
4111
  {
3805
- jss: [styles10.fill, getBackground(color)],
4112
+ jss: [styles8.fill, getBackground(color)],
3806
4113
  style: { transform: `scaleX(${value})` }
3807
4114
  }
3808
4115
  )
3809
4116
  }
3810
4117
  );
3811
4118
  }
3812
- var styles11 = {
4119
+ var styles9 = {
3813
4120
  root: {
3814
4121
  display: "block"
3815
4122
  },
@@ -3853,7 +4160,7 @@ function ProgressCircle({
3853
4160
  "aria-valuemin": 0,
3854
4161
  "aria-valuemax": 100,
3855
4162
  "aria-valuenow": Math.round(value * 100),
3856
- className: toClassnames([styles11.root, jss]),
4163
+ className: toClassnames([styles9.root, jss]),
3857
4164
  width: diameter,
3858
4165
  height: diameter,
3859
4166
  viewBox: `0 0 ${diameter} ${diameter}`,
@@ -3861,7 +4168,7 @@ function ProgressCircle({
3861
4168
  /* @__PURE__ */ jsx(
3862
4169
  "circle",
3863
4170
  {
3864
- className: toClassnames(styles11.track),
4171
+ className: toClassnames(styles9.track),
3865
4172
  strokeWidth: stroke,
3866
4173
  r: radius,
3867
4174
  cx: center,
@@ -3871,7 +4178,7 @@ function ProgressCircle({
3871
4178
  /* @__PURE__ */ jsx(
3872
4179
  "circle",
3873
4180
  {
3874
- className: toClassnames(styles11.fill),
4181
+ className: toClassnames(styles9.fill),
3875
4182
  stroke: getColorValue(color),
3876
4183
  strokeWidth: stroke,
3877
4184
  strokeLinecap: value === 0 ? "butt" : "round",
@@ -4407,32 +4714,90 @@ function useStream({
4407
4714
  frame
4408
4715
  };
4409
4716
  }
4717
+ function Disclosure({
4718
+ expanded,
4719
+ children,
4720
+ jss,
4721
+ ...props
4722
+ }) {
4723
+ const [present, setPresent] = useState(expanded);
4724
+ if (expanded && !present) setPresent(true);
4725
+ const mount = useRefEffect(
4726
+ useCallback(
4727
+ (element) => {
4728
+ element.inert = !expanded;
4729
+ if (expanded) return;
4730
+ let current = true;
4731
+ element.getBoundingClientRect();
4732
+ const animations = element.getAnimations();
4733
+ void Promise.allSettled(
4734
+ animations.map((animation) => animation.finished)
4735
+ ).then(() => {
4736
+ if (current) setPresent(false);
4737
+ });
4738
+ return () => {
4739
+ current = false;
4740
+ };
4741
+ },
4742
+ [expanded]
4743
+ )
4744
+ );
4745
+ return /* @__PURE__ */ jsx(
4746
+ BaseView,
4747
+ {
4748
+ ...props,
4749
+ ref: mount,
4750
+ "aria-hidden": !expanded,
4751
+ jss: [
4752
+ {
4753
+ display: "grid",
4754
+ gridTemplateRows: expanded ? "1fr" : "0fr",
4755
+ minWidth: 0,
4756
+ transition: "grid-template-rows 180ms cubic-bezier(0.2, 0.8, 0.2, 1)",
4757
+ "@media (prefers-reduced-motion: reduce)": { transition: "none" }
4758
+ },
4759
+ jss
4760
+ ],
4761
+ children: /* @__PURE__ */ jsx(BaseView, { jss: { minHeight: 0, overflow: "hidden" }, children: (expanded || present) && children })
4762
+ }
4763
+ );
4764
+ }
4410
4765
  function Sublist({
4411
4766
  children,
4412
4767
  label,
4413
4768
  labelBold,
4414
4769
  initialState = { collapsed: false },
4770
+ expanded: controlledExpanded,
4771
+ onExpandedChange,
4415
4772
  jss
4416
4773
  }) {
4417
- const [collapsed, setCollapsed] = React35.useState(initialState.collapsed);
4774
+ const [localExpanded, setExpanded] = useState(!initialState.collapsed);
4775
+ const expanded = controlledExpanded ?? localExpanded;
4776
+ const id = useId();
4418
4777
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4419
4778
  /* @__PURE__ */ jsx(
4420
4779
  ListButtonItem,
4421
4780
  {
4422
4781
  headline: label,
4423
4782
  headlineBold: labelBold,
4424
- onClick: () => setCollapsed((x) => !x),
4783
+ "aria-expanded": expanded,
4784
+ "aria-controls": id,
4785
+ onClick: () => {
4786
+ if (controlledExpanded === void 0) setExpanded(!expanded);
4787
+ onExpandedChange?.(!expanded);
4788
+ },
4425
4789
  jss,
4426
4790
  icon: "chevron-right",
4427
4791
  iconPosition: "end",
4428
4792
  iconJss: {
4429
- transition: "transform 0.15s ease-in",
4430
- ...!collapsed && { transform: "rotateZ(90deg)" }
4793
+ transition: "transform 180ms ease",
4794
+ transform: expanded ? "rotateZ(90deg)" : "none",
4795
+ "@media (prefers-reduced-motion: reduce)": { transition: "none" }
4431
4796
  },
4432
4797
  color: "secondary"
4433
4798
  }
4434
4799
  ),
4435
- collapsed ? null : children
4800
+ /* @__PURE__ */ jsx(Disclosure, { id, tag: "li", role: "rowgroup", expanded, children: /* @__PURE__ */ jsx(BaseList, { role: "presentation", children }) })
4436
4801
  ] });
4437
4802
  }
4438
4803
  function SubmitIconInput({ icon, ...otherProps }) {
@@ -4470,7 +4835,7 @@ function SubmitIconInput({ icon, ...otherProps }) {
4470
4835
  }
4471
4836
  );
4472
4837
  }
4473
- var styles12 = {
4838
+ var styles10 = {
4474
4839
  root: {},
4475
4840
  default: {
4476
4841
  backgroundColor: cssVar("--nav-bar")
@@ -4563,11 +4928,11 @@ function TabBar({
4563
4928
  tag: "nav",
4564
4929
  "aria-label": ariaLabel,
4565
4930
  jss: [
4566
- styles12.root,
4567
- styles12[variant],
4568
- variant === "default" && (horizontal ? styles12.horizontal : styles12.vertical),
4569
- fixed && styles12.fixed,
4570
- fixed && (horizontal ? styles12.fixedHorizontal : styles12.fixedVertical),
4931
+ styles10.root,
4932
+ styles10[variant],
4933
+ variant === "default" && (horizontal ? styles10.horizontal : styles10.vertical),
4934
+ fixed && styles10.fixed,
4935
+ fixed && (horizontal ? styles10.fixedHorizontal : styles10.fixedVertical),
4571
4936
  jss
4572
4937
  ],
4573
4938
  children: [
@@ -4578,16 +4943,16 @@ function TabBar({
4578
4943
  ...otherProps,
4579
4944
  direction,
4580
4945
  align,
4581
- jss: horizontal ? styles12.horizontalBar : styles12.verticalBar,
4946
+ jss: horizontal ? styles10.horizontalBar : styles10.verticalBar,
4582
4947
  children: tabs.map((tab) => {
4583
4948
  const { label, icon, href, onClick } = tab;
4584
4949
  const selected = tab.selected === true;
4585
4950
  const color = selected ? "highlight" : "secondary";
4586
4951
  const tabJSS = [
4587
- styles12.item,
4588
- horizontal ? styles12.horizontalItem : styles12.verticalItem,
4589
- variant === "default" && styles12.defaultItem,
4590
- variant === "floating" && horizontal && styles12.floatingHorizontalItem,
4952
+ styles10.item,
4953
+ horizontal ? styles10.horizontalItem : styles10.verticalItem,
4954
+ variant === "default" && styles10.defaultItem,
4955
+ variant === "floating" && horizontal && styles10.floatingHorizontalItem,
4591
4956
  selected && {
4592
4957
  backgroundColor: cssVar("--light-highlight")
4593
4958
  },
@@ -4638,12 +5003,12 @@ function TabBar({
4638
5003
  })
4639
5004
  }
4640
5005
  ),
4641
- horizontal && /* @__PURE__ */ jsx(BaseView, { "aria-hidden": true, jss: styles12.safeArea })
5006
+ horizontal && /* @__PURE__ */ jsx(BaseView, { "aria-hidden": true, jss: styles10.safeArea })
4642
5007
  ]
4643
5008
  }
4644
5009
  );
4645
5010
  }
4646
- var styles13 = {
5011
+ var styles11 = {
4647
5012
  root: {
4648
5013
  overflowX: "auto",
4649
5014
  overflowY: "hidden",
@@ -4699,135 +5064,242 @@ function Table({
4699
5064
  material,
4700
5065
  padding,
4701
5066
  gap,
4702
- jss: [styles13.root, jss],
4703
- children: /* @__PURE__ */ jsx("table", { ...tableProps, className: toClassnames([styles13.table, jssTable]), children })
5067
+ jss: [styles11.root, jss],
5068
+ children: /* @__PURE__ */ jsx("table", { ...tableProps, className: toClassnames([styles11.table, jssTable]), children })
4704
5069
  }
4705
5070
  );
4706
5071
  }
4707
- function Tabs({
5072
+ var Tabs = React35.forwardRef(function Tabs2({
4708
5073
  tabs,
4709
5074
  variant = "underline",
4710
5075
  gap = "none",
4711
5076
  padding = "none",
4712
- tabPadding = "medium",
4713
- labelSize = "large",
5077
+ tabPadding = variant === "document" ? ["small", "medium"] : "medium",
5078
+ labelSize = variant === "document" ? "small" : "large",
4714
5079
  iconSize = "medium",
4715
5080
  jss,
4716
5081
  jssTab,
4717
5082
  labelRenderer,
4718
- ["aria-controls"]: ariaControls,
4719
- ...otherProps
4720
- }) {
4721
- const root = useNavigation();
5083
+ "aria-controls": ariaControls,
5084
+ onKeyDown,
5085
+ bare = true,
5086
+ ...props
5087
+ }, ref) {
5088
+ const root = useRef(null);
5089
+ const lastSelected = useRef(void 0);
5090
+ const instance = useId();
5091
+ const selectedIndex = Math.max(
5092
+ 0,
5093
+ tabs.findIndex((tab) => tab.selected)
5094
+ );
5095
+ const selectedId = tabs[selectedIndex]?.id ?? tabs[selectedIndex]?.label;
5096
+ const closeTab = (index) => {
5097
+ const tab = tabs[index];
5098
+ const next = tabs[index + 1] ?? tabs[index - 1];
5099
+ const target = index === selectedIndex ? next : tabs[selectedIndex];
5100
+ const targetIndex = tabs.indexOf(target);
5101
+ root.current?.querySelectorAll('[role="tab"]')[targetIndex]?.focus();
5102
+ if (index === selectedIndex) next?.onClick?.();
5103
+ tab.onClose?.();
5104
+ };
4722
5105
  return /* @__PURE__ */ jsx(
4723
5106
  Row,
4724
5107
  {
5108
+ ...props,
4725
5109
  role: "tablist",
5110
+ ref: (element) => {
5111
+ root.current = element;
5112
+ if (typeof ref === "function") ref(element);
5113
+ else if (ref) ref.current = element;
5114
+ if (element && selectedId !== lastSelected.current) {
5115
+ const tab = element.querySelector('[aria-selected="true"]');
5116
+ if (tab && variant === "document") {
5117
+ const box = tab.getBoundingClientRect();
5118
+ const viewport = element.getBoundingClientRect();
5119
+ if (box.left < viewport.left)
5120
+ element.scrollLeft -= viewport.left - box.left;
5121
+ else if (box.right > viewport.right)
5122
+ element.scrollLeft += box.right - viewport.right;
5123
+ }
5124
+ lastSelected.current = selectedId;
5125
+ }
5126
+ },
5127
+ gap,
5128
+ padding,
4726
5129
  jss: [
5130
+ { minWidth: 0, maxWidth: "100%" },
4727
5131
  variant === "segmented" && {
4728
- isolation: "isolate",
4729
- backgroundColor: cssVar("--hovered-background"),
5132
+ background: cssVar("--hovered-background"),
4730
5133
  borderRadius: cssVar("--border-radius-l"),
4731
- maxWidth: "100%",
4732
5134
  padding: cssVar("--spacing-xs"),
4733
5135
  width: "fit-content"
4734
5136
  },
5137
+ variant === "document" && {
5138
+ overflowX: "auto",
5139
+ overscrollBehavior: "contain",
5140
+ scrollbarWidth: "thin",
5141
+ alignItems: "center",
5142
+ gap: 3,
5143
+ padding: 3
5144
+ },
4735
5145
  jss
4736
5146
  ],
4737
- gap,
4738
- padding,
4739
- ref: root,
4740
- ...otherProps,
4741
- children: tabs.map(
4742
- ({
5147
+ onKeyDown: (event) => {
5148
+ onKeyDown?.(event);
5149
+ if (event.defaultPrevented || event.nativeEvent.isComposing || event.altKey || event.metaKey || event.ctrlKey)
5150
+ return;
5151
+ const elements = Array.from(
5152
+ event.currentTarget.querySelectorAll('[role="tab"]')
5153
+ );
5154
+ const index = elements.indexOf(event.target);
5155
+ if (index < 0) return;
5156
+ if (event.key === "Delete" && tabs[index].onClose) {
5157
+ event.preventDefault();
5158
+ closeTab(index);
5159
+ return;
5160
+ }
5161
+ const next = event.key === "Home" ? 0 : event.key === "End" ? tabs.length - 1 : event.key === "ArrowRight" ? (index + 1) % tabs.length : event.key === "ArrowLeft" ? (index - 1 + tabs.length) % tabs.length : -1;
5162
+ if (next < 0) return;
5163
+ event.preventDefault();
5164
+ event.stopPropagation();
5165
+ elements[next]?.focus();
5166
+ tabs[next]?.onClick?.();
5167
+ },
5168
+ children: tabs.map((tab, index) => {
5169
+ const {
5170
+ id,
4743
5171
  label,
4744
5172
  icon,
4745
5173
  href,
4746
5174
  onClick,
4747
- selected,
5175
+ onClose,
5176
+ panelId,
4748
5177
  addOn,
4749
5178
  addOnPosition = "start"
4750
- }) => {
4751
- const BaseComponent = href != null ? BaseLink : BaseButton;
4752
- return /* @__PURE__ */ jsxs(
4753
- BaseComponent,
4754
- {
4755
- "aria-controls": ariaControls,
4756
- role: "tab",
4757
- "aria-selected": selected ? "true" : void 0,
4758
- bare: true,
4759
- color: selected ? "primary" : "secondary",
4760
- href,
4761
- onClick,
4762
- animateInteraction: false,
4763
- jss: [
5179
+ } = tab;
5180
+ const selected = index === selectedIndex;
5181
+ const BaseComponent = href != null ? BaseLink : BaseButton;
5182
+ return /* @__PURE__ */ jsxs(
5183
+ Row,
5184
+ {
5185
+ "data-aidos-action-scope": true,
5186
+ align: "center",
5187
+ gap: "none",
5188
+ jss: [
5189
+ { minWidth: 0 },
5190
+ variant === "document" && {
5191
+ height: 30,
5192
+ minWidth: 110,
5193
+ maxWidth: 220,
5194
+ flexShrink: 0,
5195
+ borderRadius: 6,
5196
+ background: selected ? cssVar("--light-highlight") : "transparent",
5197
+ ":hover": {
5198
+ background: selected ? cssVar("--light-highlight") : cssVar("--hovered-background")
5199
+ }
5200
+ }
5201
+ ],
5202
+ children: [
5203
+ /* @__PURE__ */ jsxs(
5204
+ BaseComponent,
4764
5205
  {
4765
- alignItems: "center",
4766
- gap: cssVar("--spacing-s"),
4767
- textDecoration: "none"
4768
- },
4769
- variant === "underline" && {
4770
- borderBottom: selected ? `3px solid ${cssVar("--highlight")}` : `3px solid transparent`,
4771
- ":active span": {
4772
- transform: "scale(0.97)"
4773
- },
4774
- ":first-child": {
4775
- borderTopLeftRadius: cssVar("--border-radius-m")
4776
- },
4777
- ":last-child": {
4778
- borderTopRightRadius: cssVar("--border-radius-m")
4779
- },
4780
- ":hover": {
4781
- backgroundColor: cssVar("--hovered-background")
4782
- },
4783
- ":active:hover": {
4784
- backgroundColor: cssVar("--pressed-background")
4785
- }
4786
- },
4787
- variant === "segmented" && {
4788
- position: "relative",
4789
- zIndex: selected ? 1 : 0,
4790
- borderRadius: cssVar("--border-radius-m"),
4791
- backgroundColor: selected ? cssVar("--overlay-background") : "transparent",
4792
- boxShadow: selected ? `0 0 0 1px ${cssVar("--divider")}, 0 0 4px color-mix(in srgb, ${cssVar("--primary-text")} 10%, transparent)` : "none",
4793
- transition: `background-color ${cssVar("--transition-fast")}, box-shadow ${cssVar("--transition-fast")}`,
4794
- ":hover": {
4795
- backgroundColor: selected ? cssVar("--overlay-background") : cssVar("--hovered-background")
4796
- },
4797
- ":active:hover": {
4798
- top: 1,
4799
- backgroundColor: cssVar("--pressed-background")
4800
- }
4801
- },
4802
- getPadding(tabPadding),
4803
- typeof jssTab === "function" ? jssTab({ selected }) : jssTab
4804
- ],
4805
- children: [
4806
- addOnPosition === "start" && addOn,
4807
- icon && /* @__PURE__ */ jsx(
4808
- Icon,
4809
- {
4810
- icon,
4811
- size: iconSize,
4812
- color: selected ? "primary" : "secondary"
5206
+ id: id ?? `${instance}-${index}`,
5207
+ "aria-controls": panelId ?? ariaControls,
5208
+ role: "tab",
5209
+ "aria-selected": selected,
5210
+ tabIndex: selected ? 0 : -1,
5211
+ bare,
5212
+ color: selected ? "primary" : "secondary",
5213
+ href,
5214
+ onClick,
5215
+ animateInteraction: false,
5216
+ jss: [
5217
+ {
5218
+ minWidth: 0,
5219
+ flex: 1,
5220
+ alignItems: "center",
5221
+ gap: cssVar("--spacing-s"),
5222
+ textDecoration: "none",
5223
+ ":focus-visible": { outlineOffset: -2 }
5224
+ },
5225
+ variant === "underline" && {
5226
+ borderBottom: `3px solid ${selected ? cssVar("--highlight") : "transparent"}`,
5227
+ borderRadius: "var(--border-radius-s) var(--border-radius-s) 0 0",
5228
+ ":hover": { background: cssVar("--hovered-background") }
5229
+ },
5230
+ variant === "segmented" && {
5231
+ borderRadius: cssVar("--border-radius-m"),
5232
+ background: selected ? cssVar("--overlay-background") : "transparent",
5233
+ boxShadow: selected ? cssVar("--shadow-sm") : "none"
5234
+ },
5235
+ variant === "document" && {
5236
+ height: "100%",
5237
+ borderRadius: 6,
5238
+ background: "transparent"
5239
+ },
5240
+ getPadding(tabPadding),
5241
+ typeof jssTab === "function" ? jssTab({ selected }) : jssTab
5242
+ ],
5243
+ children: [
5244
+ addOnPosition === "start" && addOn,
5245
+ icon && /* @__PURE__ */ jsx(
5246
+ Icon,
5247
+ {
5248
+ icon,
5249
+ size: iconSize,
5250
+ color: selected ? "primary" : "secondary",
5251
+ jss: { flexShrink: 0 }
5252
+ }
5253
+ ),
5254
+ /* @__PURE__ */ jsx(
5255
+ Text,
5256
+ {
5257
+ size: labelSize,
5258
+ color: selected ? "primary" : "secondary",
5259
+ jss: { minWidth: 0 },
5260
+ children: labelRenderer ? labelRenderer(label) : label
5261
+ }
5262
+ ),
5263
+ addOnPosition === "end" && addOn
5264
+ ]
5265
+ }
5266
+ ),
5267
+ onClose && /* @__PURE__ */ jsx(
5268
+ IconButton,
5269
+ {
5270
+ "data-aidos-actions": true,
5271
+ "aria-label": `Close ${label}`,
5272
+ tabIndex: selected ? 0 : -1,
5273
+ bare: true,
5274
+ color: "secondary",
5275
+ icon: "x",
5276
+ size: "xsmall",
5277
+ onClick: () => closeTab(index),
5278
+ jss: {
5279
+ borderRadius: 5,
5280
+ marginInlineEnd: 3,
5281
+ opacity: selected ? 1 : 0,
5282
+ ":focus-visible": { opacity: 1, outlineOffset: -2 },
5283
+ "@media (hover: none)": { opacity: 1 }
4813
5284
  }
4814
- ),
4815
- /* @__PURE__ */ jsx(Text, { size: labelSize, color: selected ? "primary" : "secondary", children: labelRenderer ? labelRenderer(label) : label }),
4816
- addOnPosition === "end" && addOn
4817
- ]
4818
- },
4819
- label
4820
- );
4821
- }
4822
- )
5285
+ }
5286
+ )
5287
+ ]
5288
+ },
5289
+ id ?? label
5290
+ );
5291
+ })
4823
5292
  }
4824
5293
  );
4825
- }
5294
+ });
4826
5295
  var TextArea = React35.forwardRef(function TextArea2({
4827
5296
  jss,
4828
5297
  onValueChange,
4829
5298
  value,
4830
5299
  padding = "medium",
5300
+ size = "medium",
5301
+ autoGrow = false,
5302
+ rows = autoGrow ? 1 : 3,
4831
5303
  ...otherProps
4832
5304
  }, ref) {
4833
5305
  return /* @__PURE__ */ jsx(
@@ -4835,29 +5307,43 @@ var TextArea = React35.forwardRef(function TextArea2({
4835
5307
  {
4836
5308
  ...otherProps,
4837
5309
  ref,
5310
+ rows,
4838
5311
  className: toClassnames([
4839
5312
  {
5313
+ display: "block",
5314
+ minWidth: 0,
4840
5315
  flexGrow: 1,
4841
5316
  color: cssVar("--primary-text"),
4842
- outline: "none",
4843
- fontSize: 20,
4844
- lineHeight: 24 / 20,
5317
+ ...getTypography(size),
4845
5318
  backgroundColor: cssVar("--overlay-background"),
4846
5319
  border: `1px solid ${cssVar("--divider")}`,
4847
5320
  borderRadius: cssVar("--border-radius-m"),
4848
- "::placeholder": {
4849
- color: cssVar("--subtle-text")
4850
- },
5321
+ "::placeholder": { color: cssVar("--subtle-text") },
4851
5322
  ":focus-visible": {
4852
- outline: `2px solid ${cssVar("--highlight")}`,
5323
+ outline: `2px solid ${cssVar("--outline")}`,
4853
5324
  outlineOffset: -2
5325
+ },
5326
+ "[aria-invalid=true]": { borderColor: cssVar("--negative-text") },
5327
+ "[aria-invalid=true]:focus-visible": {
5328
+ outlineColor: cssVar("--negative-text")
5329
+ },
5330
+ ":disabled": {
5331
+ color: cssVar("--subtle-text"),
5332
+ backgroundColor: cssVar("--secondary-background"),
5333
+ cursor: "not-allowed"
4854
5334
  }
4855
5335
  },
5336
+ autoGrow && {
5337
+ fieldSizing: "content",
5338
+ minHeight: `calc(${rows}lh + 2 * ${getSpacing(Array.isArray(padding) ? padding[0] : padding)} + 2px)`,
5339
+ maxHeight: 180,
5340
+ overflowY: "auto"
5341
+ },
4856
5342
  getPadding(padding),
4857
5343
  jss
4858
5344
  ]),
4859
5345
  value,
4860
- onChange: onValueChange ? (e) => onValueChange(e.target.value) : void 0
5346
+ onChange: onValueChange ? (event) => onValueChange(event.target.value) : void 0
4861
5347
  }
4862
5348
  );
4863
5349
  });
@@ -4867,66 +5353,82 @@ var TextInput = React35.forwardRef(function TextInput2({
4867
5353
  jssRoot,
4868
5354
  jss,
4869
5355
  addOn,
4870
- gap = "none",
5356
+ gap,
4871
5357
  addOnPosition = "start",
4872
- padding = "medium",
5358
+ padding,
4873
5359
  size = "medium",
4874
5360
  ...inputProps
4875
5361
  }, ref) {
4876
- return /* @__PURE__ */ jsxs(InputFrame, { gap, jss: jssRoot, children: [
4877
- addOnPosition === "start" && addOn && /* @__PURE__ */ jsx(
4878
- Column,
4879
- {
4880
- justify: "center",
4881
- align: "center",
4882
- jss: [getPadding(padding), { paddingRight: 0 }],
4883
- children: addOn
4884
- }
4885
- ),
4886
- /* @__PURE__ */ jsx(
4887
- BaseInput,
4888
- {
4889
- ...inputProps,
4890
- ref,
4891
- value,
4892
- onChange: onValueChange ? (e) => onValueChange(e.target.value) : void 0,
4893
- jss: [
5362
+ const metrics = controlSizes[size];
5363
+ const inputPadding = padding != null ? getPadding(padding) : { padding: `0 ${metrics?.padding ?? 8}px` };
5364
+ return /* @__PURE__ */ jsxs(
5365
+ InputFrame,
5366
+ {
5367
+ gap: gap ?? (size === "xsmall" || size === "small" ? "small" : "medium"),
5368
+ jss: jssRoot,
5369
+ children: [
5370
+ addOnPosition === "start" && addOn && /* @__PURE__ */ jsx(
5371
+ Column,
4894
5372
  {
4895
- minWidth: 0,
4896
- flexGrow: 1,
4897
- backgroundColor: "transparent",
4898
- color: cssVar("--primary-text"),
4899
- outline: "none",
4900
- border: "none",
4901
- ...getTypography(size),
4902
- "::placeholder": {
4903
- color: cssVar("--subtle-text")
4904
- },
4905
- ":disabled": {
4906
- color: cssVar("--subtle-text"),
4907
- cursor: "not-allowed"
4908
- },
4909
- "[aria-invalid=true]": {
4910
- color: cssVar("--negative-text")
4911
- }
4912
- },
4913
- getPadding(padding),
4914
- addOn && addOnPosition === "start" ? { paddingLeft: 0 } : null,
4915
- addOn && addOnPosition === "end" ? { paddingRight: 0 } : null,
4916
- jss
4917
- ]
4918
- }
4919
- ),
4920
- addOnPosition === "end" && addOn && /* @__PURE__ */ jsx(
4921
- Column,
4922
- {
4923
- justify: "center",
4924
- align: "center",
4925
- jss: [getPadding(padding), { paddingLeft: 0 }],
4926
- children: addOn
4927
- }
4928
- )
4929
- ] });
5373
+ justify: "center",
5374
+ align: "center",
5375
+ jss: [
5376
+ padding != null ? getPadding(padding) : { paddingLeft: metrics?.padding ?? 8 },
5377
+ { paddingRight: 0, flexShrink: 0 }
5378
+ ],
5379
+ children: addOn
5380
+ }
5381
+ ),
5382
+ /* @__PURE__ */ jsx(
5383
+ BaseInput,
5384
+ {
5385
+ ...inputProps,
5386
+ ref,
5387
+ value,
5388
+ onChange: onValueChange ? (e) => onValueChange(e.target.value) : void 0,
5389
+ jss: [
5390
+ {
5391
+ minWidth: 0,
5392
+ minHeight: metrics ? metrics.height - 2 : void 0,
5393
+ flexGrow: 1,
5394
+ backgroundColor: "transparent",
5395
+ color: cssVar("--primary-text"),
5396
+ outline: "none",
5397
+ border: "none",
5398
+ ...getTypography(metrics?.text ?? size),
5399
+ "::placeholder": {
5400
+ color: cssVar("--subtle-text")
5401
+ },
5402
+ ":disabled": {
5403
+ color: cssVar("--subtle-text"),
5404
+ cursor: "not-allowed"
5405
+ },
5406
+ "[aria-invalid=true]": {
5407
+ color: cssVar("--negative-text")
5408
+ }
5409
+ },
5410
+ inputPadding,
5411
+ addOn && addOnPosition === "start" ? { paddingLeft: 0 } : null,
5412
+ addOn && addOnPosition === "end" ? { paddingRight: 0 } : null,
5413
+ jss
5414
+ ]
5415
+ }
5416
+ ),
5417
+ addOnPosition === "end" && addOn && /* @__PURE__ */ jsx(
5418
+ Column,
5419
+ {
5420
+ justify: "center",
5421
+ align: "center",
5422
+ jss: [
5423
+ padding != null ? getPadding(padding) : { paddingRight: metrics?.padding ?? 8 },
5424
+ { paddingLeft: 0, flexShrink: 0 }
5425
+ ],
5426
+ children: addOn
5427
+ }
5428
+ )
5429
+ ]
5430
+ }
5431
+ );
4930
5432
  });
4931
5433
  function getInitialValue(valueRef) {
4932
5434
  return valueRef.current;
@@ -5127,99 +5629,93 @@ var Toolbar = React35.forwardRef(function Toolbar2({
5127
5629
  ] });
5128
5630
  });
5129
5631
  Toolbar.displayName = "Toolbar";
5130
- var styles14 = {
5131
- tooltip: {
5132
- top: "auto",
5133
- right: "auto",
5134
- bottom: `calc(100% + ${cssVar("--spacing-s")})`,
5135
- left: "50%",
5136
- margin: 0,
5137
- translate: "-50% 0",
5138
- transformOrigin: "bottom center",
5139
- backgroundColor: cssVar("--primary-background"),
5140
- padding: `${cssVar("--spacing-s")} ${cssVar("--spacing-m")}`,
5141
- borderRadius: cssVar("--border-radius-m"),
5142
- border: `1px solid ${cssVar("--divider")}`,
5143
- boxShadow: cssVar("--shadow-md"),
5144
- overflow: "hidden",
5145
- animation: "popoverFadeIn 0.15s ease-out"
5146
- }
5147
- };
5148
- function Tooltip({ content, jss, tag, children }) {
5149
- const [tooltip, setTooltip] = useState(null);
5150
- const dialogRef = useRef(null);
5151
- const focusTrapRoot = useRefEffect(
5152
- useCallback((root) => {
5153
- dialogRef.current = root;
5154
- const keydown = (e) => {
5155
- if (e.key === "Escape") {
5156
- dialogRef.current?.close();
5157
- } else if (e.key === "Tab") {
5158
- dialogRef.current?.close();
5159
- }
5160
- };
5161
- const click = () => {
5162
- dialogRef.current?.close();
5163
- };
5164
- window.addEventListener("keydown", keydown);
5165
- window.addEventListener("click", click);
5166
- const activeElement = document.activeElement;
5167
- root.show();
5168
- if (activeElement instanceof HTMLElement) {
5169
- activeElement.focus();
5170
- }
5171
- return () => {
5172
- window.removeEventListener("keydown", keydown);
5173
- window.removeEventListener("click", click);
5174
- };
5175
- }, [])
5632
+ function Tooltip({
5633
+ content,
5634
+ jss,
5635
+ tag,
5636
+ children,
5637
+ placement = "top",
5638
+ align = "center"
5639
+ }) {
5640
+ const id = useId();
5641
+ const [open, setOpen] = useState(false);
5642
+ const anchor = useRef(null);
5643
+ const surface = useRef(null);
5644
+ const timeout = useRef(void 0);
5645
+ const position = useFloatingPosition(
5646
+ anchor,
5647
+ placement,
5648
+ align,
5649
+ () => setOpen(false)
5176
5650
  );
5177
- const toggle = () => {
5178
- if (tooltip == null) {
5179
- setTooltip(
5180
- /* @__PURE__ */ jsx(
5181
- "dialog",
5182
- {
5183
- role: "tooltip",
5184
- ref: (ref) => {
5185
- dialogRef.current = ref;
5186
- focusTrapRoot(ref);
5187
- },
5188
- className: toClassnames(styles14.tooltip),
5189
- onClose: () => {
5190
- setTooltip(null);
5191
- },
5192
- onClick: (e) => {
5193
- e.preventDefault();
5194
- e.stopPropagation();
5195
- },
5196
- children: /* @__PURE__ */ jsx(Text, { size: "medium", color: "secondary", children: content })
5197
- }
5198
- )
5199
- );
5200
- } else {
5201
- setTooltip(null);
5202
- }
5651
+ const show = () => {
5652
+ clearTimeout(timeout.current);
5653
+ setOpen(true);
5654
+ };
5655
+ const leave = () => {
5656
+ clearTimeout(timeout.current);
5657
+ timeout.current = setTimeout(() => {
5658
+ if (!anchor.current?.contains(document.activeElement) && !surface.current?.matches(":hover"))
5659
+ setOpen(false);
5660
+ }, 120);
5203
5661
  };
5204
5662
  return /* @__PURE__ */ jsxs(
5205
5663
  BaseView,
5206
5664
  {
5665
+ ref: (element) => {
5666
+ anchor.current = element;
5667
+ if (!element) clearTimeout(timeout.current);
5668
+ },
5207
5669
  tag,
5208
- relative: true,
5209
- jss: [{ display: "inline-block" }, jss],
5210
- onMouseEnter: () => {
5211
- if (tooltip == null) {
5212
- toggle();
5213
- }
5670
+ jss: [{ display: "inline-block", minWidth: 0 }, jss],
5671
+ onFocus: show,
5672
+ onKeyDown: (event) => {
5673
+ if (event.key === "Tab") setOpen(false);
5214
5674
  },
5215
- onMouseLeave: () => {
5216
- if (tooltip != null) {
5217
- toggle();
5218
- }
5675
+ onBlur: (event) => {
5676
+ if (!event.currentTarget.contains(event.relatedTarget) && !event.currentTarget.matches(":hover") && !surface.current?.matches(":hover"))
5677
+ setOpen(false);
5219
5678
  },
5679
+ onMouseEnter: show,
5680
+ onMouseLeave: leave,
5220
5681
  children: [
5221
- children,
5222
- tooltip
5682
+ React35.cloneElement(children, {
5683
+ "aria-describedby": [children.props["aria-describedby"], open && id].filter(Boolean).join(" ") || void 0
5684
+ }),
5685
+ open && createPortal(
5686
+ /* @__PURE__ */ jsx(
5687
+ "div",
5688
+ {
5689
+ id,
5690
+ role: "tooltip",
5691
+ popover: "hint",
5692
+ ref: (element) => {
5693
+ surface.current = element;
5694
+ position(element);
5695
+ },
5696
+ onMouseEnter: show,
5697
+ onMouseLeave: leave,
5698
+ className: toClassnames({
5699
+ position: "fixed",
5700
+ inset: "auto",
5701
+ margin: 0,
5702
+ zIndex: 1e3,
5703
+ width: "max-content",
5704
+ maxWidth: "min(320px, var(--aidos-overlay-width, calc(100vw - 24px)))",
5705
+ maxHeight: "var(--aidos-overlay-height, calc(100dvh - 24px))",
5706
+ padding: `${cssVar("--spacing-s")} ${cssVar("--spacing-m")}`,
5707
+ border: `1px solid ${cssVar("--divider")}`,
5708
+ borderRadius: cssVar("--border-radius-m"),
5709
+ background: cssVar("--overlay-background"),
5710
+ color: cssVar("--primary-text"),
5711
+ boxShadow: cssVar("--shadow-md"),
5712
+ overflow: "auto"
5713
+ }),
5714
+ children: /* @__PURE__ */ jsx(Text, { size: "small", color: "secondary", ellipsis: false, children: content })
5715
+ }
5716
+ ),
5717
+ anchor.current.closest("dialog[open], [popover]") ?? document.body
5718
+ )
5223
5719
  ]
5224
5720
  }
5225
5721
  );
@@ -5278,7 +5774,610 @@ function usePromise(promiseFactory, inputs, initialValue) {
5278
5774
  });
5279
5775
  return [value, error];
5280
5776
  }
5777
+ var Composer = React35.forwardRef(function Composer2({
5778
+ value,
5779
+ onValueChange,
5780
+ onSubmit,
5781
+ footer,
5782
+ action,
5783
+ submitDisabled = false,
5784
+ submitLabel = "Send message",
5785
+ embedded = false,
5786
+ jssRoot,
5787
+ jss,
5788
+ onKeyDown,
5789
+ disabled,
5790
+ readOnly,
5791
+ ...props
5792
+ }, ref) {
5793
+ const canSubmit = !disabled && !readOnly && !submitDisabled && Boolean(value.trim());
5794
+ const submit = () => {
5795
+ if (canSubmit) onSubmit();
5796
+ };
5797
+ return /* @__PURE__ */ jsxs(
5798
+ InputFrame,
5799
+ {
5800
+ "data-aidos-composer": true,
5801
+ jss: [
5802
+ {
5803
+ flexDirection: "column",
5804
+ width: "100%",
5805
+ minWidth: 0,
5806
+ borderRadius: 20,
5807
+ overflow: "visible",
5808
+ boxShadow: cssVar("--shadow-sm"),
5809
+ ":hover": {
5810
+ borderColor: "color-mix(in srgb, var(--strong-divider) 60%, var(--divider))"
5811
+ },
5812
+ ":has(:is(input, textarea, select):focus-visible)": {
5813
+ borderColor: cssVar("--strong-divider"),
5814
+ outline: `1px solid ${cssVar("--strong-divider")}`,
5815
+ outlineOffset: -1
5816
+ },
5817
+ ":has(:is(input, textarea, select)[aria-invalid=true]:focus-visible)": {
5818
+ borderColor: cssVar("--negative-text"),
5819
+ outlineWidth: 1
5820
+ }
5821
+ },
5822
+ embedded && {
5823
+ background: "transparent",
5824
+ borderColor: "transparent",
5825
+ boxShadow: "none",
5826
+ borderRadius: cssVar("--border-radius-m")
5827
+ },
5828
+ jssRoot
5829
+ ],
5830
+ children: [
5831
+ /* @__PURE__ */ jsx(
5832
+ TextArea,
5833
+ {
5834
+ ...props,
5835
+ ref,
5836
+ value,
5837
+ onValueChange,
5838
+ autoGrow: true,
5839
+ disabled,
5840
+ readOnly,
5841
+ "aria-label": props["aria-label"] ?? "Message",
5842
+ onKeyDown: (event) => {
5843
+ onKeyDown?.(event);
5844
+ if (event.defaultPrevented || event.nativeEvent.isComposing || event.keyCode === 229 || event.repeat)
5845
+ return;
5846
+ if (event.key === "Enter" && !event.shiftKey && !event.altKey && !event.ctrlKey && !event.metaKey) {
5847
+ event.preventDefault();
5848
+ submit();
5849
+ }
5850
+ },
5851
+ jss: [
5852
+ {
5853
+ width: "100%",
5854
+ minHeight: 44,
5855
+ resize: "none",
5856
+ border: "none",
5857
+ borderRadius: "inherit",
5858
+ background: "transparent",
5859
+ padding: "14px 16px 10px",
5860
+ outline: "none",
5861
+ ":focus-visible": { outline: "none" }
5862
+ },
5863
+ jss
5864
+ ]
5865
+ }
5866
+ ),
5867
+ /* @__PURE__ */ jsxs(
5868
+ Row,
5869
+ {
5870
+ align: "center",
5871
+ gap: "small",
5872
+ jss: { minWidth: 0, padding: "0 10px 10px" },
5873
+ children: [
5874
+ /* @__PURE__ */ jsx(
5875
+ Row,
5876
+ {
5877
+ align: "center",
5878
+ gap: "xsmall",
5879
+ grow: true,
5880
+ jss: { minWidth: 0, flexWrap: "wrap" },
5881
+ children: footer
5882
+ }
5883
+ ),
5884
+ action ?? /* @__PURE__ */ jsx(
5885
+ IconButton,
5886
+ {
5887
+ icon: "arrow-up",
5888
+ color: "primary",
5889
+ size: "small",
5890
+ "aria-label": submitLabel,
5891
+ disabled: !canSubmit,
5892
+ onClick: submit
5893
+ }
5894
+ )
5895
+ ]
5896
+ }
5897
+ )
5898
+ ]
5899
+ }
5900
+ );
5901
+ });
5902
+ function ActionScope(props) {
5903
+ return /* @__PURE__ */ jsx(BaseView, { ...props, "data-aidos-action-scope": true });
5904
+ }
5905
+ function ContextualActions({ jss, ...props }) {
5906
+ return /* @__PURE__ */ jsx(
5907
+ Row,
5908
+ {
5909
+ ...props,
5910
+ "data-aidos-actions": true,
5911
+ align: "center",
5912
+ gap: "xsmall",
5913
+ jss: [
5914
+ {
5915
+ flexShrink: 0,
5916
+ opacity: 0,
5917
+ pointerEvents: "none",
5918
+ ":focus-within": { opacity: 1, pointerEvents: "auto" },
5919
+ ":has([aria-expanded=true])": { opacity: 1, pointerEvents: "auto" },
5920
+ "@media (hover: none)": { opacity: 1, pointerEvents: "auto" }
5921
+ },
5922
+ jss
5923
+ ]
5924
+ }
5925
+ );
5926
+ }
5927
+ var MenuContext = createContext(() => {
5928
+ });
5929
+ function Menu({
5930
+ label,
5931
+ onClose = () => {
5932
+ },
5933
+ children,
5934
+ jss,
5935
+ ...props
5936
+ }) {
5937
+ const navigation = useNavigation({ orientation: "vertical" });
5938
+ return /* @__PURE__ */ jsx(MenuContext.Provider, { value: onClose, children: /* @__PURE__ */ jsx(
5939
+ Column,
5940
+ {
5941
+ ...props,
5942
+ ref: navigation,
5943
+ role: "menu",
5944
+ "aria-label": label,
5945
+ gap: "none",
5946
+ jss: [
5947
+ {
5948
+ minWidth: "min(220px, calc(100vw - 32px))",
5949
+ maxHeight: "min(360px, calc(100dvh - 32px))",
5950
+ overflowY: "auto"
5951
+ },
5952
+ jss
5953
+ ],
5954
+ children
5955
+ }
5956
+ ) });
5957
+ }
5958
+ function MenuItem({
5959
+ children,
5960
+ icon,
5961
+ description,
5962
+ trailing,
5963
+ checked,
5964
+ destructive = false,
5965
+ disabled,
5966
+ jss,
5967
+ onClick,
5968
+ role = checked == null ? "menuitem" : "menuitemcheckbox",
5969
+ ...props
5970
+ }) {
5971
+ const close = useContext(MenuContext);
5972
+ return /* @__PURE__ */ jsxs(
5973
+ BaseButton,
5974
+ {
5975
+ ...props,
5976
+ role,
5977
+ "aria-checked": checked,
5978
+ title: description,
5979
+ bare: true,
5980
+ color: destructive ? "negative" : "secondary",
5981
+ disabled,
5982
+ animateInteraction: false,
5983
+ onClick: (event) => {
5984
+ onClick?.(event);
5985
+ if (!event.defaultPrevented) close();
5986
+ },
5987
+ jss: [
5988
+ {
5989
+ width: "100%",
5990
+ minHeight: 32,
5991
+ padding: "6px 10px",
5992
+ gap: 8,
5993
+ textAlign: "left",
5994
+ minWidth: 0,
5995
+ borderRadius: cssVar("--border-radius-s"),
5996
+ color: cssVar(
5997
+ disabled ? "--subtle-text" : destructive ? "--negative-text" : "--primary-text"
5998
+ ),
5999
+ ":hover": {
6000
+ background: cssVar("--hovered-background"),
6001
+ filter: "none"
6002
+ },
6003
+ ":focus-visible": { outlineOffset: -2 }
6004
+ },
6005
+ jss
6006
+ ],
6007
+ children: [
6008
+ icon && /* @__PURE__ */ jsx(
6009
+ Icon,
6010
+ {
6011
+ icon,
6012
+ size: "small",
6013
+ color: "inherit",
6014
+ jss: { width: 14, height: 14, flexShrink: 0 }
6015
+ }
6016
+ ),
6017
+ /* @__PURE__ */ jsx(Span, { size: "small", color: "inherit", jss: { minWidth: 0, flex: 1 }, children }),
6018
+ trailing && /* @__PURE__ */ jsx(Span, { size: "small", color: "secondary", jss: { flexShrink: 0 }, children: trailing }),
6019
+ checked != null && /* @__PURE__ */ jsx("span", { "aria-hidden": true, style: { width: 14, flexShrink: 0 }, children: checked && /* @__PURE__ */ jsx(Icon, { icon: "check", size: "small", color: "inherit" }) })
6020
+ ]
6021
+ }
6022
+ );
6023
+ }
6024
+ function MenuSeparator() {
6025
+ return /* @__PURE__ */ jsx(
6026
+ "div",
6027
+ {
6028
+ role: "separator",
6029
+ style: {
6030
+ height: 1,
6031
+ margin: "4px 0",
6032
+ background: "var(--divider)",
6033
+ flexShrink: 0
6034
+ }
6035
+ }
6036
+ );
6037
+ }
6038
+ function Prose({ jss, ...props }) {
6039
+ return /* @__PURE__ */ jsx(
6040
+ BaseView,
6041
+ {
6042
+ ...props,
6043
+ jss: [
6044
+ {
6045
+ minWidth: 0,
6046
+ color: "var(--primary-text)",
6047
+ fontSize: "var(--font-medium)",
6048
+ lineHeight: 1.6,
6049
+ overflowWrap: "anywhere",
6050
+ " > :first-child": { marginTop: 0 },
6051
+ " > :last-child": { marginBottom: 0 },
6052
+ " p": { margin: "0 0 12px" },
6053
+ " h1": {
6054
+ fontSize: "var(--font-xlarge)",
6055
+ lineHeight: 1.3,
6056
+ margin: "20px 0 8px",
6057
+ fontWeight: 600
6058
+ },
6059
+ " h2": {
6060
+ fontSize: "var(--font-large)",
6061
+ lineHeight: 1.4,
6062
+ margin: "16px 0 8px",
6063
+ fontWeight: 600
6064
+ },
6065
+ " :is(h3, h4, h5, h6)": {
6066
+ fontSize: "var(--font-medium)",
6067
+ margin: "12px 0 8px",
6068
+ fontWeight: 600
6069
+ },
6070
+ " :is(ul, ol)": { margin: "0 0 12px", paddingInlineStart: 24 },
6071
+ " li": { marginBlock: 4 },
6072
+ " blockquote": {
6073
+ margin: "12px 0",
6074
+ paddingInlineStart: 14,
6075
+ borderInlineStart: "2px solid var(--divider)",
6076
+ color: "var(--secondary-text)"
6077
+ },
6078
+ " code": {
6079
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
6080
+ fontSize: "0.92em",
6081
+ padding: "1px 4px",
6082
+ borderRadius: 4,
6083
+ background: "var(--secondary-background)"
6084
+ },
6085
+ " pre": {
6086
+ margin: "12px 0",
6087
+ padding: 12,
6088
+ borderRadius: 8,
6089
+ overflowX: "auto",
6090
+ whiteSpace: "pre",
6091
+ background: "var(--secondary-background)"
6092
+ },
6093
+ " pre code": {
6094
+ padding: 0,
6095
+ background: "transparent",
6096
+ fontSize: "inherit"
6097
+ },
6098
+ " hr": { borderTop: "1px solid var(--divider)", margin: "16px 0" },
6099
+ " a": { color: "var(--highlight-text)", textUnderlineOffset: "2px" },
6100
+ " table": {
6101
+ display: "block",
6102
+ maxWidth: "100%",
6103
+ overflowX: "auto",
6104
+ borderCollapse: "collapse"
6105
+ },
6106
+ " :is(th, td)": {
6107
+ padding: "6px 10px",
6108
+ borderBottom: "1px solid var(--divider)",
6109
+ textAlign: "start"
6110
+ }
6111
+ },
6112
+ jss
6113
+ ]
6114
+ }
6115
+ );
6116
+ }
6117
+ function SearchList({
6118
+ label,
6119
+ options,
6120
+ onSelect,
6121
+ query: controlledQuery,
6122
+ onQueryChange,
6123
+ filter = true,
6124
+ placeholder = "Search\u2026",
6125
+ loading = false,
6126
+ footer
6127
+ }) {
6128
+ const id = useId();
6129
+ const [localQuery, setQuery] = useState("");
6130
+ const query = controlledQuery ?? localQuery;
6131
+ const [selection, setSelection] = useState(
6132
+ null
6133
+ );
6134
+ const results = filter ? options.filter(
6135
+ (option) => `${option.label} ${option.description ?? ""} ${option.keywords ?? ""}`.toLocaleLowerCase().includes(query.trim().toLocaleLowerCase())
6136
+ ) : options;
6137
+ const active = results.find(
6138
+ (option) => selection?.query === query && option.value === selection.value
6139
+ ) ?? results[0];
6140
+ const optionId = (value) => `${id}-${encodeURIComponent(value)}`;
6141
+ return /* @__PURE__ */ jsxs(Column, { gap: "none", jss: { width: "100%", minHeight: 0 }, children: [
6142
+ /* @__PURE__ */ jsxs(
6143
+ Row,
6144
+ {
6145
+ align: "center",
6146
+ gap: "medium",
6147
+ padding: "large",
6148
+ jss: {
6149
+ flexShrink: 0,
6150
+ borderBottom: "2px solid var(--divider)",
6151
+ ":has(input:focus-visible)": { borderBottomColor: "var(--outline)" }
6152
+ },
6153
+ children: [
6154
+ /* @__PURE__ */ jsx(Icon, { icon: "search", size: "small", color: "secondary" }),
6155
+ /* @__PURE__ */ jsx(
6156
+ BaseInput,
6157
+ {
6158
+ "data-autofocus": "true",
6159
+ role: "combobox",
6160
+ "aria-label": label,
6161
+ "aria-controls": id,
6162
+ "aria-expanded": true,
6163
+ "aria-autocomplete": "list",
6164
+ "aria-activedescendant": active ? optionId(active.value) : void 0,
6165
+ autoComplete: "off",
6166
+ spellCheck: false,
6167
+ placeholder,
6168
+ value: query,
6169
+ onChange: (event) => {
6170
+ if (controlledQuery === void 0) setQuery(event.target.value);
6171
+ onQueryChange?.(event.target.value);
6172
+ },
6173
+ onKeyDown: (event) => {
6174
+ if (event.nativeEvent.isComposing || event.keyCode === 229) return;
6175
+ if (event.key === "Enter") {
6176
+ event.preventDefault();
6177
+ if (active && !active.disabled) onSelect(active.value);
6178
+ return;
6179
+ }
6180
+ const control = event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey;
6181
+ const index = results.indexOf(active);
6182
+ const next = event.key === "ArrowDown" || control && event.key === "j" ? index + 1 : event.key === "ArrowUp" || control && event.key === "k" ? index - 1 : event.key === "Home" && event.ctrlKey ? 0 : event.key === "End" && event.ctrlKey ? results.length - 1 : null;
6183
+ if (next == null || !results.length) return;
6184
+ event.preventDefault();
6185
+ const option = results[(next + results.length) % results.length];
6186
+ setSelection({ query, value: option.value });
6187
+ },
6188
+ jss: {
6189
+ flex: 1,
6190
+ minWidth: 0,
6191
+ background: "transparent",
6192
+ border: 0,
6193
+ outline: "none",
6194
+ color: "var(--primary-text)",
6195
+ fontSize: "var(--font-medium)",
6196
+ lineHeight: 20 / 14
6197
+ }
6198
+ }
6199
+ )
6200
+ ]
6201
+ }
6202
+ ),
6203
+ /* @__PURE__ */ jsx(
6204
+ BaseView,
6205
+ {
6206
+ role: "listbox",
6207
+ "aria-label": label,
6208
+ "aria-busy": loading,
6209
+ id,
6210
+ jss: {
6211
+ minHeight: 0,
6212
+ maxHeight: "min(320px, 50dvh)",
6213
+ overflowY: "auto",
6214
+ padding: 6
6215
+ },
6216
+ ref: (element) => {
6217
+ const row = element?.querySelector('[aria-selected="true"]');
6218
+ if (!row) return;
6219
+ const box = row.getBoundingClientRect();
6220
+ const viewport = element.getBoundingClientRect();
6221
+ if (box.top < viewport.top)
6222
+ element.scrollTop -= viewport.top - box.top;
6223
+ else if (box.bottom > viewport.bottom)
6224
+ element.scrollTop += box.bottom - viewport.bottom;
6225
+ },
6226
+ children: results.map((option) => /* @__PURE__ */ jsxs(
6227
+ Row,
6228
+ {
6229
+ id: optionId(option.value),
6230
+ role: "option",
6231
+ "aria-selected": option === active,
6232
+ "aria-disabled": option.disabled || void 0,
6233
+ align: "center",
6234
+ gap: "medium",
6235
+ padding: "medium",
6236
+ onMouseDown: (event) => event.preventDefault(),
6237
+ onClick: () => {
6238
+ if (!option.disabled) onSelect(option.value);
6239
+ },
6240
+ jss: {
6241
+ minHeight: 36,
6242
+ borderRadius: 8,
6243
+ cursor: option.disabled ? "default" : "pointer",
6244
+ background: option === active ? "var(--light-highlight)" : "transparent",
6245
+ ":hover": { background: "var(--hovered-background)" },
6246
+ "@media (forced-colors: active)": {
6247
+ outline: option === active ? "2px solid Highlight" : "none",
6248
+ outlineOffset: -2
6249
+ }
6250
+ },
6251
+ children: [
6252
+ option.icon && /* @__PURE__ */ jsx(Icon, { icon: option.icon, size: "small", color: "secondary" }),
6253
+ /* @__PURE__ */ jsxs(Column, { grow: true, gap: "xsmall", jss: { minWidth: 0 }, children: [
6254
+ /* @__PURE__ */ jsx(Text, { color: option.disabled ? "secondary" : "primary", children: option.label }),
6255
+ option.description && /* @__PURE__ */ jsx(Text, { size: "small", color: "secondary", children: option.description })
6256
+ ] }),
6257
+ option.trailing && /* @__PURE__ */ jsx(Text, { size: "small", color: "secondary", jss: { flexShrink: 0 }, children: option.trailing })
6258
+ ]
6259
+ },
6260
+ option.value
6261
+ ))
6262
+ }
6263
+ ),
6264
+ (loading || !results.length) && /* @__PURE__ */ jsx(Text, { role: "status", color: "secondary", jss: { padding: 16 }, children: loading ? "Loading\u2026" : "No results" }),
6265
+ footer && /* @__PURE__ */ jsx(
6266
+ BaseView,
6267
+ {
6268
+ jss: {
6269
+ padding: "8px 16px",
6270
+ borderTop: "1px solid var(--divider)",
6271
+ flexShrink: 0
6272
+ },
6273
+ children: footer
6274
+ }
6275
+ )
6276
+ ] });
6277
+ }
6278
+ function SearchPalette({
6279
+ open,
6280
+ onClose,
6281
+ onSelect,
6282
+ onAfterClose,
6283
+ footer = /* @__PURE__ */ jsx(Text, { size: "small", color: "secondary", children: "\u2191\u2193 Navigate \xB7 Enter Select \xB7 Esc Close" }),
6284
+ ...props
6285
+ }) {
6286
+ const pending = useRef(void 0);
6287
+ return /* @__PURE__ */ jsx(
6288
+ Modal,
6289
+ {
6290
+ open,
6291
+ label: props.label,
6292
+ onClose,
6293
+ onAfterClose: () => {
6294
+ const value = pending.current;
6295
+ pending.current = void 0;
6296
+ if (value !== void 0) onSelect(value);
6297
+ onAfterClose?.();
6298
+ },
6299
+ jss: { marginTop: "10dvh", width: "min(640px, calc(100vw - 32px))" },
6300
+ children: /* @__PURE__ */ jsx(
6301
+ SearchList,
6302
+ {
6303
+ ...props,
6304
+ footer,
6305
+ onSelect: (value) => {
6306
+ pending.current = value;
6307
+ onClose();
6308
+ }
6309
+ }
6310
+ )
6311
+ }
6312
+ );
6313
+ }
6314
+ var Switch = React35.forwardRef(function Switch2({ label, checked, onCheckedChange, disabled, jss, ...props }, ref) {
6315
+ return /* @__PURE__ */ jsx(
6316
+ BaseButton,
6317
+ {
6318
+ ...props,
6319
+ ref,
6320
+ bare: true,
6321
+ color: "secondary",
6322
+ role: "switch",
6323
+ "aria-label": label,
6324
+ "aria-checked": checked,
6325
+ disabled,
6326
+ animateInteraction: false,
6327
+ onClick: () => onCheckedChange(!checked),
6328
+ jss: [
6329
+ {
6330
+ width: 36,
6331
+ height: 24,
6332
+ padding: 2,
6333
+ flexShrink: 0,
6334
+ borderRadius: 12,
6335
+ opacity: disabled ? 0.5 : 1
6336
+ },
6337
+ jss
6338
+ ],
6339
+ children: /* @__PURE__ */ jsx(
6340
+ BaseView,
6341
+ {
6342
+ "aria-hidden": true,
6343
+ jss: {
6344
+ width: 32,
6345
+ height: 20,
6346
+ padding: 2,
6347
+ borderRadius: 10,
6348
+ background: checked ? "var(--background-button-primary)" : "var(--background-button-secondary)",
6349
+ border: "1px solid transparent",
6350
+ display: "flex",
6351
+ alignItems: "center",
6352
+ "@media (forced-colors: active)": {
6353
+ background: checked ? "Highlight" : "Canvas",
6354
+ borderColor: "ButtonText"
6355
+ }
6356
+ },
6357
+ children: /* @__PURE__ */ jsx(
6358
+ BaseView,
6359
+ {
6360
+ jss: {
6361
+ width: 14,
6362
+ height: 14,
6363
+ borderRadius: "50%",
6364
+ background: "var(--light-text)",
6365
+ transform: checked ? "translateX(12px)" : "none",
6366
+ boxShadow: "var(--shadow-sm)",
6367
+ transition: "transform 120ms ease",
6368
+ "@media (prefers-reduced-motion: reduce)": { transition: "none" },
6369
+ "@media (forced-colors: active)": {
6370
+ background: checked ? "HighlightText" : "ButtonText"
6371
+ }
6372
+ }
6373
+ }
6374
+ )
6375
+ }
6376
+ )
6377
+ }
6378
+ );
6379
+ });
5281
6380
 
5282
- export { Avatar, AvatarStack, Badge, BaseButton, BaseInput, BaseLink, BaseLinkComponentOverrideContext, BaseList, BaseListAddOn, BaseListItem, BaseView, Box, Button, ButtonGroup, Calendar, Card, Checkbox, Circle, Column, DESKTOP_MEDIA, DarkModeContext, DarkModeProvider, DarkModeToggle, DateInput, DatetimeInput, Dialog, DialogProvider, FlexLayout, H1, H2, H3, H4, Icon, IconButton, IconLink, JSSProvider, JSServerStyles, LAPTOP, LAPTOP_MEDIA, Label, Li, Link, List, ListButtonItem, ListDivider, ListHeaderItem, ListItem, ListLinkItem, ListSpacer, MOBILE, MOBILE_MEDIA, MenuIcon, NavigationSplitView, OnVisible, P, Popover, PopoverTrigger, ProgressBar, ProgressCircle, Providers, RangeInput, RootView, Row, Select, Span, StackContextProvider, StaticCheckbox, Sublist, SubmitIconInput, TABLET, TABLET_MEDIA, TabBar, Table, Tabs, Text, TextArea, TextInput, TextInputWithState, TextPairing, TimeInput, Toggle, Toolbar, Tooltip, baseStyles, createEmitter, createStorage, cssVar, darkTheme, desktop, getBackground, getBaseStyles, getColorValue, getCookie, getMargin, getMaterial, getPadding, getSize, getSpacing, getSurface, getTextColor, guid, hasCookie, hash, laptop, lightTheme, mobile, numberToBase, sizes3 as sizes, stateMachineContextFactory, tablet, timeFormatter, toClassnames, useCookie, useDialog, useIsTopOfStack, useKeyboard, useNavigation, usePromise, useRefEffect, useStream };
6381
+ export { ActionScope, Avatar, AvatarStack, Badge, BaseButton, BaseInput, BaseLink, BaseLinkComponentOverrideContext, BaseList, BaseListAddOn, BaseListItem, BaseView, Box, Button, ButtonGroup, Calendar, Card, Checkbox, Circle, Column, Composer, ContextualActions, DESKTOP_MEDIA, DarkModeContext, DarkModeProvider, DarkModeToggle, DateInput, DatetimeInput, Dialog, DialogProvider, Disclosure, FlexLayout, H1, H2, H3, H4, Icon, IconButton, IconLink, JSSProvider, JSServerStyles, LAPTOP, LAPTOP_MEDIA, Label, Li, Link, List, ListButtonItem, ListDivider, ListHeaderItem, ListItem, ListLinkItem, ListSpacer, MOBILE, MOBILE_MEDIA, Menu, MenuIcon, MenuItem, MenuSeparator, Modal, NavigationSplitView, OnVisible, P, Popover, PopoverTrigger, ProgressBar, ProgressCircle, Prose, Providers, RangeInput, RootView, Row, SearchList, SearchPalette, Select, Span, StackContextProvider, StaticCheckbox, Sublist, SubmitIconInput, Switch, TABLET, TABLET_MEDIA, TabBar, Table, Tabs, Text, TextArea, TextInput, TextInputWithState, TextPairing, TimeInput, Toggle, Toolbar, Tooltip, baseStyles, createEmitter, createStorage, cssVar, darkTheme, desktop, getBackground, getBaseStyles, getColorValue, getCookie, getMargin, getMaterial, getPadding, getSize, getSpacing, getSurface, getTextColor, guid, hasCookie, hash, laptop, lightTheme, mobile, numberToBase, sizes3 as sizes, stateMachineContextFactory, tablet, timeFormatter, toClassnames, useCookie, useDialog, useIsTopOfStack, useKeyboard, useNavigation, usePromise, useRefEffect, useStream };
5283
6382
  //# sourceMappingURL=index.js.map
5284
6383
  //# sourceMappingURL=index.js.map