efficient-shell 4.132.0 → 4.137.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/README.md +142 -18
  2. package/dist/{Browser-XPVJ2K7B.js → Browser-ZNX4WFUH.js} +13 -13
  3. package/dist/{Browser-XPVJ2K7B.js.map → Browser-ZNX4WFUH.js.map} +1 -1
  4. package/dist/{Calculator-ZXJPXG7F.js → Calculator-6FGNKOXU.js} +11 -11
  5. package/dist/{Calculator-ZXJPXG7F.js.map → Calculator-6FGNKOXU.js.map} +1 -1
  6. package/dist/ConfirmDialog-NPQMIGUR.js +4 -0
  7. package/dist/{ConfirmDialog-MTC7QMUJ.js.map → ConfirmDialog-NPQMIGUR.js.map} +1 -1
  8. package/dist/{CurrencyConverter-WSJ2BBSX.js → CurrencyConverter-FF7EXRYL.js} +11 -11
  9. package/dist/{CurrencyConverter-WSJ2BBSX.js.map → CurrencyConverter-FF7EXRYL.js.map} +1 -1
  10. package/dist/{Documents-ONGSXUJI.js → Documents-H3R7XSBH.js} +13 -13
  11. package/dist/{Documents-ONGSXUJI.js.map → Documents-H3R7XSBH.js.map} +1 -1
  12. package/dist/{Files-GQZMFWXQ.js → Files-ZHJIAUC2.js} +19 -19
  13. package/dist/{Files-GQZMFWXQ.js.map → Files-ZHJIAUC2.js.map} +1 -1
  14. package/dist/{Notepad-HM73XAM4.js → Notepad-VE7ISWRQ.js} +14 -14
  15. package/dist/{Notepad-HM73XAM4.js.map → Notepad-VE7ISWRQ.js.map} +1 -1
  16. package/dist/PdfViewer-SQBFYAGW.js +5 -0
  17. package/dist/{PdfViewer-M2YGZIYX.js.map → PdfViewer-SQBFYAGW.js.map} +1 -1
  18. package/dist/{PomodoroTimer-DG3LI5CX.js → PomodoroTimer-IR3WREED.js} +13 -13
  19. package/dist/{PomodoroTimer-DG3LI5CX.js.map → PomodoroTimer-IR3WREED.js.map} +1 -1
  20. package/dist/{Preview-TUSV4UMO.js → Preview-DAQGRNRM.js} +16 -16
  21. package/dist/{Preview-TUSV4UMO.js.map → Preview-DAQGRNRM.js.map} +1 -1
  22. package/dist/{Sidebar-BPU7RCZP.js → Sidebar-YW6H4NDJ.js} +3 -3
  23. package/dist/{Sidebar-BPU7RCZP.js.map → Sidebar-YW6H4NDJ.js.map} +1 -1
  24. package/dist/{Spreadsheet-3WTXCHYQ.js → Spreadsheet-HOCPHJOC.js} +14 -14
  25. package/dist/{Spreadsheet-3WTXCHYQ.js.map → Spreadsheet-HOCPHJOC.js.map} +1 -1
  26. package/dist/{Stock-YMPOMUAW.js → Stock-LVRQPURG.js} +11 -11
  27. package/dist/{Stock-YMPOMUAW.js.map → Stock-LVRQPURG.js.map} +1 -1
  28. package/dist/{Weather-NZO3CWLH.js → Weather-LZQGVDJL.js} +11 -11
  29. package/dist/{Weather-NZO3CWLH.js.map → Weather-LZQGVDJL.js.map} +1 -1
  30. package/dist/{WorldClock-HUC6D3AD.js → WorldClock-XPD7WOZT.js} +11 -11
  31. package/dist/{WorldClock-HUC6D3AD.js.map → WorldClock-XPD7WOZT.js.map} +1 -1
  32. package/dist/apps/index.d.ts +2 -2
  33. package/dist/apps/index.js +30 -30
  34. package/dist/apps/index.js.map +1 -1
  35. package/dist/brand.css +1 -1
  36. package/dist/{chunk-CT3HVZRZ.js → chunk-5O42JXQE.js} +2 -2
  37. package/dist/chunk-5O42JXQE.js.map +1 -0
  38. package/dist/{chunk-CGXMWHQW.js → chunk-5RPTS3BT.js} +3 -3
  39. package/dist/{chunk-CGXMWHQW.js.map → chunk-5RPTS3BT.js.map} +1 -1
  40. package/dist/{chunk-D276EMXS.js → chunk-6XJEJWNJ.js} +7 -3
  41. package/dist/chunk-6XJEJWNJ.js.map +1 -0
  42. package/dist/{chunk-I464GYJJ.js → chunk-BE7FZOFU.js} +2 -2
  43. package/dist/chunk-BE7FZOFU.js.map +1 -0
  44. package/dist/{chunk-CJYO4RVV.js → chunk-COWYSHG2.js} +5 -5
  45. package/dist/chunk-COWYSHG2.js.map +1 -0
  46. package/dist/{chunk-3L463T5H.js → chunk-DVZWYWSD.js} +2 -2
  47. package/dist/chunk-DVZWYWSD.js.map +1 -0
  48. package/dist/{chunk-MQPX6ERJ.js → chunk-E7TB6WD2.js} +4 -4
  49. package/dist/{chunk-MQPX6ERJ.js.map → chunk-E7TB6WD2.js.map} +1 -1
  50. package/dist/{chunk-SEWF4O3H.js → chunk-FIHOGVUP.js} +3 -3
  51. package/dist/chunk-FIHOGVUP.js.map +1 -0
  52. package/dist/{chunk-TQURTLK2.js → chunk-HUBJAUGG.js} +5 -5
  53. package/dist/{chunk-TQURTLK2.js.map → chunk-HUBJAUGG.js.map} +1 -1
  54. package/dist/{chunk-XH3ELPQZ.js → chunk-I2TAAJHS.js} +3 -3
  55. package/dist/chunk-I2TAAJHS.js.map +1 -0
  56. package/dist/{chunk-ZKHD4J73.js → chunk-ICTRCKUE.js} +10 -10
  57. package/dist/chunk-ICTRCKUE.js.map +1 -0
  58. package/dist/{chunk-E3TWIN7Z.js → chunk-JOPU6WPY.js} +7 -6
  59. package/dist/chunk-JOPU6WPY.js.map +1 -0
  60. package/dist/{chunk-7MA5XBWD.js → chunk-PVPPAWVM.js} +5 -5
  61. package/dist/{chunk-7MA5XBWD.js.map → chunk-PVPPAWVM.js.map} +1 -1
  62. package/dist/{chunk-FONEQRBH.js → chunk-R7QGMK6N.js} +3 -3
  63. package/dist/{chunk-FONEQRBH.js.map → chunk-R7QGMK6N.js.map} +1 -1
  64. package/dist/{chunk-LQTVTOSY.js → chunk-RT6DSB5Y.js} +45 -19
  65. package/dist/chunk-RT6DSB5Y.js.map +1 -0
  66. package/dist/{chunk-BFBWLCO6.js → chunk-TW7LPMVR.js} +2 -2
  67. package/dist/chunk-TW7LPMVR.js.map +1 -0
  68. package/dist/{chunk-EENVXIVU.js → chunk-UTYKLGGT.js} +3 -3
  69. package/dist/{chunk-EENVXIVU.js.map → chunk-UTYKLGGT.js.map} +1 -1
  70. package/dist/{chunk-KWEX4ZAF.js → chunk-VNJJCH5A.js} +3 -3
  71. package/dist/{chunk-KWEX4ZAF.js.map → chunk-VNJJCH5A.js.map} +1 -1
  72. package/dist/{chunk-TFXJRHJV.js → chunk-XJHZWSKV.js} +3 -3
  73. package/dist/{chunk-TFXJRHJV.js.map → chunk-XJHZWSKV.js.map} +1 -1
  74. package/dist/{chunk-VWZIGZFF.js → chunk-Y3GYJ7YR.js} +4 -4
  75. package/dist/{chunk-VWZIGZFF.js.map → chunk-Y3GYJ7YR.js.map} +1 -1
  76. package/dist/{chunk-BJ34QOR3.js → chunk-YA4EE7ST.js} +842 -272
  77. package/dist/chunk-YA4EE7ST.js.map +1 -0
  78. package/dist/{chunk-CLGNTGC5.js → chunk-YDHXWCCJ.js} +3 -3
  79. package/dist/{chunk-CLGNTGC5.js.map → chunk-YDHXWCCJ.js.map} +1 -1
  80. package/dist/{chunk-7IN7YZAL.js → chunk-YE6GUDGP.js} +4 -3
  81. package/dist/chunk-YE6GUDGP.js.map +1 -0
  82. package/dist/chunk-ZS7PMGUW.js +7 -0
  83. package/dist/{chunk-JMKYYPOF.js.map → chunk-ZS7PMGUW.js.map} +1 -1
  84. package/dist/file-intake/index.js +2 -2
  85. package/dist/{index-COwksV6G.d.ts → index-DVI9DMSu.d.ts} +383 -20
  86. package/dist/index.d.ts +3 -3
  87. package/dist/index.js +39 -39
  88. package/dist/index.js.map +1 -1
  89. package/dist/map/index.js +1 -1
  90. package/dist/markdown/index.d.ts +4 -4
  91. package/dist/markdown/index.js.map +1 -1
  92. package/dist/markup/index.d.ts +2 -2
  93. package/dist/markup/index.js.map +1 -1
  94. package/dist/page-tabs/index.js +5 -5
  95. package/dist/shell.css +1 -1
  96. package/dist/styles.css +4 -4
  97. package/dist/themes.css +3 -3
  98. package/dist/ui/index.d.ts +1 -1
  99. package/dist/ui/index.js +14 -14
  100. package/dist/ui.css +311 -18
  101. package/package.json +1 -1
  102. package/dist/ConfirmDialog-MTC7QMUJ.js +0 -4
  103. package/dist/PdfViewer-M2YGZIYX.js +0 -5
  104. package/dist/chunk-3L463T5H.js.map +0 -1
  105. package/dist/chunk-7IN7YZAL.js.map +0 -1
  106. package/dist/chunk-BFBWLCO6.js.map +0 -1
  107. package/dist/chunk-BJ34QOR3.js.map +0 -1
  108. package/dist/chunk-CJYO4RVV.js.map +0 -1
  109. package/dist/chunk-CT3HVZRZ.js.map +0 -1
  110. package/dist/chunk-D276EMXS.js.map +0 -1
  111. package/dist/chunk-E3TWIN7Z.js.map +0 -1
  112. package/dist/chunk-I464GYJJ.js.map +0 -1
  113. package/dist/chunk-JMKYYPOF.js +0 -7
  114. package/dist/chunk-LQTVTOSY.js.map +0 -1
  115. package/dist/chunk-SEWF4O3H.js.map +0 -1
  116. package/dist/chunk-XH3ELPQZ.js.map +0 -1
  117. package/dist/chunk-ZKHD4J73.js.map +0 -1
@@ -1,35 +1,26 @@
1
- import { Breadcrumbs } from './chunk-CGXMWHQW.js';
2
- import { SidebarLayout } from './chunk-FONEQRBH.js';
1
+ import { Breadcrumbs } from './chunk-5RPTS3BT.js';
2
+ import { SidebarLayout } from './chunk-R7QGMK6N.js';
3
3
  import { BrandMark } from './chunk-TRCWINHF.js';
4
- import { toast_default } from './chunk-EENVXIVU.js';
5
- import { useIsMobile, useShortcutLabel, useShellPrefs } from './chunk-TQURTLK2.js';
6
- import { useFileIntake, humanSize, FileIntakeAlert } from './chunk-CLGNTGC5.js';
7
- import { BUTTON_BASE, BUTTON_VARIANTS, Button_default } from './chunk-LQTVTOSY.js';
8
- import { PopupMenu, PopupMenuItem } from './chunk-E3TWIN7Z.js';
9
- import { registerModalEscapeInterceptor, onOverlayOpen, Z_LAYERS, useDismissPopupsOnOpen, useFocusTrap, useScrollLock } from './chunk-XH3ELPQZ.js';
10
- import { glassStyle } from './chunk-D276EMXS.js';
11
- import { useShellLocale, useShellStrings, DEFAULT_SHELL_STRINGS, currentShellStrings, formatPlain, formatFixed, formatPercent, splitAround } from './chunk-7IN7YZAL.js';
4
+ import { toast_default } from './chunk-UTYKLGGT.js';
5
+ import { useIsMobile, useShortcutLabel, useShellPrefs } from './chunk-HUBJAUGG.js';
6
+ import { useFileIntake, humanSize, FileIntakeAlert } from './chunk-YDHXWCCJ.js';
7
+ import { iconButtonClasses, Button_default } from './chunk-RT6DSB5Y.js';
8
+ import { PopupMenu, PopupMenuDivider, PopupMenuLabel, itemLook } from './chunk-JOPU6WPY.js';
9
+ import { registerModalEscapeInterceptor, onOverlayOpen, Z_LAYERS, useDismissPopupsOnOpen, useFocusTrap, useScrollLock } from './chunk-I2TAAJHS.js';
10
+ import { glassStyle, glassFill } from './chunk-6XJEJWNJ.js';
11
+ import { useShellLocale, useShellStrings, DEFAULT_SHELL_STRINGS, currentShellStrings, formatPlain, formatFixed, formatPercent, splitAround } from './chunk-YE6GUDGP.js';
12
12
  import { useBrowserLayoutEffect, useBrowserValue, useBrowserValueOnce } from './chunk-IRWSRJ4K.js';
