aidos-ui 5.0.10 → 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,
@@ -1490,9 +1533,10 @@ var BaseListItem = React35.forwardRef(function BaseListItem2({
1490
1533
  icon,
1491
1534
  iconPosition = "start",
1492
1535
  iconSize = "medium",
1536
+ iconJss,
1493
1537
  addOn,
1494
1538
  disabled = false,
1495
- padding = "medium",
1539
+ padding = size === "medium" || size === "large" ? "medium" : "small",
1496
1540
  gap = "medium",
1497
1541
  selected,
1498
1542
  headlineBold,
@@ -1505,7 +1549,15 @@ var BaseListItem = React35.forwardRef(function BaseListItem2({
1505
1549
  headlineBold,
1506
1550
  padding,
1507
1551
  gap,
1508
- addOn: icon ? /* @__PURE__ */ jsx(Icon, { icon, size: iconSize, color: contentColor }) : void 0,
1552
+ addOn: icon ? /* @__PURE__ */ jsx(
1553
+ Icon,
1554
+ {
1555
+ icon,
1556
+ size: iconSize,
1557
+ color: contentColor,
1558
+ jss: iconJss
1559
+ }
1560
+ ) : void 0,
1509
1561
  addOnPosition: iconPosition,
1510
1562
  headline,
1511
1563
  headlineSize,
@@ -1516,7 +1568,8 @@ var BaseListItem = React35.forwardRef(function BaseListItem2({
1516
1568
  bodyColor: disabled || selected ? contentColor : bodyColor,
1517
1569
  bodyEllipsis,
1518
1570
  grow: true,
1519
- shrink: false
1571
+ shrink: false,
1572
+ jss: jssPrimary
1520
1573
  }
1521
1574
  );
1522
1575
  return /* @__PURE__ */ jsxs(
@@ -1525,9 +1578,15 @@ var BaseListItem = React35.forwardRef(function BaseListItem2({
1525
1578
  ...otherProps,
1526
1579
  ref,
1527
1580
  relative: true,
1581
+ "data-aidos-action-scope": true,
1528
1582
  tag: "li",
1529
1583
  role: "row",
1530
- 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
+ ],
1531
1590
  children: [
1532
1591
  /* @__PURE__ */ jsx(
1533
1592
  Row,
@@ -1540,7 +1599,17 @@ var BaseListItem = React35.forwardRef(function BaseListItem2({
1540
1599
  children: children({ content })
1541
1600
  }
1542
1601
  ),
1543
- 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
+ )
1544
1613
  ]
1545
1614
  }
1546
1615
  );
@@ -1561,6 +1630,14 @@ function Box({
1561
1630
  }
1562
1631
  );
1563
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
+ };
1564
1641
  var Button = React35.forwardRef(function Button2({
1565
1642
  children,
1566
1643
  color,
@@ -1568,12 +1645,18 @@ var Button = React35.forwardRef(function Button2({
1568
1645
  disabled,
1569
1646
  icon,
1570
1647
  iconPosition = "left",
1648
+ size = "medium",
1649
+ leading,
1650
+ trailing,
1651
+ rowProps,
1571
1652
  align = "center",
1572
1653
  gap = "medium",
1573
1654
  justify = "center",
1574
1655
  jss,
1575
1656
  ...otherProps
1576
1657
  }, ref) {
1658
+ const metrics = controlSizes[size];
1659
+ const glyph = getGlyphColor(color, disabled, bare);
1577
1660
  return /* @__PURE__ */ jsx(
1578
1661
  BaseButton,
1579
1662
  {
@@ -1585,69 +1668,86 @@ var Button = React35.forwardRef(function Button2({
1585
1668
  padding: "none",
1586
1669
  jss: [
1587
1670
  {
1588
- height: 34,
1589
- padding: "0 14px",
1671
+ height: metrics.height,
1672
+ minWidth: 0,
1673
+ maxWidth: "100%",
1674
+ padding: `0 ${metrics.padding}px`,
1590
1675
  borderRadius: cssVar("--border-radius-l"),
1591
1676
  justifyContent: "center",
1592
1677
  userSelect: "none"
1593
1678
  },
1594
1679
  jss
1595
1680
  ],
1596
- children: /* @__PURE__ */ jsxs(Row, { grow: true, align, gap, justify, children: [
1597
- icon && iconPosition === "left" && /* @__PURE__ */ jsx(
1598
- Icon,
1599
- {
1600
- icon,
1601
- size: "medium",
1602
- color: getGlyphColor(color, disabled, bare)
1603
- }
1604
- ),
1605
- /* @__PURE__ */ jsx(
1606
- Text,
1607
- {
1608
- size: "medium",
1609
- color: getGlyphColor(color, disabled, bare),
1610
- jss: {
1611
- fontWeight: 600,
1612
- letterSpacing: "-0.01em"
1613
- },
1614
- children
1615
- }
1616
- ),
1617
- icon && iconPosition === "right" && /* @__PURE__ */ jsx(
1618
- Icon,
1619
- {
1620
- icon,
1621
- size: "medium",
1622
- color: getGlyphColor(color, disabled, bare)
1623
- }
1624
- )
1625
- ] })
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
+ )
1626
1728
  }
1627
1729
  );
1628
1730
  });
1629
1731
 
1630
1732
  // src/aria.ts
1631
1733
  function queryFocusables(root) {
1632
- const focusables = Array.from(
1734
+ return Array.from(
1633
1735
  root.querySelectorAll(
1634
- "button,input,textarea,a,[tabindex='0'],[tabindex='-1']"
1736
+ 'button, input, textarea, select, a[href], [tabindex], [contenteditable="true"]'
1635
1737
  )
1738
+ ).filter(
1739
+ (element) => !element.matches(':disabled, input[type="hidden"]') && !element.closest("[inert], [hidden]") && element.getClientRects().length > 0 && getComputedStyle(element).visibility !== "hidden"
1636
1740
  );
1637
- return focusables.filter((element) => !element["disabled"]);
1638
1741
  }
1639
- var normalizeElements = (focusables, index) => {
1640
- for (const element2 of focusables) {
1641
- element2.tabIndex = -1;
1642
- }
1643
- const element = focusables[index] ?? focusables[focusables.length - 1];
1644
- element.tabIndex = 0;
1645
- };
1646
- var focusElement = (focusables, index) => {
1647
- normalizeElements(focusables, index);
1648
- const element = focusables[index] ?? focusables[focusables.length - 1];
1649
- element.focus();
1650
- };
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
+ }
1651
1751
  function useRefEffect(callback) {
1652
1752
  const unsubscribeRef = useRef(null);
1653
1753
  return useCallback(
@@ -1671,81 +1771,74 @@ function useNavigation({
1671
1771
  autofocus = false,
1672
1772
  rowLength = 1,
1673
1773
  enabled = true,
1674
- initialIndex = 0
1774
+ initialIndex = 0,
1775
+ orientation = "both"
1675
1776
  } = {}) {
1676
1777
  return useRefEffect(
1677
1778
  useCallback(
1678
1779
  (root) => {
1679
- if (!enabled) {
1680
- return;
1681
- }
1682
- let index = Math.max(
1683
- 0,
1684
- Math.min(initialIndex, queryFocusables(root).length - 1)
1685
- );
1686
- const elements = queryFocusables(root);
1687
- if (elements.length === 0) {
1688
- return;
1689
- }
1690
- if (elements.length !== 0 && autofocus) {
1691
- focusElement(elements, index);
1692
- } 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;
1693
1789
  normalizeElements(elements, index);
1694
- }
1695
- const onKeyDown = (e) => {
1696
- const elements2 = queryFocusables(root);
1697
- 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)
1698
1797
  return;
1699
- }
1700
- let newIndex = -1;
1701
- if (e.code === "ArrowUp") {
1702
- if (index - rowLength < 0) {
1703
- newIndex = elements2.length - elements2.length % rowLength + index;
1704
- } else {
1705
- newIndex = index - rowLength;
1706
- }
1707
- } else if (e.code === "ArrowLeft") {
1708
- if (index <= 0) {
1709
- newIndex = elements2.length - 1;
1710
- } else {
1711
- newIndex = index - 1;
1712
- }
1713
- } else if (e.code === "ArrowRight") {
1714
- if (index >= elements2.length - 1) {
1715
- newIndex = 0;
1716
- } else {
1717
- newIndex = index + 1;
1718
- }
1719
- } else if (e.code === "ArrowDown") {
1720
- if (index + rowLength > elements2.length - 1) {
1721
- newIndex = (index + rowLength) % rowLength;
1722
- } else {
1723
- newIndex = index + rowLength;
1724
- }
1725
- }
1726
- if (newIndex !== -1 && index !== newIndex) {
1727
- index = newIndex;
1728
- focusElement(elements2, index);
1729
- e.preventDefault();
1730
- e.stopPropagation();
1731
- }
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
+ );
1732
1825
  };
1733
- root.addEventListener("keydown", onKeyDown);
1734
- const observer = new MutationObserver((mutationList) => {
1735
- if (mutationList.filter((m) => m.type === "childList").length > 0) {
1736
- const elements2 = queryFocusables(root);
1737
- if (elements2.length > 0) {
1738
- normalizeElements(elements2, index);
1739
- }
1740
- }
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"]
1741
1834
  });
1742
- observer.observe(root, { childList: true });
1743
1835
  return () => {
1744
- root.removeEventListener("keydown", onKeyDown);
1745
1836
  observer.disconnect();
1837
+ root.removeEventListener("focusin", focusin);
1838
+ root.removeEventListener("keydown", keydown);
1746
1839
  };
1747
1840
  },
1748
- [autofocus, enabled, initialIndex, rowLength]
1841
+ [autofocus, rowLength, enabled, initialIndex, orientation]
1749
1842
  )
1750
1843
  );
1751
1844
  }
@@ -2090,7 +2183,17 @@ function Circle({
2090
2183
  }
2091
2184
  );
2092
2185
  }
2093
- 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];
2094
2197
  return /* @__PURE__ */ jsxs(
2095
2198
  BaseButton,
2096
2199
  {
@@ -2102,9 +2205,12 @@ var IconButton = React35.forwardRef(function IconButton2({ icon, color, bare, di
2102
2205
  display: "flex",
2103
2206
  justifyContent: "center",
2104
2207
  alignItems: "center",
2105
- height: 34,
2106
- width: 34,
2107
- 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
2108
2214
  },
2109
2215
  jss
2110
2216
  ],
@@ -2116,6 +2222,7 @@ var IconButton = React35.forwardRef(function IconButton2({ icon, color, bare, di
2116
2222
  Icon,
2117
2223
  {
2118
2224
  size: "medium",
2225
+ jss: { width: metrics.icon, height: metrics.icon },
2119
2226
  icon,
2120
2227
  color: getGlyphColor(color, disabled, bare)
2121
2228
  }
@@ -2230,19 +2337,19 @@ var InputFrame = React35.forwardRef(function InputFrame2({ children, jss, ...row
2230
2337
  ":hover": {
2231
2338
  borderColor: cssVar("--strong-divider")
2232
2339
  },
2233
- ":has(:focus-visible)": {
2340
+ ":has(:is(input, textarea, select):focus-visible)": {
2234
2341
  borderColor: cssVar("--outline"),
2235
2342
  outline: `2px solid ${cssVar("--outline")}`,
2236
- outlineOffset: 1
2343
+ outlineOffset: -2
2237
2344
  },
2238
- ":has(:disabled)": {
2345
+ ":has(:is(input, textarea, select):disabled)": {
2239
2346
  backgroundColor: cssVar("--secondary-background"),
2240
2347
  borderColor: cssVar("--divider")
2241
2348
  },
2242
- ":has([aria-invalid=true])": {
2349
+ ":has(:is(input, textarea, select)[aria-invalid=true])": {
2243
2350
  borderColor: cssVar("--negative-text")
2244
2351
  },
2245
- ":has([aria-invalid=true]:focus-visible)": {
2352
+ ":has(:is(input, textarea, select)[aria-invalid=true]:focus-visible)": {
2246
2353
  outline: `2px solid ${cssVar("--negative-text")}`,
2247
2354
  outlineColor: cssVar("--negative-text")
2248
2355
  }
@@ -2324,97 +2431,185 @@ var NumericInputSegment = React35.forwardRef(
2324
2431
  );
2325
2432
  }
2326
2433
  );
2327
- var styles5 = {
2328
- popover: {
2329
- padding: 0,
2330
- zIndex: 1e3,
2331
- top: `calc(100% + ${cssVar("--spacing-xs")})`,
2332
- right: "auto",
2333
- left: 0,
2334
- margin: 0,
2335
- border: 0,
2336
- overflow: "visible",
2337
- background: "transparent",
2338
- animation: "popoverFadeIn 0.15s ease-out"
2339
- },
2340
- card: {
2341
- minWidth: 220,
2342
- maxWidth: "calc(100vw - 32px)",
2343
- overflow: "hidden"
2344
- }
2345
- };
2346
- function Popover({
2347
- children,
2348
- close
2349
- }) {
2350
- const activeElementRef = useRef(null);
2351
- 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(
2352
2440
  useCallback(
2353
- (root) => {
2354
- activeElementRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
2355
- const selectedElement = root.querySelector(
2356
- '[aria-selected="true"]'
2357
- );
2358
- const autofocusElement = root.querySelector(
2359
- '[data-autofocus="true"]'
2360
- );
2361
- const [firstElement] = queryFocusables(root);
2362
- const element = selectedElement ?? autofocusElement ?? firstElement;
2363
- if (element) {
2364
- element.focus();
2365
- } else {
2366
- root.focus();
2367
- }
2368
- const keydown = (e) => {
2369
- if (e.key === "Escape") {
2370
- close();
2371
- } else if (e.key === "Tab") {
2372
- const focusables = queryFocusables(root).filter(
2373
- (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`
2374
2493
  );
2375
- if (focusables.length === 0) {
2376
- e.stopPropagation();
2377
- e.preventDefault();
2378
- }
2379
- const focusedIndex = focusables.findIndex(
2380
- (x) => x === document.activeElement
2494
+ else
2495
+ element.style.setProperty(
2496
+ "--aidos-overlay-width",
2497
+ `${available}px`
2381
2498
  );
2382
- if (focusables.length === 0) {
2383
- e.stopPropagation();
2384
- e.preventDefault();
2385
- } else if (e.shiftKey && focusedIndex === 0) {
2386
- focusables[focusables.length - 1].focus();
2387
- e.stopPropagation();
2388
- e.preventDefault();
2389
- } else if (!e.shiftKey && focusedIndex === focusables.length - 1) {
2390
- focusables[0].focus();
2391
- e.stopPropagation();
2392
- e.preventDefault();
2393
- } else ;
2394
- }
2499
+ element.dataset.placement = side;
2395
2500
  };
2396
- const click = () => {
2397
- close();
2398
- };
2399
- const timeout = window.setTimeout(() => {
2400
- window.addEventListener("keydown", keydown);
2401
- window.addEventListener("click", click);
2402
- }, 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);
2403
2510
  return () => {
2404
- window.clearTimeout(timeout);
2405
- activeElementRef.current?.focus();
2406
- window.removeEventListener("keydown", keydown);
2407
- 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);
2408
2517
  };
2409
2518
  },
2410
- [close]
2519
+ [placement, align]
2411
2520
  )
2412
2521
  );
2413
- 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
+ );
2414
2605
  }
2415
2606
  function PopoverTrigger({
2416
2607
  PopoverComponent,
2608
+ content,
2417
2609
  ariaLabel,
2610
+ placement = "bottom",
2611
+ align = "start",
2612
+ role = "dialog",
2418
2613
  jss,
2419
2614
  jssDialog,
2420
2615
  grow,
@@ -2422,59 +2617,71 @@ function PopoverTrigger({
2422
2617
  tag,
2423
2618
  children
2424
2619
  }) {
2425
- const [popover, setPopover] = useState(null);
2426
- const dialogRef = useRef(null);
2427
- useEffect(() => {
2428
- if (popover == null) {
2429
- dialogRef.current?.close();
2430
- } else {
2431
- dialogRef.current?.show();
2432
- }
2433
- }, [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);
2434
2627
  const toggle = (input) => {
2435
- if (popover == null) {
2436
- setPopover(
2437
- /* @__PURE__ */ jsx(
2438
- PopoverComponent,
2439
- {
2440
- ...input,
2441
- close: () => {
2442
- setPopover(null);
2443
- }
2444
- }
2445
- )
2446
- );
2447
- } else {
2448
- setPopover(null);
2449
- }
2628
+ if (open || pointerOpen.current) close();
2629
+ else
2630
+ setOpen({
2631
+ element: PopoverComponent ? /* @__PURE__ */ jsx(PopoverComponent, { ...input, close }) : null
2632
+ });
2633
+ pointerOpen.current = false;
2450
2634
  };
2451
2635
  return /* @__PURE__ */ jsxs(
2452
2636
  BaseView,
2453
2637
  {
2638
+ ref: anchor,
2454
2639
  grow,
2455
2640
  shrink,
2456
2641
  tag,
2457
- relative: true,
2458
- 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
+ },
2459
2647
  children: [
2460
- children({ toggle, expanded: popover != null }),
2461
- /* @__PURE__ */ jsx(
2462
- "dialog",
2463
- {
2464
- "aria-label": ariaLabel,
2465
- ref: (ref) => {
2466
- dialogRef.current = ref;
2467
- },
2468
- className: toClassnames([styles5.popover, jssDialog]),
2469
- onClose: () => {
2470
- setPopover(null);
2471
- },
2472
- onClick: (e) => {
2473
- e.preventDefault();
2474
- e.stopPropagation();
2475
- },
2476
- children: popover
2477
- }
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
2478
2685
  )
2479
2686
  ]
2480
2687
  }
@@ -2974,7 +3181,7 @@ var DateInput = React35.forwardRef(function DateInput2({
2974
3181
  field
2975
3182
  ] });
2976
3183
  });
2977
- var styles6 = {
3184
+ var styles5 = {
2978
3185
  root: {
2979
3186
  backgroundColor: "var(--primary-background)"
2980
3187
  },
@@ -2983,7 +3190,10 @@ var styles6 = {
2983
3190
  flexGrow: 1,
2984
3191
  backgroundColor: "var(--primary-background)",
2985
3192
  color: "var(--primary-text)",
2986
- outline: "none",
3193
+ ":focus-visible": {
3194
+ outline: "2px solid var(--outline)",
3195
+ outlineOffset: -2
3196
+ },
2987
3197
  border: "none",
2988
3198
  fontSize: 20,
2989
3199
  lineHeight: 24 / 20,
@@ -2996,7 +3206,7 @@ var styles6 = {
2996
3206
  }
2997
3207
  };
2998
3208
  var DatetimeInput = React35.forwardRef(function DatetimeInput2({ date, onDateChange, jss, icon, addOn, ...inputProps }, ref) {
2999
- return /* @__PURE__ */ jsxs(Row, { jss: styles6.root, children: [
3209
+ return /* @__PURE__ */ jsxs(Row, { jss: styles5.root, children: [
3000
3210
  icon && /* @__PURE__ */ jsx(Box, { padding: "medium", children: /* @__PURE__ */ jsx(Icon, { size: "medium", color: "secondary", icon }) }),
3001
3211
  /* @__PURE__ */ jsx(
3002
3212
  BaseInput,
@@ -3010,81 +3220,142 @@ var DatetimeInput = React35.forwardRef(function DatetimeInput2({ date, onDateCha
3010
3220
  onDateChange(parseDatetimeInputValue(e.target.value));
3011
3221
  }
3012
3222
  },
3013
- jss: [styles6.input, jss]
3223
+ jss: [styles5.input, jss]
3014
3224
  }
3015
3225
  ),
3016
3226
  addOn
3017
3227
  ] });
3018
3228
  });
3019
- var styles7 = {
3020
- root: {
3021
- width: "100%",
3022
- borderBottom: "1px solid var(--divider)"
3023
- }
3024
- };
3025
- function ListDivider() {
3026
- 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;
3027
3232
  }
3028
- var styles8 = {
3029
- dialog: {
3030
- border: "1px solid var(--divider)",
3031
- borderRadius: "var(--border-radius-l)",
3032
- padding: 0,
3033
- boxShadow: "var(--shadow-lg)",
3034
- animation: "dialogFadeIn 0.2s ease-out",
3035
- "::backdrop": {
3036
- backgroundColor: "rgba(0, 0, 0, 0.4)",
3037
- animation: "backdropFadeIn 0.2s ease-out"
3038
- }
3039
- },
3040
- root: {
3041
- display: "grid",
3042
- width: "calc(100vw - 48px)",
3043
- gridTemplateAreas: `
3044
- "header"
3045
- "content"
3046
- `,
3047
- "@media (min-width: 750px)": {
3048
- maxWidth: 750
3049
- },
3050
- backgroundColor: "var(--secondary-background)"
3051
- },
3052
- header: {
3053
- gridArea: "header"
3054
- },
3055
- content: {
3056
- gridArea: "content"
3057
- }
3058
- };
3059
- var Dialog = ({
3233
+ function ModalSurface({
3060
3234
  label,
3061
3235
  children,
3062
- close
3063
- }) => {
3064
- return /* @__PURE__ */ jsxs(BaseView, { jss: styles8.root, children: [
3065
- /* @__PURE__ */ jsxs(Column, { jss: styles8.header, children: [
3066
- /* @__PURE__ */ jsxs(Row, { padding: "medium", justify: "space-between", align: "center", children: [
3067
- /* @__PURE__ */ jsx(Text, { size: "medium", color: "secondary", children: label }),
3068
- /* @__PURE__ */ jsx(
3069
- IconButton,
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,
3070
3345
  {
3071
- autoFocus: true,
3072
- bare: true,
3073
- icon: "x",
3074
- onClick: close,
3075
- color: "secondary"
3346
+ padding: "large",
3347
+ gap: "small",
3348
+ justify: "flex-end",
3349
+ jss: { flexShrink: 0, borderTop: "1px solid var(--divider)" },
3350
+ children: footer
3076
3351
  }
3077
3352
  )
3078
- ] }),
3079
- /* @__PURE__ */ jsx(ListDivider, {})
3080
- ] }),
3081
- /* @__PURE__ */ jsx(BaseView, { jss: styles8.content, children })
3082
- ] });
3083
- };
3084
- var DialogContext = React35.createContext({
3085
- setDialog: () => {
3086
- }
3087
- });
3353
+ ]
3354
+ }
3355
+ );
3356
+ }
3357
+ var DialogContext = createContext({ setDialog: () => {
3358
+ } });
3088
3359
  function DialogProvider({ children }) {
3089
3360
  const [dialog, setDialog] = useState(null);
3090
3361
  const value = useMemo(() => ({ setDialog }), []);
@@ -3095,50 +3366,20 @@ function DialogProvider({ children }) {
3095
3366
  }
3096
3367
  function useDialog(DialogComponent, options) {
3097
3368
  const { setDialog } = useContext(DialogContext);
3098
- const dialogRef = useRef(null);
3099
- const activeElementRef = useRef(null);
3100
- const close = useCallback(() => {
3101
- dialogRef.current?.close();
3102
- activeElementRef.current?.focus();
3103
- dialogRef.current = null;
3104
- activeElementRef.current = null;
3105
- setDialog(null);
3106
- }, [setDialog]);
3107
- const open = (input) => {
3108
- activeElementRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
3109
- setDialog(
3110
- /* @__PURE__ */ jsx(
3111
- "dialog",
3112
- {
3113
- ref: (ref) => {
3114
- dialogRef.current = ref;
3115
- ref?.showModal();
3116
- },
3117
- className: toClassnames(styles8.dialog),
3118
- onClose: () => {
3119
- close();
3120
- },
3121
- onClick: (e) => {
3122
- if (dialogRef.current == null) {
3123
- return;
3124
- }
3125
- const dialogDimensions = dialogRef.current.getBoundingClientRect();
3126
- if (options.closeOnOutsideClick === false) {
3127
- return;
3128
- }
3129
- if (e.clientX < dialogDimensions.left || e.clientX > dialogDimensions.right || e.clientY > dialogDimensions.bottom || e.clientY < dialogDimensions.top) {
3130
- dialogRef.current.close();
3131
- }
3132
- },
3133
- children: /* @__PURE__ */ jsx(DialogComponent, { ...input, close })
3134
- }
3135
- )
3136
- );
3137
- };
3138
- return {
3139
- open,
3140
- close
3141
- };
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 };
3142
3383
  }
3143
3384
 
3144
3385
  // src/Emitter.ts
@@ -3168,7 +3409,16 @@ function guid() {
3168
3409
  return v.toString(16);
3169
3410
  });
3170
3411
  }
3171
- 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];
3172
3422
  return /* @__PURE__ */ jsx(
3173
3423
  BaseLink,
3174
3424
  {
@@ -3179,9 +3429,12 @@ var IconLink = React35.forwardRef(function IconLink2({ icon, color, bare, disabl
3179
3429
  display: "flex",
3180
3430
  justifyContent: "center",
3181
3431
  alignItems: "center",
3182
- height: 34,
3183
- width: 34,
3184
- 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,
3185
3438
  textDecoration: "none"
3186
3439
  },
3187
3440
  jss
@@ -3193,6 +3446,7 @@ var IconLink = React35.forwardRef(function IconLink2({ icon, color, bare, disabl
3193
3446
  Icon,
3194
3447
  {
3195
3448
  size: "medium",
3449
+ jss: { width: metrics.icon, height: metrics.icon },
3196
3450
  icon,
3197
3451
  color: getGlyphColor(color, disabled, bare)
3198
3452
  }
@@ -3208,6 +3462,10 @@ var Link = React35.forwardRef(function Link2({
3208
3462
  icon,
3209
3463
  underline,
3210
3464
  iconPosition = "left",
3465
+ size = "medium",
3466
+ leading,
3467
+ trailing,
3468
+ rowProps,
3211
3469
  align = "center",
3212
3470
  gap = "medium",
3213
3471
  justify = "center",
@@ -3215,6 +3473,8 @@ var Link = React35.forwardRef(function Link2({
3215
3473
  inline = true,
3216
3474
  ...otherProps
3217
3475
  }, ref) {
3476
+ const metrics = controlSizes[size];
3477
+ const glyph = getGlyphColor(color, disabled, bare);
3218
3478
  return /* @__PURE__ */ jsx(
3219
3479
  BaseLink,
3220
3480
  {
@@ -3226,8 +3486,10 @@ var Link = React35.forwardRef(function Link2({
3226
3486
  padding: "none",
3227
3487
  jss: [
3228
3488
  {
3229
- height: 34,
3230
- padding: "0 14px",
3489
+ height: metrics.height,
3490
+ minWidth: 0,
3491
+ maxWidth: "100%",
3492
+ padding: `0 ${metrics.padding}px`,
3231
3493
  borderRadius: cssVar("--border-radius-l"),
3232
3494
  justifyContent: "center",
3233
3495
  userSelect: "none",
@@ -3245,28 +3507,37 @@ var Link = React35.forwardRef(function Link2({
3245
3507
  children: /* @__PURE__ */ jsxs(
3246
3508
  Row,
3247
3509
  {
3248
- jss: {
3249
- display: inline ? "inline-flex" : "flex"
3250
- },
3510
+ ...rowProps,
3511
+ direction: "row",
3512
+ jss: [
3513
+ {
3514
+ display: inline ? "inline-flex" : "flex",
3515
+ minWidth: 0
3516
+ },
3517
+ rowProps?.jss
3518
+ ],
3251
3519
  grow: true,
3252
3520
  align,
3253
3521
  gap,
3254
3522
  justify,
3255
3523
  children: [
3524
+ leading,
3256
3525
  icon && iconPosition === "left" && /* @__PURE__ */ jsx(
3257
3526
  Icon,
3258
3527
  {
3259
3528
  icon,
3260
3529
  size: "medium",
3261
- color: getGlyphColor(color, disabled, bare)
3530
+ jss: { width: metrics.icon, height: metrics.icon, flexShrink: 0 },
3531
+ color: glyph
3262
3532
  }
3263
3533
  ),
3264
3534
  /* @__PURE__ */ jsx(
3265
3535
  Text,
3266
3536
  {
3267
- size: "medium",
3268
- color: getGlyphColor(color, disabled, bare),
3537
+ size: metrics.text,
3538
+ color: glyph,
3269
3539
  jss: {
3540
+ minWidth: 0,
3270
3541
  fontWeight: 600,
3271
3542
  letterSpacing: "-0.01em"
3272
3543
  },
@@ -3278,9 +3549,11 @@ var Link = React35.forwardRef(function Link2({
3278
3549
  {
3279
3550
  icon,
3280
3551
  size: "medium",
3281
- color: getGlyphColor(color, disabled, bare)
3552
+ jss: { width: metrics.icon, height: metrics.icon, flexShrink: 0 },
3553
+ color: glyph
3282
3554
  }
3283
- )
3555
+ ),
3556
+ trailing
3284
3557
  ]
3285
3558
  }
3286
3559
  )
@@ -3312,7 +3585,13 @@ var ListButtonItem = React35.forwardRef(function ListButtonItem2({
3312
3585
  onClick,
3313
3586
  color = "secondary",
3314
3587
  disabled = false,
3315
- 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,
3316
3595
  jss,
3317
3596
  gap,
3318
3597
  selected,
@@ -3322,6 +3601,7 @@ var ListButtonItem = React35.forwardRef(function ListButtonItem2({
3322
3601
  return /* @__PURE__ */ jsx(
3323
3602
  BaseListItem,
3324
3603
  {
3604
+ size,
3325
3605
  disabled,
3326
3606
  padding: "none",
3327
3607
  gap,
@@ -3348,7 +3628,17 @@ var ListButtonItem = React35.forwardRef(function ListButtonItem2({
3348
3628
  color,
3349
3629
  ref,
3350
3630
  "data-list-primary": true,
3351
- 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
+ ],
3352
3642
  onClick,
3353
3643
  children: content
3354
3644
  }
@@ -3356,6 +3646,15 @@ var ListButtonItem = React35.forwardRef(function ListButtonItem2({
3356
3646
  }
3357
3647
  );
3358
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
+ }
3359
3658
  function ListHeaderItem({
3360
3659
  highlight,
3361
3660
  headline,
@@ -3387,7 +3686,13 @@ var ListLinkItem = React35.forwardRef(function ListLinkItem2({
3387
3686
  onClick,
3388
3687
  href,
3389
3688
  disabled = false,
3390
- 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,
3391
3696
  jss,
3392
3697
  gap,
3393
3698
  selected,
@@ -3399,6 +3704,7 @@ var ListLinkItem = React35.forwardRef(function ListLinkItem2({
3399
3704
  return /* @__PURE__ */ jsx(
3400
3705
  BaseListItem,
3401
3706
  {
3707
+ size,
3402
3708
  disabled,
3403
3709
  "aria-selected": selected,
3404
3710
  padding: "none",
@@ -3428,7 +3734,17 @@ var ListLinkItem = React35.forwardRef(function ListLinkItem2({
3428
3734
  href,
3429
3735
  ref,
3430
3736
  "data-list-primary": true,
3431
- 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
+ ],
3432
3748
  onClick,
3433
3749
  children: content
3434
3750
  }
@@ -3436,7 +3752,7 @@ var ListLinkItem = React35.forwardRef(function ListLinkItem2({
3436
3752
  }
3437
3753
  );
3438
3754
  });
3439
- var styles9 = {
3755
+ var styles7 = {
3440
3756
  root: {
3441
3757
  height: "var(--spacing-xl)",
3442
3758
  backgroundColor: "var(--secondary-background)",
@@ -3444,7 +3760,7 @@ var styles9 = {
3444
3760
  }
3445
3761
  };
3446
3762
  function ListSpacer() {
3447
- return /* @__PURE__ */ jsx(BaseView, { jss: styles9.root });
3763
+ return /* @__PURE__ */ jsx(BaseView, { jss: styles7.root });
3448
3764
  }
3449
3765
  function MenuIcon({ open, color }) {
3450
3766
  return /* @__PURE__ */ jsxs(Column, { gap: "small", children: [
@@ -3745,7 +4061,7 @@ function OnVisible({
3745
4061
  }, [onVisible]);
3746
4062
  return children(refCallback);
3747
4063
  }
3748
- var styles10 = {
4064
+ var styles8 = {
3749
4065
  root: {
3750
4066
  width: "100%",
3751
4067
  position: "relative",
@@ -3789,18 +4105,18 @@ function ProgressBar({
3789
4105
  "aria-valuemin": 0,
3790
4106
  "aria-valuemax": 100,
3791
4107
  "aria-valuenow": Math.round(value * 100),
3792
- jss: [styles10.root, { height: sizes4[size] }, jss],
4108
+ jss: [styles8.root, { height: sizes4[size] }, jss],
3793
4109
  children: /* @__PURE__ */ jsx(
3794
4110
  BaseView,
3795
4111
  {
3796
- jss: [styles10.fill, getBackground(color)],
4112
+ jss: [styles8.fill, getBackground(color)],
3797
4113
  style: { transform: `scaleX(${value})` }
3798
4114
  }
3799
4115
  )
3800
4116
  }
3801
4117
  );
3802
4118
  }
3803
- var styles11 = {
4119
+ var styles9 = {
3804
4120
  root: {
3805
4121
  display: "block"
3806
4122
  },
@@ -3844,7 +4160,7 @@ function ProgressCircle({
3844
4160
  "aria-valuemin": 0,
3845
4161
  "aria-valuemax": 100,
3846
4162
  "aria-valuenow": Math.round(value * 100),
3847
- className: toClassnames([styles11.root, jss]),
4163
+ className: toClassnames([styles9.root, jss]),
3848
4164
  width: diameter,
3849
4165
  height: diameter,
3850
4166
  viewBox: `0 0 ${diameter} ${diameter}`,
@@ -3852,7 +4168,7 @@ function ProgressCircle({
3852
4168
  /* @__PURE__ */ jsx(
3853
4169
  "circle",
3854
4170
  {
3855
- className: toClassnames(styles11.track),
4171
+ className: toClassnames(styles9.track),
3856
4172
  strokeWidth: stroke,
3857
4173
  r: radius,
3858
4174
  cx: center,
@@ -3862,7 +4178,7 @@ function ProgressCircle({
3862
4178
  /* @__PURE__ */ jsx(
3863
4179
  "circle",
3864
4180
  {
3865
- className: toClassnames(styles11.fill),
4181
+ className: toClassnames(styles9.fill),
3866
4182
  stroke: getColorValue(color),
3867
4183
  strokeWidth: stroke,
3868
4184
  strokeLinecap: value === 0 ? "butt" : "round",
@@ -4398,45 +4714,90 @@ function useStream({
4398
4714
  frame
4399
4715
  };
4400
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
+ }
4401
4765
  function Sublist({
4402
4766
  children,
4403
4767
  label,
4404
4768
  labelBold,
4405
4769
  initialState = { collapsed: false },
4406
- jss,
4407
- secondaryAddOn
4770
+ expanded: controlledExpanded,
4771
+ onExpandedChange,
4772
+ jss
4408
4773
  }) {
4409
- const [collapsed, setCollapsed] = React35.useState(initialState.collapsed);
4774
+ const [localExpanded, setExpanded] = useState(!initialState.collapsed);
4775
+ const expanded = controlledExpanded ?? localExpanded;
4776
+ const id = useId();
4410
4777
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4411
4778
  /* @__PURE__ */ jsx(
4412
4779
  ListButtonItem,
4413
4780
  {
4414
4781
  headline: label,
4415
4782
  headlineBold: labelBold,
4416
- 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
+ },
4417
4789
  jss,
4418
- addOn: /* @__PURE__ */ jsxs(Row, { gap: "medium", align: "center", children: [
4419
- secondaryAddOn,
4420
- /* @__PURE__ */ jsx(
4421
- Box,
4422
- {
4423
- padding: "none",
4424
- jss: [
4425
- {
4426
- transition: "transform 0.15s ease-in"
4427
- },
4428
- !collapsed && {
4429
- transform: "rotateZ(90deg)"
4430
- }
4431
- ],
4432
- children: /* @__PURE__ */ jsx(Icon, { color: "inherit", size: "medium", icon: "chevron-right" })
4433
- }
4434
- )
4435
- ] }),
4790
+ icon: "chevron-right",
4791
+ iconPosition: "end",
4792
+ iconJss: {
4793
+ transition: "transform 180ms ease",
4794
+ transform: expanded ? "rotateZ(90deg)" : "none",
4795
+ "@media (prefers-reduced-motion: reduce)": { transition: "none" }
4796
+ },
4436
4797
  color: "secondary"
4437
4798
  }
4438
4799
  ),
4439
- collapsed ? null : children
4800
+ /* @__PURE__ */ jsx(Disclosure, { id, tag: "li", role: "rowgroup", expanded, children: /* @__PURE__ */ jsx(BaseList, { role: "presentation", children }) })
4440
4801
  ] });
4441
4802
  }
4442
4803
  function SubmitIconInput({ icon, ...otherProps }) {
@@ -4474,7 +4835,7 @@ function SubmitIconInput({ icon, ...otherProps }) {
4474
4835
  }
4475
4836
  );
4476
4837
  }
4477
- var styles12 = {
4838
+ var styles10 = {
4478
4839
  root: {},
4479
4840
  default: {
4480
4841
  backgroundColor: cssVar("--nav-bar")
@@ -4567,11 +4928,11 @@ function TabBar({
4567
4928
  tag: "nav",
4568
4929
  "aria-label": ariaLabel,
4569
4930
  jss: [
4570
- styles12.root,
4571
- styles12[variant],
4572
- variant === "default" && (horizontal ? styles12.horizontal : styles12.vertical),
4573
- fixed && styles12.fixed,
4574
- 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),
4575
4936
  jss
4576
4937
  ],
4577
4938
  children: [
@@ -4582,16 +4943,16 @@ function TabBar({
4582
4943
  ...otherProps,
4583
4944
  direction,
4584
4945
  align,
4585
- jss: horizontal ? styles12.horizontalBar : styles12.verticalBar,
4946
+ jss: horizontal ? styles10.horizontalBar : styles10.verticalBar,
4586
4947
  children: tabs.map((tab) => {
4587
4948
  const { label, icon, href, onClick } = tab;
4588
4949
  const selected = tab.selected === true;
4589
4950
  const color = selected ? "highlight" : "secondary";
4590
4951
  const tabJSS = [
4591
- styles12.item,
4592
- horizontal ? styles12.horizontalItem : styles12.verticalItem,
4593
- variant === "default" && styles12.defaultItem,
4594
- 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,
4595
4956
  selected && {
4596
4957
  backgroundColor: cssVar("--light-highlight")
4597
4958
  },
@@ -4642,12 +5003,12 @@ function TabBar({
4642
5003
  })
4643
5004
  }
4644
5005
  ),
4645
- horizontal && /* @__PURE__ */ jsx(BaseView, { "aria-hidden": true, jss: styles12.safeArea })
5006
+ horizontal && /* @__PURE__ */ jsx(BaseView, { "aria-hidden": true, jss: styles10.safeArea })
4646
5007
  ]
4647
5008
  }
4648
5009
  );
4649
5010
  }
4650
- var styles13 = {
5011
+ var styles11 = {
4651
5012
  root: {
4652
5013
  overflowX: "auto",
4653
5014
  overflowY: "hidden",
@@ -4703,135 +5064,242 @@ function Table({
4703
5064
  material,
4704
5065
  padding,
4705
5066
  gap,
4706
- jss: [styles13.root, jss],
4707
- 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 })
4708
5069
  }
4709
5070
  );
4710
5071
  }
4711
- function Tabs({
5072
+ var Tabs = React35.forwardRef(function Tabs2({
4712
5073
  tabs,
4713
5074
  variant = "underline",
4714
5075
  gap = "none",
4715
5076
  padding = "none",
4716
- tabPadding = "medium",
4717
- labelSize = "large",
5077
+ tabPadding = variant === "document" ? ["small", "medium"] : "medium",
5078
+ labelSize = variant === "document" ? "small" : "large",
4718
5079
  iconSize = "medium",
4719
5080
  jss,
4720
5081
  jssTab,
4721
5082
  labelRenderer,
4722
- ["aria-controls"]: ariaControls,
4723
- ...otherProps
4724
- }) {
4725
- 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
+ };
4726
5105
  return /* @__PURE__ */ jsx(
4727
5106
  Row,
4728
5107
  {
5108
+ ...props,
4729
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,
4730
5129
  jss: [
5130
+ { minWidth: 0, maxWidth: "100%" },
4731
5131
  variant === "segmented" && {
4732
- isolation: "isolate",
4733
- backgroundColor: cssVar("--hovered-background"),
5132
+ background: cssVar("--hovered-background"),
4734
5133
  borderRadius: cssVar("--border-radius-l"),
4735
- maxWidth: "100%",
4736
5134
  padding: cssVar("--spacing-xs"),
4737
5135
  width: "fit-content"
4738
5136
  },
5137
+ variant === "document" && {
5138
+ overflowX: "auto",
5139
+ overscrollBehavior: "contain",
5140
+ scrollbarWidth: "thin",
5141
+ alignItems: "center",
5142
+ gap: 3,
5143
+ padding: 3
5144
+ },
4739
5145
  jss
4740
5146
  ],
4741
- gap,
4742
- padding,
4743
- ref: root,
4744
- ...otherProps,
4745
- children: tabs.map(
4746
- ({
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,
4747
5171
  label,
4748
5172
  icon,
4749
5173
  href,
4750
5174
  onClick,
4751
- selected,
5175
+ onClose,
5176
+ panelId,
4752
5177
  addOn,
4753
5178
  addOnPosition = "start"
4754
- }) => {
4755
- const BaseComponent = href != null ? BaseLink : BaseButton;
4756
- return /* @__PURE__ */ jsxs(
4757
- BaseComponent,
4758
- {
4759
- "aria-controls": ariaControls,
4760
- role: "tab",
4761
- "aria-selected": selected ? "true" : void 0,
4762
- bare: true,
4763
- color: selected ? "primary" : "secondary",
4764
- href,
4765
- onClick,
4766
- animateInteraction: false,
4767
- 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,
4768
5205
  {
4769
- alignItems: "center",
4770
- gap: cssVar("--spacing-s"),
4771
- textDecoration: "none"
4772
- },
4773
- variant === "underline" && {
4774
- borderBottom: selected ? `3px solid ${cssVar("--highlight")}` : `3px solid transparent`,
4775
- ":active span": {
4776
- transform: "scale(0.97)"
4777
- },
4778
- ":first-child": {
4779
- borderTopLeftRadius: cssVar("--border-radius-m")
4780
- },
4781
- ":last-child": {
4782
- borderTopRightRadius: cssVar("--border-radius-m")
4783
- },
4784
- ":hover": {
4785
- backgroundColor: cssVar("--hovered-background")
4786
- },
4787
- ":active:hover": {
4788
- backgroundColor: cssVar("--pressed-background")
4789
- }
4790
- },
4791
- variant === "segmented" && {
4792
- position: "relative",
4793
- zIndex: selected ? 1 : 0,
4794
- borderRadius: cssVar("--border-radius-m"),
4795
- backgroundColor: selected ? cssVar("--overlay-background") : "transparent",
4796
- boxShadow: selected ? `0 0 0 1px ${cssVar("--divider")}, 0 0 4px color-mix(in srgb, ${cssVar("--primary-text")} 10%, transparent)` : "none",
4797
- transition: `background-color ${cssVar("--transition-fast")}, box-shadow ${cssVar("--transition-fast")}`,
4798
- ":hover": {
4799
- backgroundColor: selected ? cssVar("--overlay-background") : cssVar("--hovered-background")
4800
- },
4801
- ":active:hover": {
4802
- top: 1,
4803
- backgroundColor: cssVar("--pressed-background")
4804
- }
4805
- },
4806
- getPadding(tabPadding),
4807
- typeof jssTab === "function" ? jssTab({ selected }) : jssTab
4808
- ],
4809
- children: [
4810
- addOnPosition === "start" && addOn,
4811
- icon && /* @__PURE__ */ jsx(
4812
- Icon,
4813
- {
4814
- icon,
4815
- size: iconSize,
4816
- 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 }
4817
5284
  }
4818
- ),
4819
- /* @__PURE__ */ jsx(Text, { size: labelSize, color: selected ? "primary" : "secondary", children: labelRenderer ? labelRenderer(label) : label }),
4820
- addOnPosition === "end" && addOn
4821
- ]
4822
- },
4823
- label
4824
- );
4825
- }
4826
- )
5285
+ }
5286
+ )
5287
+ ]
5288
+ },
5289
+ id ?? label
5290
+ );
5291
+ })
4827
5292
  }
4828
5293
  );
4829
- }
5294
+ });
4830
5295
  var TextArea = React35.forwardRef(function TextArea2({
4831
5296
  jss,
4832
5297
  onValueChange,
4833
5298
  value,
4834
5299
  padding = "medium",
5300
+ size = "medium",
5301
+ autoGrow = false,
5302
+ rows = autoGrow ? 1 : 3,
4835
5303
  ...otherProps
4836
5304
  }, ref) {
4837
5305
  return /* @__PURE__ */ jsx(
@@ -4839,29 +5307,43 @@ var TextArea = React35.forwardRef(function TextArea2({
4839
5307
  {
4840
5308
  ...otherProps,
4841
5309
  ref,
5310
+ rows,
4842
5311
  className: toClassnames([
4843
5312
  {
5313
+ display: "block",
5314
+ minWidth: 0,
4844
5315
  flexGrow: 1,
4845
5316
  color: cssVar("--primary-text"),
4846
- outline: "none",
4847
- fontSize: 20,
4848
- lineHeight: 24 / 20,
5317
+ ...getTypography(size),
4849
5318
  backgroundColor: cssVar("--overlay-background"),
4850
5319
  border: `1px solid ${cssVar("--divider")}`,
4851
5320
  borderRadius: cssVar("--border-radius-m"),
4852
- "::placeholder": {
4853
- color: cssVar("--subtle-text")
4854
- },
5321
+ "::placeholder": { color: cssVar("--subtle-text") },
4855
5322
  ":focus-visible": {
4856
- outline: `2px solid ${cssVar("--highlight")}`,
5323
+ outline: `2px solid ${cssVar("--outline")}`,
4857
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"
4858
5334
  }
4859
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
+ },
4860
5342
  getPadding(padding),
4861
5343
  jss
4862
5344
  ]),
4863
5345
  value,
4864
- onChange: onValueChange ? (e) => onValueChange(e.target.value) : void 0
5346
+ onChange: onValueChange ? (event) => onValueChange(event.target.value) : void 0
4865
5347
  }
4866
5348
  );
4867
5349
  });
@@ -4871,66 +5353,82 @@ var TextInput = React35.forwardRef(function TextInput2({
4871
5353
  jssRoot,
4872
5354
  jss,
4873
5355
  addOn,
4874
- gap = "none",
5356
+ gap,
4875
5357
  addOnPosition = "start",
4876
- padding = "medium",
5358
+ padding,
4877
5359
  size = "medium",
4878
5360
  ...inputProps
4879
5361
  }, ref) {
4880
- return /* @__PURE__ */ jsxs(InputFrame, { gap, jss: jssRoot, children: [
4881
- addOnPosition === "start" && addOn && /* @__PURE__ */ jsx(
4882
- Column,
4883
- {
4884
- justify: "center",
4885
- align: "center",
4886
- jss: [getPadding(padding), { paddingRight: 0 }],
4887
- children: addOn
4888
- }
4889
- ),
4890
- /* @__PURE__ */ jsx(
4891
- BaseInput,
4892
- {
4893
- ...inputProps,
4894
- ref,
4895
- value,
4896
- onChange: onValueChange ? (e) => onValueChange(e.target.value) : void 0,
4897
- 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,
4898
5372
  {
4899
- minWidth: 0,
4900
- flexGrow: 1,
4901
- backgroundColor: "transparent",
4902
- color: cssVar("--primary-text"),
4903
- outline: "none",
4904
- border: "none",
4905
- ...getTypography(size),
4906
- "::placeholder": {
4907
- color: cssVar("--subtle-text")
4908
- },
4909
- ":disabled": {
4910
- color: cssVar("--subtle-text"),
4911
- cursor: "not-allowed"
4912
- },
4913
- "[aria-invalid=true]": {
4914
- color: cssVar("--negative-text")
4915
- }
4916
- },
4917
- getPadding(padding),
4918
- addOn && addOnPosition === "start" ? { paddingLeft: 0 } : null,
4919
- addOn && addOnPosition === "end" ? { paddingRight: 0 } : null,
4920
- jss
4921
- ]
4922
- }
4923
- ),
4924
- addOnPosition === "end" && addOn && /* @__PURE__ */ jsx(
4925
- Column,
4926
- {
4927
- justify: "center",
4928
- align: "center",
4929
- jss: [getPadding(padding), { paddingLeft: 0 }],
4930
- children: addOn
4931
- }
4932
- )
4933
- ] });
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
+ );
4934
5432
  });
4935
5433
  function getInitialValue(valueRef) {
4936
5434
  return valueRef.current;
@@ -5131,99 +5629,93 @@ var Toolbar = React35.forwardRef(function Toolbar2({
5131
5629
  ] });
5132
5630
  });
5133
5631
  Toolbar.displayName = "Toolbar";
5134
- var styles14 = {
5135
- tooltip: {
5136
- top: "auto",
5137
- right: "auto",
5138
- bottom: `calc(100% + ${cssVar("--spacing-s")})`,
5139
- left: "50%",
5140
- margin: 0,
5141
- translate: "-50% 0",
5142
- transformOrigin: "bottom center",
5143
- backgroundColor: cssVar("--primary-background"),
5144
- padding: `${cssVar("--spacing-s")} ${cssVar("--spacing-m")}`,
5145
- borderRadius: cssVar("--border-radius-m"),
5146
- border: `1px solid ${cssVar("--divider")}`,
5147
- boxShadow: cssVar("--shadow-md"),
5148
- overflow: "hidden",
5149
- animation: "popoverFadeIn 0.15s ease-out"
5150
- }
5151
- };
5152
- function Tooltip({ content, jss, tag, children }) {
5153
- const [tooltip, setTooltip] = useState(null);
5154
- const dialogRef = useRef(null);
5155
- const focusTrapRoot = useRefEffect(
5156
- useCallback((root) => {
5157
- dialogRef.current = root;
5158
- const keydown = (e) => {
5159
- if (e.key === "Escape") {
5160
- dialogRef.current?.close();
5161
- } else if (e.key === "Tab") {
5162
- dialogRef.current?.close();
5163
- }
5164
- };
5165
- const click = () => {
5166
- dialogRef.current?.close();
5167
- };
5168
- window.addEventListener("keydown", keydown);
5169
- window.addEventListener("click", click);
5170
- const activeElement = document.activeElement;
5171
- root.show();
5172
- if (activeElement instanceof HTMLElement) {
5173
- activeElement.focus();
5174
- }
5175
- return () => {
5176
- window.removeEventListener("keydown", keydown);
5177
- window.removeEventListener("click", click);
5178
- };
5179
- }, [])
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)
5180
5650
  );
5181
- const toggle = () => {
5182
- if (tooltip == null) {
5183
- setTooltip(
5184
- /* @__PURE__ */ jsx(
5185
- "dialog",
5186
- {
5187
- role: "tooltip",
5188
- ref: (ref) => {
5189
- dialogRef.current = ref;
5190
- focusTrapRoot(ref);
5191
- },
5192
- className: toClassnames(styles14.tooltip),
5193
- onClose: () => {
5194
- setTooltip(null);
5195
- },
5196
- onClick: (e) => {
5197
- e.preventDefault();
5198
- e.stopPropagation();
5199
- },
5200
- children: /* @__PURE__ */ jsx(Text, { size: "medium", color: "secondary", children: content })
5201
- }
5202
- )
5203
- );
5204
- } else {
5205
- setTooltip(null);
5206
- }
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);
5207
5661
  };
5208
5662
  return /* @__PURE__ */ jsxs(
5209
5663
  BaseView,
5210
5664
  {
5665
+ ref: (element) => {
5666
+ anchor.current = element;
5667
+ if (!element) clearTimeout(timeout.current);
5668
+ },
5211
5669
  tag,
5212
- relative: true,
5213
- jss: [{ display: "inline-block" }, jss],
5214
- onMouseEnter: () => {
5215
- if (tooltip == null) {
5216
- toggle();
5217
- }
5670
+ jss: [{ display: "inline-block", minWidth: 0 }, jss],
5671
+ onFocus: show,
5672
+ onKeyDown: (event) => {
5673
+ if (event.key === "Tab") setOpen(false);
5218
5674
  },
5219
- onMouseLeave: () => {
5220
- if (tooltip != null) {
5221
- toggle();
5222
- }
5675
+ onBlur: (event) => {
5676
+ if (!event.currentTarget.contains(event.relatedTarget) && !event.currentTarget.matches(":hover") && !surface.current?.matches(":hover"))
5677
+ setOpen(false);
5223
5678
  },
5679
+ onMouseEnter: show,
5680
+ onMouseLeave: leave,
5224
5681
  children: [
5225
- children,
5226
- 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
+ )
5227
5719
  ]
5228
5720
  }
5229
5721
  );
@@ -5282,7 +5774,610 @@ function usePromise(promiseFactory, inputs, initialValue) {
5282
5774
  });
5283
5775
  return [value, error];
5284
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
+ });
5285
6380
 
5286
- 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 };
5287
6382
  //# sourceMappingURL=index.js.map
5288
6383
  //# sourceMappingURL=index.js.map