13
13
  import { forwardRef, useCallback, useState, useRef, useId, useEffect, createContext, useMemo, Children, isValidElement, cloneElement, useContext, Fragment as Fragment$1, Component, useSyncExternalStore, useLayoutEffect } from 'react';
14
14
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
15
15
  import { createPortal } from 'react-dom';
16
16
 
17
- var SQUARE = {
18
- sm: "h-6 w-6",
19
- md: "h-8 w-8",
20
- lg: "h-10 w-10",
21
- "touch-sm": "h-11 w-11",
22
- "touch": "h-14 w-14",
23
- "touch-lg": "h-16 w-16",
24
- "touch-xl": "h-20 w-20"
25
- };
26
17
  var IconButton = forwardRef(function IconButton2({ children, variant = "ghost", size = "md", type = "button", className = "", ...rest }, ref) {
27
18
  return /* @__PURE__ */ jsx(
28
19
  "button",
29
20
  {
30
21
  ref,
31
22
  type,
32
- className: [BUTTON_BASE, BUTTON_VARIANTS[variant], SQUARE[size], "shrink-0 p-0", className].filter(Boolean).join(" "),
23
+ className: iconButtonClasses({ variant, size, className }),
33
24
  ...rest,
34
25
  children
35
26
  }
@@ -130,11 +121,142 @@ function popupBounds(trigger) {
130
121
  bottom: Math.min(viewport.bottom, rect.bottom)
131
122
  };
132
123
  }
124
+ var OPPOSITE = {
125
+ top: "bottom",
126
+ bottom: "top",
127
+ left: "right",
128
+ right: "left"
129
+ };
130
+ var ACROSS = {
131
+ top: ["right", "left"],
132
+ bottom: ["right", "left"],
133
+ left: ["top", "bottom"],
134
+ right: ["top", "bottom"]
135
+ };
136
+ function roomAround(anchor, bounds, gap) {
137
+ return {
138
+ top: anchor.top - gap - (bounds.top + VIEWPORT_MARGIN),
139
+ bottom: bounds.bottom - VIEWPORT_MARGIN - (anchor.bottom + gap),
140
+ left: anchor.left - gap - (bounds.left + VIEWPORT_MARGIN),
141
+ right: bounds.right - VIEWPORT_MARGIN - (anchor.right + gap)
142
+ };
143
+ }
144
+ var within = (value, lo, hi) => Math.max(lo, Math.min(value, hi));
145
+ function placeBeside(anchor, size, side, bounds, gap) {
146
+ const room = roomAround(anchor, bounds, gap);
147
+ const spare = (s) => room[s] - (s === "top" || s === "bottom" ? size.height : size.width);
148
+ const order = [side, OPPOSITE[side], ...ACROSS[side]];
149
+ const chosen = order.find((s) => spare(s) >= 0) ?? order.reduce((best, s) => spare(s) > spare(best) ? s : best);
150
+ const centreX = (anchor.left + anchor.right) / 2;
151
+ const centreY = (anchor.top + anchor.bottom) / 2;
152
+ let left;
153
+ let top;
154
+ switch (chosen) {
155
+ case "top":
156
+ left = centreX - size.width / 2;
157
+ top = anchor.top - gap - size.height;
158
+ break;
159
+ case "bottom":
160
+ left = centreX - size.width / 2;
161
+ top = anchor.bottom + gap;
162
+ break;
163
+ case "left":
164
+ left = anchor.left - gap - size.width;
165
+ top = centreY - size.height / 2;
166
+ break;
167
+ case "right":
168
+ left = anchor.right + gap;
169
+ top = centreY - size.height / 2;
170
+ break;
171
+ }
172
+ return {
173
+ side: chosen,
174
+ left: within(left, bounds.left + VIEWPORT_MARGIN, bounds.right - VIEWPORT_MARGIN - size.width),
175
+ top: within(top, bounds.top + VIEWPORT_MARGIN, bounds.bottom - VIEWPORT_MARGIN - size.height)
176
+ };
177
+ }
178
+ function placeArrow(anchor, placed, size, inset, depth) {
179
+ const { side, left, top } = placed;
180
+ const right = left + size.width;
181
+ const bottom = top + size.height;
182
+ const clearance = {
183
+ top: anchor.top - bottom,
184
+ bottom: top - anchor.bottom,
185
+ left: anchor.left - right,
186
+ right: left - anchor.right
187
+ }[side];
188
+ if (clearance < depth) return null;
189
+ const along = (target, start, length) => length < 2 * inset ? start + length / 2 : Math.max(start + inset, Math.min(target, start + length - inset));
190
+ const centreX = (anchor.left + anchor.right) / 2;
191
+ const centreY = (anchor.top + anchor.bottom) / 2;
192
+ switch (side) {
193
+ case "top":
194
+ return { side, x: along(centreX, left, size.width), y: bottom };
195
+ case "bottom":
196
+ return { side, x: along(centreX, left, size.width), y: top };
197
+ case "left":
198
+ return { side, x: right, y: along(centreY, top, size.height) };
199
+ case "right":
200
+ return { side, x: left, y: along(centreY, top, size.height) };
201
+ }
202
+ }
203
+ function followAnchor(anchor, onMove, watch) {
204
+ let lastLeft = NaN, lastTop = NaN, lastRight = NaN, lastBottom = NaN, lastWatched = NaN;
205
+ const remember = () => {
206
+ const rect = anchor()?.getBoundingClientRect();
207
+ if (!rect) return false;
208
+ const watched = watch ? watch() : NaN;
209
+ const moved = rect.left !== lastLeft || rect.top !== lastTop || rect.right !== lastRight || rect.bottom !== lastBottom || watched !== lastWatched && !(Number.isNaN(watched) && Number.isNaN(lastWatched));
210
+ lastLeft = rect.left;
211
+ lastTop = rect.top;
212
+ lastRight = rect.right;
213
+ lastBottom = rect.bottom;
214
+ lastWatched = watched;
215
+ return moved;
216
+ };
217
+ remember();
218
+ const run = () => {
219
+ remember();
220
+ onMove();
221
+ };
222
+ let raf = requestAnimationFrame(function tick() {
223
+ if (remember()) onMove();
224
+ raf = requestAnimationFrame(tick);
225
+ });
226
+ window.addEventListener("scroll", run, true);
227
+ window.addEventListener("resize", run);
228
+ return () => {
229
+ cancelAnimationFrame(raf);
230
+ window.removeEventListener("scroll", run, true);
231
+ window.removeEventListener("resize", run);
232
+ };
233
+ }
234
+ function placeMenu({ trigger, menu, bounds, align, side }) {
235
+ const room = roomAround(trigger, bounds, MENU_GAP);
236
+ const other = side === "bottom" ? "top" : "bottom";
237
+ const chosen = menu.height > room[side] && (menu.height <= room[other] || room[other] > room[side]) ? other : side;
238
+ const maxHeight = Math.max(Math.min(menu.height, 96), room[chosen]);
239
+ const height = Math.min(menu.height, maxHeight);
240
+ const top = within(
241
+ chosen === "bottom" ? trigger.bottom + MENU_GAP : trigger.top - MENU_GAP - height,
242
+ bounds.top + VIEWPORT_MARGIN,
243
+ bounds.bottom - VIEWPORT_MARGIN - height
244
+ );
245
+ const maxWidth = Math.max(0, bounds.right - bounds.left - 2 * VIEWPORT_MARGIN);
246
+ const width = Math.min(menu.width, maxWidth);
247
+ const left = within(
248
+ align === "start" ? trigger.left : trigger.right - width,
249
+ bounds.left + VIEWPORT_MARGIN,
250
+ bounds.right - VIEWPORT_MARGIN - width
251
+ );
252
+ return { left, top, side: chosen, maxHeight, maxWidth };
253
+ }
133
254
  function useDropdownPosition(triggerRef, open, options = {}) {
134
255
  const {
135
256
  matchTriggerWidth = false,
136
257
  preferredMaxWidth = POPUP_MAX_WIDTH,
137
- preferredMaxHeight = MENU_MAX_HEIGHT
258
+ preferredMaxHeight = MENU_MAX_HEIGHT,
259
+ popupRef
138
260
  } = options;
139
261
  const [pos, setPos] = useState(null);
140
262
  useBrowserLayoutEffect(() => {
@@ -142,15 +264,10 @@ function useDropdownPosition(triggerRef, open, options = {}) {
142
264
  setPos(null);
143
265
  return;
144
266
  }
145
- let lastLeft = NaN, lastTop = NaN, lastRight = NaN, lastBottom = NaN;
146
267
  const compute = () => {
147
268
  const trigger = triggerRef.current;
148
269
  const rect = trigger?.getBoundingClientRect();
149
270
  if (!rect) return;
150
- lastLeft = rect.left;
151
- lastTop = rect.top;
152
- lastRight = rect.right;
153
- lastBottom = rect.bottom;
154
271
  const bounds = popupBounds(trigger);
155
272
  const spaceBelow = bounds.bottom - rect.bottom - MENU_GAP - VIEWPORT_MARGIN;
156
273
  const spaceAbove = rect.top - bounds.top - MENU_GAP - VIEWPORT_MARGIN;
@@ -170,6 +287,13 @@ function useDropdownPosition(triggerRef, open, options = {}) {
170
287
  Math.max(bounds.left + VIEWPORT_MARGIN, rect.left),
171
288
  bounds.right - VIEWPORT_MARGIN - width
172
289
  );
290
+ } else if (popupRef && bounds.right - VIEWPORT_MARGIN - rect.left < next.maxWidth && Math.min(rect.right, bounds.right - VIEWPORT_MARGIN) - bounds.left - VIEWPORT_MARGIN < next.maxWidth) {
291
+ const measured = popupRef.current?.offsetWidth ?? 0;
292
+ const width = measured > 0 ? Math.min(measured, next.maxWidth) : next.maxWidth;
293
+ next.left = Math.max(
294
+ bounds.left + VIEWPORT_MARGIN,
295
+ Math.min(rect.left, bounds.right - VIEWPORT_MARGIN - width)
296
+ );
173
297
  } else if (bounds.right - VIEWPORT_MARGIN - rect.left < next.maxWidth) {
174
298
  const rightEdge = Math.min(rect.right, bounds.right - VIEWPORT_MARGIN);
175
299
  next.right = window.innerWidth - rightEdge;
@@ -185,21 +309,12 @@ function useDropdownPosition(triggerRef, open, options = {}) {
185
309
  setPos(next);
186
310
  };
187
311
  compute();
188
- let raf = requestAnimationFrame(function tick() {
189
- const rect = triggerRef.current?.getBoundingClientRect();
190
- if (rect && (rect.left !== lastLeft || rect.top !== lastTop || rect.right !== lastRight || rect.bottom !== lastBottom)) {
191
- compute();
192
- }
193
- raf = requestAnimationFrame(tick);
194
- });
195
- window.addEventListener("scroll", compute, true);
196
- window.addEventListener("resize", compute);
197
- return () => {
198
- cancelAnimationFrame(raf);
199
- window.removeEventListener("scroll", compute, true);
200
- window.removeEventListener("resize", compute);
201
- };
202
- }, [open, triggerRef, matchTriggerWidth, preferredMaxWidth, preferredMaxHeight]);
312
+ return followAnchor(
313
+ () => triggerRef.current,
314
+ compute,
315
+ popupRef ? () => popupRef.current?.offsetWidth ?? NaN : void 0
316
+ );
317
+ }, [open, triggerRef, matchTriggerWidth, preferredMaxWidth, preferredMaxHeight, popupRef]);
203
318
  return pos;
204
319
  }
205
320
 
@@ -1535,6 +1650,22 @@ function calendarNames(locale) {
1535
1650
  localeNames.set(locale, names);
1536
1651
  return names;
1537
1652
  }
1653
+ var weekStarts = /* @__PURE__ */ new Map();
1654
+ function firstDayOfWeek(locale) {
1655
+ if (!locale) return 0;
1656
+ let first = weekStarts.get(locale);
1657
+ if (first === void 0) {
1658
+ first = 0;
1659
+ try {
1660
+ const tag = new Intl.Locale(locale);
1661
+ const info = typeof tag.getWeekInfo === "function" ? tag.getWeekInfo() : tag.weekInfo;
1662
+ if (info?.firstDay === 1) first = 1;
1663
+ } catch {
1664
+ }
1665
+ weekStarts.set(locale, first);
1666
+ }
1667
+ return first;
1668
+ }
1538
1669
  var pad = (n) => String(n).padStart(2, "0");
1539
1670
  function toKey(d) {
1540
1671
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
@@ -1576,7 +1707,7 @@ function Calendar({
1576
1707
  month,
1577
1708
  defaultMonth,
1578
1709
  onMonthChange,
1579
- weekStartsOn = 0,
1710
+ weekStartsOn: weekStartsOnProp,
1580
1711
  quickJump = true,
1581
1712
  "aria-label": ariaLabel,
1582
1713
  className = ""
@@ -1585,7 +1716,10 @@ function Calendar({
1585
1716
  const todayKey = useBrowserValue(readTodayKey, null);
1586
1717
  const today = fromKey(todayKey);
1587
1718
  const strings = useShellStrings().calendar;
1588
- const names = calendarNames(useShellLocale());
1719
+ const locale = useShellLocale();
1720
+ const names = calendarNames(locale);
1721
+ const localeWeekStart = useBrowserValue(() => firstDayOfWeek(locale), 0);
1722
+ const weekStartsOn = weekStartsOnProp ?? localeWeekStart;
1589
1723
  const openingMonth = () => {
1590
1724
  if (!today) return null;
1591
1725
  const here = monthKey(today);
@@ -1834,7 +1968,13 @@ function DateRangePicker({
1834
1968
  to,
1835
1969
  onChange,
1836
1970
  formatDisplay: formatDisplayProp,
1837
- clearable = true,
1971
+ clearable: clearableProp,
1972
+ required = false,
1973
+ name,
1974
+ id,
1975
+ "aria-labelledby": ariaLabelledBy,
1976
+ "aria-label": ariaLabel,
1977
+ weekStartsOn,
1838
1978
  placeholder: placeholderProp,
1839
1979
  fullWidth = false
1840
1980
  }) {
@@ -1842,16 +1982,44 @@ function DateRangePicker({
1842
1982
  const locale = useShellLocale();
1843
1983
  const formatDisplay = formatDisplayProp ?? (locale ? localeFormatDisplay(locale) : defaultFormatDisplay);
1844
1984
  const placeholder = placeholderProp ?? strings.placeholder;
1985
+ const clearable = clearableProp ?? !required;
1845
1986
  const [open, setOpen] = useState(false);
1846
1987
  const [tempFrom, setTempFrom] = useState(from);
1847
1988
  const [tempTo, setTempTo] = useState(to);
1848
1989
  const [activePreset, setActivePreset] = useState(null);
1849
1990
  const ref = useRef(null);
1991
+ const triggerRef = useRef(null);
1850
1992
  const panelRef = useRef(null);
1993
+ const panelId = useId();
1994
+ const descriptionId = useId();
1995
+ const [stacked, setStacked] = useState(false);
1851
1996
  const pos = useDropdownPosition(ref, open, {
1852
1997
  preferredMaxWidth: 520,
1853
- preferredMaxHeight: 560
1998
+ preferredMaxHeight: stacked ? 720 : 560,
1999
+ popupRef: panelRef
1854
2000
  });
2001
+ const sideRowRef = useRef(null);
2002
+ const sideWidth = useRef(null);
2003
+ useBrowserLayoutEffect(() => {
2004
+ const panel = panelRef.current;
2005
+ if (!open || !pos || !panel) return;
2006
+ const style = getComputedStyle(panel);
2007
+ const room = pos.maxWidth - (panel.offsetWidth - panel.clientWidth) - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight);
2008
+ if (!stacked) {
2009
+ const natural = sideRowRef.current?.offsetWidth ?? 0;
2010
+ if (natural === 0) return;
2011
+ sideWidth.current = natural;
2012
+ if (natural > room + 0.5) setStacked(true);
2013
+ } else if (sideWidth.current !== null && sideWidth.current <= room) {
2014
+ setStacked(false);
2015
+ }
2016
+ });
2017
+ const [hasLabelElement, setHasLabelElement] = useState(false);
2018
+ useBrowserLayoutEffect(() => {
2019
+ const labelled = !!id && (triggerRef.current?.labels?.length ?? 0) > 0;
2020
+ if (labelled !== hasLabelElement) setHasLabelElement(labelled);
2021
+ });
2022
+ const namedElsewhere = !!ariaLabel || !!ariaLabelledBy || hasLabelElement;
1855
2023
  const now = /* @__PURE__ */ new Date();
1856
2024
  const [viewMonth, setViewMonth] = useState(() => monthKeyOf(from ? parseDate(from) : now));
1857
2025
  const displayDate = (s) => s ? formatDisplay(s) : "";
@@ -1931,6 +2099,37 @@ function DateRangePicker({
1931
2099
  setOpen(false);
1932
2100
  };
1933
2101
  const displayText = from && to ? `${displayDate(from)} \u2014 ${displayDate(to)}` : from ? strings.fromOnly(displayDate(from)) : to ? strings.toOnly(displayDate(to)) : "";
2102
+ const names = calendarNames(locale);
2103
+ const spoken = (iso) => {
2104
+ const d = fromKey(iso);
2105
+ return d ? names.longDate(d.getFullYear(), d.getMonth(), d.getDate()) : iso;
2106
+ };
2107
+ const description = from && to ? strings.range(spoken(from), spoken(to)) : from ? strings.fromOnly(spoken(from)) : to ? strings.toOnly(spoken(to)) : placeholder;
2108
+ const presetClass = (key) => stacked ? `rounded-md border px-2.5 py-1 text-sm transition-colors ${activePreset === key ? "border-blue-300 bg-blue-50 text-blue-700 font-medium" : "border-gray-200 text-gray-700 hover:bg-gray-50"}` : `text-left px-3 py-1.5 text-sm rounded-md transition-colors ${activePreset === key ? "bg-blue-50 text-blue-700 font-medium" : "text-gray-700 hover:bg-gray-50"}`;
2109
+ const presets = /* @__PURE__ */ jsxs(Fragment, { children: [
2110
+ PRESETS.map((label) => /* @__PURE__ */ jsx("button", { type: "button", onClick: () => handlePreset(label), className: presetClass(label), children: strings[label] }, label)),
2111
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setActivePreset("Custom"), className: presetClass("Custom"), children: strings.custom })
2112
+ ] });
2113
+ const calendar = (
2114
+ // The grid, its keyboard model and its ARIA all come from Calendar, which
2115
+ // is also what DatePicker draws — so a range and a single date look and
2116
+ // behave like the same control. This used to be 95 lines of hand-built
2117
+ // cells here with no arrow keys and a day whose accessible name was its
2118
+ // number.
2119
+ /* @__PURE__ */ jsx(
2120
+ Calendar,
2121
+ {
2122
+ mode: "range",
2123
+ value: tempFrom || null,
2124
+ endValue: tempTo || null,
2125
+ month: viewMonth,
2126
+ onMonthChange: setViewMonth,
2127
+ onSelect: handleCalendarSelect,
2128
+ weekStartsOn,
2129
+ "aria-label": strings.dialog
2130
+ }
2131
+ )
2132
+ );
1934
2133
  return /* @__PURE__ */ jsxs("div", { className: `relative${fullWidth ? " w-full" : ""}`, ref, children: [
1935
2134
  /* @__PURE__ */ jsxs(
1936
2135
  "div",
@@ -1940,13 +2139,20 @@ function DateRangePicker({
1940
2139
  /* @__PURE__ */ jsxs(
1941
2140
  "button",
1942
2141
  {
2142
+ ref: triggerRef,
1943
2143
  type: "button",
1944
2144
  onClick: handleOpen,
1945
2145
  "aria-haspopup": "dialog",
1946
2146
  "aria-expanded": open,
2147
+ id,
2148
+ "aria-label": ariaLabel,
2149
+ "aria-labelledby": ariaLabelledBy,
2150
+ "aria-describedby": namedElsewhere ? descriptionId : void 0,
2151
+ "aria-controls": open ? panelId : void 0,
2152
+ "aria-required": required || void 0,
1947
2153
  className: `inline-flex items-center gap-2 rosh-focus-ring${fullWidth ? " min-w-0 flex-1 justify-start" : ""}`,
1948
2154
  children: [
1949
- /* @__PURE__ */ jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
2155
+ /* @__PURE__ */ jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
1950
2156
  /* @__PURE__ */ jsx("span", { className: "truncate", children: displayText || placeholder })
1951
2157
  ]
1952
2158
  }
@@ -1964,13 +2170,20 @@ function DateRangePicker({
1964
2170
  ]
1965
2171
  }
1966
2172
  ),
2173
+ namedElsewhere && /* @__PURE__ */ jsx("span", { id: descriptionId, className: "sr-only", children: description }),
2174
+ name && /* @__PURE__ */ jsxs(Fragment, { children: [
2175
+ /* @__PURE__ */ jsx("input", { type: "hidden", name: name.from, value: from }),
2176
+ /* @__PURE__ */ jsx("input", { type: "hidden", name: name.to, value: to })
2177
+ ] }),
1967
2178
  open && createPortal(
1968
2179
  /* @__PURE__ */ jsxs(
1969
2180
  "div",
1970
2181
  {
1971
2182
  ref: panelRef,
2183
+ id: panelId,
1972
2184
  role: "dialog",
1973
2185
  "aria-label": strings.dialog,
2186
+ "data-layout": stacked ? "stacked" : "side",
1974
2187
  className: "fixed rounded-2xl p-4",
1975
2188
  style: {
1976
2189
  zIndex: Z_LAYERS.popup,
@@ -1980,8 +2193,9 @@ function DateRangePicker({
1980
2193
  bottom: pos?.bottom,
1981
2194
  // The panel states its own size. `max-content` is the calendar plus
1982
2195
  // the presets column at whatever font size the reader has, and the
1983
- // cap is what the owning window allows.
1984
- width: "max-content",
2196
+ // cap is what the owning window allows. Stacked, it is the cap
2197
+ // itself: the calendar fills it, and its days are bigger targets.
2198
+ width: stacked && pos ? pos.maxWidth : "max-content",
1985
2199
  maxWidth: pos?.maxWidth,
1986
2200
  maxHeight: pos?.maxHeight,
1987
2201
  overflowY: "auto",
@@ -1991,53 +2205,29 @@ function DateRangePicker({
1991
2205
  ...glassStyle()
1992
2206
  },
1993
2207
  children: [
1994
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-3", children: [
1995
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2208
+ /* @__PURE__ */ jsxs("div", { className: stacked ? "mb-3 flex flex-wrap items-center gap-x-4 gap-y-2" : "flex items-center gap-3 mb-3", children: [
2209
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 whitespace-nowrap", children: [
1996
2210
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: strings.from }),
1997
2211
  /* @__PURE__ */ jsx("span", { className: `text-sm px-2 py-1 rounded border min-w-[90px] ${tempFrom ? "border-blue-300 bg-blue-50 text-blue-700" : "border-gray-200 bg-gray-50 text-gray-400"}`, children: tempFrom ? displayDate(tempFrom) : strings.start })
1998
2212
  ] }),
1999
- /* @__PURE__ */ jsx("span", { className: "text-gray-300", children: "\u2014" }),
2000
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2213
+ !stacked && /* @__PURE__ */ jsx("span", { className: "text-gray-300", children: "\u2014" }),
2214
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 whitespace-nowrap", children: [
2001
2215
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: strings.to }),
2002
2216
  /* @__PURE__ */ jsx("span", { className: `text-sm px-2 py-1 rounded border min-w-[90px] ${tempTo ? "border-blue-300 bg-blue-50 text-blue-700" : "border-gray-200 bg-gray-50 text-gray-400"}`, children: tempTo ? displayDate(tempTo) : strings.end })
2003
2217
  ] })
2004
2218
  ] }),
2005
- /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
2006
- /* @__PURE__ */ jsx("div", { className: "w-64", children: /* @__PURE__ */ jsx(
2007
- Calendar,
2008
- {
2009
- mode: "range",
2010
- value: tempFrom || null,
2011
- endValue: tempTo || null,
2012
- month: viewMonth,
2013
- onMonthChange: setViewMonth,
2014
- onSelect: handleCalendarSelect,
2015
- "aria-label": strings.dialog
2016
- }
2017
- ) }),
2018
- /* @__PURE__ */ jsxs("div", { className: "border-l border-gray-200 pl-4 flex flex-col gap-1 min-w-[130px]", children: [
2019
- PRESETS.map((label) => /* @__PURE__ */ jsx(
2020
- "button",
2021
- {
2022
- type: "button",
2023
- onClick: () => handlePreset(label),
2024
- className: `text-left px-3 py-1.5 text-sm rounded-md transition-colors ${activePreset === label ? "bg-blue-50 text-blue-700 font-medium" : "text-gray-700 hover:bg-gray-50"}`,
2025
- children: strings[label]
2026
- },
2027
- label
2028
- )),
2029
- /* @__PURE__ */ jsx(
2030
- "button",
2031
- {
2032
- type: "button",
2033
- onClick: () => setActivePreset("Custom"),
2034
- className: `text-left px-3 py-1.5 text-sm rounded-md transition-colors ${activePreset === "Custom" ? "bg-blue-50 text-blue-700 font-medium" : "text-gray-700 hover:bg-gray-50"}`,
2035
- children: strings.custom
2036
- }
2037
- )
2219
+ stacked ? /* @__PURE__ */ jsxs(Fragment, { children: [
2220
+ /* @__PURE__ */ jsx("div", { className: "mb-3 flex flex-wrap gap-1.5", children: presets }),
2221
+ /* @__PURE__ */ jsx("div", { className: "w-full", children: calendar })
2222
+ ] }) : (
2223
+ // `w-max`: the row is drawn at its natural width even in a panel
2224
+ // capped narrower, which is what the measurement above reads.
2225
+ /* @__PURE__ */ jsxs("div", { ref: sideRowRef, className: "flex w-max gap-4", children: [
2226
+ /* @__PURE__ */ jsx("div", { className: "w-64", children: calendar }),
2227
+ /* @__PURE__ */ jsx("div", { className: "border-l border-gray-200 pl-4 flex flex-col gap-1 min-w-[130px]", children: presets })
2038
2228
  ] })
2039
- ] }),
2040
- /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 mt-4 pt-3 border-t border-gray-200", children: [
2229
+ ),
2230
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap justify-end gap-2 mt-4 pt-3 border-t border-gray-200", children: [
2041
2231
  clearable && /* @__PURE__ */ jsx("button", { type: "button", onClick: handleClear, className: "px-3 py-1.5 text-sm text-gray-500 hover:text-gray-700", children: strings.clear }),
2042
2232
  /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setOpen(false), className: "px-3 py-1.5 text-sm text-gray-600 border border-gray-300 rounded-md hover:bg-gray-50", children: strings.cancel }),
2043
2233
  /* @__PURE__ */ jsx(
@@ -2091,6 +2281,7 @@ var TimePicker = forwardRef(function TimePicker2({ value, onChange, min, max, in
2091
2281
  });
2092
2282
  var TimePicker_default = TimePicker;
2093
2283
  var ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
2284
+ var GLOBAL_ATTRIBUTE = /^(aria|data)-/;
2094
2285
  function toInputValue2(value) {
2095
2286
  if (value === null || value === void 0 || value === "") return "";
2096
2287
  if (value instanceof Date) return Number.isNaN(value.getTime()) ? "" : toISODate(value);
@@ -2120,12 +2311,22 @@ var DatePicker = forwardRef(function DatePicker2({
2120
2311
  className = "",
2121
2312
  "aria-label": ariaLabel,
2122
2313
  "aria-describedby": describedBy,
2314
+ "aria-labelledby": labelledBy,
2123
2315
  id,
2124
2316
  name,
2125
2317
  disabled,
2126
2318
  placeholder,
2319
+ required,
2320
+ clearable: clearableProp,
2321
+ form,
2322
+ title,
2323
+ tabIndex,
2324
+ autoFocus,
2325
+ onFocus,
2326
+ onBlur,
2127
2327
  ...rest
2128
2328
  }, ref) {
2329
+ const clearable = clearableProp ?? !required;
2129
2330
  const current = toInputValue2(value);
2130
2331
  const lo = toInputValue2(min);
2131
2332
  const hi = toInputValue2(max);
@@ -2137,7 +2338,14 @@ var DatePicker = forwardRef(function DatePicker2({
2137
2338
  const triggerRef = useRef(null);
2138
2339
  const panelRef = useRef(null);
2139
2340
  const panelId = useId();
2140
- const pos = useDropdownPosition(triggerRef, open);
2341
+ const valueId = useId();
2342
+ const pos = useDropdownPosition(triggerRef, open, { popupRef: panelRef });
2343
+ const [hasLabelElement, setHasLabelElement] = useState(false);
2344
+ useBrowserLayoutEffect(() => {
2345
+ const labelled = !!id && (triggerRef.current?.labels?.length ?? 0) > 0;
2346
+ if (labelled !== hasLabelElement) setHasLabelElement(labelled);
2347
+ });
2348
+ const describeValue = !ariaLabel && (!!labelledBy || hasLabelElement);
2141
2349
  useEffect(() => {
2142
2350
  if (!open) return;
2143
2351
  const onPointerDown = (e) => {
@@ -2179,33 +2387,56 @@ var DatePicker = forwardRef(function DatePicker2({
2179
2387
  max: hi || void 0,
2180
2388
  onChange: (event) => onChange?.(fromInputValue(event.target.value)),
2181
2389
  className: inputClasses({ invalid, size, className }),
2390
+ "aria-labelledby": labelledBy,
2391
+ required,
2392
+ form,
2393
+ title,
2394
+ tabIndex,
2395
+ autoFocus,
2396
+ onFocus,
2397
+ onBlur,
2182
2398
  ...rest
2183
2399
  }
2184
2400
  );
2185
2401
  }
2402
+ const triggerAttributes = Object.fromEntries(
2403
+ Object.entries(rest).filter(([key]) => GLOBAL_ATTRIBUTE.test(key))
2404
+ );
2405
+ const todayKey = toISODate(/* @__PURE__ */ new Date());
2406
+ const todayAllowed = (!lo || todayKey >= lo) && (!hi || todayKey <= hi);
2407
+ const placeholderText = placeholder ?? strings.placeholder;
2186
2408
  return /* @__PURE__ */ jsxs("div", { ref: wrapRef, className: "relative", children: [
2187
- /* @__PURE__ */ jsx("input", { ref, type: "hidden", name, value: current }),
2409
+ /* @__PURE__ */ jsx("input", { ref, type: "hidden", name, form, value: current }),
2188
2410
  /* @__PURE__ */ jsxs(
2189
2411
  "button",
2190
2412
  {
2191
2413
  ref: triggerRef,
2192
2414
  type: "button",
2415
+ ...triggerAttributes,
2193
2416
  id,
2194
2417
  disabled,
2418
+ title,
2419
+ tabIndex,
2420
+ autoFocus,
2421
+ onFocus,
2422
+ onBlur,
2195
2423
  "aria-haspopup": "dialog",
2196
2424
  "aria-expanded": open,
2197
2425
  "aria-controls": open ? panelId : void 0,
2198
- "aria-describedby": describedBy,
2426
+ "aria-labelledby": labelledBy,
2427
+ "aria-describedby": [describeValue ? valueId : void 0, describedBy].filter(Boolean).join(" ") || void 0,
2199
2428
  "aria-invalid": invalid || void 0,
2429
+ "aria-required": required || void 0,
2200
2430
  "aria-label": ariaLabel ? `${ariaLabel}${current ? `, ${display(current, names)}` : ""}` : void 0,
2201
2431
  onClick: () => setOpen((o) => !o),
2202
2432
  className: `${inputClasses({ invalid, size, className })} flex items-center justify-between text-left`,
2203
2433
  children: [
2204
- /* @__PURE__ */ jsx("span", { className: current ? "text-gray-900" : "text-gray-400", children: current ? display(current, names) : placeholder ?? strings.placeholder }),
2434
+ /* @__PURE__ */ jsx("span", { className: current ? "text-gray-900" : "text-gray-400", children: current ? display(current, names) : placeholderText }),
2205
2435
  /* @__PURE__ */ jsx("svg", { className: "h-4 w-4 shrink-0 text-gray-400", fill: "none", stroke: "currentColor", strokeWidth: "1.75", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3M4 11h16M5 7h14a1 1 0 011 1v11a1 1 0 01-1 1H5a1 1 0 01-1-1V8a1 1 0 011-1z" }) })
2206
2436
  ]
2207
2437
  }
2208
2438
  ),
2439
+ describeValue && /* @__PURE__ */ jsx("span", { id: valueId, className: "sr-only", children: current ? display(current, names) : placeholderText }),
2209
2440
  open && createPortal(
2210
2441
  /* @__PURE__ */ jsxs(
2211
2442
  "div",
@@ -2221,6 +2452,9 @@ var DatePicker = forwardRef(function DatePicker2({
2221
2452
  right: pos?.right,
2222
2453
  top: pos?.top,
2223
2454
  bottom: pos?.bottom,
2455
+ // 288 px where it fits; narrower, never past the box's margins,
2456
+ // in a box that cannot hold that.
2457
+ maxWidth: pos?.maxWidth,
2224
2458
  // Hidden for the first paint until the layout effect measures the
2225
2459
  // trigger, so the panel never flashes at (0,0).
2226
2460
  visibility: pos ? void 0 : "hidden"
@@ -2240,8 +2474,8 @@ var DatePicker = forwardRef(function DatePicker2({
2240
2474
  }
2241
2475
  }
2242
2476
  ),
2243
- /* @__PURE__ */ jsxs("div", { className: "mt-2 flex justify-between border-t border-gray-100 pt-2", children: [
2244
- /* @__PURE__ */ jsx(
2477
+ (clearable || todayAllowed) && /* @__PURE__ */ jsxs("div", { className: "mt-2 flex justify-between border-t border-gray-100 pt-2", children: [
2478
+ clearable && /* @__PURE__ */ jsx(
2245
2479
  "button",
2246
2480
  {
2247
2481
  type: "button",
@@ -2254,7 +2488,7 @@ var DatePicker = forwardRef(function DatePicker2({
2254
2488
  children: strings.clear
2255
2489
  }
2256
2490
  ),
2257
- /* @__PURE__ */ jsx(
2491
+ todayAllowed && /* @__PURE__ */ jsx(
2258
2492
  "button",
2259
2493
  {
2260
2494
  type: "button",
@@ -2263,7 +2497,7 @@ var DatePicker = forwardRef(function DatePicker2({
2263
2497
  triggerRef.current?.focus();
2264
2498
  onChange?.(/* @__PURE__ */ new Date());
2265
2499
  },
2266
- className: "rounded-md px-2 py-1 text-sm font-medium text-blue-600 hover:bg-blue-50",
2500
+ className: "ml-auto rounded-md px-2 py-1 text-sm font-medium text-blue-600 hover:bg-blue-50",
2267
2501
  children: strings.today
2268
2502
  }
2269
2503
  )
@@ -4227,14 +4461,21 @@ function Accordion({
4227
4461
  }) });
4228
4462
  }
4229
4463
  var SIDE_POS = {
4230
- top: "bottom-full left-1/2 -translate-x-1/2 mb-1.5",
4231
- bottom: "top-full left-1/2 -translate-x-1/2 mt-1.5",
4232
- left: "right-full top-1/2 -translate-y-1/2 mr-1.5",
4233
- right: "left-full top-1/2 -translate-y-1/2 ml-1.5"
4464
+ top: "bottom-full left-1/2 -translate-x-1/2 mb-3",
4465
+ bottom: "top-full left-1/2 -translate-x-1/2 mt-3",
4466
+ left: "right-full top-1/2 -translate-y-1/2 mr-3",
4467
+ right: "left-full top-1/2 -translate-y-1/2 ml-3"
4234
4468
  };
4469
+ var GAP2 = 6;
4470
+ var ARROW_DEPTH = 6;
4471
+ var ARROW_INSET = 16;
4472
+ var samePlace = (a, b) => a.left === b.left && a.top === b.top && a.maxWidth === b.maxWidth && a.maxHeight === b.maxHeight && a.side === b.side && a.arrow?.left === b.arrow?.left && a.arrow?.top === b.arrow?.top;
4235
4473
  function Tooltip({ content, side = "top", delay = 200, children }) {
4236
4474
  const [show, setShow] = useState(false);
4475
+ const [placed, setPlaced] = useState(null);
4237
4476
  const timer = useRef(void 0);
4477
+ const wrapRef = useRef(null);
4478
+ const tipRef = useRef(null);
4238
4479
  const id = useId();
4239
4480
  const open = () => {
4240
4481
  timer.current = window.setTimeout(() => setShow(true), delay);
@@ -4244,6 +4485,43 @@ function Tooltip({ content, side = "top", delay = 200, children }) {
4244
4485
  setShow(false);
4245
4486
  };
4246
4487
  useEffect(() => () => window.clearTimeout(timer.current), []);
4488
+ useBrowserLayoutEffect(() => {
4489
+ if (!show) {
4490
+ setPlaced(null);
4491
+ return;
4492
+ }
4493
+ const place = () => {
4494
+ const wrap = wrapRef.current;
4495
+ const tip = tipRef.current;
4496
+ if (!wrap || !tip) return;
4497
+ const bounds = popupBounds(wrap);
4498
+ const maxWidth = Math.max(0, bounds.right - bounds.left - 2 * VIEWPORT_MARGIN);
4499
+ const maxHeight = Math.max(0, bounds.bottom - bounds.top - 2 * VIEWPORT_MARGIN);
4500
+ tip.style.maxWidth = `${maxWidth}px`;
4501
+ tip.style.maxHeight = `${maxHeight}px`;
4502
+ const size = tip.getBoundingClientRect();
4503
+ if (size.width <= 0 || size.height <= 0) return;
4504
+ const anchor = wrap.getBoundingClientRect();
4505
+ const at = placeBeside(anchor, size, side, bounds, GAP2 + ARROW_DEPTH);
4506
+ const point = placeArrow(anchor, at, size, ARROW_INSET, ARROW_DEPTH);
4507
+ const next = {
4508
+ left: at.left - anchor.left,
4509
+ top: at.top - anchor.top,
4510
+ maxWidth,
4511
+ maxHeight,
4512
+ side: at.side,
4513
+ arrow: point && { left: point.x - anchor.left, top: point.y - anchor.top }
4514
+ };
4515
+ setPlaced((prev) => prev && samePlace(prev, next) ? prev : next);
4516
+ };
4517
+ place();
4518
+ window.addEventListener("scroll", place, true);
4519
+ window.addEventListener("resize", place);
4520
+ return () => {
4521
+ window.removeEventListener("scroll", place, true);
4522
+ window.removeEventListener("resize", place);
4523
+ };
4524
+ }, [show, side, content]);
4247
4525
  useEffect(() => {
4248
4526
  if (!show) return;
4249
4527
  return registerModalEscapeInterceptor((event) => {
@@ -4256,9 +4534,12 @@ function Tooltip({ content, side = "top", delay = 200, children }) {
4256
4534
  const trigger = isValidElement(children) ? cloneElement(children, {
4257
4535
  "aria-describedby": [children.props["aria-describedby"], describedBy].filter(Boolean).join(" ") || void 0
4258
4536
  }) : children;
4537
+ const glass = show ? glassStyle() : void 0;
4538
+ const fill = show ? glassFill() : void 0;
4259
4539
  return /* @__PURE__ */ jsxs(
4260
4540
  "span",
4261
4541
  {
4542
+ ref: wrapRef,
4262
4543
  className: "relative inline-flex",
4263
4544
  "aria-describedby": isValidElement(children) ? void 0 : describedBy,
4264
4545
  onMouseEnter: open,
@@ -4267,15 +4548,61 @@ function Tooltip({ content, side = "top", delay = 200, children }) {
4267
4548
  onBlur: close,
4268
4549
  children: [
4269
4550
  trigger,
4270
- show && /* @__PURE__ */ jsx(
4551
+ show && // `w-max` rather than the `whitespace-nowrap` this was: both keep a
4552
+ // short bubble on one line however narrow its trigger, but only
4553
+ // `w-max` lets the width cap above take effect — a bubble longer than
4554
+ // its window is wide wraps inside it instead of running past both
4555
+ // edges. `whitespace-normal` and `text-start` so a trigger inside a
4556
+ // `nowrap` or right-aligned cell does not hand the bubble its own.
4557
+ // `box-border` so the caps measure the whole bubble, padding and
4558
+ // border included, in a host without Tailwind's preflight.
4559
+ // Nothing here animates, so there is no motion to reduce.
4560
+ /* @__PURE__ */ jsx(
4271
4561
  "span",
4272
4562
  {
4563
+ ref: tipRef,
4273
4564
  id,
4274
4565
  role: "tooltip",
4275
- className: `pointer-events-none absolute z-[300] whitespace-nowrap rounded-md px-2 py-1 text-xs text-gray-800 ${SIDE_POS[side]}`,
4276
- style: glassStyle(),
4566
+ className: `pointer-events-none absolute z-[300] box-border w-max overflow-hidden whitespace-normal break-words text-start rounded-md px-2 py-1 text-xs text-gray-800 ${placed ? "" : SIDE_POS[side]}`,
4567
+ style: {
4568
+ ...glass,
4569
+ ...placed && {
4570
+ left: placed.left,
4571
+ top: placed.top,
4572
+ maxWidth: placed.maxWidth,
4573
+ maxHeight: placed.maxHeight
4574
+ }
4575
+ },
4277
4576
  children: content
4278
4577
  }
4578
+ ),
4579
+ show && (!placed || placed.arrow) && // The arrow is the bubble's SIBLING, not its child: the bubble is
4580
+ // `overflow: hidden` for its height cap, and an arrow inside it would
4581
+ // be cut off at the very edge it is meant to stand out from. Drawn after
4582
+ // the bubble on the same layer, so it lies over the bubble's border
4583
+ // where the two meet and there is no seam.
4584
+ //
4585
+ // `data-side` is the side the BUBBLE is on, after any flip; ui.css
4586
+ // turns it into which way the arrow points and which two of its edges
4587
+ // carry the border. Unmeasured, it is the side asked for and ui.css
4588
+ // centres the arrow there, as `SIDE_POS` centres the bubble.
4589
+ //
4590
+ // Decorative: the bubble's text is the description, and the arrow says
4591
+ // nothing a screen reader needs.
4592
+ /* @__PURE__ */ jsx(
4593
+ "span",
4594
+ {
4595
+ "aria-hidden": "true",
4596
+ className: "rosh-tooltip-arrow",
4597
+ "data-side": placed?.side ?? side,
4598
+ style: {
4599
+ background: fill,
4600
+ // The bubble's border as one value, for ui.css to put on the two
4601
+ // edges that face outward — the side's own rule picks which.
4602
+ ["--rosh-tooltip-edge"]: glass?.border,
4603
+ ...placed?.arrow && { left: placed.arrow.left, top: placed.arrow.top }
4604
+ }
4605
+ }
4279
4606
  )
4280
4607
  ]
4281
4608
  }
@@ -4455,7 +4782,7 @@ function reportUnknownSeverity(component, described) {
4455
4782
  if (reported.has(key)) return;
4456
4783
  reported.add(key);
4457
4784
  console.error(
4458
- `[react-os-shell] ${component}: severity ${described} is not one of ${SEVERITY_TONES.join(" | ")}. Rendering an "unknown severity" marker \u2014 a health marker must never silently disappear. If this came from a backend rollup, map it to the shell's vocabulary at the fetch boundary (see isSeverityTone).`
4785
+ `[efficient-shell] ${component}: severity ${described} is not one of ${SEVERITY_TONES.join(" | ")}. Rendering an "unknown severity" marker \u2014 a health marker must never silently disappear. If this came from a backend rollup, map it to the shell's vocabulary at the fetch boundary (see isSeverityTone).`
4459
4786
  );
4460
4787
  }
4461
4788
  function resolveSeverity(severity, component) {
@@ -4512,7 +4839,7 @@ function MetricBar({
4512
4839
  if (scale == null) {
4513
4840
  warnOnce(
4514
4841
  `MetricBar:max:${String(max)}`,
4515
- `[react-os-shell] MetricBar: max=${String(max)} is not a positive finite number, so there is no scale to draw a proportional bar against. Printing the value without a bar. Pass the real capacity, or leave the reading out entirely (value={null}) when it is unknown \u2014 do not pass 0.`
4842
+ `[efficient-shell] MetricBar: max=${String(max)} is not a positive finite number, so there is no scale to draw a proportional bar against. Printing the value without a bar. Pass the real capacity, or leave the reading out entirely (value={null}) when it is unknown \u2014 do not pass 0.`
4516
4843
  );
4517
4844
  }
4518
4845
  const supplied = resolveSeverity(severity, "MetricBar");
@@ -8334,6 +8661,12 @@ function TopNav({ items, activeKey, onSelect, brand, actions, className }) {
8334
8661
  }
8335
8662
  );
8336
8663
  }
8664
+ var TRIGGER_CLASS = "inline-flex items-center justify-center rounded-md text-gray-600 transition-colors hover:bg-gray-100 hover:text-gray-900 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)] disabled:cursor-not-allowed disabled:opacity-60";
8665
+ var OWNS_Z = /(^|[\s:])!?z-/;
8666
+ var TYPEAHEAD_MS = 500;
8667
+ var CHECK = /* @__PURE__ */ jsx("svg", { "aria-hidden": true, className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.5 12.75l6 6 9-13.5" }) });
8668
+ var isLink = (entry) => entry.type === "link" || entry.type === void 0 && typeof entry.href === "string";
8669
+ var isFocusable = (entry) => !!entry && entry.type !== "label" && entry.type !== "divider" && !entry.disabled;
8337
8670
  function DropdownMenu({
8338
8671
  trigger,
8339
8672
  items,
@@ -8341,35 +8674,84 @@ function DropdownMenu({
8341
8674
  side = "bottom",
8342
8675
  "aria-label": ariaLabel,
8343
8676
  className = "",
8677
+ triggerClassName,
8678
+ menuClassName = "",
8679
+ minWidth = 180,
8680
+ linkAs,
8344
8681
  disabled
8345
8682
  }) {
8346
8683
  const [open, setOpen] = useState(false);
8347
- const [active, setActive] = useState(0);
8684
+ const [active, setActive] = useState(-1);
8348
8685
  const wrapRef = useRef(null);
8349
8686
  const triggerRef = useRef(null);
8350
- const itemRefs = useRef([]);
8687
+ const menuRef = useRef(null);
8688
+ const typed = useRef({ text: "", at: 0 });
8351
8689
  const menuId = useId();
8690
+ const triggerId = useId();
8352
8691
  const close = useCallback((restoreFocus) => {
8353
8692
  setOpen(false);
8354
8693
  if (restoreFocus) triggerRef.current?.focus();
8355
8694
  }, []);
8356
- const enabledFrom = (from, step) => {
8357
- for (let i = 0; i < items.length; i += 1) {
8358
- const at = ((from + step * i) % items.length + items.length) % items.length;
8359
- if (!items[at]?.disabled) return at;
8695
+ const focusableFrom = (from, step) => {
8696
+ const n = items.length;
8697
+ for (let i = 0; i < n; i += 1) {
8698
+ const at = ((from + step * i) % n + n) % n;
8699
+ if (isFocusable(items[at])) return at;
8360
8700
  }
8361
- return from;
8701
+ return -1;
8362
8702
  };
8703
+ const surface = () => menuRef.current?.closest("[data-popup-menu-tree]") ?? null;
8363
8704
  useEffect(() => {
8364
8705
  if (!open) return;
8365
8706
  const onPointerDown = (e) => {
8366
- if (!wrapRef.current?.contains(e.target)) close(false);
8707
+ const target = e.target;
8708
+ if (wrapRef.current?.contains(target) || surface()?.contains(target)) return;
8709
+ close(false);
8367
8710
  };
8368
8711
  document.addEventListener("pointerdown", onPointerDown, true);
8369
- return () => document.removeEventListener("pointerdown", onPointerDown, true);
8712
+ const offOverlay = onOverlayOpen(() => close(false));
8713
+ return () => {
8714
+ document.removeEventListener("pointerdown", onPointerDown, true);
8715
+ offOverlay();
8716
+ };
8370
8717
  }, [open, close]);
8718
+ const place = useCallback(() => {
8719
+ const el = surface();
8720
+ const anchor = triggerRef.current;
8721
+ if (!el || !anchor) return;
8722
+ const s = el.style;
8723
+ s.left = "0px";
8724
+ s.top = "0px";
8725
+ s.maxWidth = "none";
8726
+ s.maxHeight = "none";
8727
+ const size = { width: el.offsetWidth, height: el.offsetHeight };
8728
+ const at = placeMenu({
8729
+ trigger: anchor.getBoundingClientRect(),
8730
+ menu: size,
8731
+ bounds: popupBounds(anchor),
8732
+ align,
8733
+ side
8734
+ });
8735
+ s.left = `${at.left}px`;
8736
+ s.top = `${at.top}px`;
8737
+ s.maxWidth = `${at.maxWidth}px`;
8738
+ s.maxHeight = `${at.maxHeight}px`;
8739
+ s.overflowY = size.height > at.maxHeight ? "auto" : "";
8740
+ el.dataset.side = at.side;
8741
+ el.dataset.align = align;
8742
+ }, [align, side]);
8743
+ useBrowserLayoutEffect(() => {
8744
+ if (open) place();
8745
+ });
8371
8746
  useEffect(() => {
8372
- if (open) itemRefs.current[active]?.focus();
8747
+ if (!open) return;
8748
+ return followAnchor(() => triggerRef.current, place);
8749
+ }, [open, place]);
8750
+ useEffect(() => {
8751
+ if (!open) return;
8752
+ const menu = menuRef.current;
8753
+ const target = isFocusable(items[active]) ? menu?.querySelector(`[data-dropdown-index="${active}"]`) : null;
8754
+ (target ?? menu)?.focus({ preventScroll: true });
8373
8755
  }, [open, active]);
8374
8756
  useEffect(() => {
8375
8757
  if (!open) return;
@@ -8386,80 +8768,212 @@ function DropdownMenu({
8386
8768
  const onTriggerKeyDown = (e) => {
8387
8769
  if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
8388
8770
  e.preventDefault();
8389
- openAt(enabledFrom(0, 1));
8771
+ openAt(focusableFrom(0, 1));
8390
8772
  } else if (e.key === "ArrowUp") {
8391
8773
  e.preventDefault();
8392
- openAt(enabledFrom(items.length - 1, -1));
8774
+ openAt(focusableFrom(items.length - 1, -1));
8775
+ }
8776
+ };
8777
+ const typeahead = (e) => {
8778
+ const now = Date.now();
8779
+ const char = e.key.toLowerCase();
8780
+ const text = now - typed.current.at < TYPEAHEAD_MS ? typed.current.text + char : char;
8781
+ typed.current = { text, at: now };
8782
+ const repeated = [...text].every((c) => c === text[0]);
8783
+ const query = repeated ? text[0] : text;
8784
+ const from = repeated ? active + 1 : Math.max(active, 0);
8785
+ const menu = menuRef.current;
8786
+ const n = items.length;
8787
+ for (let i = 0; i < n; i += 1) {
8788
+ const at = ((from + i) % n + n) % n;
8789
+ if (!isFocusable(items[at])) continue;
8790
+ const label = menu?.querySelector(`[data-dropdown-index="${at}"]`)?.textContent?.trim().toLowerCase() ?? "";
8791
+ if (label.startsWith(query)) {
8792
+ e.preventDefault();
8793
+ setActive(at);
8794
+ return;
8795
+ }
8393
8796
  }
8394
8797
  };
8395
8798
  const onMenuKeyDown = (e) => {
8396
8799
  if (e.key === "ArrowDown") {
8397
8800
  e.preventDefault();
8398
- setActive(enabledFrom(active + 1, 1));
8801
+ setActive(focusableFrom(active + 1, 1));
8399
8802
  } else if (e.key === "ArrowUp") {
8400
8803
  e.preventDefault();
8401
- setActive(enabledFrom(active - 1, -1));
8804
+ setActive(focusableFrom(active - 1, -1));
8402
8805
  } else if (e.key === "Home") {
8403
8806
  e.preventDefault();
8404
- setActive(enabledFrom(0, 1));
8807
+ setActive(focusableFrom(0, 1));
8405
8808
  } else if (e.key === "End") {
8406
8809
  e.preventDefault();
8407
- setActive(enabledFrom(items.length - 1, -1));
8810
+ setActive(focusableFrom(items.length - 1, -1));
8408
8811
  } else if (e.key === "Tab") {
8409
8812
  e.preventDefault();
8410
8813
  close(true);
8814
+ } else if (e.key === " ") {
8815
+ const target = e.target;
8816
+ if (target.matches?.("a[href]")) {
8817
+ e.preventDefault();
8818
+ target.click();
8819
+ }
8820
+ } else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
8821
+ typeahead(e);
8411
8822
  }
8412
8823
  };
8413
- const select = (item) => {
8414
- if (item.disabled) return;
8824
+ const choose = (entry) => {
8825
+ if (entry.disabled) return;
8415
8826
  close(true);
8416
- item.onSelect();
8827
+ entry.onSelect();
8828
+ };
8829
+ const Link = linkAs ?? "a";
8830
+ const rowProps = (i, entry) => ({
8831
+ "data-dropdown-index": i,
8832
+ // One tab stop for the whole menu; the arrows move inside it.
8833
+ tabIndex: i === active ? 0 : -1,
8834
+ onMouseEnter: () => {
8835
+ if (!entry.disabled) setActive(i);
8836
+ }
8837
+ });
8838
+ const renderEntry = (entry, i) => {
8839
+ if (entry.type === "divider") {
8840
+ return /* @__PURE__ */ jsx("div", { role: "separator", children: /* @__PURE__ */ jsx(PopupMenuDivider, {}) }, entry.key);
8841
+ }
8842
+ if (entry.type === "label") {
8843
+ return /* @__PURE__ */ jsx("div", { id: `${menuId}-label-${i}`, children: /* @__PURE__ */ jsx(PopupMenuLabel, { children: entry.label }) }, entry.key);
8844
+ }
8845
+ if (entry.type === "radio") {
8846
+ const look2 = itemLook(false, entry.disabled, "");
8847
+ return /* @__PURE__ */ jsxs(
8848
+ "button",
8849
+ {
8850
+ type: "button",
8851
+ role: "menuitemradio",
8852
+ "aria-checked": entry.checked,
8853
+ disabled: entry.disabled,
8854
+ className: look2.className,
8855
+ style: look2.style,
8856
+ onClick: () => choose(entry),
8857
+ ...rowProps(i, entry),
8858
+ children: [
8859
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "inline-flex h-4 w-4 shrink-0 items-center justify-center", children: entry.checked && CHECK }),
8860
+ entry.icon,
8861
+ entry.label
8862
+ ]
8863
+ },
8864
+ entry.key
8865
+ );
8866
+ }
8867
+ if (isLink(entry)) {
8868
+ const look2 = itemLook(false, entry.disabled, `no-underline ${entry.current ? "font-medium" : ""}`);
8869
+ if (entry.disabled) {
8870
+ return /* @__PURE__ */ jsxs("a", { role: "menuitem", "aria-disabled": "true", className: look2.className, style: look2.style, ...rowProps(i, entry), children: [
8871
+ entry.icon,
8872
+ entry.label
8873
+ ] }, entry.key);
8874
+ }
8875
+ return /* @__PURE__ */ jsxs(
8876
+ Link,
8877
+ {
8878
+ href: entry.href,
8879
+ role: "menuitem",
8880
+ "aria-current": entry.current ? "page" : void 0,
8881
+ className: look2.className,
8882
+ style: look2.style,
8883
+ onClick: () => close(true),
8884
+ ...rowProps(i, entry),
8885
+ children: [
8886
+ entry.icon,
8887
+ entry.label
8888
+ ]
8889
+ },
8890
+ entry.key
8891
+ );
8892
+ }
8893
+ const look = itemLook(entry.danger, entry.disabled, "");
8894
+ return /* @__PURE__ */ jsxs(
8895
+ "button",
8896
+ {
8897
+ type: "button",
8898
+ role: "menuitem",
8899
+ disabled: entry.disabled,
8900
+ className: look.className,
8901
+ style: look.style,
8902
+ onClick: () => choose(entry),
8903
+ ...rowProps(i, entry),
8904
+ children: [
8905
+ entry.icon,
8906
+ entry.label
8907
+ ]
8908
+ },
8909
+ entry.key
8910
+ );
8911
+ };
8912
+ const renderEntries = () => {
8913
+ const out = [];
8914
+ for (let i = 0; i < items.length; ) {
8915
+ const entry = items[i];
8916
+ if (entry.type !== "radio") {
8917
+ out.push(renderEntry(entry, i));
8918
+ i += 1;
8919
+ continue;
8920
+ }
8921
+ const start = i;
8922
+ const run = [];
8923
+ while (i < items.length && items[i].type === "radio") {
8924
+ run.push(renderEntry(items[i], i));
8925
+ i += 1;
8926
+ }
8927
+ const heading = items[start - 1]?.type === "label" ? `${menuId}-label-${start - 1}` : void 0;
8928
+ out.push(/* @__PURE__ */ jsx("div", { role: "group", "aria-labelledby": heading, children: run }, `group:${entry.key}`));
8929
+ }
8930
+ return out;
8931
+ };
8932
+ const menuStyle = {
8933
+ // The popup layer, as every portalled kit popup: above dialogs and the
8934
+ // window stack, so a menu opened in either is drawn over it. A caller that
8935
+ // layered it with a `z-…` class keeps its own.
8936
+ ...OWNS_Z.test(menuClassName) ? {} : { zIndex: Z_LAYERS.popup },
8937
+ minWidth
8417
8938
  };
8418
8939
  return /* @__PURE__ */ jsxs("div", { ref: wrapRef, className: `relative inline-flex ${className}`.trim(), children: [
8419
8940
  /* @__PURE__ */ jsx(
8420
8941
  "button",
8421
8942
  {
8422
8943
  ref: triggerRef,
8944
+ id: triggerId,
8423
8945
  type: "button",
8424
8946
  "aria-haspopup": "menu",
8425
8947
  "aria-expanded": open,
8426
8948
  "aria-controls": open ? menuId : void 0,
8427
8949
  "aria-label": ariaLabel,
8428
8950
  disabled,
8429
- onClick: () => open ? close(false) : openAt(enabledFrom(0, 1)),
8951
+ onClick: () => open ? close(false) : openAt(focusableFrom(0, 1)),
8430
8952
  onKeyDown: onTriggerKeyDown,
8431
- className: "inline-flex items-center justify-center rounded-md text-gray-600 transition-colors hover:bg-gray-100 hover:text-gray-900 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)] disabled:cursor-not-allowed disabled:opacity-60",
8953
+ className: triggerClassName ?? TRIGGER_CLASS,
8432
8954
  children: trigger
8433
8955
  }
8434
8956
  ),
8435
- open && /* @__PURE__ */ jsx(
8957
+ open && // No `onClose`: PopupMenu's own dismissal calls the same callback for
8958
+ // Escape and for a click elsewhere, and those want opposite things.
8959
+ // Escape is the user putting the menu away, so focus goes back to the
8960
+ // trigger; a click elsewhere is them going somewhere, and dragging
8961
+ // focus back would take them off what they just clicked. The handlers
8962
+ // above tell the two apart.
8963
+ /* @__PURE__ */ jsx(PopupMenu, { portal: true, className: menuClassName, style: menuStyle, children: /* @__PURE__ */ jsx(
8436
8964
  "div",
8437
8965
  {
8438
- className: `absolute z-50 ${side === "top" ? "bottom-full mb-1" : "top-full mt-1"} ${align === "end" ? "right-0" : "left-0"}`,
8966
+ ref: menuRef,
8967
+ id: menuId,
8968
+ role: "menu",
8969
+ "aria-orientation": "vertical",
8970
+ "aria-label": ariaLabel,
8971
+ "aria-labelledby": ariaLabel ? void 0 : triggerId,
8972
+ tabIndex: -1,
8439
8973
  onKeyDown: onMenuKeyDown,
8440
- children: /* @__PURE__ */ jsx(PopupMenu, { portal: false, minWidth: 180, children: /* @__PURE__ */ jsx("div", { id: menuId, role: "menu", "aria-orientation": "vertical", "aria-label": ariaLabel, children: items.map((item, i) => /* @__PURE__ */ jsxs(
8441
- PopupMenuItem,
8442
- {
8443
- ref: (el) => {
8444
- itemRefs.current[i] = el;
8445
- },
8446
- role: "menuitem",
8447
- tabIndex: i === active ? 0 : -1,
8448
- danger: item.danger,
8449
- disabled: item.disabled,
8450
- onMouseEnter: () => {
8451
- if (!item.disabled) setActive(i);
8452
- },
8453
- onClick: () => select(item),
8454
- children: [
8455
- item.icon,
8456
- item.label
8457
- ]
8458
- },
8459
- item.key
8460
- )) }) })
8974
+ children: renderEntries()
8461
8975
  }
8462
- )
8976
+ ) })
8463
8977
  ] });
8464
8978
  }
8465
8979
  var APP_UPDATE_POLL_MS = 6e4;
@@ -9045,11 +9559,18 @@ function DataTable({
9045
9559
  selection,
9046
9560
  footer,
9047
9561
  virtualized,
9562
+ stackOnNarrow = false,
9048
9563
  className = ""
9049
9564
  }) {
9050
9565
  const strings = useShellStrings();
9051
9566
  const emptyContent = emptyText ?? strings.table.empty;
9052
9567
  const keyOf = (row, i) => typeof rowKey === "function" ? rowKey(row, i) : String(row[rowKey]);
9568
+ const stack = stackOnNarrow && !virtualized;
9569
+ const role = (r) => stack ? { role: r } : {};
9570
+ const textOf = (title, label) => {
9571
+ const text = label ?? (typeof title === "string" || typeof title === "number" ? String(title) : "");
9572
+ return text.trim() || void 0;
9573
+ };
9053
9574
  const [startRow, setStartRow] = useState(0);
9054
9575
  const overscan = virtualized?.overscan ?? 6;
9055
9576
  const onBodyScroll = virtualized ? (e) => {
@@ -9082,6 +9603,17 @@ function DataTable({
9082
9603
  };
9083
9604
  const leaves = columns.flatMap((h) => isGroup(h) ? h.columns : [h]);
9084
9605
  const grouped = columns.some(isGroup);
9606
+ const groupOf = /* @__PURE__ */ new Map();
9607
+ if (stack) {
9608
+ for (const h of columns) {
9609
+ if (isGroup(h)) for (const c of h.columns) groupOf.set(c, textOf(h.title, h.label));
9610
+ }
9611
+ }
9612
+ const cardLabel = (col) => {
9613
+ const own = textOf(col.title, col.label);
9614
+ const group = groupOf.get(col);
9615
+ return own && group ? `${group} \xB7 ${own}` : own;
9616
+ };
9085
9617
  const selectedSet = new Set(selection?.selected ?? []);
9086
9618
  const pageKeys = selection ? data.map((row, i) => keyOf(row, i)) : [];
9087
9619
  const allSelected = pageKeys.length > 0 && pageKeys.every((k) => selectedSet.has(k));
@@ -9108,12 +9640,14 @@ function DataTable({
9108
9640
  const dir = directionFor(col);
9109
9641
  const align = ALIGN2[col.align ?? (col.numeric ? "right" : "left")];
9110
9642
  const pinned = col.fixed === "left";
9643
+ const sorts = !!(col.sortable && onSortChange);
9111
9644
  return /* @__PURE__ */ jsx(
9112
9645
  "th",
9113
9646
  {
9114
9647
  scope: "col",
9648
+ ...role("columnheader"),
9115
9649
  rowSpan: rowSpan > 1 ? rowSpan : void 0,
9116
- "aria-sort": dir === "asc" ? "ascending" : dir === "desc" ? "descending" : col.sortable && onSortChange ? "none" : void 0,
9650
+ "aria-sort": dir === "asc" ? "ascending" : dir === "desc" ? "descending" : sorts ? "none" : void 0,
9117
9651
  style: {
9118
9652
  width: col.width,
9119
9653
  ...pinned ? { left: (offsets[ci] ?? 0) + selOffset } : {},
@@ -9128,13 +9662,17 @@ function DataTable({
9128
9662
  "font-semibold uppercase tracking-wide text-gray-500",
9129
9663
  size === "sm" ? "text-[10px]" : "text-xs",
9130
9664
  pinned ? virtualized ? "sticky z-20 bg-gray-50" : "sticky z-10 bg-gray-50" : virtualized ? "sticky z-10 bg-gray-50" : "",
9665
+ // Stacked, a sortable header is one of the sort row's chips and
9666
+ // every other header is hidden from sight — see `rosh-dt-head`.
9667
+ stack && sorts ? "rosh-dt-sort" : "",
9131
9668
  col.headerClassName ?? ""
9132
9669
  ].filter(Boolean).join(" "),
9133
- children: col.sortable && onSortChange ? /* @__PURE__ */ jsxs(
9670
+ children: sorts ? /* @__PURE__ */ jsxs(
9134
9671
  "button",
9135
9672
  {
9136
9673
  type: "button",
9137
9674
  onClick: () => toggleSort(col),
9675
+ "data-group": stack ? groupOf.get(col) : void 0,
9138
9676
  className: `inline-flex items-center font-semibold uppercase tracking-wide hover:text-gray-700 ${align}`,
9139
9677
  children: [
9140
9678
  col.title,
@@ -9153,13 +9691,13 @@ function DataTable({
9153
9691
  fixedOffset += col.width ?? 0;
9154
9692
  return at;
9155
9693
  });
9156
- return /* @__PURE__ */ jsxs("div", { className, children: [
9694
+ return /* @__PURE__ */ jsxs("div", { className: stack ? `rosh-dt-stack ${className}`.trim() : className, children: [
9157
9695
  /* @__PURE__ */ jsxs(
9158
9696
  "div",
9159
9697
  {
9160
9698
  onScroll: onBodyScroll,
9161
9699
  style: virtualized ? { maxHeight: virtualized.height } : void 0,
9162
- className: `relative overflow-x-auto ${virtualized ? "overflow-y-auto" : ""} ${bordered ? "rounded-lg border border-gray-200" : ""}`.trim(),
9700
+ className: `relative overflow-x-auto ${virtualized ? "overflow-y-auto" : ""} ${bordered ? "rounded-lg border border-gray-200" : ""}${stack ? " rosh-dt-scroll" : ""}`.trim(),
9163
9701
  children: [
9164
9702
  loading && // An overlay rather than replacing the rows: the table keeps its
9165
9703
  // height and its scroll position, so re-sorting does not throw the
@@ -9168,140 +9706,172 @@ function DataTable({
9168
9706
  /* @__PURE__ */ jsx("span", { className: "h-6 w-6 animate-spin rounded-full border-2 border-gray-200 border-t-blue-600" }),
9169
9707
  /* @__PURE__ */ jsx("span", { className: "sr-only", children: strings.table.loading })
9170
9708
  ] }),
9171
- /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse tabular-nums", style: minWidth ? { minWidth } : void 0, children: [
9172
- caption && /* @__PURE__ */ jsx("caption", { className: "sr-only", children: caption }),
9173
- /* @__PURE__ */ jsxs("thead", { children: [
9174
- /* @__PURE__ */ jsxs("tr", { ref: headRowRef, className: "border-b border-gray-200 bg-gray-50", children: [
9175
- selection && /* @__PURE__ */ jsx(
9176
- "th",
9177
- {
9178
- scope: "col",
9179
- rowSpan: grouped ? 2 : void 0,
9180
- style: { width: SELECT_W, ...virtualized ? { top: 0 } : {} },
9181
- className: [
9182
- cellBase,
9183
- hasPinned || virtualized ? "sticky z-20 bg-gray-50" : "",
9184
- hasPinned ? "left-0" : ""
9185
- ].filter(Boolean).join(" "),
9186
- children: /* @__PURE__ */ jsx(
9187
- Checkbox_default,
9188
- {
9189
- "aria-label": strings.table.selectAll,
9190
- checked: allSelected,
9191
- indeterminate: someSelected && !allSelected,
9192
- onChange: toggleAll
9193
- }
9194
- )
9195
- }
9196
- ),
9197
- columns.map((h, hi) => {
9198
- if (isGroup(h)) {
9199
- return /* @__PURE__ */ jsx(
9709
+ /* @__PURE__ */ jsxs(
9710
+ "table",
9711
+ {
9712
+ ...role("table"),
9713
+ className: `${stack ? "rosh-dt-table " : ""}w-full border-collapse tabular-nums`,
9714
+ style: minWidth ? { minWidth } : void 0,
9715
+ children: [
9716
+ caption && /* @__PURE__ */ jsx("caption", { className: "sr-only", children: caption }),
9717
+ /* @__PURE__ */ jsxs("thead", { ...role("rowgroup"), className: stack ? "rosh-dt-head" : void 0, children: [
9718
+ /* @__PURE__ */ jsxs("tr", { ref: headRowRef, ...role("row"), className: "border-b border-gray-200 bg-gray-50", children: [
9719
+ selection && /* @__PURE__ */ jsx(
9200
9720
  "th",
9201
9721
  {
9202
- scope: "colgroup",
9203
- colSpan: h.columns.length,
9204
- style: virtualized ? { top: 0 } : void 0,
9722
+ scope: "col",
9723
+ ...role("columnheader"),
9724
+ rowSpan: grouped ? 2 : void 0,
9725
+ style: { width: SELECT_W, ...virtualized ? { top: 0 } : {} },
9205
9726
  className: [
9206
9727
  cellBase,
9207
- "text-center",
9208
- "font-semibold uppercase tracking-wide text-gray-500",
9209
- size === "sm" ? "text-[10px]" : "text-xs",
9210
- "border-b border-gray-200",
9211
- virtualized ? "sticky z-10 bg-gray-50" : "",
9212
- h.headerClassName ?? ""
9728
+ hasPinned || virtualized ? "sticky z-20 bg-gray-50" : "",
9729
+ hasPinned ? "left-0" : "",
9730
+ // Stacked, "select all" leads the sort row.
9731
+ stack ? "rosh-dt-select" : ""
9213
9732
  ].filter(Boolean).join(" "),
9214
- children: h.title
9215
- },
9216
- h.key ?? `group-${hi}`
9217
- );
9218
- }
9219
- return headerCell(h, leaves.indexOf(h), grouped ? 2 : 1);
9220
- })
9221
- ] }),
9222
- grouped && /* @__PURE__ */ jsx("tr", { className: "border-b border-gray-200 bg-gray-50", children: columns.flatMap((h) => isGroup(h) ? h.columns : []).map(
9223
- (col) => headerCell(col, leaves.indexOf(col), 1, headRowH)
9224
- ) })
9225
- ] }),
9226
- /* @__PURE__ */ jsx("tbody", { children: data.length === 0 && !loading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: colCount, className: `${cellBase} py-10 text-center text-gray-500`, children: emptyContent }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
9227
- topPad > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx("td", { colSpan: colCount, style: { height: topPad, padding: 0, border: 0 } }) }),
9228
- data.slice(start, end).map((row, si) => {
9229
- const i = start + si;
9230
- const rowProps = onRow?.(row, i);
9231
- return /* @__PURE__ */ jsxs(
9232
- "tr",
9233
- {
9234
- style: virtualized ? { height: virtualized.rowHeight } : void 0,
9235
- onClick: rowProps?.onClick,
9236
- ...rowProps?.onClick ? {
9237
- tabIndex: 0,
9238
- onKeyDown: (e) => {
9239
- if (e.target !== e.currentTarget) return;
9240
- if (e.key !== "Enter" && e.key !== " ") return;
9241
- e.preventDefault();
9242
- rowProps.onClick?.();
9243
- }
9244
- } : {},
9245
- className: [
9246
- "border-b border-gray-100 last:border-b-0",
9247
- rowProps?.onClick ? "cursor-pointer hover:bg-gray-50 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[color:var(--rosh-focus-ring-solid)]" : "",
9248
- rowClassName?.(row, i) ?? "",
9249
- rowProps?.className ?? ""
9250
- ].filter(Boolean).join(" "),
9251
- children: [
9252
- selection && (() => {
9253
- const key = keyOf(row, i);
9254
- return /* @__PURE__ */ jsx(
9255
- "td",
9733
+ children: /* @__PURE__ */ jsx(
9734
+ Checkbox_default,
9256
9735
  {
9257
- style: { width: SELECT_W },
9258
- onClick: (e) => e.stopPropagation(),
9259
- className: [cellBase, hasPinned ? "sticky left-0 z-10 bg-white" : ""].filter(Boolean).join(" "),
9260
- children: /* @__PURE__ */ jsx(
9261
- Checkbox_default,
9262
- {
9263
- "aria-label": strings.table.selectRow,
9264
- checked: selectedSet.has(key),
9265
- onChange: () => toggleRow(key)
9266
- }
9267
- )
9736
+ "aria-label": strings.table.selectAll,
9737
+ checked: allSelected,
9738
+ indeterminate: someSelected && !allSelected,
9739
+ onChange: toggleAll
9268
9740
  }
9269
- );
9270
- })(),
9271
- leaves.map((col, ci) => {
9272
- const pinned = col.fixed === "left";
9741
+ )
9742
+ }
9743
+ ),
9744
+ columns.map((h, hi) => {
9745
+ if (isGroup(h)) {
9273
9746
  return /* @__PURE__ */ jsx(
9274
- "td",
9747
+ "th",
9275
9748
  {
9276
- style: pinned ? { left: (offsets[ci] ?? 0) + selOffset } : void 0,
9749
+ scope: "colgroup",
9750
+ ...role("columnheader"),
9751
+ colSpan: h.columns.length,
9752
+ style: virtualized ? { top: 0 } : void 0,
9277
9753
  className: [
9278
9754
  cellBase,
9279
- ALIGN2[col.align ?? (col.numeric ? "right" : "left")],
9280
- col.numeric ? "font-mono" : "",
9281
- "text-gray-900",
9282
- col.ellipsis ? "max-w-0 truncate" : "",
9283
- // A pinned cell needs its own background or the
9284
- // scrolling columns show through it.
9285
- pinned ? "sticky z-10 bg-white" : ""
9755
+ "text-center",
9756
+ "font-semibold uppercase tracking-wide text-gray-500",
9757
+ size === "sm" ? "text-[10px]" : "text-xs",
9758
+ "border-b border-gray-200",
9759
+ virtualized ? "sticky z-10 bg-gray-50" : "",
9760
+ h.headerClassName ?? ""
9286
9761
  ].filter(Boolean).join(" "),
9287
- children: col.render ? col.render(row, i) : col.dataIndex ? row[col.dataIndex] : null
9762
+ children: h.title
9288
9763
  },
9289
- col.key
9764
+ h.key ?? `group-${hi}`
9290
9765
  );
9291
- })
9292
- ]
9293
- },
9294
- keyOf(row, i)
9295
- );
9296
- }),
9297
- bottomPad > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx("td", { colSpan: colCount, style: { height: bottomPad, padding: 0, border: 0 } }) })
9298
- ] }) })
9299
- ] }),
9766
+ }
9767
+ return headerCell(h, leaves.indexOf(h), grouped ? 2 : 1);
9768
+ })
9769
+ ] }),
9770
+ grouped && /* @__PURE__ */ jsx("tr", { ...role("row"), className: "border-b border-gray-200 bg-gray-50", children: columns.flatMap((h) => isGroup(h) ? h.columns : []).map(
9771
+ (col) => headerCell(col, leaves.indexOf(col), 1, headRowH)
9772
+ ) })
9773
+ ] }),
9774
+ /* @__PURE__ */ jsx("tbody", { ...role("rowgroup"), className: stack ? "rosh-dt-body" : void 0, children: data.length === 0 && !loading ? /* @__PURE__ */ jsx("tr", { ...role("row"), className: stack ? "rosh-dt-empty" : void 0, children: /* @__PURE__ */ jsx("td", { ...role("cell"), colSpan: colCount, className: `${cellBase} py-10 text-center text-gray-500`, children: emptyContent }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
9775
+ topPad > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx("td", { colSpan: colCount, style: { height: topPad, padding: 0, border: 0 } }) }),
9776
+ data.slice(start, end).map((row, si) => {
9777
+ const i = start + si;
9778
+ const rowProps = onRow?.(row, i);
9779
+ return /* @__PURE__ */ jsxs(
9780
+ "tr",
9781
+ {
9782
+ ...role("row"),
9783
+ style: virtualized ? { height: virtualized.rowHeight } : void 0,
9784
+ onClick: rowProps?.onClick,
9785
+ ...rowProps?.onClick ? {
9786
+ tabIndex: 0,
9787
+ onKeyDown: (e) => {
9788
+ if (e.target !== e.currentTarget) return;
9789
+ if (e.key !== "Enter" && e.key !== " ") return;
9790
+ e.preventDefault();
9791
+ rowProps.onClick?.();
9792
+ }
9793
+ } : {},
9794
+ className: [
9795
+ stack ? selection ? "rosh-dt-row rosh-dt-row-select" : "rosh-dt-row" : "",
9796
+ "border-b border-gray-100 last:border-b-0",
9797
+ rowProps?.onClick ? "cursor-pointer hover:bg-gray-50 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[color:var(--rosh-focus-ring-solid)]" : "",
9798
+ rowClassName?.(row, i) ?? "",
9799
+ rowProps?.className ?? ""
9800
+ ].filter(Boolean).join(" "),
9801
+ children: [
9802
+ selection && (() => {
9803
+ const key = keyOf(row, i);
9804
+ return /* @__PURE__ */ jsx(
9805
+ "td",
9806
+ {
9807
+ ...role("cell"),
9808
+ style: { width: SELECT_W },
9809
+ onClick: (e) => e.stopPropagation(),
9810
+ className: [
9811
+ cellBase,
9812
+ hasPinned ? "sticky left-0 z-10 bg-white" : "",
9813
+ stack ? "rosh-dt-select" : ""
9814
+ ].filter(Boolean).join(" "),
9815
+ children: /* @__PURE__ */ jsx(
9816
+ Checkbox_default,
9817
+ {
9818
+ "aria-label": strings.table.selectRow,
9819
+ checked: selectedSet.has(key),
9820
+ onChange: () => toggleRow(key)
9821
+ }
9822
+ )
9823
+ }
9824
+ );
9825
+ })(),
9826
+ leaves.map((col, ci) => {
9827
+ const pinned = col.fixed === "left";
9828
+ const content = col.render ? col.render(row, i) : col.dataIndex ? row[col.dataIndex] : null;
9829
+ return /* @__PURE__ */ jsx(
9830
+ "td",
9831
+ {
9832
+ ...role("cell"),
9833
+ "data-label": stack ? cardLabel(col) : void 0,
9834
+ style: pinned ? { left: (offsets[ci] ?? 0) + selOffset } : void 0,
9835
+ className: [
9836
+ stack ? col.ellipsis ? "rosh-dt-cell rosh-dt-clip" : "rosh-dt-cell" : "",
9837
+ cellBase,
9838
+ ALIGN2[col.align ?? (col.numeric ? "right" : "left")],
9839
+ // Stacked, the monospace moves onto the value, so
9840
+ // the label beside it keeps the header's typeface.
9841
+ col.numeric && !stack ? "font-mono" : "",
9842
+ "text-gray-900",
9843
+ col.ellipsis ? "max-w-0 truncate" : "",
9844
+ // A pinned cell needs its own background or the
9845
+ // scrolling columns show through it.
9846
+ pinned ? "sticky z-10 bg-white" : ""
9847
+ ].filter(Boolean).join(" "),
9848
+ children: stack ? (
9849
+ // One box for the value, whatever `render` returns
9850
+ // — text, a fragment, three badges — so the card
9851
+ // line is always two items: the label and this.
9852
+ // `display: contents` in the wide layout, where
9853
+ // the cell lays its content out exactly as before.
9854
+ /* @__PURE__ */ jsx("span", { className: col.numeric ? "rosh-dt-value font-mono" : "rosh-dt-value", children: content })
9855
+ ) : content
9856
+ },
9857
+ col.key
9858
+ );
9859
+ })
9860
+ ]
9861
+ },
9862
+ keyOf(row, i)
9863
+ );
9864
+ }),
9865
+ bottomPad > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx("td", { colSpan: colCount, style: { height: bottomPad, padding: 0, border: 0 } }) })
9866
+ ] }) })
9867
+ ]
9868
+ }
9869
+ ),
9300
9870
  footer
9301
9871
  ]
9302
9872
  }
9303
9873
  ),
9304
- pagination && pagination.pageCount > 1 && /* @__PURE__ */ jsx("div", { className: "mt-3 flex justify-end", children: /* @__PURE__ */ jsx(
9874
+ pagination && pagination.pageCount > 1 && /* @__PURE__ */ jsx("div", { className: stack ? "rosh-dt-pager mt-3 flex justify-end" : "mt-3 flex justify-end", children: /* @__PURE__ */ jsx(
9305
9875
  Pagination,
9306
9876
  {
9307
9877
  page: pagination.page,
@@ -13532,6 +14102,6 @@ function ChordChart({
13532
14102
  ] });
13533
14103
  }
13534
14104
 
13535
- export { APP_UPDATE_POLL_MS, Accordion, AppUpdateBanner, AttachButton, AttachmentDropZone, AttachmentList, AuthScreen, Avatar, AvatarGroup, Banner, BarChart, BoxPlotChart, BrandAssetEditor, BudgetBar, CHART_INK, Calendar, CandlestickChart, Card, CartesianPlot, ChartBrush, ChartDefs, ChartDot, ChartFrame, ChartHighlightProvider, ChartSkeleton, ChartTooltip, ChatTemplate, Checkbox_default, CheckoutTemplate, ChordChart, ColoredBadge, ColumnChart, ComposerAttachments, ContainerFillChart, CountBadge, DAY_MS, DashboardTemplate, DataTable, DataTablePage, DatePicker_default, DateRangePicker, DateTimePicker_default, DescriptionList, Divider, DonutChart, Drawer, DropdownMenu, EmailTemplate, EmptyState, ErrorBoundary, ErrorPage, FilePicker_default, FormErrorSummary, FormField, FormLayoutPage, FunnelChart, GROUP_COLORS, GROUP_COLORS_SOLID, GalleryTemplate, GlobalSearch, Grid, HeatmapChart, HelpCenter, HistogramChart, INPUT_BASE, INPUT_SIZES, IconButton_default, Inline, InputNumber_default, Input_default, Kanban, Label, LineChart, ListFooter, ListLoadError, MAX_FRACTION_DIGITS, MENU_MAX_HEIGHT, MOTION, Markdown, MediaUploadField, MediaUploadGrid, Meter, MetricBar, MilestoneTimeline, NativeSelect, NumericKeypad, POPUP_MAX_WIDTH, POST_PRODUCTION_STATUSES, PageHeader, Pagination, PaperclipGlyph, Paragraph, PieChart, PortalBrandingProvider, ProductionTimeline, RADAR_SERIES_CAP, RadarChart, RadialBarChart, RadioGroup, Radio_default, RangeChart, RankedBars, SCATTER_SERIES_CAP, SERIES_SLOT_COUNT, SERIES_VARS, STAGES, STATUS_VARS, SankeyChart, ScatterChart, SearchableSelect, Segmented, Select_default, SettingRow, SidebarActionButton, SidebarGroupLabel, SidebarNavItem, Skeleton, Snippet, Sparkline, Stack, StatCard, StatTile, Statistic, StatusBadge, StatusBadgeProvider, Stepper, SunburstChart, Switch_default, Tabs, TagInput, Text, Textarea_default, TileButton_default, TimePicker_default, TimeSeriesChart, TimelineTrack, Title, Tooltip, TopNav, TreemapChart, WaterfallChart, angleScale, appendKey, applyThemePrefs, arcPath, areaBetween, areaFrom, autoHighlightIndex, backspace, bandScale, binValues, budgetState, bumpPath, calcOverall, calcReportOverall, copyToClipboard, curvePath, dashFor, fillFor, fillId, firstEnabledIndex, fmtSliderDate, formatDate, fromKey, glowId, groundId, groupColors, highlightOpacity, inputClasses, isSeverityTone, ladderScale, lastEnabledIndex, linearPath, linearScale, logScale, maskId, matchTypeahead, mediaFileName, monotonePath, nextEnabledIndex, niceMax, polygonPoints, popupBounds, radiusScale, resolvePortalBrandAsset, resolveSeriesColor, resolveTheme, selectionAt, seriesColor, severityOf, splinePath, squarify, stagger, stepPath, tabButtonId, tabPanelId, toDayMs, toISODate, toKey, useAppUpdate, useClickOutside, useDropdownPosition, useHighlight, usePlotWidth, usePortalBranding, useProductionTimeline, useTheme };
13536
- //# sourceMappingURL=chunk-BJ34QOR3.js.map
13537
- //# sourceMappingURL=chunk-BJ34QOR3.js.map
14105
+ export { APP_UPDATE_POLL_MS, Accordion, AppUpdateBanner, AttachButton, AttachmentDropZone, AttachmentList, AuthScreen, Avatar, AvatarGroup, Banner, BarChart, BoxPlotChart, BrandAssetEditor, BudgetBar, CHART_INK, Calendar, CandlestickChart, Card, CartesianPlot, ChartBrush, ChartDefs, ChartDot, ChartFrame, ChartHighlightProvider, ChartSkeleton, ChartTooltip, ChatTemplate, Checkbox_default, CheckoutTemplate, ChordChart, ColoredBadge, ColumnChart, ComposerAttachments, ContainerFillChart, CountBadge, DAY_MS, DashboardTemplate, DataTable, DataTablePage, DatePicker_default, DateRangePicker, DateTimePicker_default, DescriptionList, Divider, DonutChart, Drawer, DropdownMenu, EmailTemplate, EmptyState, ErrorBoundary, ErrorPage, FilePicker_default, FormErrorSummary, FormField, FormLayoutPage, FunnelChart, GROUP_COLORS, GROUP_COLORS_SOLID, GalleryTemplate, GlobalSearch, Grid, HeatmapChart, HelpCenter, HistogramChart, INPUT_BASE, INPUT_SIZES, IconButton_default, Inline, InputNumber_default, Input_default, Kanban, Label, LineChart, ListFooter, ListLoadError, MAX_FRACTION_DIGITS, MENU_MAX_HEIGHT, MOTION, Markdown, MediaUploadField, MediaUploadGrid, Meter, MetricBar, MilestoneTimeline, NativeSelect, NumericKeypad, POPUP_MAX_WIDTH, POST_PRODUCTION_STATUSES, PageHeader, Pagination, PaperclipGlyph, Paragraph, PieChart, PortalBrandingProvider, ProductionTimeline, RADAR_SERIES_CAP, RadarChart, RadialBarChart, RadioGroup, Radio_default, RangeChart, RankedBars, SCATTER_SERIES_CAP, SERIES_SLOT_COUNT, SERIES_VARS, STAGES, STATUS_VARS, SankeyChart, ScatterChart, SearchableSelect, Segmented, Select_default, SettingRow, SidebarActionButton, SidebarGroupLabel, SidebarNavItem, Skeleton, Snippet, Sparkline, Stack, StatCard, StatTile, Statistic, StatusBadge, StatusBadgeProvider, Stepper, SunburstChart, Switch_default, Tabs, TagInput, Text, Textarea_default, TileButton_default, TimePicker_default, TimeSeriesChart, TimelineTrack, Title, Tooltip, TopNav, TreemapChart, WaterfallChart, angleScale, appendKey, applyThemePrefs, arcPath, areaBetween, areaFrom, autoHighlightIndex, backspace, bandScale, binValues, budgetState, bumpPath, calcOverall, calcReportOverall, copyToClipboard, curvePath, dashFor, fillFor, fillId, firstDayOfWeek, firstEnabledIndex, fmtSliderDate, formatDate, fromKey, glowId, groundId, groupColors, highlightOpacity, inputClasses, isSeverityTone, ladderScale, lastEnabledIndex, linearPath, linearScale, logScale, maskId, matchTypeahead, mediaFileName, monotonePath, nextEnabledIndex, niceMax, polygonPoints, popupBounds, radiusScale, resolvePortalBrandAsset, resolveSeriesColor, resolveTheme, selectionAt, seriesColor, severityOf, splinePath, squarify, stagger, stepPath, tabButtonId, tabPanelId, toDayMs, toISODate, toKey, useAppUpdate, useClickOutside, useDropdownPosition, useHighlight, usePlotWidth, usePortalBranding, useProductionTimeline, useTheme };
14106
+ //# sourceMappingURL=chunk-YA4EE7ST.js.map
14107
+ //# sourceMappingURL=chunk-YA4EE7ST.js.map