twico-ui 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  "use client";
2
- import * as React23 from 'react';
3
- import React23__default from 'react';
2
+ import * as React24 from 'react';
3
+ import React24__default from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
  import { createPortal } from 'react-dom';
6
6
 
7
7
  // components/navigation/Accordion.jsx
8
- var SUPPORTS_STYLE_HOIST = parseInt(String(React23.version), 10) >= 19;
8
+ var SUPPORTS_STYLE_HOIST = parseInt(String(React24.version), 10) >= 19;
9
9
  function useScopedStyles(id, css) {
10
- React23.useInsertionEffect(() => {
10
+ React24.useInsertionEffect(() => {
11
11
  if (SUPPORTS_STYLE_HOIST) return;
12
12
  if (typeof document === "undefined" || document.getElementById(id)) return;
13
13
  const el = document.createElement("style");
@@ -15,7 +15,7 @@ function useScopedStyles(id, css) {
15
15
  el.textContent = css;
16
16
  document.head.appendChild(el);
17
17
  }, [id, css]);
18
- return SUPPORTS_STYLE_HOIST ? React23.createElement("style", { href: id, precedence: "twc-ui" }, css) : null;
18
+ return SUPPORTS_STYLE_HOIST ? React24.createElement("style", { href: id, precedence: "twc-ui" }, css) : null;
19
19
  }
20
20
  var ACCORDION_CSS = `
21
21
  .twc-accordion { display: flex; flex-direction: column; font-family: var(--font-sans);
@@ -29,7 +29,9 @@ var ACCORDION_CSS = `
29
29
  color: var(--color-text); text-align: start;
30
30
  transition: background-color var(--duration-fast) var(--ease-standard);
31
31
  }
32
- .twc-accordion__trigger:hover { background: var(--color-surface-sunken); }
32
+ .twc-accordion__heading { margin: 0; font: inherit; }
33
+ .twc-accordion__trigger:hover:not(:disabled) { background: var(--color-surface-sunken); }
34
+ .twc-accordion__trigger:disabled { opacity: 0.45; cursor: not-allowed; }
33
35
  .twc-accordion__trigger:focus-visible { outline: none; box-shadow: var(--ring); }
34
36
  .twc-accordion__label { flex: 1; }
35
37
  .twc-accordion__chevron { flex: none; color: var(--color-text-subtle); transition: transform var(--duration-base) var(--ease-spring); }
@@ -48,14 +50,19 @@ function Accordion({
48
50
  defaultOpen = [],
49
51
  open: openProp,
50
52
  onOpenChange,
53
+ headingLevel = 3,
51
54
  className = "",
55
+ onKeyDown: onKeyDownProp,
52
56
  ...rest
53
57
  }) {
54
58
  const __twcStyles = useScopedStyles("twc-accordion-styles", ACCORDION_CSS);
55
- const [internal, setInternal] = React23__default.useState(() => new Set(defaultOpen));
59
+ const rootRef = React24__default.useRef(null);
60
+ const [internal, setInternal] = React24__default.useState(() => new Set(defaultOpen));
56
61
  const open = openProp !== void 0 ? new Set(openProp) : internal;
57
- const baseId = React23__default.useId();
62
+ const baseId = React24__default.useId();
58
63
  function toggle(val) {
64
+ const item = items.find((x) => x.value === val);
65
+ if (item?.disabled) return;
59
66
  const next = new Set(open);
60
67
  if (next.has(val)) next.delete(val);
61
68
  else {
@@ -65,18 +72,47 @@ function Accordion({
65
72
  if (openProp === void 0) setInternal(next);
66
73
  onOpenChange?.([...next]);
67
74
  }
68
- return /* @__PURE__ */ jsxs("div", { className: `twc-accordion ${className}`, ...rest, children: [
75
+ function handleKeyDown(e) {
76
+ onKeyDownProp?.(e);
77
+ if (!(e.target instanceof HTMLElement) || !e.target.classList.contains("twc-accordion__trigger")) return;
78
+ const triggers = Array.from(rootRef.current.querySelectorAll(".twc-accordion__trigger")).filter((b) => !b.disabled);
79
+ const i = triggers.indexOf(e.target);
80
+ if (i < 0) return;
81
+ const len2 = triggers.length;
82
+ let next;
83
+ switch (e.key) {
84
+ case "ArrowDown":
85
+ next = (i + 1) % len2;
86
+ break;
87
+ case "ArrowUp":
88
+ next = (i - 1 + len2) % len2;
89
+ break;
90
+ case "Home":
91
+ next = 0;
92
+ break;
93
+ case "End":
94
+ next = len2 - 1;
95
+ break;
96
+ default:
97
+ return;
98
+ }
99
+ e.preventDefault();
100
+ triggers[next].focus();
101
+ }
102
+ return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: `twc-accordion ${className}`, onKeyDown: handleKeyDown, ...rest, children: [
69
103
  __twcStyles,
70
104
  items.map((it, i) => {
71
105
  const isOpen = open.has(it.value);
72
106
  const triggerId = `${baseId}-trigger-${i}`;
73
107
  const panelId = `${baseId}-panel-${i}`;
108
+ const lvl = Math.min(6, Math.max(1, it.headingLevel ?? headingLevel));
109
+ const Heading2 = `h${lvl}`;
74
110
  return /* @__PURE__ */ jsxs("div", { className: "twc-accordion__item", children: [
75
- /* @__PURE__ */ jsxs("button", { type: "button", id: triggerId, className: "twc-accordion__trigger", "data-open": isOpen || void 0, "aria-expanded": isOpen, "aria-controls": panelId, onClick: () => toggle(it.value), children: [
111
+ /* @__PURE__ */ jsx(Heading2, { className: "twc-accordion__heading", children: /* @__PURE__ */ jsxs("button", { type: "button", id: triggerId, className: "twc-accordion__trigger", "data-open": isOpen || void 0, disabled: it.disabled || void 0, "aria-disabled": it.disabled || void 0, "data-disabled": it.disabled || void 0, "aria-expanded": isOpen, "aria-controls": panelId, onClick: () => toggle(it.value), children: [
76
112
  it.icon,
77
113
  /* @__PURE__ */ jsx("span", { className: "twc-accordion__label", children: it.label }),
78
114
  /* @__PURE__ */ jsx("span", { className: "twc-accordion__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" }) }) })
79
- ] }),
115
+ ] }) }),
80
116
  /* @__PURE__ */ jsx("div", { className: "twc-accordion__panel", id: panelId, role: "region", "aria-labelledby": triggerId, "data-open": isOpen || void 0, children: /* @__PURE__ */ jsx("div", { className: "twc-accordion__panel-inner", children: /* @__PURE__ */ jsx("div", { className: "twc-accordion__content", children: it.content }) }) })
81
117
  ] }, it.value);
82
118
  })
@@ -132,11 +168,15 @@ function Alert({
132
168
  title,
133
169
  icon,
134
170
  onClose,
171
+ live,
172
+ closeLabel = "Dismiss",
135
173
  className = "",
136
174
  ...rest
137
175
  }) {
138
176
  const __twcStyles = useScopedStyles("twc-alert-styles", ALERT_CSS);
139
- return /* @__PURE__ */ jsxs("div", { className: `twc-alert ${className}`, "data-tone": tone, "data-variant": variant, role: "alert", ...rest, children: [
177
+ const resolvedLive = live ?? (tone === "danger" || tone === "warning" ? "assertive" : tone === "success" || tone === "info" ? "polite" : "off");
178
+ const liveProps = resolvedLive === "assertive" ? { role: "alert" } : resolvedLive === "polite" ? { role: "status" } : {};
179
+ return /* @__PURE__ */ jsxs("div", { className: `twc-alert ${className}`, "data-tone": tone, "data-variant": variant, ...liveProps, ...rest, children: [
140
180
  __twcStyles,
141
181
  /* @__PURE__ */ jsx("span", { className: "twc-alert__icon", "aria-hidden": "true", children: icon || /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
142
182
  /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
@@ -146,7 +186,7 @@ function Alert({
146
186
  title ? /* @__PURE__ */ jsx("div", { className: "twc-alert__title", children: title }) : null,
147
187
  children ? /* @__PURE__ */ jsx("div", { className: "twc-alert__desc", children }) : null
148
188
  ] }),
149
- onClose ? /* @__PURE__ */ jsx("button", { className: "twc-alert__close", onClick: onClose, "aria-label": "Dismiss", type: "button", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
189
+ onClose ? /* @__PURE__ */ jsx("button", { className: "twc-alert__close", onClick: onClose, "aria-label": closeLabel, type: "button", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
150
190
  ] });
151
191
  }
152
192
  var AVATAR_CSS = `
@@ -191,20 +231,25 @@ function safeSrc(url) {
191
231
  if (s.startsWith("data:") && !s.startsWith("data:image/")) return void 0;
192
232
  return url;
193
233
  }
234
+ var STATUS_LABELS = { online: "Online", busy: "Busy", away: "Away", offline: "Offline" };
194
235
  function Avatar({
195
236
  src,
196
237
  name,
197
238
  size = "md",
198
239
  square = false,
199
240
  status,
241
+ statusLabel,
242
+ statusLabels,
200
243
  ring = false,
201
244
  className = "",
202
245
  ...rest
203
246
  }) {
204
247
  const __twcStyles = useScopedStyles("twc-avatar-styles", AVATAR_CSS);
205
- const [errored, setErrored] = React23__default.useState(false);
248
+ const [errored, setErrored] = React24__default.useState(false);
206
249
  const cleanSrc = safeSrc(src);
207
250
  const showImg = cleanSrc && !errored;
251
+ const _statusLabel = status ? statusLabel ?? statusLabels?.[status] ?? STATUS_LABELS[status] : void 0;
252
+ const baseName = name || "avatar";
208
253
  return /* @__PURE__ */ jsxs(
209
254
  "span",
210
255
  {
@@ -212,12 +257,12 @@ function Avatar({
212
257
  "data-size": size,
213
258
  "data-square": square || void 0,
214
259
  role: "img",
215
- "aria-label": name || "avatar",
260
+ "aria-label": _statusLabel ? `${baseName}, ${_statusLabel}` : baseName,
216
261
  ...rest,
217
262
  children: [
218
263
  __twcStyles,
219
264
  showImg ? /* @__PURE__ */ jsx("img", { className: "twc-avatar__img", src: cleanSrc, alt: name || "", onError: () => setErrored(true) }, cleanSrc) : initials(name),
220
- status ? /* @__PURE__ */ jsx("span", { className: "twc-avatar__status", "data-status": status }) : null
265
+ status ? /* @__PURE__ */ jsx("span", { className: "twc-avatar__status", "data-status": status, title: _statusLabel }) : null
221
266
  ]
222
267
  }
223
268
  );
@@ -258,6 +303,11 @@ var MENU_CSS = `
258
303
  .twc-menu__item-label { flex: 1 1 auto; min-width: 0; }
259
304
  .twc-menu__shortcut { margin-inline-start: auto; padding-inline-start: var(--space-3); font-size: var(--text-xs); color: var(--color-text-subtle); font-family: var(--font-mono); }
260
305
  `;
306
+ var safeHref = (url) => {
307
+ if (url == null) return void 0;
308
+ const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
309
+ return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
310
+ };
261
311
  function Menu({
262
312
  trigger,
263
313
  items,
@@ -267,26 +317,29 @@ function Menu({
267
317
  open: openProp,
268
318
  defaultOpen = false,
269
319
  onOpenChange,
320
+ "aria-label": ariaLabel,
321
+ "aria-labelledby": ariaLabelledby,
270
322
  className = "",
271
323
  ...rest
272
324
  }) {
273
325
  const __twcStyles = useScopedStyles("twc-menu-styles", MENU_CSS);
274
- const [openState, setOpenState] = React23__default.useState(defaultOpen);
275
- const [render, setRender] = React23__default.useState(false);
276
- const [pos, setPos] = React23__default.useState(null);
277
- const [active, setActive] = React23__default.useState(-1);
278
- const wrapRef = React23__default.useRef(null);
279
- const menuRef = React23__default.useRef(null);
280
- const menuId = React23__default.useId();
326
+ const [openState, setOpenState] = React24__default.useState(defaultOpen);
327
+ const [render, setRender] = React24__default.useState(false);
328
+ const [pos, setPos] = React24__default.useState(null);
329
+ const [active, setActive] = React24__default.useState(-1);
330
+ const wrapRef = React24__default.useRef(null);
331
+ const menuRef = React24__default.useRef(null);
332
+ const menuId = React24__default.useId();
333
+ const headerId = `${menuId}-header`;
281
334
  const controlled = openProp !== void 0;
282
335
  const open = controlled ? !!openProp : openState;
283
- const openRef = React23__default.useRef(open);
336
+ const openRef = React24__default.useRef(open);
284
337
  openRef.current = open;
285
- const controlledRef = React23__default.useRef(controlled);
338
+ const controlledRef = React24__default.useRef(controlled);
286
339
  controlledRef.current = controlled;
287
- const onOpenChangeRef = React23__default.useRef(onOpenChange);
340
+ const onOpenChangeRef = React24__default.useRef(onOpenChange);
288
341
  onOpenChangeRef.current = onOpenChange;
289
- const setOpen = React23__default.useCallback((next) => {
342
+ const setOpen = React24__default.useCallback((next) => {
290
343
  const value = typeof next === "function" ? next(openRef.current) : next;
291
344
  if (value === openRef.current) return;
292
345
  if (!controlledRef.current) setOpenState(value);
@@ -294,7 +347,7 @@ function Menu({
294
347
  }, []);
295
348
  const RD = { createPortal: typeof createPortal === "function" ? createPortal : typeof window !== "undefined" && window.ReactDOM && window.ReactDOM.createPortal };
296
349
  const interactiveIdx = items.map((it, i) => !it.separator && !it.heading ? i : -1).filter((i) => i >= 0);
297
- const place = React23__default.useCallback(() => {
350
+ const place = React24__default.useCallback(() => {
298
351
  const t = wrapRef.current;
299
352
  if (!t) return;
300
353
  const r = t.getBoundingClientRect();
@@ -309,7 +362,7 @@ function Menu({
309
362
  const avail = (flip ? r.top : vh - r.bottom) - gap - M;
310
363
  setPos({ top, bottom, left, width: w, flip, maxHeight: Math.max(120, avail) });
311
364
  }, [align, width]);
312
- React23__default.useEffect(() => {
365
+ React24__default.useEffect(() => {
313
366
  if (!open) return;
314
367
  place();
315
368
  const onMove = () => place();
@@ -327,7 +380,7 @@ function Menu({
327
380
  document.removeEventListener("mousedown", onDown);
328
381
  };
329
382
  }, [open, place]);
330
- React23__default.useEffect(() => {
383
+ React24__default.useEffect(() => {
331
384
  if (open) {
332
385
  setRender(true);
333
386
  return;
@@ -373,8 +426,12 @@ function Menu({
373
426
  e.preventDefault();
374
427
  const it = items[active];
375
428
  if (it && !it.disabled) {
376
- it.onClick?.();
377
- setOpen(false);
429
+ const el = typeof document !== "undefined" ? document.getElementById(`${menuId}-item-${active}`) : null;
430
+ if (el && el.tagName === "A") el.click();
431
+ else {
432
+ it.onClick?.();
433
+ setOpen(false);
434
+ }
378
435
  }
379
436
  }
380
437
  }
@@ -388,29 +445,32 @@ function Menu({
388
445
  "data-align": align,
389
446
  "data-flip": pos.flip || void 0,
390
447
  role: "menu",
448
+ "aria-label": ariaLabel,
449
+ "aria-labelledby": ariaLabelledby ?? (ariaLabel ? void 0 : header ? headerId : void 0),
391
450
  style: { top: pos.top, bottom: pos.bottom, left: pos.left, minWidth: pos.width, width: pos.width, maxHeight: pos.maxHeight },
392
451
  children: [
393
452
  __twcStyles,
394
- header ? /* @__PURE__ */ jsx("div", { className: "twc-menu__header", children: header }) : null,
453
+ header ? /* @__PURE__ */ jsx("div", { className: "twc-menu__header", id: headerId, children: header }) : null,
395
454
  items.map((it, i) => {
396
455
  if (it.separator) return /* @__PURE__ */ jsx("div", { className: "twc-menu__sep", role: "separator" }, `s${i}`);
397
456
  if (it.label && it.heading) return /* @__PURE__ */ jsx("div", { className: "twc-menu__label", children: it.label }, `h${i}`);
457
+ const href = !it.disabled ? safeHref(it.href) : void 0;
458
+ const Tag2 = href ? "a" : "button";
398
459
  return /* @__PURE__ */ jsxs(
399
- "button",
460
+ Tag2,
400
461
  {
401
- type: "button",
402
462
  id: `${menuId}-item-${i}`,
403
463
  className: "twc-menu__item",
404
464
  role: "menuitem",
405
465
  tabIndex: -1,
406
466
  "data-danger": it.danger || void 0,
407
467
  "data-active": active === i || void 0,
408
- disabled: it.disabled,
409
468
  onMouseEnter: () => setActive(i),
410
469
  onClick: () => {
411
470
  it.onClick?.();
412
471
  setOpen(false);
413
472
  },
473
+ ...Tag2 === "button" ? { type: "button", disabled: it.disabled } : { href, target: it.target, rel: it.rel },
414
474
  children: [
415
475
  it.icon,
416
476
  /* @__PURE__ */ jsx("span", { className: "twc-menu__item-label", children: it.label }),
@@ -424,7 +484,7 @@ function Menu({
424
484
  }
425
485
  ) : null;
426
486
  const activeDescId = open && active >= 0 ? `${menuId}-item-${active}` : void 0;
427
- const triggerEl = React23__default.isValidElement(trigger) ? React23__default.cloneElement(trigger, {
487
+ const triggerEl = React24__default.isValidElement(trigger) ? React24__default.cloneElement(trigger, {
428
488
  onClick: (e) => {
429
489
  trigger.props.onClick?.(e);
430
490
  toggle();
@@ -507,7 +567,7 @@ function AvatarMenu({
507
567
  ]
508
568
  }
509
569
  );
510
- return /* @__PURE__ */ jsx(Menu, { className, trigger, items, header, align, width: 240, ...rest });
570
+ return /* @__PURE__ */ jsx(Menu, { className, trigger, items, header, align, width: 240, "aria-label": `${name || "Account"} menu`, ...rest });
511
571
  }
512
572
  var BADGE_CSS = `
513
573
  .twc-badge {
@@ -574,7 +634,7 @@ var BREADCRUMB_CSS = `
574
634
  .twc-breadcrumb__ellipsis { border: none; background: transparent; cursor: pointer; color: var(--color-text-subtle); padding: 3px 7px; border-radius: var(--radius-sm); font: inherit; }
575
635
  .twc-breadcrumb__ellipsis:hover { background: var(--color-surface-sunken); color: var(--color-text); }
576
636
  `;
577
- function safeHref(url) {
637
+ function safeHref2(url) {
578
638
  if (url == null) return void 0;
579
639
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
580
640
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -588,7 +648,7 @@ function Breadcrumb({
588
648
  ...rest
589
649
  }) {
590
650
  const __twcStyles = useScopedStyles("twc-breadcrumb-styles", BREADCRUMB_CSS);
591
- const [expanded, setExpanded] = React23__default.useState(false);
651
+ const [expanded, setExpanded] = React24__default.useState(false);
592
652
  const sep = separator || /* @__PURE__ */ jsx(ChevronSep, {});
593
653
  let display = items;
594
654
  if (maxItems > 0 && items.length > maxItems && !expanded) {
@@ -601,7 +661,7 @@ function Breadcrumb({
601
661
  __twcStyles,
602
662
  display.map((it, i) => {
603
663
  const last = i === display.length - 1;
604
- return /* @__PURE__ */ jsxs(React23__default.Fragment, { children: [
664
+ return /* @__PURE__ */ jsxs(React24__default.Fragment, { children: [
605
665
  it.ellipsis ? /* @__PURE__ */ jsx("button", { className: "twc-breadcrumb__ellipsis", "aria-label": "Show more", onClick: () => setExpanded(true), children: "\u2026" }) : last ? /* @__PURE__ */ jsxs(
606
666
  "span",
607
667
  {
@@ -617,7 +677,7 @@ function Breadcrumb({
617
677
  "a",
618
678
  {
619
679
  className: "twc-breadcrumb__item",
620
- href: safeHref(it.href) || "#",
680
+ href: safeHref2(it.href) || "#",
621
681
  onClick: it.onClick,
622
682
  children: [
623
683
  it.icon ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { display: "inline-flex" }, children: it.icon }) : null,
@@ -720,7 +780,7 @@ var CSS2 = `
720
780
  animation: twico-ripple var(--duration-slow) var(--ease-out) forwards;
721
781
  }
722
782
  `;
723
- function safeHref2(url) {
783
+ function safeHref3(url) {
724
784
  if (url == null) return void 0;
725
785
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
726
786
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -742,7 +802,7 @@ function Button({
742
802
  ...rest
743
803
  }) {
744
804
  const __twcStyles = useScopedStyles("twc-btn-styles", CSS2);
745
- const [ripples, setRipples] = React23__default.useState([]);
805
+ const [ripples, setRipples] = React24__default.useState([]);
746
806
  const Tag2 = as;
747
807
  const inert = Tag2 === "a" && (disabled || loading);
748
808
  function handleClick(e) {
@@ -771,7 +831,7 @@ function Button({
771
831
  "data-block": fullWidth || void 0,
772
832
  disabled: Tag2 === "button" ? disabled || loading : void 0,
773
833
  type: Tag2 === "button" ? "button" : void 0,
774
- href: inert ? void 0 : safeHref2(href),
834
+ href: inert ? void 0 : safeHref3(href),
775
835
  "aria-disabled": inert || void 0,
776
836
  tabIndex: inert ? -1 : void 0,
777
837
  "aria-busy": loading || void 0,
@@ -879,6 +939,15 @@ var CAROUSEL_CSS = `
879
939
  .twc-carousel__dot { width: 8px; height: 8px; border-radius: var(--radius-full); border: none; padding: 0; cursor: pointer;
880
940
  background: var(--color-border-strong); transition: width var(--duration-base) var(--ease-spring), background-color var(--duration-fast); }
881
941
  .twc-carousel__dot[data-active="true"] { width: 22px; background: var(--color-primary); }
942
+ .twc-carousel__pause { position: absolute; top: 12px; inset-inline-end: 12px; z-index: 2;
943
+ display: grid; place-items: center; width: 34px; height: 34px; border-radius: var(--radius-full);
944
+ background: color-mix(in srgb, var(--color-surface) 88%, transparent); color: var(--color-text);
945
+ border: var(--border-thin) solid var(--color-border); box-shadow: var(--shadow-sm); cursor: pointer;
946
+ backdrop-filter: blur(6px); transition: background-color var(--duration-fast) var(--ease-standard); }
947
+ .twc-carousel__pause:hover { background: var(--color-surface); }
948
+ .twc-carousel__pause svg { width: 15px; height: 15px; display: block; }
949
+ .twc-carousel__live { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
950
+ overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
882
951
  `;
883
952
  function Carousel({
884
953
  children,
@@ -887,35 +956,76 @@ function Carousel({
887
956
  onIndexChange,
888
957
  showArrows = true,
889
958
  showDots = true,
959
+ showPauseButton = true,
890
960
  loop = true,
891
961
  autoPlay = false,
892
962
  interval = 4e3,
963
+ label,
964
+ pauseLabel = "Pause",
965
+ playLabel = "Play",
893
966
  className = "",
967
+ onKeyDown: onKeyDownProp,
968
+ "aria-label": ariaLabelProp,
969
+ "aria-labelledby": ariaLabelledbyProp,
894
970
  ...rest
895
971
  }) {
896
972
  const __twcStyles = useScopedStyles("twc-carousel-styles", CAROUSEL_CSS);
897
- const slides = React23__default.Children.toArray(children);
973
+ const slides = React24__default.Children.toArray(children);
898
974
  const count = slides.length;
899
- const [internal, setInternal] = React23__default.useState(defaultIndex);
975
+ const [internal, setInternal] = React24__default.useState(defaultIndex);
900
976
  const index = indexProp !== void 0 ? indexProp : internal;
901
- const [paused, setPaused] = React23__default.useState(false);
902
- const setIndex = React23__default.useCallback((i) => {
977
+ const [paused, setPaused] = React24__default.useState(false);
978
+ const [userPaused, setUserPaused] = React24__default.useState(false);
979
+ const [prefersReduced, setPrefersReduced] = React24__default.useState(false);
980
+ React24__default.useEffect(() => {
981
+ if (typeof window === "undefined" || !window.matchMedia) return void 0;
982
+ const mql = window.matchMedia("(prefers-reduced-motion: reduce)");
983
+ const on = () => setPrefersReduced(mql.matches);
984
+ on();
985
+ mql.addEventListener("change", on);
986
+ return () => mql.removeEventListener("change", on);
987
+ }, []);
988
+ const setIndex = React24__default.useCallback((i) => {
903
989
  if (indexProp === void 0) setInternal(i);
904
990
  onIndexChange?.(i);
905
991
  }, [indexProp, onIndexChange]);
906
- const go = React23__default.useCallback((i) => {
992
+ const go = React24__default.useCallback((i) => {
907
993
  setIndex(loop ? (i + count) % count : Math.min(Math.max(i, 0), count - 1));
908
994
  }, [count, loop, setIndex]);
909
- React23__default.useEffect(() => {
910
- if (!autoPlay || paused || count <= 1) return;
995
+ const autoRotating = autoPlay && !paused && !userPaused && !prefersReduced && count > 1;
996
+ React24__default.useEffect(() => {
997
+ if (!autoRotating) return void 0;
911
998
  const t = setInterval(() => {
912
999
  const next = loop ? (index + 1) % count : index + 1 >= count ? index : index + 1;
913
1000
  if (next !== index) setIndex(next);
914
1001
  }, interval);
915
1002
  return () => clearInterval(t);
916
- }, [autoPlay, paused, count, interval, loop, index, setIndex]);
1003
+ }, [autoRotating, count, interval, loop, index, setIndex]);
917
1004
  const atStart = !loop && index === 0;
918
1005
  const atEnd = !loop && index === count - 1;
1006
+ const handleKeyDown = (e) => {
1007
+ onKeyDownProp?.(e);
1008
+ if (e.defaultPrevented) return;
1009
+ if (e.target.closest && e.target.closest('input, textarea, select, [contenteditable="true"]')) return;
1010
+ switch (e.key) {
1011
+ case "ArrowLeft":
1012
+ go(index - 1);
1013
+ break;
1014
+ case "ArrowRight":
1015
+ go(index + 1);
1016
+ break;
1017
+ case "Home":
1018
+ go(0);
1019
+ break;
1020
+ case "End":
1021
+ go(count - 1);
1022
+ break;
1023
+ default:
1024
+ return;
1025
+ }
1026
+ e.preventDefault();
1027
+ };
1028
+ const ariaLabel = ariaLabelledbyProp ? void 0 : ariaLabelProp ?? label ?? "Carousel";
919
1029
  return /* @__PURE__ */ jsxs(
920
1030
  "div",
921
1031
  {
@@ -924,12 +1034,17 @@ function Carousel({
924
1034
  onMouseLeave: () => setPaused(false),
925
1035
  onFocusCapture: () => setPaused(true),
926
1036
  onBlurCapture: () => setPaused(false),
1037
+ onKeyDown: handleKeyDown,
927
1038
  role: "region",
928
1039
  "aria-roledescription": "carousel",
1040
+ "aria-label": ariaLabel,
1041
+ "aria-labelledby": ariaLabelledbyProp,
929
1042
  ...rest,
930
1043
  children: [
931
1044
  __twcStyles,
932
- /* @__PURE__ */ jsx("div", { className: "twc-carousel__viewport", children: /* @__PURE__ */ jsx("div", { className: "twc-carousel__track", style: { transform: `translateX(-${index * 100}%)` }, children: slides.map((s, i) => /* @__PURE__ */ jsx("div", { className: "twc-carousel__slide", role: "group", "aria-roledescription": "slide", "aria-label": `${i + 1} of ${count}`, "aria-hidden": i !== index || void 0, inert: i !== index || void 0, children: s }, i)) }) }),
1045
+ /* @__PURE__ */ jsx("div", { className: "twc-carousel__viewport", tabIndex: 0, children: /* @__PURE__ */ jsx("div", { className: "twc-carousel__track", style: { transform: `translateX(-${index * 100}%)` }, children: slides.map((s, i) => /* @__PURE__ */ jsx("div", { className: "twc-carousel__slide", role: "group", "aria-roledescription": "slide", "aria-label": `${i + 1} of ${count}`, "aria-hidden": i !== index || void 0, inert: i !== index || void 0, children: s }, i)) }) }),
1046
+ /* @__PURE__ */ jsx("div", { className: "twc-carousel__live", "aria-live": autoRotating ? "off" : "polite", "aria-atomic": "true", children: count > 1 ? `Slide ${index + 1} of ${count}` : null }),
1047
+ autoPlay && showPauseButton && count > 1 ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-carousel__pause", "aria-label": userPaused ? playLabel : pauseLabel, onClick: () => setUserPaused((v) => !v), children: userPaused ? /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" }) }) : /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M6 5h4v14H6zM14 5h4v14h-4z" }) }) }) : null,
933
1048
  showArrows && count > 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [
934
1049
  /* @__PURE__ */ jsx("button", { className: "twc-carousel__arrow", "data-dir": "prev", "aria-label": "Previous", disabled: atStart, onClick: () => go(index - 1), children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m15 18-6-6 6-6" }) }) }),
935
1050
  /* @__PURE__ */ jsx("button", { className: "twc-carousel__arrow", "data-dir": "next", "aria-label": "Next", disabled: atEnd, onClick: () => go(index + 1), children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" }) }) })
@@ -952,6 +1067,7 @@ var CHART_CSS = `
952
1067
  .twc-chart__leg { display: inline-flex; align-items: center; gap: 6px; }
953
1068
  .twc-chart__leg-sw { width: 10px; height: 10px; border-radius: 3px; }
954
1069
  @keyframes twc-chart-grow { from { transform: scaleY(0); } to { transform: scaleY(1); } }
1070
+ .twc-chart__sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
955
1071
  `;
956
1072
  var SERIES_COLORS = ["var(--brand-500)", "var(--sky-500)", "var(--emerald-500)", "var(--amber-500)", "var(--rose-500)"];
957
1073
  function Chart({
@@ -966,10 +1082,14 @@ function Chart({
966
1082
  valueFormat,
967
1083
  ariaLabel,
968
1084
  "aria-label": ariaLabelProp,
1085
+ tableFallback = true,
1086
+ caption,
969
1087
  className = "",
970
1088
  ...rest
971
1089
  }) {
972
1090
  const __twcStyles = useScopedStyles("twc-chart-styles", CHART_CSS);
1091
+ const uid = React24__default.useId();
1092
+ const tableId = tableFallback ? `${uid}-table` : void 0;
973
1093
  const keys = series || ["value"];
974
1094
  const palette = colors && colors.length ? colors : SERIES_COLORS;
975
1095
  const W = 600, H = height, padL = showAxis ? 40 : 8, padR = 8, padT = 12, padB = showAxis ? 26 : 8;
@@ -982,7 +1102,7 @@ function Chart({
982
1102
  const svgAriaLabel = ariaLabelProp ?? ariaLabel ?? `${type} chart`;
983
1103
  return /* @__PURE__ */ jsxs("div", { className: `twc-chart ${className}`, ...rest, children: [
984
1104
  __twcStyles,
985
- /* @__PURE__ */ jsxs("svg", { viewBox: `0 0 ${W} ${H}`, role: "img", "aria-label": svgAriaLabel, preserveAspectRatio: "none", children: [
1105
+ /* @__PURE__ */ jsxs("svg", { viewBox: `0 0 ${W} ${H}`, role: "img", "aria-label": svgAriaLabel, "aria-describedby": tableId, preserveAspectRatio: "none", children: [
986
1106
  showGrid ? Array.from({ length: ticks + 1 }).map((_, i) => {
987
1107
  const gy = padT + innerH / ticks * i;
988
1108
  return /* @__PURE__ */ jsx("line", { className: "twc-chart__grid", x1: padL, y1: gy, x2: W - padR, y2: gy }, i);
@@ -1032,6 +1152,17 @@ function Chart({
1032
1152
  return /* @__PURE__ */ jsx("text", { className: "twc-chart__axis", x: cx, y: H - 8, textAnchor: "middle", children: d.label }, i);
1033
1153
  }) : null
1034
1154
  ] }),
1155
+ tableFallback ? /* @__PURE__ */ jsxs("table", { className: "twc-chart__sr", id: tableId, children: [
1156
+ /* @__PURE__ */ jsx("caption", { children: caption ?? svgAriaLabel }),
1157
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
1158
+ /* @__PURE__ */ jsx("th", { scope: "col" }),
1159
+ keys.map((k) => /* @__PURE__ */ jsx("th", { scope: "col", children: k }, k))
1160
+ ] }) }),
1161
+ /* @__PURE__ */ jsx("tbody", { children: data.map((d, i) => /* @__PURE__ */ jsxs("tr", { children: [
1162
+ /* @__PURE__ */ jsx("th", { scope: "row", children: d.label }),
1163
+ keys.map((k) => /* @__PURE__ */ jsx("td", { children: fmt(Number(d[k]) || 0) }, k))
1164
+ ] }, i)) })
1165
+ ] }) : null,
1035
1166
  showLegend && keys.length > 1 ? /* @__PURE__ */ jsx("div", { className: "twc-chart__legend", children: keys.map((k, si) => /* @__PURE__ */ jsxs("span", { className: "twc-chart__leg", children: [
1036
1167
  /* @__PURE__ */ jsx("span", { className: "twc-chart__leg-sw", style: { background: palette[si % palette.length] } }),
1037
1168
  k
@@ -1104,12 +1235,12 @@ function Checkbox({
1104
1235
  .twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
1105
1236
  .twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
1106
1237
  `);
1107
- const autoId = React23__default.useId();
1238
+ const autoId = React24__default.useId();
1108
1239
  const fieldId = id || autoId;
1109
1240
  const errId = `${fieldId}-error`;
1110
1241
  const invalid = Boolean(error);
1111
- const ref = React23__default.useRef(null);
1112
- React23__default.useEffect(() => {
1242
+ const ref = React24__default.useRef(null);
1243
+ React24__default.useEffect(() => {
1113
1244
  if (ref.current) ref.current.indeterminate = indeterminate;
1114
1245
  }, [indeterminate]);
1115
1246
  const describedBy = [rest["aria-describedby"], error ? errId : null].filter(Boolean).join(" ") || void 0;
@@ -1246,20 +1377,20 @@ function ColorPicker({
1246
1377
  }) {
1247
1378
  const __twcStyles0 = useScopedStyles("twc-field-styles", FIELD_CSS);
1248
1379
  const __twcStyles1 = useScopedStyles("twc-colorpicker-styles", COLORPICKER_CSS);
1249
- const [internal, setInternal] = React23__default.useState(defaultValue);
1380
+ const [internal, setInternal] = React24__default.useState(defaultValue);
1250
1381
  const hex = (value !== void 0 ? value : internal) || "#000000";
1251
- const lastValidRef = React23__default.useRef(hex);
1382
+ const lastValidRef = React24__default.useRef(hex);
1252
1383
  if (/^#[0-9a-f]{6}$/i.test(hex)) lastValidRef.current = hex;
1253
- const [open, setOpen] = React23__default.useState(false);
1254
- const [hsv, setHsv] = React23__default.useState(() => hexToHsv(hex) || { h: 239, s: 60, v: 94 });
1255
- const [coords, setCoords] = React23__default.useState(null);
1256
- const wrapRef = React23__default.useRef(null);
1257
- const triggerRef = React23__default.useRef(null);
1258
- const popRef = React23__default.useRef(null);
1259
- const areaRef = React23__default.useRef(null);
1260
- const hueRef = React23__default.useRef(null);
1384
+ const [open, setOpen] = React24__default.useState(false);
1385
+ const [hsv, setHsv] = React24__default.useState(() => hexToHsv(hex) || { h: 239, s: 60, v: 94 });
1386
+ const [coords, setCoords] = React24__default.useState(null);
1387
+ const wrapRef = React24__default.useRef(null);
1388
+ const triggerRef = React24__default.useRef(null);
1389
+ const popRef = React24__default.useRef(null);
1390
+ const areaRef = React24__default.useRef(null);
1391
+ const hueRef = React24__default.useRef(null);
1261
1392
  const POP_W = 240;
1262
- const place = React23__default.useCallback(() => {
1393
+ const place = React24__default.useCallback(() => {
1263
1394
  const el = triggerRef.current;
1264
1395
  if (!el) return;
1265
1396
  const r = el.getBoundingClientRect();
@@ -1270,7 +1401,7 @@ function ColorPicker({
1270
1401
  left = Math.max(8, left);
1271
1402
  setCoords({ left, top: flip ? void 0 : Math.round(r.bottom + 6), bottom: flip ? Math.round(vh - r.top + 6) : void 0 });
1272
1403
  }, []);
1273
- React23__default.useEffect(() => {
1404
+ React24__default.useEffect(() => {
1274
1405
  if (!open) return void 0;
1275
1406
  place();
1276
1407
  const onMove = () => place();
@@ -1281,17 +1412,17 @@ function ColorPicker({
1281
1412
  window.removeEventListener("resize", onMove);
1282
1413
  };
1283
1414
  }, [open, place]);
1284
- const labelId = React23__default.useId();
1415
+ const labelId = React24__default.useId();
1285
1416
  const descId = `${labelId}-desc`;
1286
1417
  const invalid = Boolean(error);
1287
- React23__default.useEffect(() => {
1418
+ React24__default.useEffect(() => {
1288
1419
  if (disabled) setOpen(false);
1289
1420
  }, [disabled]);
1290
- React23__default.useEffect(() => {
1421
+ React24__default.useEffect(() => {
1291
1422
  const v = hexToHsv(hex);
1292
1423
  if (v && hsvToHex(v.h, v.s, v.v).toLowerCase() !== hsvToHex(hsv.h, hsv.s, hsv.v).toLowerCase()) setHsv(v);
1293
1424
  }, [hex]);
1294
- React23__default.useEffect(() => {
1425
+ React24__default.useEffect(() => {
1295
1426
  if (!open) return;
1296
1427
  const onDown = (e) => {
1297
1428
  if (wrapRef.current && wrapRef.current.contains(e.target)) return;
@@ -1308,8 +1439,8 @@ function ColorPicker({
1308
1439
  document.removeEventListener("keydown", onKey);
1309
1440
  };
1310
1441
  }, [open]);
1311
- const prevOpen = React23__default.useRef(false);
1312
- React23__default.useEffect(() => {
1442
+ const prevOpen = React24__default.useRef(false);
1443
+ React24__default.useEffect(() => {
1313
1444
  let id;
1314
1445
  if (!prevOpen.current && open) {
1315
1446
  id = setTimeout(() => areaRef.current?.focus({ preventScroll: true }), 20);
@@ -1629,29 +1760,29 @@ function Combobox({
1629
1760
  ...rest
1630
1761
  }) {
1631
1762
  const __twcStyles = useScopedStyles("twc-combo-styles", COMBO_CSS);
1632
- const groups = React23__default.useMemo(() => normalizeGroups(options), [options]);
1633
- const flat = React23__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
1634
- const autoId = React23__default.useId();
1763
+ const groups = React24__default.useMemo(() => normalizeGroups(options), [options]);
1764
+ const flat = React24__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
1765
+ const autoId = React24__default.useId();
1635
1766
  const fieldId = id || autoId;
1636
- const [internal, setInternal] = React23__default.useState(defaultValue);
1767
+ const [internal, setInternal] = React24__default.useState(defaultValue);
1637
1768
  const current = value !== void 0 ? value : internal;
1638
1769
  const selected = flat.find((o) => o.value === current);
1639
- const [open, setOpen] = React23__default.useState(false);
1640
- const [query, setQuery] = React23__default.useState("");
1641
- const [active, setActive] = React23__default.useState(0);
1642
- const [coords, setCoords] = React23__default.useState(null);
1643
- const wrapRef = React23__default.useRef(null);
1644
- const controlRef = React23__default.useRef(null);
1645
- const inputRef = React23__default.useRef(null);
1646
- const popRef = React23__default.useRef(null);
1647
- const listRef = React23__default.useRef(null);
1648
- const activeRef = React23__default.useRef(null);
1649
- const fGroups = React23__default.useMemo(
1770
+ const [open, setOpen] = React24__default.useState(false);
1771
+ const [query, setQuery] = React24__default.useState("");
1772
+ const [active, setActive] = React24__default.useState(0);
1773
+ const [coords, setCoords] = React24__default.useState(null);
1774
+ const wrapRef = React24__default.useRef(null);
1775
+ const controlRef = React24__default.useRef(null);
1776
+ const inputRef = React24__default.useRef(null);
1777
+ const popRef = React24__default.useRef(null);
1778
+ const listRef = React24__default.useRef(null);
1779
+ const activeRef = React24__default.useRef(null);
1780
+ const fGroups = React24__default.useMemo(
1650
1781
  () => groups.map((g) => ({ group: g.group, options: g.options.filter((o) => matches(o, query.trim())) })).filter((g) => g.options.length),
1651
1782
  [groups, query]
1652
1783
  );
1653
- const visible = React23__default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
1654
- const place = React23__default.useCallback(() => {
1784
+ const visible = React24__default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
1785
+ const place = React24__default.useCallback(() => {
1655
1786
  const el = controlRef.current;
1656
1787
  if (!el) return;
1657
1788
  const r = el.getBoundingClientRect();
@@ -1666,7 +1797,7 @@ function Combobox({
1666
1797
  flip
1667
1798
  });
1668
1799
  }, [placement, minWidth]);
1669
- React23__default.useEffect(() => {
1800
+ React24__default.useEffect(() => {
1670
1801
  if (!open || !portal) return;
1671
1802
  place();
1672
1803
  const onMove = () => place();
@@ -1677,7 +1808,7 @@ function Combobox({
1677
1808
  window.removeEventListener("resize", onMove);
1678
1809
  };
1679
1810
  }, [open, portal, place]);
1680
- React23__default.useEffect(() => {
1811
+ React24__default.useEffect(() => {
1681
1812
  if (!open) return;
1682
1813
  const onDown = (e) => {
1683
1814
  if (wrapRef.current && wrapRef.current.contains(e.target)) return;
@@ -1687,10 +1818,10 @@ function Combobox({
1687
1818
  document.addEventListener("mousedown", onDown);
1688
1819
  return () => document.removeEventListener("mousedown", onDown);
1689
1820
  }, [open]);
1690
- React23__default.useEffect(() => {
1821
+ React24__default.useEffect(() => {
1691
1822
  setActive(0);
1692
1823
  }, [query]);
1693
- React23__default.useEffect(() => {
1824
+ React24__default.useEffect(() => {
1694
1825
  if (open) ensureVisible(listRef.current, activeRef.current);
1695
1826
  }, [active, open]);
1696
1827
  function openMenu() {
@@ -1733,7 +1864,7 @@ function Combobox({
1733
1864
  const descId = `${fieldId}-desc`;
1734
1865
  const describedBy = error || hint ? descId : void 0;
1735
1866
  let counter = -1;
1736
- const popInner = /* @__PURE__ */ jsx("div", { className: "twc-pop__list", ref: listRef, children: visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: "No results found" }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React23__default.Fragment, { children: [
1867
+ const popInner = /* @__PURE__ */ jsx("div", { className: "twc-pop__list", ref: listRef, children: visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: "No results found" }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React24__default.Fragment, { children: [
1737
1868
  g.group ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: g.group }) : null,
1738
1869
  g.options.map((o) => {
1739
1870
  counter += 1;
@@ -1871,6 +2002,52 @@ function Combobox({
1871
2002
  error ? /* @__PURE__ */ jsx("span", { id: descId, className: "twc-field__error", children: error }) : hint ? /* @__PURE__ */ jsx("span", { id: descId, className: "twc-field__hint", children: hint }) : null
1872
2003
  ] });
1873
2004
  }
2005
+ var canUseDOM = typeof window !== "undefined" && typeof document !== "undefined";
2006
+ var FOCUSABLE = 'a[href]:not([tabindex="-1"]), button:not([disabled]):not([tabindex="-1"]), textarea:not([disabled]):not([tabindex="-1"]), input:not([disabled]):not([tabindex="-1"]), select:not([disabled]):not([tabindex="-1"]), [tabindex]:not([tabindex="-1"])';
2007
+ function useFocusTrap(ref, active = true, { restoreFocus = true } = {}) {
2008
+ React24__default.useEffect(() => {
2009
+ if (!active || !canUseDOM) return void 0;
2010
+ const node = ref.current;
2011
+ if (!node) return void 0;
2012
+ const prevFocused = document.activeElement;
2013
+ const first = node.querySelector(FOCUSABLE);
2014
+ (first || node).focus();
2015
+ return () => {
2016
+ if (restoreFocus && prevFocused && typeof prevFocused.focus === "function") prevFocused.focus();
2017
+ };
2018
+ }, [active]);
2019
+ React24__default.useEffect(() => {
2020
+ if (!active || !canUseDOM) return void 0;
2021
+ const node = ref.current;
2022
+ const onKey = (e) => {
2023
+ if (e.key !== "Tab" || !node) return;
2024
+ const f = Array.from(node.querySelectorAll(FOCUSABLE)).filter((el) => el.offsetParent !== null);
2025
+ if (!f.length) {
2026
+ e.preventDefault();
2027
+ node.focus();
2028
+ return;
2029
+ }
2030
+ const first = f[0], last = f[f.length - 1], ae = document.activeElement;
2031
+ if (e.shiftKey) {
2032
+ if (ae === first || ae === node || !node.contains(ae)) {
2033
+ e.preventDefault();
2034
+ last.focus();
2035
+ }
2036
+ } else if (ae === last || !node.contains(ae)) {
2037
+ e.preventDefault();
2038
+ first.focus();
2039
+ }
2040
+ };
2041
+ document.addEventListener("keydown", onKey);
2042
+ return () => document.removeEventListener("keydown", onKey);
2043
+ }, [active]);
2044
+ }
2045
+ function usePortal() {
2046
+ return React24__default.useCallback((node) => {
2047
+ if (typeof document === "undefined") return null;
2048
+ return typeof createPortal === "function" ? createPortal(node, document.body) : node;
2049
+ }, []);
2050
+ }
1874
2051
  var COMMAND_CSS = `
1875
2052
  .twc-cmdk__overlay { position: fixed; inset: 0; z-index: var(--z-modal); background: var(--color-overlay); backdrop-filter: blur(3px);
1876
2053
  display: flex; align-items: flex-start; justify-content: center; padding-top: 12vh; }
@@ -1916,14 +2093,15 @@ function CommandPalette({
1916
2093
  ...rest
1917
2094
  }) {
1918
2095
  const __twcStyles = useScopedStyles("twc-cmdk-styles", COMMAND_CSS);
1919
- const [query, setQuery] = React23__default.useState("");
1920
- const [active, setActive] = React23__default.useState(0);
1921
- const inputRef = React23__default.useRef(null);
1922
- const listRef = React23__default.useRef(null);
1923
- const paletteRef = React23__default.useRef(null);
1924
- const baseId = React23__default.useId();
1925
- const [mounted, setMounted] = React23__default.useState(open);
1926
- React23__default.useEffect(() => {
2096
+ const renderPortal = usePortal();
2097
+ const [query, setQuery] = React24__default.useState("");
2098
+ const [active, setActive] = React24__default.useState(0);
2099
+ const inputRef = React24__default.useRef(null);
2100
+ const listRef = React24__default.useRef(null);
2101
+ const paletteRef = React24__default.useRef(null);
2102
+ const baseId = React24__default.useId();
2103
+ const [mounted, setMounted] = React24__default.useState(open);
2104
+ React24__default.useEffect(() => {
1927
2105
  if (open) {
1928
2106
  setMounted(true);
1929
2107
  return;
@@ -1931,7 +2109,7 @@ function CommandPalette({
1931
2109
  const t = setTimeout(() => setMounted(false), 170);
1932
2110
  return () => clearTimeout(t);
1933
2111
  }, [open]);
1934
- React23__default.useEffect(() => {
2112
+ React24__default.useEffect(() => {
1935
2113
  if (!open) return void 0;
1936
2114
  const prev = document.body.style.overflow;
1937
2115
  document.body.style.overflow = "hidden";
@@ -1939,58 +2117,26 @@ function CommandPalette({
1939
2117
  document.body.style.overflow = prev;
1940
2118
  };
1941
2119
  }, [open]);
1942
- React23__default.useEffect(() => {
2120
+ React24__default.useEffect(() => {
1943
2121
  if (open) {
1944
2122
  setQuery("");
1945
2123
  setActive(0);
1946
- const t = setTimeout(() => inputRef.current?.focus(), 30);
1947
- return () => clearTimeout(t);
1948
2124
  }
1949
2125
  }, [open]);
1950
- React23__default.useEffect(() => {
1951
- if (!open) return;
1952
- const prevFocused = document.activeElement;
1953
- return () => {
1954
- if (prevFocused && typeof prevFocused.focus === "function") prevFocused.focus();
1955
- };
1956
- }, [open]);
1957
- React23__default.useEffect(() => {
1958
- if (!open) return;
1959
- const focusables = (node) => node ? Array.from(
1960
- node.querySelectorAll(
1961
- 'a[href]:not([tabindex="-1"]), button:not([disabled]):not([tabindex="-1"]), textarea:not([disabled]):not([tabindex="-1"]), input:not([disabled]):not([tabindex="-1"]), select:not([disabled]):not([tabindex="-1"]), [tabindex]:not([tabindex="-1"])'
1962
- )
1963
- ).filter((el) => el.offsetParent !== null) : [];
2126
+ useFocusTrap(paletteRef, open && mounted);
2127
+ React24__default.useEffect(() => {
2128
+ if (!open) return void 0;
1964
2129
  const onKey = (e) => {
1965
2130
  if (e.key === "Escape") {
1966
2131
  e.preventDefault();
1967
2132
  onClose?.();
1968
- return;
1969
- }
1970
- if (e.key !== "Tab") return;
1971
- const node = paletteRef.current;
1972
- const f = focusables(node);
1973
- if (!f.length) {
1974
- e.preventDefault();
1975
- node?.focus();
1976
- return;
1977
- }
1978
- const first = f[0], last = f[f.length - 1], ae = document.activeElement;
1979
- if (e.shiftKey) {
1980
- if (ae === first || ae === node || !node.contains(ae)) {
1981
- e.preventDefault();
1982
- last.focus();
1983
- }
1984
- } else if (ae === last || !node.contains(ae)) {
1985
- e.preventDefault();
1986
- first.focus();
1987
2133
  }
1988
2134
  };
1989
2135
  document.addEventListener("keydown", onKey);
1990
2136
  return () => document.removeEventListener("keydown", onKey);
1991
2137
  }, [open, onClose]);
1992
2138
  const q = query.trim().toLowerCase();
1993
- const filtered = React23__default.useMemo(() => commands.filter(
2139
+ const filtered = React24__default.useMemo(() => commands.filter(
1994
2140
  (c) => !q || c.label.toLowerCase().includes(q) || (c.keywords || "").toLowerCase().includes(q) || (c.group || "").toLowerCase().includes(q)
1995
2141
  ), [commands, q]);
1996
2142
  const groups = [];
@@ -2005,7 +2151,7 @@ function CommandPalette({
2005
2151
  g.items.push(c);
2006
2152
  flat.push(c);
2007
2153
  });
2008
- React23__default.useEffect(() => {
2154
+ React24__default.useEffect(() => {
2009
2155
  setActive(0);
2010
2156
  }, [query]);
2011
2157
  const run = (cmd) => {
@@ -2025,11 +2171,11 @@ function CommandPalette({
2025
2171
  if (cmd) run(cmd);
2026
2172
  }
2027
2173
  }
2028
- React23__default.useEffect(() => {
2174
+ React24__default.useEffect(() => {
2029
2175
  const node = listRef.current?.querySelector('[data-active="true"]');
2030
2176
  if (node) node.scrollIntoView({ block: "nearest" });
2031
2177
  }, [active]);
2032
- if (!mounted || typeof document === "undefined") return null;
2178
+ if (!mounted) return null;
2033
2179
  const state = open ? "open" : "closed";
2034
2180
  const listId = `${baseId}-list`;
2035
2181
  const optionId = (i) => `${baseId}-opt-${i}`;
@@ -2095,8 +2241,7 @@ function CommandPalette({
2095
2241
  ] }, g.key || "_")) })
2096
2242
  ] })
2097
2243
  ] });
2098
- const RD = typeof createPortal === "function" ? createPortal : null;
2099
- return RD ? RD(overlay, document.body) : overlay;
2244
+ return renderPortal(overlay);
2100
2245
  }
2101
2246
  var CURRENCIES = {
2102
2247
  USD: { code: "USD", symbol: "$", precision: 2, label: "US Dollar" },
@@ -2199,11 +2344,11 @@ function Currency({
2199
2344
  const prec = precision != null ? precision : meta.precision;
2200
2345
  const sym = symbol != null ? symbol : meta.symbol;
2201
2346
  const cur = code != null ? code : meta.code;
2202
- const autoId = React23__default.useId();
2347
+ const autoId = React24__default.useId();
2203
2348
  const fieldId = id || autoId;
2204
2349
  const invalid = Boolean(error);
2205
2350
  const controlled = value !== void 0;
2206
- const [internal, setInternal] = React23__default.useState(() => clampPrecision(String(defaultValue ?? ""), prec));
2351
+ const [internal, setInternal] = React24__default.useState(() => clampPrecision(String(defaultValue ?? ""), prec));
2207
2352
  const shown = controlled ? clampPrecision(String(value ?? ""), prec) : internal;
2208
2353
  const describedBy = [error ? `${fieldId}-error` : hint ? `${fieldId}-hint` : null, rest["aria-describedby"]].filter(Boolean).join(" ") || void 0;
2209
2354
  function handleChange(e) {
@@ -2377,32 +2522,32 @@ function Select({
2377
2522
  ...rest
2378
2523
  }) {
2379
2524
  const __twcStyles = useScopedStyles("twc-select-styles", SELECT_CSS);
2380
- const groups = React23__default.useMemo(() => normalizeGroups2(options), [options]);
2381
- const flat = React23__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
2382
- const autoId = React23__default.useId();
2525
+ const groups = React24__default.useMemo(() => normalizeGroups2(options), [options]);
2526
+ const flat = React24__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
2527
+ const autoId = React24__default.useId();
2383
2528
  const fieldId = id || autoId;
2384
- const [internal, setInternal] = React23__default.useState(defaultValue);
2529
+ const [internal, setInternal] = React24__default.useState(defaultValue);
2385
2530
  const current = value !== void 0 ? value : internal;
2386
- const [open, setOpen] = React23__default.useState(false);
2387
- const [render, setRender] = React23__default.useState(false);
2388
- const [active, setActive] = React23__default.useState(0);
2389
- const [coords, setCoords] = React23__default.useState(null);
2390
- const [query, setQuery] = React23__default.useState("");
2391
- const wrapRef = React23__default.useRef(null);
2392
- const triggerRef = React23__default.useRef(null);
2393
- const popRef = React23__default.useRef(null);
2394
- const listRef = React23__default.useRef(null);
2395
- const activeRef = React23__default.useRef(null);
2396
- const searchRef = React23__default.useRef(null);
2531
+ const [open, setOpen] = React24__default.useState(false);
2532
+ const [render, setRender] = React24__default.useState(false);
2533
+ const [active, setActive] = React24__default.useState(0);
2534
+ const [coords, setCoords] = React24__default.useState(null);
2535
+ const [query, setQuery] = React24__default.useState("");
2536
+ const wrapRef = React24__default.useRef(null);
2537
+ const triggerRef = React24__default.useRef(null);
2538
+ const popRef = React24__default.useRef(null);
2539
+ const listRef = React24__default.useRef(null);
2540
+ const activeRef = React24__default.useRef(null);
2541
+ const searchRef = React24__default.useRef(null);
2397
2542
  const showSearch = searchable === void 0 ? flat.length > 5 : searchable;
2398
- const fGroups = React23__default.useMemo(() => {
2543
+ const fGroups = React24__default.useMemo(() => {
2399
2544
  const q = query.trim().toLowerCase();
2400
2545
  if (!q) return groups;
2401
2546
  return groups.map((g) => ({ group: g.group, options: g.options.filter((o) => o.label.toLowerCase().includes(q) || o.description && o.description.toLowerCase().includes(q)) })).filter((g) => g.options.length);
2402
2547
  }, [groups, query]);
2403
- const visible = React23__default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
2548
+ const visible = React24__default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
2404
2549
  const selected = flat.find((o) => o.value === current);
2405
- const place = React23__default.useCallback(() => {
2550
+ const place = React24__default.useCallback(() => {
2406
2551
  const el = triggerRef.current;
2407
2552
  if (!el) return;
2408
2553
  const r = el.getBoundingClientRect();
@@ -2417,7 +2562,7 @@ function Select({
2417
2562
  flip
2418
2563
  });
2419
2564
  }, [placement, minWidth]);
2420
- React23__default.useEffect(() => {
2565
+ React24__default.useEffect(() => {
2421
2566
  if (!open || !portal) return;
2422
2567
  place();
2423
2568
  const onMove = () => place();
@@ -2428,7 +2573,7 @@ function Select({
2428
2573
  window.removeEventListener("resize", onMove);
2429
2574
  };
2430
2575
  }, [open, portal, place]);
2431
- React23__default.useEffect(() => {
2576
+ React24__default.useEffect(() => {
2432
2577
  if (!open) return;
2433
2578
  const idx = flat.findIndex((o) => o.value === current);
2434
2579
  setActive(idx >= 0 ? idx : 0);
@@ -2444,13 +2589,13 @@ function Select({
2444
2589
  document.addEventListener("mousedown", onDown);
2445
2590
  return () => document.removeEventListener("mousedown", onDown);
2446
2591
  }, [open]);
2447
- React23__default.useEffect(() => {
2592
+ React24__default.useEffect(() => {
2448
2593
  setActive(0);
2449
2594
  }, [query]);
2450
- React23__default.useEffect(() => {
2595
+ React24__default.useEffect(() => {
2451
2596
  if (open) ensureVisible2(listRef.current, activeRef.current);
2452
2597
  }, [active, open]);
2453
- React23__default.useEffect(() => {
2598
+ React24__default.useEffect(() => {
2454
2599
  if (open) {
2455
2600
  setRender(true);
2456
2601
  return;
@@ -2458,8 +2603,8 @@ function Select({
2458
2603
  const t = setTimeout(() => setRender(false), 170);
2459
2604
  return () => clearTimeout(t);
2460
2605
  }, [open]);
2461
- const prevOpen = React23__default.useRef(false);
2462
- React23__default.useEffect(() => {
2606
+ const prevOpen = React24__default.useRef(false);
2607
+ React24__default.useEffect(() => {
2463
2608
  if (prevOpen.current && !open) {
2464
2609
  const ae = typeof document !== "undefined" ? document.activeElement : null;
2465
2610
  if (popRef.current && ae && popRef.current.contains(ae)) triggerRef.current?.focus();
@@ -2532,7 +2677,7 @@ function Select({
2532
2677
  }
2533
2678
  )
2534
2679
  ] }) : null,
2535
- /* @__PURE__ */ jsx("div", { className: "twc-pop__list", ref: listRef, children: visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: "No results found" }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React23__default.Fragment, { children: [
2680
+ /* @__PURE__ */ jsx("div", { className: "twc-pop__list", ref: listRef, children: visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: "No results found" }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React24__default.Fragment, { children: [
2536
2681
  g.group ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: g.group }) : null,
2537
2682
  g.options.map((o) => {
2538
2683
  counter += 1;
@@ -2706,19 +2851,19 @@ function CurrencyField({
2706
2851
  ...rest
2707
2852
  }) {
2708
2853
  const __twcStyles = useScopedStyles("twc-curf-styles", CURF_CSS);
2709
- const autoId = React23__default.useId();
2854
+ const autoId = React24__default.useId();
2710
2855
  const fieldId = id || autoId;
2711
2856
  const invalid = Boolean(error);
2712
2857
  const curControlled = currency !== void 0;
2713
- const [curInternal, setCurInternal] = React23__default.useState(defaultCurrency);
2858
+ const [curInternal, setCurInternal] = React24__default.useState(defaultCurrency);
2714
2859
  const cur = curControlled ? currency : curInternal;
2715
2860
  const meta = CURRENCIES[cur] || CURRENCIES.USD;
2716
2861
  const prec = meta.precision;
2717
2862
  const valControlled = value !== void 0;
2718
- const [valInternal, setValInternal] = React23__default.useState(() => clampPrecision(String(defaultValue ?? ""), prec));
2863
+ const [valInternal, setValInternal] = React24__default.useState(() => clampPrecision(String(defaultValue ?? ""), prec));
2719
2864
  const shown = valControlled ? clampPrecision(String(value ?? ""), prec) : valInternal;
2720
2865
  const describedBy = [error ? `${fieldId}-error` : hint ? `${fieldId}-hint` : null, rest["aria-describedby"]].filter(Boolean).join(" ") || void 0;
2721
- const options = React23__default.useMemo(() => {
2866
+ const options = React24__default.useMemo(() => {
2722
2867
  if (!currencies) return CURRENCY_OPTIONS;
2723
2868
  return currencies.map((c) => typeof c === "string" ? { value: c, label: `${c} \u2014 ${(CURRENCIES[c] || {}).label || c}` } : c);
2724
2869
  }, [currencies]);
@@ -2853,12 +2998,12 @@ function Input({
2853
2998
  ...rest
2854
2999
  }) {
2855
3000
  const __twcStyles = useScopedStyles("twc-field-styles", FIELD_CSS2);
2856
- const autoId = React23__default.useId();
3001
+ const autoId = React24__default.useId();
2857
3002
  const fieldId = id || autoId;
2858
3003
  const descId = `${fieldId}-desc`;
2859
3004
  const invalid = Boolean(error);
2860
3005
  const isPassword = type === "password";
2861
- const [revealed, setRevealed] = React23__default.useState(false);
3006
+ const [revealed, setRevealed] = React24__default.useState(false);
2862
3007
  const effectiveType = isPassword && revealed ? "text" : type;
2863
3008
  const suffix = rightIcon ? /* @__PURE__ */ jsx("span", { className: "twc-input__affix", children: rightIcon }) : isPassword ? /* @__PURE__ */ jsx(
2864
3009
  "button",
@@ -3039,28 +3184,28 @@ function MultiSelect({
3039
3184
  ...rest
3040
3185
  }) {
3041
3186
  const __twcStyles = useScopedStyles("twc-ms-styles", MULTI_CSS);
3042
- const groups = React23__default.useMemo(() => normalizeGroups3(options), [options]);
3043
- const flat = React23__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
3044
- const autoId = React23__default.useId();
3187
+ const groups = React24__default.useMemo(() => normalizeGroups3(options), [options]);
3188
+ const flat = React24__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
3189
+ const autoId = React24__default.useId();
3045
3190
  const fieldId = id || autoId;
3046
- const [internal, setInternal] = React23__default.useState(defaultValue);
3191
+ const [internal, setInternal] = React24__default.useState(defaultValue);
3047
3192
  const selected = value !== void 0 ? value : internal;
3048
- const [open, setOpen] = React23__default.useState(false);
3049
- const [query, setQuery] = React23__default.useState("");
3050
- const [active, setActive] = React23__default.useState(0);
3051
- const [coords, setCoords] = React23__default.useState(null);
3052
- const wrapRef = React23__default.useRef(null);
3053
- const controlRef = React23__default.useRef(null);
3054
- const inputRef = React23__default.useRef(null);
3055
- const popRef = React23__default.useRef(null);
3056
- const listRef = React23__default.useRef(null);
3057
- const activeRef = React23__default.useRef(null);
3058
- const fGroups = React23__default.useMemo(
3193
+ const [open, setOpen] = React24__default.useState(false);
3194
+ const [query, setQuery] = React24__default.useState("");
3195
+ const [active, setActive] = React24__default.useState(0);
3196
+ const [coords, setCoords] = React24__default.useState(null);
3197
+ const wrapRef = React24__default.useRef(null);
3198
+ const controlRef = React24__default.useRef(null);
3199
+ const inputRef = React24__default.useRef(null);
3200
+ const popRef = React24__default.useRef(null);
3201
+ const listRef = React24__default.useRef(null);
3202
+ const activeRef = React24__default.useRef(null);
3203
+ const fGroups = React24__default.useMemo(
3059
3204
  () => groups.map((g) => ({ group: g.group, options: g.options.filter((o) => matches2(o, query.trim())) })).filter((g) => g.options.length),
3060
3205
  [groups, query]
3061
3206
  );
3062
- const visible = React23__default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
3063
- const place = React23__default.useCallback(() => {
3207
+ const visible = React24__default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
3208
+ const place = React24__default.useCallback(() => {
3064
3209
  const el = controlRef.current;
3065
3210
  if (!el) return;
3066
3211
  const r = el.getBoundingClientRect();
@@ -3075,7 +3220,7 @@ function MultiSelect({
3075
3220
  flip
3076
3221
  });
3077
3222
  }, [placement, minWidth]);
3078
- React23__default.useEffect(() => {
3223
+ React24__default.useEffect(() => {
3079
3224
  if (!open || !portal) return;
3080
3225
  place();
3081
3226
  const onMove = () => place();
@@ -3086,7 +3231,7 @@ function MultiSelect({
3086
3231
  window.removeEventListener("resize", onMove);
3087
3232
  };
3088
3233
  }, [open, portal, place]);
3089
- React23__default.useEffect(() => {
3234
+ React24__default.useEffect(() => {
3090
3235
  if (!open) return;
3091
3236
  const onDown = (e) => {
3092
3237
  if (wrapRef.current && wrapRef.current.contains(e.target)) return;
@@ -3097,10 +3242,10 @@ function MultiSelect({
3097
3242
  document.addEventListener("mousedown", onDown);
3098
3243
  return () => document.removeEventListener("mousedown", onDown);
3099
3244
  }, [open]);
3100
- React23__default.useEffect(() => {
3245
+ React24__default.useEffect(() => {
3101
3246
  setActive(0);
3102
3247
  }, [query]);
3103
- React23__default.useEffect(() => {
3248
+ React24__default.useEffect(() => {
3104
3249
  if (open) ensureVisible3(listRef.current, activeRef.current);
3105
3250
  }, [active, open]);
3106
3251
  function commit(next) {
@@ -3137,7 +3282,7 @@ function MultiSelect({
3137
3282
  const descId = `${fieldId}-desc`;
3138
3283
  const describedBy = error || hint ? descId : void 0;
3139
3284
  let counter = -1;
3140
- const popInner = /* @__PURE__ */ jsx("div", { className: "twc-pop__list", id: listboxId, ref: listRef, role: "listbox", "aria-multiselectable": "true", children: visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: "No results found" }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React23__default.Fragment, { children: [
3285
+ const popInner = /* @__PURE__ */ jsx("div", { className: "twc-pop__list", id: listboxId, ref: listRef, role: "listbox", "aria-multiselectable": "true", children: visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: "No results found" }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React24__default.Fragment, { children: [
3141
3286
  g.group ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: g.group }) : null,
3142
3287
  g.options.map((o) => {
3143
3288
  counter += 1;
@@ -3281,6 +3426,15 @@ function MultiSelect({
3281
3426
  error ? /* @__PURE__ */ jsx("span", { id: descId, className: "twc-field__error", children: error }) : hint ? /* @__PURE__ */ jsx("span", { id: descId, className: "twc-field__hint", children: hint }) : null
3282
3427
  ] });
3283
3428
  }
3429
+
3430
+ // components/_warn.js
3431
+ var seen = /* @__PURE__ */ new Set();
3432
+ function warnOnce(key, message) {
3433
+ if (typeof process !== "undefined" && process.env && process.env.NODE_ENV === "production") return;
3434
+ if (seen.has(key)) return;
3435
+ seen.add(key);
3436
+ if (typeof console !== "undefined" && console.warn) console.warn(message);
3437
+ }
3284
3438
  var PAGINATION_CSS = `
3285
3439
  .twc-pagination { display: inline-flex; align-items: center; gap: 4px; font-family: var(--font-sans); }
3286
3440
  .twc-page {
@@ -3343,15 +3497,18 @@ function Pagination({
3343
3497
  siblings = 1,
3344
3498
  boundaries = 1,
3345
3499
  size = "md",
3346
- showJumper = false,
3500
+ showJumper,
3347
3501
  showPageJumper,
3348
3502
  jumperLabel = "Go to",
3349
3503
  className = "",
3350
3504
  ...rest
3351
3505
  }) {
3506
+ if (process.env.NODE_ENV !== "production" && showJumper !== void 0 && showPageJumper === void 0) {
3507
+ warnOnce("Pagination.showJumper", "Pagination: `showJumper` is deprecated and will be removed in 2.0 \u2014 use `showPageJumper`.");
3508
+ }
3352
3509
  const jumperEnabled = showPageJumper ?? showJumper;
3353
3510
  const __twcStyles = useScopedStyles("twc-pagination-styles", PAGINATION_CSS);
3354
- const [internal, setInternal] = React23__default.useState(defaultPage);
3511
+ const [internal, setInternal] = React24__default.useState(defaultPage);
3355
3512
  const page = pageProp !== void 0 ? pageProp : internal;
3356
3513
  const pages = buildPages(page, total, siblings, boundaries);
3357
3514
  const go = (p) => {
@@ -3359,7 +3516,7 @@ function Pagination({
3359
3516
  if (pageProp === void 0) setInternal(p);
3360
3517
  onChange?.(p);
3361
3518
  };
3362
- const [jump, setJump] = React23__default.useState("");
3519
+ const [jump, setJump] = React24__default.useState("");
3363
3520
  const submitJump = () => {
3364
3521
  const n = parseInt(jump, 10);
3365
3522
  if (!Number.isNaN(n)) go(Math.min(Math.max(n, 1), total));
@@ -3970,9 +4127,9 @@ function runDatatableQuery(rows, query, options = {}) {
3970
4127
  return { rows: page, total, filtered: out };
3971
4128
  }
3972
4129
  function useFloating() {
3973
- const [pos, setPos] = React23__default.useState(null);
3974
- const cfg = React23__default.useRef(null);
3975
- const place = React23__default.useCallback(() => {
4130
+ const [pos, setPos] = React24__default.useState(null);
4131
+ const cfg = React24__default.useRef(null);
4132
+ const place = React24__default.useCallback(() => {
3976
4133
  const c = cfg.current;
3977
4134
  if (!c || !c.el || !c.el.isConnected) return null;
3978
4135
  const r = c.el.getBoundingClientRect();
@@ -3983,17 +4140,17 @@ function useFloating() {
3983
4140
  const top = r.bottom + 6;
3984
4141
  return { top, left, width: c.width, anchorX: r.left + r.width / 2, maxHeight: Math.max(180, vh - top - M) };
3985
4142
  }, []);
3986
- const open = React23__default.useCallback((el, align = "left", width = 220) => {
4143
+ const open = React24__default.useCallback((el, align = "left", width = 220) => {
3987
4144
  cfg.current = { el, align, width };
3988
4145
  const p = place();
3989
4146
  if (p) setPos(p);
3990
4147
  }, [place]);
3991
- const close = React23__default.useCallback(() => {
4148
+ const close = React24__default.useCallback(() => {
3992
4149
  cfg.current = null;
3993
4150
  setPos(null);
3994
4151
  }, []);
3995
4152
  const isOpen = pos != null;
3996
- React23__default.useEffect(() => {
4153
+ React24__default.useEffect(() => {
3997
4154
  if (!isOpen) return void 0;
3998
4155
  const update = () => {
3999
4156
  const p = place();
@@ -4017,9 +4174,9 @@ function Caret({ pos }) {
4017
4174
  return /* @__PURE__ */ jsx("span", { className: "twc-dt__caret", style: { left } });
4018
4175
  }
4019
4176
  function EditCell({ col, value, options, onChange, onCommit, onCommitValue, onCancel, onKeyDown }) {
4020
- const ref = React23__default.useRef(null);
4177
+ const ref = React24__default.useRef(null);
4021
4178
  const isSelect = col.editType === "select" || options && col.editType !== "text";
4022
- React23__default.useEffect(() => {
4179
+ React24__default.useEffect(() => {
4023
4180
  if (isSelect) {
4024
4181
  const t = setTimeout(() => ref.current?.querySelector(".twc-sel__trigger")?.click(), 0);
4025
4182
  return () => clearTimeout(t);
@@ -4222,7 +4379,7 @@ function Datatable({
4222
4379
  ...rest
4223
4380
  }) {
4224
4381
  const __twcStyles = useScopedStyles("twc-dt-styles", DT_CSS);
4225
- const cols = React23__default.useMemo(() => {
4382
+ const cols = React24__default.useMemo(() => {
4226
4383
  const out = columns.map((c) => {
4227
4384
  const isActions = c.type === "actions";
4228
4385
  return {
@@ -4257,7 +4414,7 @@ function Datatable({
4257
4414
  }
4258
4415
  return out;
4259
4416
  }, [columns, rowPinning]);
4260
- const _autoKey = React23__default.useRef();
4417
+ const _autoKey = React24__default.useRef();
4261
4418
  if (!_autoKey.current) _autoKey.current = { map: /* @__PURE__ */ new WeakMap(), n: 0 };
4262
4419
  const keyOf = rowKey || ((r, i) => {
4263
4420
  if (r != null && r.id != null) return r.id;
@@ -4272,17 +4429,17 @@ function Datatable({
4272
4429
  }
4273
4430
  return i;
4274
4431
  });
4275
- const [sort, setSort] = React23__default.useState(null);
4276
- const [filters, setFilters] = React23__default.useState([]);
4277
- const [hidden, setHidden] = React23__default.useState(() => /* @__PURE__ */ new Set());
4278
- const [showRowNum, setShowRowNum] = React23__default.useState(rowNumbers);
4279
- const [wrapped, setWrapped] = React23__default.useState(() => new Set((columns || []).filter((c) => c.wrapText).map((c) => c.field)));
4432
+ const [sort, setSort] = React24__default.useState(null);
4433
+ const [filters, setFilters] = React24__default.useState([]);
4434
+ const [hidden, setHidden] = React24__default.useState(() => /* @__PURE__ */ new Set());
4435
+ const [showRowNum, setShowRowNum] = React24__default.useState(rowNumbers);
4436
+ const [wrapped, setWrapped] = React24__default.useState(() => new Set((columns || []).filter((c) => c.wrapText).map((c) => c.field)));
4280
4437
  const toggleWrap = (field) => setWrapped((w) => {
4281
4438
  const n = new Set(w);
4282
4439
  n.has(field) ? n.delete(field) : n.add(field);
4283
4440
  return n;
4284
4441
  });
4285
- const [pins, setPins] = React23__default.useState(() => {
4442
+ const [pins, setPins] = React24__default.useState(() => {
4286
4443
  const left = [], right = [];
4287
4444
  columns.forEach((c) => {
4288
4445
  if (c.pinned === "left") left.push(c.field);
@@ -4290,34 +4447,34 @@ function Datatable({
4290
4447
  });
4291
4448
  return { left, right };
4292
4449
  });
4293
- const [density, setDensity] = React23__default.useState(densityProp);
4294
- const [quick, setQuick] = React23__default.useState("");
4295
- const [selected, setSelected] = React23__default.useState(() => /* @__PURE__ */ new Set());
4296
- const [activeRow, setActiveRow] = React23__default.useState(null);
4297
- const [activeCell, setActiveCell] = React23__default.useState(null);
4298
- const [page, setPage] = React23__default.useState(0);
4299
- const [rowsPerPage, setRowsPerPage] = React23__default.useState(pageSize > 0 ? pageSize : 10);
4300
- const [colQuery, setColQuery] = React23__default.useState("");
4301
- const [widths, setWidths] = React23__default.useState({});
4302
- const [order, setOrder] = React23__default.useState(() => columns.map((c) => c.field));
4303
- const [drag, setDrag] = React23__default.useState({ from: null, over: null, after: false });
4304
- const [aggOn, setAggOn] = React23__default.useState(showAggregation);
4305
- const [focus, setFocus] = React23__default.useState({ r: 0, c: 0 });
4306
- const gridRef = React23__default.useRef(null);
4307
- const [groupBy, setGroupBy] = React23__default.useState(rowGrouping || []);
4308
- const [collapsed, setCollapsed] = React23__default.useState(() => /* @__PURE__ */ new Set());
4309
- const [pinnedRows, setPinnedRows] = React23__default.useState({ top: [], bottom: [] });
4310
- const [headH, setHeadH] = React23__default.useState(41);
4311
- const theadRef = React23__default.useRef(null);
4312
- const [rowOrder, setRowOrder] = React23__default.useState(null);
4313
- const [rowHeights, setRowHeights] = React23__default.useState({});
4314
- const [rowDrag, setRowDrag] = React23__default.useState({ from: null, over: null, after: false });
4315
- const [rowGrab, setRowGrab] = React23__default.useState(null);
4316
- const [reorderMsg, setReorderMsg] = React23__default.useState("");
4317
- const rowFocusRef = React23__default.useRef(null);
4318
- const rootRef = React23__default.useRef(null);
4319
- const [compact, setCompact] = React23__default.useState(false);
4320
- React23__default.useEffect(() => {
4450
+ const [density, setDensity] = React24__default.useState(densityProp);
4451
+ const [quick, setQuick] = React24__default.useState("");
4452
+ const [selected, setSelected] = React24__default.useState(() => /* @__PURE__ */ new Set());
4453
+ const [activeRow, setActiveRow] = React24__default.useState(null);
4454
+ const [activeCell, setActiveCell] = React24__default.useState(null);
4455
+ const [page, setPage] = React24__default.useState(0);
4456
+ const [rowsPerPage, setRowsPerPage] = React24__default.useState(pageSize > 0 ? pageSize : 10);
4457
+ const [colQuery, setColQuery] = React24__default.useState("");
4458
+ const [widths, setWidths] = React24__default.useState({});
4459
+ const [order, setOrder] = React24__default.useState(() => columns.map((c) => c.field));
4460
+ const [drag, setDrag] = React24__default.useState({ from: null, over: null, after: false });
4461
+ const [aggOn, setAggOn] = React24__default.useState(showAggregation);
4462
+ const [focus, setFocus] = React24__default.useState({ r: 0, c: 0 });
4463
+ const gridRef = React24__default.useRef(null);
4464
+ const [groupBy, setGroupBy] = React24__default.useState(rowGrouping || []);
4465
+ const [collapsed, setCollapsed] = React24__default.useState(() => /* @__PURE__ */ new Set());
4466
+ const [pinnedRows, setPinnedRows] = React24__default.useState({ top: [], bottom: [] });
4467
+ const [headH, setHeadH] = React24__default.useState(41);
4468
+ const theadRef = React24__default.useRef(null);
4469
+ const [rowOrder, setRowOrder] = React24__default.useState(null);
4470
+ const [rowHeights, setRowHeights] = React24__default.useState({});
4471
+ const [rowDrag, setRowDrag] = React24__default.useState({ from: null, over: null, after: false });
4472
+ const [rowGrab, setRowGrab] = React24__default.useState(null);
4473
+ const [reorderMsg, setReorderMsg] = React24__default.useState("");
4474
+ const rowFocusRef = React24__default.useRef(null);
4475
+ const rootRef = React24__default.useRef(null);
4476
+ const [compact, setCompact] = React24__default.useState(false);
4477
+ React24__default.useEffect(() => {
4321
4478
  const el = rootRef.current;
4322
4479
  if (!el) return void 0;
4323
4480
  const measure = () => setCompact((el.clientWidth || 0) < 720);
@@ -4330,11 +4487,11 @@ function Datatable({
4330
4487
  else if (typeof window !== "undefined") window.removeEventListener("resize", measure);
4331
4488
  };
4332
4489
  }, []);
4333
- const scrollRef = React23__default.useRef(null);
4334
- const [scrollTop, setScrollTop] = React23__default.useState(0);
4335
- const [viewportH, setViewportH] = React23__default.useState(0);
4336
- const [pivotOn, setPivotOn] = React23__default.useState(pivotMode);
4337
- const [aggConfig, setAggConfig] = React23__default.useState(() => {
4490
+ const scrollRef = React24__default.useRef(null);
4491
+ const [scrollTop, setScrollTop] = React24__default.useState(0);
4492
+ const [viewportH, setViewportH] = React24__default.useState(0);
4493
+ const [pivotOn, setPivotOn] = React24__default.useState(pivotMode);
4494
+ const [aggConfig, setAggConfig] = React24__default.useState(() => {
4338
4495
  const m = {};
4339
4496
  (columns || []).forEach((c) => {
4340
4497
  if (typeof c.aggregation === "string") m[c.field] = c.aggregation;
@@ -4342,13 +4499,13 @@ function Datatable({
4342
4499
  return m;
4343
4500
  });
4344
4501
  const aggOf = (c) => aggConfig[c.field] || (typeof c.aggregation === "function" ? c.aggregation : null);
4345
- const [pivotConfig, setPivotConfig] = React23__default.useState(() => ({
4502
+ const [pivotConfig, setPivotConfig] = React24__default.useState(() => ({
4346
4503
  rows: pivot && pivot.rows || [],
4347
4504
  columns: pivot && pivot.columns || [],
4348
4505
  values: pivot && pivot.values || []
4349
4506
  }));
4350
4507
  const pivotActive = pivotOn && pivotConfig.rows.length > 0 && pivotConfig.values.length > 0;
4351
- React23__default.useEffect(() => {
4508
+ React24__default.useEffect(() => {
4352
4509
  setOrder((prev) => {
4353
4510
  const fields = columns.map((c) => c.field);
4354
4511
  const kept = prev.filter((f) => fields.includes(f));
@@ -4356,32 +4513,32 @@ function Datatable({
4356
4513
  return [...kept, ...added];
4357
4514
  });
4358
4515
  }, [columns]);
4359
- React23__default.useEffect(() => {
4516
+ React24__default.useEffect(() => {
4360
4517
  setDensity(densityProp);
4361
4518
  }, [densityProp]);
4362
- React23__default.useEffect(() => {
4519
+ React24__default.useEffect(() => {
4363
4520
  setAggOn(showAggregation);
4364
4521
  }, [showAggregation]);
4365
4522
  const rowGroupingKey = (rowGrouping || []).join("\0");
4366
- const rowGroupingKeyRef = React23__default.useRef(rowGroupingKey);
4367
- React23__default.useEffect(() => {
4523
+ const rowGroupingKeyRef = React24__default.useRef(rowGroupingKey);
4524
+ React24__default.useEffect(() => {
4368
4525
  if (rowGroupingKeyRef.current === rowGroupingKey) return;
4369
4526
  rowGroupingKeyRef.current = rowGroupingKey;
4370
4527
  setGroupBy(rowGrouping || []);
4371
4528
  }, [rowGroupingKey]);
4372
4529
  const widthOf = (c) => widths[c.field] ?? c.width ?? 160;
4373
- const [colMenu, setColMenu] = React23__default.useState(null);
4530
+ const [colMenu, setColMenu] = React24__default.useState(null);
4374
4531
  const [menuPos, openMenu, closeMenu] = useFloating();
4375
- const [panel, setPanel] = React23__default.useState(null);
4532
+ const [panel, setPanel] = React24__default.useState(null);
4376
4533
  const [panelPos, openPanel, closePanel] = useFloating();
4377
- const [rowMenu, setRowMenu] = React23__default.useState(null);
4534
+ const [rowMenu, setRowMenu] = React24__default.useState(null);
4378
4535
  const [rowMenuPos, openRowMenu, closeRowMenu] = useFloating();
4379
- const [exportOpen, setExportOpen] = React23__default.useState(false);
4536
+ const [exportOpen, setExportOpen] = React24__default.useState(false);
4380
4537
  const [exportPos, openExport, closeExport] = useFloating();
4381
- const menuTriggerRef = React23__default.useRef(null);
4382
- const colMenuRef = React23__default.useRef(null);
4383
- const rowMenuRef = React23__default.useRef(null);
4384
- const exportMenuRef = React23__default.useRef(null);
4538
+ const menuTriggerRef = React24__default.useRef(null);
4539
+ const colMenuRef = React24__default.useRef(null);
4540
+ const rowMenuRef = React24__default.useRef(null);
4541
+ const exportMenuRef = React24__default.useRef(null);
4385
4542
  function focusFirstItem(container) {
4386
4543
  if (!container) return;
4387
4544
  const first = container.querySelector('[role="menuitem"]:not([disabled])');
@@ -4420,16 +4577,16 @@ function Datatable({
4420
4577
  restoreTriggerFocus();
4421
4578
  }
4422
4579
  }
4423
- React23__default.useEffect(() => {
4580
+ React24__default.useEffect(() => {
4424
4581
  if (colMenu) focusFirstItem(colMenuRef.current);
4425
4582
  }, [colMenu]);
4426
- React23__default.useEffect(() => {
4583
+ React24__default.useEffect(() => {
4427
4584
  if (rowMenu) focusFirstItem(rowMenuRef.current);
4428
4585
  }, [rowMenu]);
4429
- React23__default.useEffect(() => {
4586
+ React24__default.useEffect(() => {
4430
4587
  if (exportOpen) focusFirstItem(exportMenuRef.current);
4431
4588
  }, [exportOpen]);
4432
- React23__default.useEffect(() => {
4589
+ React24__default.useEffect(() => {
4433
4590
  if (!colMenu && !panel && !rowMenu) return;
4434
4591
  const closeAll = () => {
4435
4592
  setColMenu(null);
@@ -4452,7 +4609,7 @@ function Datatable({
4452
4609
  document.removeEventListener("keydown", onKey);
4453
4610
  };
4454
4611
  }, [colMenu, panel, rowMenu]);
4455
- React23__default.useEffect(() => {
4612
+ React24__default.useEffect(() => {
4456
4613
  if (!exportOpen) return;
4457
4614
  const close = () => {
4458
4615
  setExportOpen(false);
@@ -4471,9 +4628,9 @@ function Datatable({
4471
4628
  document.removeEventListener("keydown", onKey);
4472
4629
  };
4473
4630
  }, [exportOpen]);
4474
- const colByField = React23__default.useMemo(() => Object.fromEntries(cols.map((c) => [c.field, c])), [cols]);
4631
+ const colByField = React24__default.useMemo(() => Object.fromEntries(cols.map((c) => [c.field, c])), [cols]);
4475
4632
  const visibleCols = cols.filter((c) => !hidden.has(c.field));
4476
- const ordered = React23__default.useMemo(() => {
4633
+ const ordered = React24__default.useMemo(() => {
4477
4634
  const orderIdx = (f) => {
4478
4635
  const i = order.indexOf(f);
4479
4636
  return i === -1 ? 9999 : i;
@@ -4508,7 +4665,7 @@ function Datatable({
4508
4665
  }
4509
4666
  return {};
4510
4667
  };
4511
- const processed = React23__default.useMemo(() => {
4668
+ const processed = React24__default.useMemo(() => {
4512
4669
  if (serverMode) {
4513
4670
  if (rowOrder) {
4514
4671
  const idx = new Map(rowOrder.map((k, i) => [k, i]));
@@ -4547,10 +4704,10 @@ function Datatable({
4547
4704
  const totalRows = serverMode ? serverTotal : processed.length;
4548
4705
  const totalPages = paginated ? Math.max(1, Math.ceil(totalRows / rowsPerPage)) : 1;
4549
4706
  const paged = !paginated || serverMode ? processed : processed.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage);
4550
- React23__default.useEffect(() => {
4707
+ React24__default.useEffect(() => {
4551
4708
  if (page > totalPages - 1) setPage(0);
4552
4709
  }, [totalPages]);
4553
- const activeGroupBy = React23__default.useMemo(() => groupBy.filter((f) => colByField[f]), [groupBy, colByField]);
4710
+ const activeGroupBy = React24__default.useMemo(() => groupBy.filter((f) => colByField[f]), [groupBy, colByField]);
4554
4711
  function subtotalText(rowsIn) {
4555
4712
  const parts = [];
4556
4713
  for (const c of ordered) {
@@ -4577,7 +4734,7 @@ function Datatable({
4577
4734
  if (agg === "max") return Math.max(...nums);
4578
4735
  return null;
4579
4736
  }
4580
- const displayItems = React23__default.useMemo(() => {
4737
+ const displayItems = React24__default.useMemo(() => {
4581
4738
  if (!activeGroupBy.length) return null;
4582
4739
  const build = (rowsIn, depth, prefix) => {
4583
4740
  if (depth >= activeGroupBy.length) return rowsIn.map((row) => ({ kind: "leaf", row }));
@@ -4619,7 +4776,7 @@ function Datatable({
4619
4776
  return { top, bottom };
4620
4777
  });
4621
4778
  }
4622
- React23__default.useEffect(() => {
4779
+ React24__default.useEffect(() => {
4623
4780
  if (!rowPinning) return;
4624
4781
  const measure = () => {
4625
4782
  if (theadRef.current) setHeadH(theadRef.current.offsetHeight || 41);
@@ -4633,12 +4790,12 @@ function Datatable({
4633
4790
  const pinnedTopRows = canPinRows ? pinnedRows.top.map((k) => leafRows.find((r, i) => keyOf(r, i) === k)).filter(Boolean) : [];
4634
4791
  const pinnedBottomRows = canPinRows ? pinnedRows.bottom.map((k) => leafRows.find((r, i) => keyOf(r, i) === k)).filter(Boolean) : [];
4635
4792
  const middleRows = canPinRows ? leafRows.filter((r, i) => !pinSideOf(keyOf(r, i))) : leafRows;
4636
- const keyIndex = React23__default.useMemo(() => {
4793
+ const keyIndex = React24__default.useMemo(() => {
4637
4794
  const m = /* @__PURE__ */ new Map();
4638
4795
  leafRows.forEach((r, i) => m.set(keyOf(r, i), i));
4639
4796
  return m;
4640
4797
  }, [leafRows]);
4641
- const keyIndexMid = React23__default.useMemo(() => {
4798
+ const keyIndexMid = React24__default.useMemo(() => {
4642
4799
  const m = /* @__PURE__ */ new Map();
4643
4800
  middleRows.forEach((r, i) => m.set(keyOf(r, keyIndex.get(keyOf(r)) ?? i), i));
4644
4801
  return m;
@@ -4723,7 +4880,7 @@ function Datatable({
4723
4880
  setReorderMsg("Reorder cancelled.");
4724
4881
  }
4725
4882
  }
4726
- React23__default.useEffect(() => {
4883
+ React24__default.useEffect(() => {
4727
4884
  if (rowFocusRef.current == null) return;
4728
4885
  const key = rowFocusRef.current;
4729
4886
  rowFocusRef.current = null;
@@ -4735,7 +4892,7 @@ function Datatable({
4735
4892
  });
4736
4893
  const estRowH = rowHeight ?? (density === "compact" ? 36 : density === "comfortable" ? 56 : 44);
4737
4894
  const virtualizing = virtualized && !paginated && !activeGroupBy.length && !loading;
4738
- React23__default.useEffect(() => {
4895
+ React24__default.useEffect(() => {
4739
4896
  if (!virtualizing) return;
4740
4897
  const el = scrollRef.current;
4741
4898
  if (!el) return;
@@ -4745,13 +4902,13 @@ function Datatable({
4745
4902
  if (ro) ro.observe(el);
4746
4903
  return () => ro && ro.disconnect();
4747
4904
  }, [virtualizing, height]);
4748
- const onScrollVirtual = React23__default.useCallback((e) => {
4905
+ const onScrollVirtual = React24__default.useCallback((e) => {
4749
4906
  setScrollTop(e.currentTarget.scrollTop);
4750
4907
  }, []);
4751
4908
  const vh = viewportH || (typeof height === "number" ? height : 440);
4752
- const rowHRef = React23__default.useRef(/* @__PURE__ */ new Map());
4753
- const [measureTick, setMeasureTick] = React23__default.useState(0);
4754
- const offsets = React23__default.useMemo(() => {
4909
+ const rowHRef = React24__default.useRef(/* @__PURE__ */ new Map());
4910
+ const [measureTick, setMeasureTick] = React24__default.useState(0);
4911
+ const offsets = React24__default.useMemo(() => {
4755
4912
  if (!virtualizing) return null;
4756
4913
  const total = middleRows.length;
4757
4914
  const arr = new Float64Array(total + 1);
@@ -4761,7 +4918,7 @@ function Datatable({
4761
4918
  }
4762
4919
  return arr;
4763
4920
  }, [virtualizing, middleRows, estRowH, measureTick]);
4764
- const vWindow = React23__default.useMemo(() => {
4921
+ const vWindow = React24__default.useMemo(() => {
4765
4922
  if (!virtualizing || !offsets) return null;
4766
4923
  const total = middleRows.length;
4767
4924
  const totalH = offsets[total];
@@ -4790,7 +4947,7 @@ function Datatable({
4790
4947
  if (start > end) start = end;
4791
4948
  return { start, end, padTop: offsets[start], padBottom: Math.max(0, totalH - offsets[end]) };
4792
4949
  }, [virtualizing, offsets, middleRows.length, vh, scrollTop, overscan]);
4793
- React23__default.useLayoutEffect(() => {
4950
+ React24__default.useLayoutEffect(() => {
4794
4951
  if (!virtualizing) return;
4795
4952
  const el = scrollRef.current;
4796
4953
  if (!el) return;
@@ -4805,9 +4962,9 @@ function Datatable({
4805
4962
  }
4806
4963
  if (changed) setMeasureTick((t) => t + 1);
4807
4964
  });
4808
- const onServerChangeRef = React23__default.useRef(onServerChange);
4965
+ const onServerChangeRef = React24__default.useRef(onServerChange);
4809
4966
  onServerChangeRef.current = onServerChange;
4810
- React23__default.useEffect(() => {
4967
+ React24__default.useEffect(() => {
4811
4968
  if (!serverMode) return;
4812
4969
  const t = setTimeout(() => {
4813
4970
  onServerChangeRef.current?.({
@@ -4842,7 +4999,7 @@ function Datatable({
4842
4999
  return n;
4843
5000
  });
4844
5001
  }
4845
- const movableMidFields = React23__default.useMemo(
5002
+ const movableMidFields = React24__default.useMemo(
4846
5003
  () => ordered.filter((c) => !pins.left.includes(c.field) && !pins.right.includes(c.field)).map((c) => c.field),
4847
5004
  [ordered, pins]
4848
5005
  );
@@ -4873,7 +5030,7 @@ function Datatable({
4873
5030
  }
4874
5031
  return [...set].sort((a, b) => a.localeCompare(b)).map((v) => ({ value: v, label: v }));
4875
5032
  }
4876
- const [resizing, setResizing] = React23__default.useState(false);
5033
+ const [resizing, setResizing] = React24__default.useState(false);
4877
5034
  function startResize(e, field) {
4878
5035
  e.preventDefault();
4879
5036
  e.stopPropagation();
@@ -4980,7 +5137,7 @@ function Datatable({
4980
5137
  if (!agg) return null;
4981
5138
  if (aggregationValues && col.field in aggregationValues) {
4982
5139
  const pre = aggregationValues[col.field];
4983
- if (pre && typeof pre === "object" && !React23__default.isValidElement(pre)) {
5140
+ if (pre && typeof pre === "object" && !React24__default.isValidElement(pre)) {
4984
5141
  if (typeof agg === "string" && agg in pre) return pre[agg];
4985
5142
  } else {
4986
5143
  return pre;
@@ -5098,14 +5255,14 @@ function Datatable({
5098
5255
  focusCell(r, c);
5099
5256
  }
5100
5257
  }
5101
- React23__default.useEffect(() => {
5258
+ React24__default.useEffect(() => {
5102
5259
  setFocus((f) => ({ r: Math.min(f.r, Math.max(0, leafRows.length - 1)), c: Math.min(f.c, Math.max(0, ordered.length - 1)) }));
5103
5260
  }, [leafRows.length, ordered.length, page]);
5104
- const selectedRows = React23__default.useMemo(() => rows.filter((r, i) => selected.has(keyOf(r, i))), [rows, selected]);
5261
+ const selectedRows = React24__default.useMemo(() => rows.filter((r, i) => selected.has(keyOf(r, i))), [rows, selected]);
5105
5262
  function clearSelection() {
5106
5263
  setSelected(/* @__PURE__ */ new Set());
5107
5264
  }
5108
- const [editing, setEditing] = React23__default.useState(null);
5265
+ const [editing, setEditing] = React24__default.useState(null);
5109
5266
  const isColEditable = (c) => c.type !== "actions" && (c.editable ?? (editMode && c.editable !== false));
5110
5267
  function beginEdit(rowK, col, row) {
5111
5268
  if (!isColEditable(col)) return;
@@ -5140,17 +5297,17 @@ function Datatable({
5140
5297
  cancelEdit();
5141
5298
  }
5142
5299
  }
5143
- const batchEditableCols = React23__default.useMemo(
5300
+ const batchEditableCols = React24__default.useMemo(
5144
5301
  () => cols.filter((c) => c.type !== "actions" && (c.editable ?? (editMode && c.editable !== false))),
5145
5302
  [cols, editMode]
5146
5303
  );
5147
- const [batchEdit, setBatchEdit] = React23__default.useState(null);
5304
+ const [batchEdit, setBatchEdit] = React24__default.useState(null);
5148
5305
  const [batchEditPos, openBatchEdit, closeBatchEdit] = useFloating();
5149
5306
  function openBatchEditor(el) {
5150
5307
  setBatchEdit({ fields: {}, values: {} });
5151
5308
  openBatchEdit(el, "left", 320);
5152
5309
  }
5153
- React23__default.useEffect(() => {
5310
+ React24__default.useEffect(() => {
5154
5311
  if (!batchEdit) return;
5155
5312
  const close = () => {
5156
5313
  setBatchEdit(null);
@@ -5169,7 +5326,7 @@ function Datatable({
5169
5326
  document.removeEventListener("keydown", onKey);
5170
5327
  };
5171
5328
  }, [batchEdit]);
5172
- React23__default.useEffect(() => {
5329
+ React24__default.useEffect(() => {
5173
5330
  if (batchEdit && selected.size === 0) {
5174
5331
  setBatchEdit(null);
5175
5332
  closeBatchEdit();
@@ -5206,7 +5363,7 @@ function Datatable({
5206
5363
  setBatchEdit(null);
5207
5364
  closeBatchEdit();
5208
5365
  }
5209
- React23__default.useEffect(() => {
5366
+ React24__default.useEffect(() => {
5210
5367
  if (!editing) return;
5211
5368
  const onDown = (e) => {
5212
5369
  if (e.target.closest(".twc-dt__editor-wrap") || e.target.closest(".twc-pop")) return;
@@ -5478,12 +5635,12 @@ function Datatable({
5478
5635
  const vlabel = (v) => v.label || (colByField[v.field]?.headerName || v.field);
5479
5636
  const rowFieldLabel = rFields.map((f) => colByField[f]?.headerName || f).join(" / ");
5480
5637
  const leafPaths = [];
5481
- const seen = /* @__PURE__ */ new Set();
5638
+ const seen2 = /* @__PURE__ */ new Set();
5482
5639
  for (const r of rows) {
5483
5640
  const path = colPathOf(r);
5484
5641
  const key = path.join("\0");
5485
- if (!seen.has(key)) {
5486
- seen.add(key);
5642
+ if (!seen2.has(key)) {
5643
+ seen2.add(key);
5487
5644
  leafPaths.push(path);
5488
5645
  }
5489
5646
  }
@@ -6011,7 +6168,7 @@ function Datatable({
6011
6168
  } }) })
6012
6169
  ] }) : null
6013
6170
  ] }),
6014
- paginated ? /* @__PURE__ */ jsx("div", { className: "twc-dt__footer-row", "data-pager": "true", children: /* @__PURE__ */ jsx(Pagination, { size: "sm", page: page + 1, total: totalPages, boundaries: 3, showJumper: showPageJumper && totalPages > 5, onChange: (p) => setPage(p - 1) }) }) : null
6171
+ paginated ? /* @__PURE__ */ jsx("div", { className: "twc-dt__footer-row", "data-pager": "true", children: /* @__PURE__ */ jsx(Pagination, { size: "sm", page: page + 1, total: totalPages, boundaries: 3, showPageJumper: showPageJumper && totalPages > 5, onChange: (p) => setPage(p - 1) }) }) : null
6015
6172
  ] }) : null,
6016
6173
  exportOpen && exportPos ? /* @__PURE__ */ jsxs(
6017
6174
  "div",
@@ -6728,23 +6885,23 @@ function DatePicker({
6728
6885
  }) {
6729
6886
  const __twcStyles0 = useScopedStyles("twc-field-styles", FIELD_CSS3);
6730
6887
  const __twcStyles1 = useScopedStyles("twc-datepicker-styles", DATEPICKER_CSS);
6731
- const autoId = React23__default.useId();
6888
+ const autoId = React24__default.useId();
6732
6889
  const fieldId = id || autoId;
6733
6890
  const descId = `${fieldId}-desc`;
6734
6891
  const invalid = Boolean(error);
6735
- const [internal, setInternal] = React23__default.useState(defaultValue);
6892
+ const [internal, setInternal] = React24__default.useState(defaultValue);
6736
6893
  const selected = value !== void 0 ? value : internal;
6737
- const [open, setOpen] = React23__default.useState(false);
6738
- const [view, setView] = React23__default.useState(selected || /* @__PURE__ */ new Date());
6739
- const [mode, setMode] = React23__default.useState("days");
6740
- const [focusDate, setFocusDate] = React23__default.useState(null);
6741
- const [coords, setCoords] = React23__default.useState(null);
6742
- const wrapRef = React23__default.useRef(null);
6743
- const triggerRef = React23__default.useRef(null);
6744
- const popRef = React23__default.useRef(null);
6745
- const gridRef = React23__default.useRef(null);
6894
+ const [open, setOpen] = React24__default.useState(false);
6895
+ const [view, setView] = React24__default.useState(selected || /* @__PURE__ */ new Date());
6896
+ const [mode, setMode] = React24__default.useState("days");
6897
+ const [focusDate, setFocusDate] = React24__default.useState(null);
6898
+ const [coords, setCoords] = React24__default.useState(null);
6899
+ const wrapRef = React24__default.useRef(null);
6900
+ const triggerRef = React24__default.useRef(null);
6901
+ const popRef = React24__default.useRef(null);
6902
+ const gridRef = React24__default.useRef(null);
6746
6903
  const POP_W = 280;
6747
- const place = React23__default.useCallback(() => {
6904
+ const place = React24__default.useCallback(() => {
6748
6905
  const el = triggerRef.current;
6749
6906
  if (!el) return;
6750
6907
  const r = el.getBoundingClientRect();
@@ -6755,7 +6912,7 @@ function DatePicker({
6755
6912
  left = Math.max(8, left);
6756
6913
  setCoords({ left, top: flip ? void 0 : Math.round(r.bottom + 6), bottom: flip ? Math.round(vh - r.top + 6) : void 0 });
6757
6914
  }, []);
6758
- React23__default.useEffect(() => {
6915
+ React24__default.useEffect(() => {
6759
6916
  if (!open) return void 0;
6760
6917
  place();
6761
6918
  const onMove = () => place();
@@ -6766,7 +6923,7 @@ function DatePicker({
6766
6923
  window.removeEventListener("resize", onMove);
6767
6924
  };
6768
6925
  }, [open, place]);
6769
- React23__default.useEffect(() => {
6926
+ React24__default.useEffect(() => {
6770
6927
  if (!open) return;
6771
6928
  setView(selected || /* @__PURE__ */ new Date());
6772
6929
  setMode("days");
@@ -6786,8 +6943,8 @@ function DatePicker({
6786
6943
  document.removeEventListener("keydown", onKey);
6787
6944
  };
6788
6945
  }, [open]);
6789
- const prevOpen = React23__default.useRef(false);
6790
- React23__default.useEffect(() => {
6946
+ const prevOpen = React24__default.useRef(false);
6947
+ React24__default.useEffect(() => {
6791
6948
  let id2;
6792
6949
  if (!prevOpen.current && open) {
6793
6950
  id2 = setTimeout(() => gridRef.current?.querySelector('[tabindex="0"]')?.focus({ preventScroll: true }), 30);
@@ -6798,9 +6955,9 @@ function DatePicker({
6798
6955
  prevOpen.current = open;
6799
6956
  return () => clearTimeout(id2);
6800
6957
  }, [open]);
6801
- const months = React23__default.useMemo(() => locale === void 0 ? MONTHS : monthNames(locale), [locale]);
6802
- const monthsShort = React23__default.useMemo(() => locale === void 0 ? MONTHS.map((n) => n.slice(0, 3)) : monthShortNames(locale), [locale]);
6803
- const dows = React23__default.useMemo(
6958
+ const months = React24__default.useMemo(() => locale === void 0 ? MONTHS : monthNames(locale), [locale]);
6959
+ const monthsShort = React24__default.useMemo(() => locale === void 0 ? MONTHS.map((n) => n.slice(0, 3)) : monthShortNames(locale), [locale]);
6960
+ const dows = React24__default.useMemo(
6804
6961
  () => locale === void 0 ? Array.from({ length: 7 }, (_, i) => DOW[(i + weekStartsOn) % 7]) : weekdayNames(locale, weekStartsOn),
6805
6962
  [locale, weekStartsOn]
6806
6963
  );
@@ -6828,7 +6985,7 @@ function DatePicker({
6828
6985
  };
6829
6986
  const cells = Array.from({ length: 42 }, (_, i) => new Date(gridStart.getFullYear(), gridStart.getMonth(), gridStart.getDate() + i));
6830
6987
  const tabbableDate = (focusDate && cells.some((c) => sameDay(c, focusDate)) ? focusDate : null) || (selected && cells.some((c) => sameDay(c, selected)) ? selected : null) || (cells.some((c) => sameDay(c, today)) ? today : null) || new Date(y, m, 1);
6831
- React23__default.useEffect(() => {
6988
+ React24__default.useEffect(() => {
6832
6989
  if (!open || mode !== "days" || !focusDate) return;
6833
6990
  gridRef.current?.querySelector(`[data-key="${keyOf(focusDate)}"]`)?.focus();
6834
6991
  }, [focusDate, open, mode]);
@@ -7051,23 +7208,23 @@ function DateRangePicker({
7051
7208
  }) {
7052
7209
  const __twcStyles0 = useScopedStyles("twc-field-styles", FIELD_CSS4);
7053
7210
  const __twcStyles1 = useScopedStyles("twc-drp-styles", RANGE_CSS);
7054
- const [internal, setInternal] = React23__default.useState(defaultValue);
7211
+ const [internal, setInternal] = React24__default.useState(defaultValue);
7055
7212
  const range = value !== void 0 ? value : internal;
7056
- const [open, setOpen] = React23__default.useState(false);
7057
- const [view, setView] = React23__default.useState(range.start || /* @__PURE__ */ new Date());
7058
- const [hover, setHover] = React23__default.useState(null);
7059
- const [coords, setCoords] = React23__default.useState(null);
7060
- const wrapRef = React23__default.useRef(null);
7061
- const triggerRef = React23__default.useRef(null);
7062
- const popRef = React23__default.useRef(null);
7063
- const labelId = React23__default.useId();
7213
+ const [open, setOpen] = React24__default.useState(false);
7214
+ const [view, setView] = React24__default.useState(range.start || /* @__PURE__ */ new Date());
7215
+ const [hover, setHover] = React24__default.useState(null);
7216
+ const [coords, setCoords] = React24__default.useState(null);
7217
+ const wrapRef = React24__default.useRef(null);
7218
+ const triggerRef = React24__default.useRef(null);
7219
+ const popRef = React24__default.useRef(null);
7220
+ const labelId = React24__default.useId();
7064
7221
  const descId = `${labelId}-desc`;
7065
7222
  const invalid = Boolean(error);
7066
- React23__default.useEffect(() => {
7223
+ React24__default.useEffect(() => {
7067
7224
  if (disabled) setOpen(false);
7068
7225
  }, [disabled]);
7069
7226
  const POP_W = 420;
7070
- const place = React23__default.useCallback(() => {
7227
+ const place = React24__default.useCallback(() => {
7071
7228
  const el = triggerRef.current;
7072
7229
  if (!el) return;
7073
7230
  const r = el.getBoundingClientRect();
@@ -7078,7 +7235,7 @@ function DateRangePicker({
7078
7235
  left = Math.max(8, left);
7079
7236
  setCoords({ left, top: flip ? void 0 : Math.round(r.bottom + 6), bottom: flip ? Math.round(vh - r.top + 6) : void 0 });
7080
7237
  }, []);
7081
- React23__default.useEffect(() => {
7238
+ React24__default.useEffect(() => {
7082
7239
  if (!open) return void 0;
7083
7240
  place();
7084
7241
  const onMove = () => place();
@@ -7089,7 +7246,7 @@ function DateRangePicker({
7089
7246
  window.removeEventListener("resize", onMove);
7090
7247
  };
7091
7248
  }, [open, place]);
7092
- React23__default.useEffect(() => {
7249
+ React24__default.useEffect(() => {
7093
7250
  if (!open) return;
7094
7251
  const onDown = (e) => {
7095
7252
  if (wrapRef.current && wrapRef.current.contains(e.target)) return;
@@ -7127,8 +7284,8 @@ function DateRangePicker({
7127
7284
  setView(start);
7128
7285
  setOpen(false);
7129
7286
  };
7130
- const months = React23__default.useMemo(() => locale === void 0 ? MONTHS2 : monthNames2(locale), [locale]);
7131
- const dows = React23__default.useMemo(
7287
+ const months = React24__default.useMemo(() => locale === void 0 ? MONTHS2 : monthNames2(locale), [locale]);
7288
+ const dows = React24__default.useMemo(
7132
7289
  () => locale === void 0 ? Array.from({ length: 7 }, (_, i) => DOW2[(i + weekStartsOn) % 7]) : weekdayNames2(locale, weekStartsOn),
7133
7290
  [locale, weekStartsOn]
7134
7291
  );
@@ -7309,13 +7466,14 @@ function Dialog({
7309
7466
  className = "",
7310
7467
  ...rest
7311
7468
  }) {
7312
- const autoId = React23__default.useId();
7469
+ const autoId = React24__default.useId();
7313
7470
  const titleId = `${autoId}-title`;
7314
7471
  const descId = `${autoId}-desc`;
7315
- const dialogRef = React23__default.useRef(null);
7472
+ const dialogRef = React24__default.useRef(null);
7316
7473
  const __twcStyles = useScopedStyles("twc-dialog-styles", DIALOG_CSS);
7317
- const [mounted, setMounted] = React23__default.useState(open);
7318
- React23__default.useEffect(() => {
7474
+ const renderPortal = usePortal();
7475
+ const [mounted, setMounted] = React24__default.useState(open);
7476
+ React24__default.useEffect(() => {
7319
7477
  if (open) {
7320
7478
  setMounted(true);
7321
7479
  return;
@@ -7323,7 +7481,7 @@ function Dialog({
7323
7481
  const t = setTimeout(() => setMounted(false), 170);
7324
7482
  return () => clearTimeout(t);
7325
7483
  }, [open]);
7326
- React23__default.useEffect(() => {
7484
+ React24__default.useEffect(() => {
7327
7485
  if (!open) return void 0;
7328
7486
  const prev = document.body.style.overflow;
7329
7487
  document.body.style.overflow = "hidden";
@@ -7331,48 +7489,13 @@ function Dialog({
7331
7489
  document.body.style.overflow = prev;
7332
7490
  };
7333
7491
  }, [open]);
7334
- React23__default.useEffect(() => {
7335
- if (!open || !mounted) return void 0;
7336
- const node = dialogRef.current;
7337
- const prevFocused = document.activeElement;
7338
- const first = node?.querySelector(
7339
- 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
7340
- );
7341
- (first || node)?.focus();
7342
- return () => {
7343
- if (prevFocused && typeof prevFocused.focus === "function") prevFocused.focus();
7344
- };
7345
- }, [open, mounted]);
7346
- React23__default.useEffect(() => {
7347
- if (!open) return;
7348
- const node = dialogRef.current;
7349
- const focusables = () => node ? Array.from(
7350
- node.querySelectorAll(
7351
- 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
7352
- )
7353
- ).filter((el) => el.offsetParent !== null) : [];
7492
+ useFocusTrap(dialogRef, open && mounted);
7493
+ React24__default.useEffect(() => {
7494
+ if (!open) return void 0;
7354
7495
  const onKey = (e) => {
7355
7496
  if (e.key === "Escape") {
7356
7497
  e.preventDefault();
7357
7498
  onClose?.();
7358
- return;
7359
- }
7360
- if (e.key !== "Tab") return;
7361
- const f = focusables();
7362
- if (!f.length) {
7363
- e.preventDefault();
7364
- node?.focus();
7365
- return;
7366
- }
7367
- const first = f[0], last = f[f.length - 1], ae = document.activeElement;
7368
- if (e.shiftKey) {
7369
- if (ae === first || ae === node || !node.contains(ae)) {
7370
- e.preventDefault();
7371
- last.focus();
7372
- }
7373
- } else if (ae === last || !node.contains(ae)) {
7374
- e.preventDefault();
7375
- first.focus();
7376
7499
  }
7377
7500
  };
7378
7501
  document.addEventListener("keydown", onKey);
@@ -7396,9 +7519,7 @@ function Dialog({
7396
7519
  footer ? /* @__PURE__ */ jsx("div", { className: "twc-dialog__footer", children: footer }) : null
7397
7520
  ] })
7398
7521
  ] });
7399
- if (typeof document === "undefined") return null;
7400
- const RD = typeof createPortal === "function" ? createPortal : null;
7401
- return RD ? RD(overlay, document.body) : overlay;
7522
+ return renderPortal(overlay);
7402
7523
  }
7403
7524
  var DIVIDER_CSS = `
7404
7525
  .twc-divider { border: none; background: var(--color-divider); }
@@ -7413,6 +7534,10 @@ var DIVIDER_CSS = `
7413
7534
  so ::before/::after land on the correct inline edge under RTL \u2014 no physical override needed. */
7414
7535
  .twc-divider-label[data-align="start"]::before { flex: 0 0 var(--space-6); }
7415
7536
  .twc-divider-label[data-align="end"]::after { flex: 0 0 var(--space-6); }
7537
+ /* Vertical labeled divider: stack the two segments above/below the label. */
7538
+ .twc-divider-label[data-orientation="vertical"] { flex-direction: column; align-self: stretch; min-height: 1em; margin: 0 var(--space-3); }
7539
+ .twc-divider-label[data-orientation="vertical"]::before,
7540
+ .twc-divider-label[data-orientation="vertical"]::after { width: 1px; height: auto; flex: 1; }
7416
7541
  `;
7417
7542
  function Divider({
7418
7543
  orientation = "horizontal",
@@ -7425,7 +7550,7 @@ function Divider({
7425
7550
  const __twcStyles = useScopedStyles("twc-divider-styles", DIVIDER_CSS);
7426
7551
  const resolvedAlign = align === "left" ? "start" : align === "right" ? "end" : align;
7427
7552
  if (children) {
7428
- return /* @__PURE__ */ jsxs("div", { className: `twc-divider-label ${className}`, "data-align": resolvedAlign, role: "separator", ...rest, children: [
7553
+ return /* @__PURE__ */ jsxs("div", { className: `twc-divider-label ${className}`, "data-align": resolvedAlign, "data-orientation": orientation, role: "separator", "aria-orientation": orientation, ...rest, children: [
7429
7554
  __twcStyles,
7430
7555
  children
7431
7556
  ] });
@@ -7512,13 +7637,14 @@ function Drawer({
7512
7637
  style,
7513
7638
  ...rest
7514
7639
  }) {
7515
- const autoId = React23__default.useId();
7640
+ const autoId = React24__default.useId();
7516
7641
  const titleId = `${autoId}-title`;
7517
7642
  const descId = `${autoId}-desc`;
7518
- const panelRef = React23__default.useRef(null);
7643
+ const panelRef = React24__default.useRef(null);
7519
7644
  const __twcStyles = useScopedStyles("twc-drawer-styles", DRAWER_CSS);
7520
- const [mounted, setMounted] = React23__default.useState(open);
7521
- React23__default.useEffect(() => {
7645
+ const renderPortal = usePortal();
7646
+ const [mounted, setMounted] = React24__default.useState(open);
7647
+ React24__default.useEffect(() => {
7522
7648
  if (open) {
7523
7649
  setMounted(true);
7524
7650
  return;
@@ -7526,7 +7652,7 @@ function Drawer({
7526
7652
  const t = setTimeout(() => setMounted(false), 170);
7527
7653
  return () => clearTimeout(t);
7528
7654
  }, [open]);
7529
- React23__default.useEffect(() => {
7655
+ React24__default.useEffect(() => {
7530
7656
  if (!open) return void 0;
7531
7657
  const prev = document.body.style.overflow;
7532
7658
  document.body.style.overflow = "hidden";
@@ -7534,48 +7660,13 @@ function Drawer({
7534
7660
  document.body.style.overflow = prev;
7535
7661
  };
7536
7662
  }, [open]);
7537
- React23__default.useEffect(() => {
7538
- if (!open || !mounted) return void 0;
7539
- const node = panelRef.current;
7540
- const prevFocused = document.activeElement;
7541
- const first = node?.querySelector(
7542
- 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
7543
- );
7544
- (first || node)?.focus();
7545
- return () => {
7546
- if (prevFocused && typeof prevFocused.focus === "function") prevFocused.focus();
7547
- };
7548
- }, [open, mounted]);
7549
- React23__default.useEffect(() => {
7550
- if (!open) return;
7551
- const node = panelRef.current;
7552
- const focusables = () => node ? Array.from(
7553
- node.querySelectorAll(
7554
- 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
7555
- )
7556
- ).filter((el) => el.offsetParent !== null) : [];
7663
+ useFocusTrap(panelRef, open && mounted);
7664
+ React24__default.useEffect(() => {
7665
+ if (!open) return void 0;
7557
7666
  const onKey = (e) => {
7558
7667
  if (e.key === "Escape") {
7559
7668
  e.preventDefault();
7560
7669
  onClose?.();
7561
- return;
7562
- }
7563
- if (e.key !== "Tab") return;
7564
- const f = focusables();
7565
- if (!f.length) {
7566
- e.preventDefault();
7567
- node?.focus();
7568
- return;
7569
- }
7570
- const first = f[0], last = f[f.length - 1], ae = document.activeElement;
7571
- if (e.shiftKey) {
7572
- if (ae === first || ae === node || !node.contains(ae)) {
7573
- e.preventDefault();
7574
- last.focus();
7575
- }
7576
- } else if (ae === last || !node.contains(ae)) {
7577
- e.preventDefault();
7578
- first.focus();
7579
7670
  }
7580
7671
  };
7581
7672
  document.addEventListener("keydown", onKey);
@@ -7603,9 +7694,7 @@ function Drawer({
7603
7694
  footer ? /* @__PURE__ */ jsx("div", { className: "twc-drawer__footer", children: footer }) : null
7604
7695
  ] })
7605
7696
  ] });
7606
- if (typeof document === "undefined") return null;
7607
- const RD = typeof createPortal === "function" ? createPortal : null;
7608
- return RD ? RD(overlay, document.body) : overlay;
7697
+ return renderPortal(overlay);
7609
7698
  }
7610
7699
  var EMPTY_CSS = `
7611
7700
  .twc-empty { display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--space-3);
@@ -7623,11 +7712,14 @@ function EmptyState({
7623
7712
  title,
7624
7713
  description,
7625
7714
  actions,
7626
- bordered = false,
7715
+ bordered,
7627
7716
  border,
7628
7717
  className = "",
7629
7718
  ...rest
7630
7719
  }) {
7720
+ if (process.env.NODE_ENV !== "production" && bordered !== void 0 && border === void 0) {
7721
+ warnOnce("EmptyState.bordered", "EmptyState: `bordered` is deprecated and will be removed in 2.0 \u2014 use `border`.");
7722
+ }
7631
7723
  const hasBorder = border ?? bordered;
7632
7724
  const __twcStyles = useScopedStyles("twc-empty-styles", EMPTY_CSS);
7633
7725
  return /* @__PURE__ */ jsxs("div", { className: `twc-empty ${className}`, "data-bordered": hasBorder || void 0, ...rest, children: [
@@ -7658,7 +7750,7 @@ function Field({
7658
7750
  ...rest
7659
7751
  }) {
7660
7752
  const __twcStyles = useScopedStyles("twc-field-styles", FIELD_CSS5);
7661
- const autoId = React23__default.useId();
7753
+ const autoId = React24__default.useId();
7662
7754
  const fieldId = id || autoId;
7663
7755
  const descId = `${fieldId}-desc`;
7664
7756
  return /* @__PURE__ */ jsxs("div", { className: `twc-field ${className}`, "data-size": size, ...rest, children: [
@@ -7738,11 +7830,11 @@ function FileUpload({
7738
7830
  ...rest
7739
7831
  }) {
7740
7832
  const __twcStyles = useScopedStyles("twc-upload-styles", UPLOAD_CSS);
7741
- const [internal, setInternal] = React23__default.useState(defaultValue);
7833
+ const [internal, setInternal] = React24__default.useState(defaultValue);
7742
7834
  const files = value !== void 0 ? value : internal;
7743
- const [drag, setDrag] = React23__default.useState(false);
7744
- const inputRef = React23__default.useRef(null);
7745
- const autoId = React23__default.useId();
7835
+ const [drag, setDrag] = React24__default.useState(false);
7836
+ const inputRef = React24__default.useRef(null);
7837
+ const autoId = React24__default.useId();
7746
7838
  const fieldId = id || autoId;
7747
7839
  const descId = `${fieldId}-desc`;
7748
7840
  const invalid = Boolean(error);
@@ -7940,19 +8032,20 @@ function Kanban({
7940
8032
  defaultCards,
7941
8033
  onCardMove,
7942
8034
  renderCard,
8035
+ getCardLabel,
7943
8036
  className = "",
7944
8037
  ...rest
7945
8038
  }) {
7946
8039
  const __twcStyles = useScopedStyles("twc-kanban-styles", KANBAN_CSS);
7947
- const [internal, setInternal] = React23__default.useState(cards ?? defaultCards ?? []);
8040
+ const [internal, setInternal] = React24__default.useState(cards ?? defaultCards ?? []);
7948
8041
  const items = cards !== void 0 ? cards : internal;
7949
- const [drag, setDrag] = React23__default.useState(null);
7950
- const [overCol, setOverCol] = React23__default.useState(null);
7951
- const [grab, setGrab] = React23__default.useState(null);
7952
- const [announce, setAnnounce] = React23__default.useState("");
7953
- const rootRef = React23__default.useRef(null);
7954
- const focusIdRef = React23__default.useRef(null);
7955
- React23__default.useEffect(() => {
8042
+ const [drag, setDrag] = React24__default.useState(null);
8043
+ const [overCol, setOverCol] = React24__default.useState(null);
8044
+ const [grab, setGrab] = React24__default.useState(null);
8045
+ const [announce, setAnnounce] = React24__default.useState("");
8046
+ const rootRef = React24__default.useRef(null);
8047
+ const focusIdRef = React24__default.useRef(null);
8048
+ React24__default.useEffect(() => {
7956
8049
  if (focusIdRef.current == null) return void 0;
7957
8050
  const raf = requestAnimationFrame(() => {
7958
8051
  const id = focusIdRef.current;
@@ -8004,7 +8097,7 @@ function Kanban({
8004
8097
  }
8005
8098
  };
8006
8099
  const keyTargetCol = grab ? columns[grab.targetIdx]?.id : null;
8007
- return /* @__PURE__ */ jsxs("div", { className: `twc-kanban ${className}`, ref: rootRef, ...rest, children: [
8100
+ return /* @__PURE__ */ jsxs("div", { className: `twc-kanban ${className}`, ref: rootRef, role: "group", "aria-label": "Board", ...rest, children: [
8008
8101
  __twcStyles,
8009
8102
  /* @__PURE__ */ jsx("div", { className: "twc-kanban__sr", role: "status", "aria-live": "polite", children: announce }),
8010
8103
  columns.map((col, colIdx) => {
@@ -8014,7 +8107,7 @@ function Kanban({
8014
8107
  {
8015
8108
  className: "twc-kanban__col",
8016
8109
  role: "group",
8017
- "aria-label": typeof col.title === "string" ? col.title : void 0,
8110
+ "aria-label": col.ariaLabel ?? colTitle(col),
8018
8111
  "data-over": overCol === col.id || keyTargetCol === col.id || void 0,
8019
8112
  onDragOver: (e) => {
8020
8113
  e.preventDefault();
@@ -8045,6 +8138,8 @@ function Kanban({
8045
8138
  tabIndex: 0,
8046
8139
  "aria-roledescription": "draggable card",
8047
8140
  "data-card-id": card.id,
8141
+ "aria-label": getCardLabel?.(card) ?? (typeof card.ariaLabel === "string" ? card.ariaLabel : cardTitle(card)),
8142
+ "aria-pressed": grab && grab.id === card.id || void 0,
8048
8143
  "data-grabbed": grab && grab.id === card.id || void 0,
8049
8144
  onKeyDown: (e) => handleCardKey(e, card, colIdx),
8050
8145
  onBlur: () => {
@@ -8098,7 +8193,7 @@ var LIST_CSS = `
8098
8193
  `;
8099
8194
  function List({ items, plain = false, className = "", ...rest }) {
8100
8195
  const __twcStyles = useScopedStyles("twc-list-styles", LIST_CSS);
8101
- const safeHref11 = (url) => {
8196
+ const safeHref12 = (url) => {
8102
8197
  if (url == null) return void 0;
8103
8198
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
8104
8199
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -8106,7 +8201,7 @@ function List({ items, plain = false, className = "", ...rest }) {
8106
8201
  return /* @__PURE__ */ jsxs("ul", { className: `twc-list ${className}`, "data-plain": plain || void 0, ...rest, children: [
8107
8202
  __twcStyles,
8108
8203
  items.map((it, i) => {
8109
- const href = safeHref11(it.href);
8204
+ const href = safeHref12(it.href);
8110
8205
  const interactive = Boolean(it.onClick || href);
8111
8206
  const Tag2 = href ? "a" : interactive ? "button" : "div";
8112
8207
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -8160,7 +8255,7 @@ button.twc-navbar__brand, a.twc-navbar__brand { cursor: pointer; }
8160
8255
  .twc-navbar__menu-btn { display: inline-grid; }
8161
8256
  }
8162
8257
  `;
8163
- function safeHref3(url) {
8258
+ function safeHref4(url) {
8164
8259
  if (url == null) return void 0;
8165
8260
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
8166
8261
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -8173,16 +8268,19 @@ function Navbar({
8173
8268
  actions,
8174
8269
  sticky = true,
8175
8270
  onMenuClick,
8271
+ menuOpen,
8272
+ menuControls,
8273
+ navLabel = "Primary",
8176
8274
  className = "",
8177
8275
  ...rest
8178
8276
  }) {
8179
8277
  const __twcStyles = useScopedStyles("twc-navbar-styles", NAVBAR_CSS);
8180
8278
  return /* @__PURE__ */ jsxs("header", { className: `twc-navbar ${className}`, "data-sticky": sticky || void 0, ...rest, children: [
8181
8279
  __twcStyles,
8182
- onMenuClick ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-navbar__menu-btn", "aria-label": "Open menu", onClick: onMenuClick, children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M4 6h16M4 12h16M4 18h16" }) }) }) : null,
8183
- brand ? brandHref ? /* @__PURE__ */ jsx("a", { className: "twc-navbar__brand", href: safeHref3(brandHref), children: brand }) : onBrandClick ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-navbar__brand", onClick: onBrandClick, children: brand }) : /* @__PURE__ */ jsx("span", { className: "twc-navbar__brand", children: brand }) : null,
8184
- /* @__PURE__ */ jsx("nav", { className: "twc-navbar__links", children: links.map((l, i) => {
8185
- const href = safeHref3(l.href);
8280
+ onMenuClick ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-navbar__menu-btn", "aria-expanded": menuOpen, "aria-controls": menuControls, "aria-label": menuOpen ? "Close menu" : "Open menu", onClick: onMenuClick, children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M4 6h16M4 12h16M4 18h16" }) }) }) : null,
8281
+ brand ? brandHref ? /* @__PURE__ */ jsx("a", { className: "twc-navbar__brand", href: safeHref4(brandHref), children: brand }) : onBrandClick ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-navbar__brand", onClick: onBrandClick, children: brand }) : /* @__PURE__ */ jsx("span", { className: "twc-navbar__brand", children: brand }) : null,
8282
+ /* @__PURE__ */ jsx("nav", { className: "twc-navbar__links", "aria-label": navLabel, children: links.map((l, i) => {
8283
+ const href = safeHref4(l.href);
8186
8284
  const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
8187
8285
  l.icon,
8188
8286
  l.label
@@ -8250,21 +8348,21 @@ function Popover({
8250
8348
  ...rest
8251
8349
  }) {
8252
8350
  const __twcStyles = useScopedStyles("twc-popover-styles", POPOVER_CSS);
8253
- const [openState, setOpenState] = React23__default.useState(defaultOpen);
8254
- const [render, setRender] = React23__default.useState(false);
8255
- const [pos, setPos] = React23__default.useState(null);
8256
- const wrapRef = React23__default.useRef(null);
8257
- const popRef = React23__default.useRef(null);
8258
- const popId = React23__default.useId();
8351
+ const [openState, setOpenState] = React24__default.useState(defaultOpen);
8352
+ const [render, setRender] = React24__default.useState(false);
8353
+ const [pos, setPos] = React24__default.useState(null);
8354
+ const wrapRef = React24__default.useRef(null);
8355
+ const popRef = React24__default.useRef(null);
8356
+ const popId = React24__default.useId();
8259
8357
  const controlled = openProp !== void 0;
8260
8358
  const open = controlled ? !!openProp : openState;
8261
- const openRef = React23__default.useRef(open);
8359
+ const openRef = React24__default.useRef(open);
8262
8360
  openRef.current = open;
8263
- const controlledRef = React23__default.useRef(controlled);
8361
+ const controlledRef = React24__default.useRef(controlled);
8264
8362
  controlledRef.current = controlled;
8265
- const onOpenChangeRef = React23__default.useRef(onOpenChange);
8363
+ const onOpenChangeRef = React24__default.useRef(onOpenChange);
8266
8364
  onOpenChangeRef.current = onOpenChange;
8267
- const setOpen = React23__default.useCallback((next) => {
8365
+ const setOpen = React24__default.useCallback((next) => {
8268
8366
  const value = typeof next === "function" ? next(openRef.current) : next;
8269
8367
  if (value === openRef.current) return;
8270
8368
  if (!controlledRef.current) setOpenState(value);
@@ -8272,7 +8370,7 @@ function Popover({
8272
8370
  }, []);
8273
8371
  const toggle = () => setOpen((o) => !o);
8274
8372
  const RD = { createPortal: typeof createPortal === "function" ? createPortal : typeof window !== "undefined" && window.ReactDOM && window.ReactDOM.createPortal };
8275
- const place = React23__default.useCallback(() => {
8373
+ const place = React24__default.useCallback(() => {
8276
8374
  const t = wrapRef.current;
8277
8375
  if (!t) return;
8278
8376
  const r = t.getBoundingClientRect();
@@ -8303,7 +8401,7 @@ function Popover({
8303
8401
  arrow = { top: Math.min(Math.max(cy - top - 5.5, 8), ph - 18), [onRight ? "left" : "right"]: -6 };
8304
8402
  setPos({ top, left, width: w, flip: false, arrow });
8305
8403
  }, [placement, align, width]);
8306
- React23__default.useEffect(() => {
8404
+ React24__default.useEffect(() => {
8307
8405
  if (!open) return;
8308
8406
  place();
8309
8407
  const onMove = () => place();
@@ -8326,7 +8424,7 @@ function Popover({
8326
8424
  document.removeEventListener("keydown", onKey);
8327
8425
  };
8328
8426
  }, [open, place]);
8329
- React23__default.useEffect(() => {
8427
+ React24__default.useEffect(() => {
8330
8428
  if (open) {
8331
8429
  setRender(true);
8332
8430
  return;
@@ -8334,12 +8432,12 @@ function Popover({
8334
8432
  const t = setTimeout(() => setRender(false), 170);
8335
8433
  return () => clearTimeout(t);
8336
8434
  }, [open]);
8337
- React23__default.useEffect(() => {
8435
+ React24__default.useEffect(() => {
8338
8436
  if (render && open) place();
8339
8437
  }, [render, place]);
8340
- const restoreRef = React23__default.useRef(null);
8341
- const needFocusRef = React23__default.useRef(false);
8342
- React23__default.useEffect(() => {
8438
+ const restoreRef = React24__default.useRef(null);
8439
+ const needFocusRef = React24__default.useRef(false);
8440
+ React24__default.useEffect(() => {
8343
8441
  if (open) {
8344
8442
  restoreRef.current = document.activeElement;
8345
8443
  needFocusRef.current = true;
@@ -8350,7 +8448,7 @@ function Popover({
8350
8448
  needFocusRef.current = false;
8351
8449
  if (prev && typeof prev.focus === "function" && popRef.current?.contains(document.activeElement)) prev.focus();
8352
8450
  }, [open]);
8353
- React23__default.useEffect(() => {
8451
+ React24__default.useEffect(() => {
8354
8452
  if (open && render && pos && needFocusRef.current) {
8355
8453
  needFocusRef.current = false;
8356
8454
  popRef.current?.focus({ preventScroll: true });
@@ -8378,7 +8476,7 @@ function Popover({
8378
8476
  ]
8379
8477
  }
8380
8478
  ) : null;
8381
- const triggerEl = React23__default.isValidElement(trigger) ? React23__default.cloneElement(trigger, {
8479
+ const triggerEl = React24__default.isValidElement(trigger) ? React24__default.cloneElement(trigger, {
8382
8480
  onClick: (e) => {
8383
8481
  trigger.props.onClick?.(e);
8384
8482
  toggle();
@@ -8417,9 +8515,12 @@ function Progress({
8417
8515
  size = "md",
8418
8516
  indeterminate = false,
8419
8517
  showLabel = false,
8518
+ label,
8420
8519
  className = "",
8421
8520
  ...rest
8422
8521
  }) {
8522
+ const labelId = React24__default.useId();
8523
+ const { "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...restProps } = rest;
8423
8524
  const __twcStyles = useScopedStyles("twc-progress-styles", `
8424
8525
  .twc-progress-wrap { display: flex; flex-direction: column; gap: 6px; font-family: var(--font-sans); }
8425
8526
  .twc-progress {
@@ -8458,14 +8559,14 @@ function Progress({
8458
8559
  return (
8459
8560
  // Single-root contract: className and ...rest (style, id, handlers, …) share the outer
8460
8561
  // wrapper; role="progressbar" + aria-value* stay on the inner track.
8461
- /* @__PURE__ */ jsxs("div", { className: `twc-progress-wrap ${className}`, ...rest, children: [
8562
+ /* @__PURE__ */ jsxs("div", { className: `twc-progress-wrap ${className}`, ...restProps, children: [
8462
8563
  __twcStyles,
8463
- showLabel && !indeterminate ? /* @__PURE__ */ jsxs("div", { className: "twc-progress__meta", children: [
8464
- /* @__PURE__ */ jsx("span", { children: "Progress" }),
8465
- /* @__PURE__ */ jsxs("span", { children: [
8564
+ (showLabel || label != null) && !indeterminate ? /* @__PURE__ */ jsxs("div", { className: "twc-progress__meta", children: [
8565
+ /* @__PURE__ */ jsx("span", { id: labelId, children: label ?? "Progress" }),
8566
+ showLabel ? /* @__PURE__ */ jsxs("span", { children: [
8466
8567
  Math.round(pct),
8467
8568
  "%"
8468
- ] })
8569
+ ] }) : null
8469
8570
  ] }) : null,
8470
8571
  /* @__PURE__ */ jsx(
8471
8572
  "div",
@@ -8478,6 +8579,8 @@ function Progress({
8478
8579
  "aria-valuenow": indeterminate ? void 0 : Math.round(pct),
8479
8580
  "aria-valuemin": 0,
8480
8581
  "aria-valuemax": 100,
8582
+ "aria-label": ariaLabel,
8583
+ "aria-labelledby": ariaLabelledby ?? (label != null ? labelId : void 0),
8481
8584
  children: /* @__PURE__ */ jsx("div", { className: "twc-progress__bar", style: indeterminate ? void 0 : { width: `${pct}%` } })
8482
8585
  }
8483
8586
  )
@@ -8539,7 +8642,7 @@ function Radio({
8539
8642
  .twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
8540
8643
  .twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
8541
8644
  `);
8542
- const autoId = React23__default.useId();
8645
+ const autoId = React24__default.useId();
8543
8646
  const fieldId = id || autoId;
8544
8647
  const errId = `${fieldId}-error`;
8545
8648
  const invalid = Boolean(error);
@@ -8617,12 +8720,12 @@ function Rating({
8617
8720
  ...rest
8618
8721
  }) {
8619
8722
  const __twcStyles = useScopedStyles("twc-rating-styles", RATING_CSS);
8620
- const [internal, setInternal] = React23__default.useState(defaultValue);
8621
- const [hover, setHover] = React23__default.useState(0);
8723
+ const [internal, setInternal] = React24__default.useState(defaultValue);
8724
+ const [hover, setHover] = React24__default.useState(0);
8622
8725
  const val = value !== void 0 ? value : internal;
8623
8726
  const shown = hover || val;
8624
8727
  const interactive = !readOnly && !disabled;
8625
- const btnRefs = React23__default.useRef([]);
8728
+ const btnRefs = React24__default.useRef([]);
8626
8729
  const tabStar = Math.min(count, Math.max(1, Math.round(val) || 1));
8627
8730
  const set = (v) => {
8628
8731
  if (!interactive) return;
@@ -8716,12 +8819,12 @@ function Tooltip({
8716
8819
  ...rest
8717
8820
  }) {
8718
8821
  const __twcStyles = useScopedStyles("twc-tooltip-styles", TOOLTIP_CSS);
8719
- const id = React23__default.useId();
8720
- const [show, setShow] = React23__default.useState(false);
8721
- const [coords, setCoords] = React23__default.useState(null);
8722
- const timer = React23__default.useRef(null);
8723
- const wrapRef = React23__default.useRef(null);
8724
- const tipRef = React23__default.useRef(null);
8822
+ const id = React24__default.useId();
8823
+ const [show, setShow] = React24__default.useState(false);
8824
+ const [coords, setCoords] = React24__default.useState(null);
8825
+ const timer = React24__default.useRef(null);
8826
+ const wrapRef = React24__default.useRef(null);
8827
+ const tipRef = React24__default.useRef(null);
8725
8828
  const open = () => {
8726
8829
  clearTimeout(timer.current);
8727
8830
  timer.current = setTimeout(() => setShow(true), delay);
@@ -8730,8 +8833,8 @@ function Tooltip({
8730
8833
  clearTimeout(timer.current);
8731
8834
  setShow(false);
8732
8835
  };
8733
- React23__default.useEffect(() => () => clearTimeout(timer.current), []);
8734
- const place = React23__default.useCallback(() => {
8836
+ React24__default.useEffect(() => () => clearTimeout(timer.current), []);
8837
+ const place = React24__default.useCallback(() => {
8735
8838
  const el = wrapRef.current;
8736
8839
  if (!el) return;
8737
8840
  const r = el.getBoundingClientRect();
@@ -8747,10 +8850,10 @@ function Tooltip({
8747
8850
  else if (placement === "right") setCoords({ ...base, top: clampY(cy), left: Math.round(r.right + gap) });
8748
8851
  else setCoords({ ...base, left: clampX(cx), bottom: Math.round(vh - r.top + gap) });
8749
8852
  }, [placement]);
8750
- React23__default.useEffect(() => {
8853
+ React24__default.useEffect(() => {
8751
8854
  place();
8752
8855
  }, [place]);
8753
- React23__default.useEffect(() => {
8856
+ React24__default.useEffect(() => {
8754
8857
  if (!show) return void 0;
8755
8858
  place();
8756
8859
  const onMove = () => place();
@@ -8761,7 +8864,7 @@ function Tooltip({
8761
8864
  window.removeEventListener("resize", onMove);
8762
8865
  };
8763
8866
  }, [show, place]);
8764
- React23__default.useEffect(() => {
8867
+ React24__default.useEffect(() => {
8765
8868
  if (!show) return;
8766
8869
  const onKeyDown = (e) => {
8767
8870
  if (e.key === "Escape") {
@@ -8773,7 +8876,7 @@ function Tooltip({
8773
8876
  return () => document.removeEventListener("keydown", onKeyDown);
8774
8877
  }, [show]);
8775
8878
  const describedBy = show ? id : void 0;
8776
- const trigger = React23__default.isValidElement(children) && children.type !== React23__default.Fragment ? React23__default.cloneElement(children, {
8879
+ const trigger = React24__default.isValidElement(children) && children.type !== React24__default.Fragment ? React24__default.cloneElement(children, {
8777
8880
  "aria-describedby": [children.props["aria-describedby"], describedBy].filter(Boolean).join(" ") || void 0
8778
8881
  }) : /* @__PURE__ */ jsx("span", { "aria-describedby": describedBy, children });
8779
8882
  return /* @__PURE__ */ jsxs(
@@ -8829,6 +8932,7 @@ var SIDEBAR_CSS = `
8829
8932
  .twc-sidebar__brand { display: inline-flex; align-items: center; gap: var(--space-2-5); font-weight: var(--font-extrabold); font-size: var(--text-lg); letter-spacing: -0.02em; color: var(--color-text); white-space: nowrap; overflow: hidden; min-width: 0;
8830
8933
  transition: font-size var(--duration-base) var(--ease-standard), gap var(--duration-base) var(--ease-standard); }
8831
8934
  .twc-sidebar__nav { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: var(--space-3); display: flex; flex-direction: column; gap: 2px; }
8935
+ .twc-sidebar__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
8832
8936
  .twc-sidebar__section { font-size: 10px; font-weight: var(--font-bold); letter-spacing: var(--tracking-wider); text-transform: uppercase; color: var(--color-text-subtle); padding: var(--space-3) var(--space-3) var(--space-1); white-space: nowrap; overflow: hidden; max-height: 2.5rem; opacity: 1; visibility: visible;
8833
8937
  transition: max-height var(--duration-base) var(--ease-standard), padding var(--duration-base) var(--ease-standard), opacity var(--duration-fast) var(--ease-standard) var(--duration-fast), visibility 0s; }
8834
8938
  .twc-sidebar[data-collapsed="true"] .twc-sidebar__section { max-height: 0; padding-top: 0; padding-bottom: 0; opacity: 0; visibility: hidden;
@@ -8870,6 +8974,23 @@ var SIDEBAR_CSS = `
8870
8974
  .twc-sidebar[data-collapsed="true"] .twc-sidebar__foot { display: flex; flex-direction: column; align-items: center; padding: var(--space-2) 0; }
8871
8975
  .twc-sidebar[data-collapsed="true"] .twc-sidebar__collapse { width: auto; padding: 11px; gap: 0; margin: 0; }
8872
8976
  .twc-sidebar[data-collapsed="true"] .twc-sidebar__collapse span { display: none; }
8977
+
8978
+ /* Off-canvas overlay mode (mobile): the rail becomes a slide-over drawer behind a
8979
+ scrim, mirroring Drawer.jsx. Logical inset + a --_off var slide it in from the
8980
+ inline-start edge (mirrored under dir="rtl"). */
8981
+ .twc-sidebar__overlay { position: fixed; inset: 0; z-index: var(--z-modal); background: var(--color-overlay); backdrop-filter: blur(2px); }
8982
+ .twc-sidebar__overlay[data-state="open"] { animation: twico-fade-in var(--duration-base) var(--ease-out); }
8983
+ .twc-sidebar__overlay[data-state="closed"] { animation: twc-sidebar-fade-out var(--duration-exit) var(--ease-in) forwards; pointer-events: none; }
8984
+ @keyframes twc-sidebar-fade-out { from { opacity: 1; } to { opacity: 0; } }
8985
+ .twc-sidebar--overlay { position: fixed; inset-block: 0; inset-inline-start: 0; height: 100%; max-width: 92vw; z-index: var(--z-modal); box-shadow: var(--shadow-xl); --_off: -100%; }
8986
+ [dir="rtl"] .twc-sidebar--overlay { inset-inline-start: auto; inset-inline-end: 0; --_off: 100%; }
8987
+ .twc-sidebar--overlay[data-state="open"] { animation: twc-sidebar-in var(--duration-base) var(--ease-out); }
8988
+ .twc-sidebar--overlay[data-state="closed"] { animation: twc-sidebar-out var(--duration-exit) var(--ease-in) forwards; }
8989
+ @keyframes twc-sidebar-in { from { transform: translateX(var(--_off)); } to { transform: translateX(0); } }
8990
+ @keyframes twc-sidebar-out { from { transform: translateX(0); } to { transform: translateX(var(--_off)); } }
8991
+ @media (prefers-reduced-motion: reduce) {
8992
+ .twc-sidebar__overlay[data-state], .twc-sidebar--overlay[data-state] { animation-duration: 1ms; }
8993
+ }
8873
8994
  `;
8874
8995
  function Sidebar({
8875
8996
  brand,
@@ -8879,63 +9000,149 @@ function Sidebar({
8879
9000
  defaultCollapsed = false,
8880
9001
  collapsible = true,
8881
9002
  onCollapsedChange,
9003
+ overlay = false,
9004
+ open: openProp,
9005
+ defaultOpen = false,
9006
+ onOpenChange,
9007
+ navLabel = "Main",
8882
9008
  className = "",
8883
9009
  ...rest
8884
9010
  }) {
8885
9011
  const __twcStyles = useScopedStyles("twc-sidebar-styles", SIDEBAR_CSS);
8886
- const [internal, setInternal] = React23__default.useState(defaultCollapsed);
9012
+ const navId = React24__default.useId();
9013
+ const panelRef = React24__default.useRef(null);
9014
+ const renderPortal = usePortal();
9015
+ const [internal, setInternal] = React24__default.useState(defaultCollapsed);
8887
9016
  const collapsed = collapsedProp !== void 0 ? collapsedProp : internal;
8888
9017
  const toggle = () => {
8889
9018
  const next = !collapsed;
8890
9019
  if (collapsedProp === void 0) setInternal(next);
8891
9020
  onCollapsedChange?.(next);
8892
9021
  };
8893
- const safeHref11 = (url) => {
9022
+ const [openInternal, setOpenInternal] = React24__default.useState(defaultOpen);
9023
+ const open = openProp !== void 0 ? openProp : openInternal;
9024
+ const setOpen = (next) => {
9025
+ if (openProp === void 0) setOpenInternal(next);
9026
+ onOpenChange?.(next);
9027
+ };
9028
+ const [mounted, setMounted] = React24__default.useState(open);
9029
+ React24__default.useEffect(() => {
9030
+ if (!overlay) return void 0;
9031
+ if (open) {
9032
+ setMounted(true);
9033
+ return void 0;
9034
+ }
9035
+ const t = setTimeout(() => setMounted(false), 170);
9036
+ return () => clearTimeout(t);
9037
+ }, [overlay, open]);
9038
+ React24__default.useEffect(() => {
9039
+ if (!overlay || !open) return void 0;
9040
+ const prev = document.body.style.overflow;
9041
+ document.body.style.overflow = "hidden";
9042
+ return () => {
9043
+ document.body.style.overflow = prev;
9044
+ };
9045
+ }, [overlay, open]);
9046
+ useFocusTrap(panelRef, overlay && open && mounted);
9047
+ React24__default.useEffect(() => {
9048
+ if (!overlay || !open) return void 0;
9049
+ const onKey = (e) => {
9050
+ if (e.key === "Escape") {
9051
+ e.preventDefault();
9052
+ if (openProp === void 0) setOpenInternal(false);
9053
+ onOpenChange?.(false);
9054
+ }
9055
+ };
9056
+ document.addEventListener("keydown", onKey);
9057
+ return () => document.removeEventListener("keydown", onKey);
9058
+ }, [overlay, open, openProp, onOpenChange]);
9059
+ const safeHref12 = (url) => {
8894
9060
  if (url == null) return void 0;
8895
9061
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
8896
9062
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
8897
9063
  };
8898
- return /* @__PURE__ */ jsxs("aside", { className: `twc-sidebar ${className}`, "data-collapsed": collapsed || void 0, ...rest, children: [
9064
+ const renderItem = (it, i) => {
9065
+ const href = safeHref12(it.href);
9066
+ const labelStr = typeof it.label === "string" ? it.label : void 0;
9067
+ const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
9068
+ it.icon ? /* @__PURE__ */ jsx("span", { className: "twc-sidebar__ic", "aria-hidden": "true", children: it.icon }) : labelStr != null ? /* @__PURE__ */ jsx("span", { className: "twc-sidebar__ic twc-sidebar__ic--initial", "aria-hidden": "true", children: labelStr.charAt(0) }) : null,
9069
+ /* @__PURE__ */ jsx("span", { className: "twc-sidebar__label", children: it.label }),
9070
+ it.badge != null ? /* @__PURE__ */ jsx("span", { className: "twc-sidebar__badge", children: it.badge }) : null
9071
+ ] });
9072
+ const common = {
9073
+ className: "twc-sidebar__item",
9074
+ "data-active": it.active || void 0,
9075
+ "aria-current": it.active ? "page" : void 0,
9076
+ onClick: it.onClick,
9077
+ "aria-label": collapsed && labelStr != null ? labelStr : void 0
9078
+ };
9079
+ const node = href != null ? /* @__PURE__ */ jsx("a", { href, ...common, children: inner }) : /* @__PURE__ */ jsx("button", { type: "button", ...common, children: inner });
9080
+ return collapsed && labelStr != null ? /* @__PURE__ */ jsx(Tooltip, { label: labelStr, placement: "right", style: { display: "block" }, children: node }) : node;
9081
+ };
9082
+ const groups = [];
9083
+ let group = { sid: null, section: null, entries: [] };
9084
+ let secN = 0;
9085
+ for (let i = 0; i < items.length; i++) {
9086
+ const it = items[i];
9087
+ if (it.section) {
9088
+ if (group.entries.length || group.section != null) groups.push(group);
9089
+ secN += 1;
9090
+ group = { sid: `${navId}-sec-${secN}`, section: it.section, entries: [] };
9091
+ } else {
9092
+ group.entries.push({ it, i });
9093
+ }
9094
+ }
9095
+ if (group.entries.length || group.section != null) groups.push(group);
9096
+ const body = /* @__PURE__ */ jsxs(Fragment, { children: [
8899
9097
  __twcStyles,
8900
9098
  brand ? /* @__PURE__ */ jsx("div", { className: "twc-sidebar__head", children: /* @__PURE__ */ jsx("span", { className: "twc-sidebar__brand", children: brand }) }) : null,
8901
- /* @__PURE__ */ jsx("nav", { className: "twc-sidebar__nav", children: items.map(
8902
- (it, i) => it.section ? /* @__PURE__ */ jsx("div", { className: "twc-sidebar__section", children: it.section }, i) : (() => {
8903
- const href = safeHref11(it.href);
8904
- const labelStr = typeof it.label === "string" ? it.label : void 0;
8905
- const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
8906
- it.icon ? /* @__PURE__ */ jsx("span", { className: "twc-sidebar__ic", "aria-hidden": "true", children: it.icon }) : labelStr != null ? /* @__PURE__ */ jsx("span", { className: "twc-sidebar__ic twc-sidebar__ic--initial", "aria-hidden": "true", children: labelStr.charAt(0) }) : null,
8907
- /* @__PURE__ */ jsx("span", { className: "twc-sidebar__label", children: it.label }),
8908
- it.badge != null ? /* @__PURE__ */ jsx("span", { className: "twc-sidebar__badge", children: it.badge }) : null
8909
- ] });
8910
- const common = {
8911
- className: "twc-sidebar__item",
8912
- "data-active": it.active || void 0,
8913
- "aria-current": it.active ? "page" : void 0,
8914
- onClick: it.onClick,
8915
- "aria-label": collapsed && labelStr != null ? labelStr : void 0
8916
- };
8917
- const node = href != null ? /* @__PURE__ */ jsx("a", { href, ...common, children: inner }, i) : /* @__PURE__ */ jsx("button", { type: "button", ...common, children: inner }, i);
8918
- return collapsed && labelStr != null ? /* @__PURE__ */ jsx(Tooltip, { label: labelStr, placement: "right", style: { display: "block" }, children: node }, i) : node;
8919
- })()
8920
- ) }),
9099
+ /* @__PURE__ */ jsx("nav", { id: navId, className: "twc-sidebar__nav", "aria-label": navLabel, children: groups.map((g, gi) => /* @__PURE__ */ jsxs(React24__default.Fragment, { children: [
9100
+ g.section != null ? /* @__PURE__ */ jsx("div", { className: "twc-sidebar__section", id: g.sid, children: g.section }) : null,
9101
+ /* @__PURE__ */ jsx("ul", { className: "twc-sidebar__list", ...g.section != null ? { "aria-labelledby": g.sid } : {}, children: g.entries.map(({ it, i }) => /* @__PURE__ */ jsx("li", { children: renderItem(it) }, i)) })
9102
+ ] }, gi)) }),
8921
9103
  footer || collapsible ? /* @__PURE__ */ jsxs("div", { className: "twc-sidebar__foot", children: [
8922
9104
  footer ? /* @__PURE__ */ jsx("div", { className: "twc-sidebar__foot-user", children: footer }) : null,
8923
- collapsible ? /* @__PURE__ */ jsxs("button", { type: "button", className: "twc-sidebar__collapse", onClick: toggle, "aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar", children: [
9105
+ collapsible ? /* @__PURE__ */ jsxs("button", { type: "button", className: "twc-sidebar__collapse", onClick: toggle, "aria-expanded": !collapsed, "aria-controls": navId, "aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar", children: [
8924
9106
  /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m15 18-6-6 6-6" }) }),
8925
9107
  /* @__PURE__ */ jsx("span", { children: "Collapse" })
8926
9108
  ] }) : null
8927
9109
  ] }) : null
8928
9110
  ] });
9111
+ if (!overlay) {
9112
+ return /* @__PURE__ */ jsx("aside", { className: `twc-sidebar ${className}`, "data-collapsed": collapsed || void 0, ...rest, children: body });
9113
+ }
9114
+ if (!mounted) return null;
9115
+ const state = open ? "open" : "closed";
9116
+ const drawer = /* @__PURE__ */ jsx("div", { className: "twc-sidebar__overlay", "data-state": state, onMouseDown: (e) => {
9117
+ if (e.target === e.currentTarget) setOpen(false);
9118
+ }, children: /* @__PURE__ */ jsx(
9119
+ "aside",
9120
+ {
9121
+ ref: panelRef,
9122
+ className: `twc-sidebar twc-sidebar--overlay ${className}`,
9123
+ "data-state": state,
9124
+ "data-collapsed": collapsed || void 0,
9125
+ role: "dialog",
9126
+ "aria-modal": "true",
9127
+ tabIndex: -1,
9128
+ "aria-label": navLabel || "Navigation",
9129
+ ...rest,
9130
+ children: body
9131
+ }
9132
+ ) });
9133
+ return renderPortal(drawer);
8929
9134
  }
8930
9135
  function Skeleton({
8931
9136
  variant = "text",
8932
9137
  width,
8933
9138
  height,
8934
9139
  lines = 1,
9140
+ label,
8935
9141
  className = "",
8936
9142
  style,
8937
9143
  ...rest
8938
9144
  }) {
9145
+ const a11y = label != null ? { role: "status", "aria-live": "polite", "aria-busy": true } : { "aria-hidden": true };
8939
9146
  const __twcStyles = useScopedStyles("twc-skeleton-styles", `
8940
9147
  .twc-skeleton {
8941
9148
  position: relative; overflow: hidden;
@@ -8951,25 +9158,31 @@ function Skeleton({
8951
9158
  .twc-skeleton[data-variant="rect"] { border-radius: var(--radius-md); }
8952
9159
  .twc-skeleton__group { display: flex; flex-direction: column; gap: 8px; }
8953
9160
  .twc-skeleton__group .twc-skeleton:last-child { width: 70%; }
9161
+ .twc-skeleton__sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
8954
9162
  /* The shimmer signals loading \u2014 keep it animating even under reduced motion. */
8955
9163
  @media (prefers-reduced-motion: reduce) {
8956
9164
  .twc-skeleton::after { animation-duration: 1.4s !important; animation-iteration-count: infinite !important; }
8957
9165
  }
8958
9166
  `);
8959
9167
  if (variant === "text" && lines > 1) {
8960
- return /* @__PURE__ */ jsxs("div", { className: `twc-skeleton__group ${className}`, style: { height, ...style }, ...rest, children: [
9168
+ return /* @__PURE__ */ jsxs("div", { className: `twc-skeleton__group ${className}`, style: { height, ...style }, ...a11y, ...rest, children: [
8961
9169
  __twcStyles,
9170
+ label != null ? /* @__PURE__ */ jsx("span", { className: "twc-skeleton__sr", children: label }) : null,
8962
9171
  Array.from({ length: lines }).map((_, i) => /* @__PURE__ */ jsx("span", { className: "twc-skeleton", "data-variant": "text", style: { width: width || "100%" } }, i))
8963
9172
  ] });
8964
9173
  }
8965
- return /* @__PURE__ */ jsx(
9174
+ return /* @__PURE__ */ jsxs(
8966
9175
  "span",
8967
9176
  {
8968
9177
  className: `twc-skeleton ${className}`,
8969
9178
  "data-variant": variant,
8970
9179
  style: { width, height, ...style },
9180
+ ...a11y,
8971
9181
  ...rest,
8972
- children: __twcStyles
9182
+ children: [
9183
+ __twcStyles,
9184
+ label != null ? /* @__PURE__ */ jsx("span", { className: "twc-skeleton__sr", children: label }) : null
9185
+ ]
8973
9186
  }
8974
9187
  );
8975
9188
  }
@@ -9036,12 +9249,12 @@ function Slider({
9036
9249
  const max = Number.isFinite(maxProp) && maxProp > min ? maxProp : min + 1;
9037
9250
  const step = Number.isFinite(stepProp) && stepProp > 0 ? stepProp : 1;
9038
9251
  const __twcStyles = useScopedStyles("twc-slider-styles", SLIDER_CSS);
9039
- const autoId = React23__default.useId();
9252
+ const autoId = React24__default.useId();
9040
9253
  const fieldId = id || autoId;
9041
- const [internal, setInternal] = React23__default.useState(defaultValue);
9254
+ const [internal, setInternal] = React24__default.useState(defaultValue);
9042
9255
  const val = value !== void 0 ? value : internal;
9043
- const trackRef = React23__default.useRef(null);
9044
- const [dragging, setDragging] = React23__default.useState(false);
9256
+ const trackRef = React24__default.useRef(null);
9257
+ const [dragging, setDragging] = React24__default.useState(false);
9045
9258
  const pct = (val - min) / (max - min) * 100;
9046
9259
  const fmt = (v) => formatValue ? formatValue(v) : v;
9047
9260
  const clampSnap = (raw) => {
@@ -9059,8 +9272,8 @@ function Slider({
9059
9272
  const ratio = Math.min(1, Math.max(0, (clientX - r.left) / r.width));
9060
9273
  return clampSnap(min + ratio * (max - min));
9061
9274
  };
9062
- const dragCleanupRef = React23__default.useRef(null);
9063
- React23__default.useEffect(() => () => dragCleanupRef.current?.(), []);
9275
+ const dragCleanupRef = React24__default.useRef(null);
9276
+ React24__default.useEffect(() => () => dragCleanupRef.current?.(), []);
9064
9277
  function onPointerDown(e) {
9065
9278
  if (disabled) return;
9066
9279
  e.preventDefault();
@@ -9135,12 +9348,15 @@ function Slider({
9135
9348
  function Spinner({
9136
9349
  size = "md",
9137
9350
  color,
9138
- tone = "current",
9351
+ tone,
9139
9352
  label = "Loading",
9140
9353
  className = "",
9141
9354
  ...rest
9142
9355
  }) {
9143
- const resolvedColor = color ?? tone;
9356
+ if (process.env.NODE_ENV !== "production" && tone !== void 0 && color === void 0) {
9357
+ warnOnce("Spinner.tone", "Spinner: `tone` is deprecated and will be removed in 2.0 \u2014 use `color`.");
9358
+ }
9359
+ const resolvedColor = color ?? tone ?? "current";
9144
9360
  const __twcStyles = useScopedStyles("twc-spinner-styles", `
9145
9361
  .twc-spinner {
9146
9362
  --_sz: 24px; --_bw: 2.5px;
@@ -9256,6 +9472,7 @@ var STEPPER_CSS = `
9256
9472
  .twc-stepper[data-orientation="vertical"] .twc-step__col { display: flex; flex-direction: column; align-items: center; }
9257
9473
  .twc-step[data-state="complete"] .twc-step__connector, .twc-step[data-state="active"] .twc-step__connector { background: var(--_accent); }
9258
9474
  .twc-stepper[data-orientation="vertical"] .twc-step__vbody { padding-bottom: var(--space-2); }
9475
+ .twc-step__sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
9259
9476
  `;
9260
9477
  var CheckIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) });
9261
9478
  var BangIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M12 8v5M12 17h.01" }) });
@@ -9271,7 +9488,7 @@ function Stepper({
9271
9488
  ...rest
9272
9489
  }) {
9273
9490
  const __twcStyles = useScopedStyles("twc-stepper-styles", STEPPER_CSS);
9274
- const [activeInternal, setActiveInternal] = React23__default.useState(defaultActive);
9491
+ const [activeInternal, setActiveInternal] = React24__default.useState(defaultActive);
9275
9492
  const active = activeProp !== void 0 ? activeProp : activeInternal;
9276
9493
  const handleStep = (i) => {
9277
9494
  if (activeProp === void 0) setActiveInternal(i);
@@ -9283,11 +9500,12 @@ function Stepper({
9283
9500
  if (i === active) return "active";
9284
9501
  return "upcoming";
9285
9502
  };
9286
- return /* @__PURE__ */ jsxs("div", { className: `twc-stepper ${className}`, "data-orientation": orientation, "data-tone": tone, ...rest, children: [
9503
+ return /* @__PURE__ */ jsxs("div", { className: `twc-stepper ${className}`, "data-orientation": orientation, "data-tone": tone, role: "group", "aria-label": "Progress", ...rest, children: [
9287
9504
  __twcStyles,
9288
9505
  steps.map((step, i) => {
9289
9506
  const state = stateOf(i, step);
9290
9507
  const last = i === steps.length - 1;
9508
+ const srText = `Step ${i + 1} of ${steps.length}${state === "complete" ? ", completed" : state === "error" ? ", error" : state === "active" ? ", current" : ", upcoming"}. `;
9291
9509
  const isClickable = clickable && i <= active;
9292
9510
  const interactive = isClickable ? {
9293
9511
  role: "button",
@@ -9309,8 +9527,10 @@ function Stepper({
9309
9527
  "data-state": state,
9310
9528
  "data-clickable": isClickable || void 0,
9311
9529
  "aria-current": state === "active" ? "step" : void 0,
9530
+ "aria-invalid": state === "error" ? "true" : void 0,
9312
9531
  ...interactive,
9313
9532
  children: [
9533
+ /* @__PURE__ */ jsx("span", { className: "twc-step__sr", children: srText }),
9314
9534
  /* @__PURE__ */ jsxs("div", { className: "twc-step__col", children: [
9315
9535
  indicator,
9316
9536
  !last ? /* @__PURE__ */ jsx("span", { className: "twc-step__connector" }) : null
@@ -9331,8 +9551,10 @@ function Stepper({
9331
9551
  "data-state": state,
9332
9552
  "data-clickable": isClickable || void 0,
9333
9553
  "aria-current": state === "active" ? "step" : void 0,
9554
+ "aria-invalid": state === "error" ? "true" : void 0,
9334
9555
  ...interactive,
9335
9556
  children: [
9557
+ /* @__PURE__ */ jsx("span", { className: "twc-step__sr", children: srText }),
9336
9558
  indicator,
9337
9559
  !last ? /* @__PURE__ */ jsx("span", { className: "twc-step__connector" }) : null,
9338
9560
  /* @__PURE__ */ jsxs("div", { className: "twc-step__body", children: [
@@ -9398,7 +9620,7 @@ function Switch({
9398
9620
  .twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
9399
9621
  .twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
9400
9622
  `);
9401
- const autoId = React23__default.useId();
9623
+ const autoId = React24__default.useId();
9402
9624
  const fieldId = id || autoId;
9403
9625
  const errId = `${fieldId}-error`;
9404
9626
  const invalid = Boolean(error);
@@ -9482,14 +9704,14 @@ function Table({
9482
9704
  ...rest
9483
9705
  }) {
9484
9706
  const __twcStyles = useScopedStyles("twc-table-styles", TABLE_CSS);
9485
- const cols = React23__default.useMemo(
9707
+ const cols = React24__default.useMemo(
9486
9708
  () => (columns || []).map((c) => ({ ...c, header: c.headerName, render: c.renderCell })),
9487
9709
  [columns]
9488
9710
  );
9489
9711
  const dataRows = rowsProp || [];
9490
- const [internalSort, setInternalSort] = React23__default.useState(defaultSort || { field: null, dir: "asc" });
9712
+ const [internalSort, setInternalSort] = React24__default.useState(defaultSort || { field: null, dir: "asc" });
9491
9713
  const sort = (sortProp !== void 0 ? sortProp : internalSort) || { field: null, dir: "asc" };
9492
- const rows = React23__default.useMemo(() => {
9714
+ const rows = React24__default.useMemo(() => {
9493
9715
  if (!sortable || !sort.field) return dataRows;
9494
9716
  const col = cols.find((c) => c.field === sort.field);
9495
9717
  if (!col) return dataRows;
@@ -9581,6 +9803,13 @@ var TABS_CSS = `
9581
9803
  .twc-tabs[data-variant="pill"] .twc-tabs__indicator {
9582
9804
  top: 4px; bottom: 4px; height: auto; background: var(--color-surface); box-shadow: var(--shadow-sm); border-radius: var(--radius-md);
9583
9805
  }
9806
+ .twc-tab[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
9807
+ /* Horizontal tablist scrolls when tabs overflow (vertical orientation untouched). Making
9808
+ overflow-x non-visible makes overflow-y compute to auto, which would clip the bottom:-1px
9809
+ indicator \u2014 so pin the horizontal indicator to bottom:0 (the list border-bottom is the baseline). */
9810
+ .twc-tabs:not([data-orientation="vertical"]) .twc-tabs__list { overflow-x: auto; scrollbar-width: none; }
9811
+ .twc-tabs:not([data-orientation="vertical"]) .twc-tabs__list::-webkit-scrollbar { display: none; }
9812
+ .twc-tabs:not([data-orientation="vertical"]) .twc-tabs__indicator { bottom: 0; }
9584
9813
  .twc-tabs__panel { padding-top: var(--space-4); }
9585
9814
 
9586
9815
  /* Vertical orientation */
@@ -9615,24 +9844,27 @@ function Tabs({
9615
9844
  }) {
9616
9845
  const vertical = orientation === "vertical";
9617
9846
  const __twcStyles = useScopedStyles("twc-tabs-styles", TABS_CSS);
9618
- const [internal, setInternal] = React23__default.useState(defaultValue ?? items[0]?.value);
9847
+ const [internal, setInternal] = React24__default.useState(defaultValue ?? items[0]?.value);
9619
9848
  const active = value ?? internal;
9620
- const listRef = React23__default.useRef(null);
9621
- const [ind, setInd] = React23__default.useState({ left: 0, width: 0, top: 0, height: 0 });
9622
- const baseId = React23__default.useId();
9849
+ const listRef = React24__default.useRef(null);
9850
+ const [ind, setInd] = React24__default.useState({ left: 0, width: 0, top: 0, height: 0 });
9851
+ const baseId = React24__default.useId();
9623
9852
  const tabIdAt = (i) => `${baseId}-tab-${i}`;
9624
9853
  const panelId = `${baseId}-panel`;
9625
9854
  const activeIndex = items.findIndex((it) => it.value === active);
9626
- const updateIndicator = React23__default.useCallback(() => {
9855
+ const updateIndicator = React24__default.useCallback(() => {
9627
9856
  const list = listRef.current;
9628
9857
  if (!list) return;
9629
9858
  const el = list.querySelector('[data-active="true"]');
9630
- if (el) setInd({ left: el.offsetLeft, width: el.offsetWidth, top: el.offsetTop, height: el.offsetHeight });
9631
- }, []);
9632
- React23__default.useEffect(() => {
9859
+ if (el) {
9860
+ setInd({ left: el.offsetLeft, width: el.offsetWidth, top: el.offsetTop, height: el.offsetHeight });
9861
+ if (!vertical) el.scrollIntoView?.({ inline: "nearest", block: "nearest" });
9862
+ }
9863
+ }, [vertical]);
9864
+ React24__default.useEffect(() => {
9633
9865
  updateIndicator();
9634
9866
  }, [active, updateIndicator, items, orientation]);
9635
- React23__default.useEffect(() => {
9867
+ React24__default.useEffect(() => {
9636
9868
  const r = () => updateIndicator();
9637
9869
  window.addEventListener("resize", r);
9638
9870
  if (typeof document !== "undefined" && document.fonts && document.fonts.ready) {
@@ -9653,20 +9885,32 @@ function Tabs({
9653
9885
  const keys = [prevKey, nextKey, "Home", "End"];
9654
9886
  if (!keys.includes(e.key)) return;
9655
9887
  const n = items.length;
9656
- if (!n) return;
9888
+ if (!n || items.every((it2) => it2.disabled)) return;
9657
9889
  e.preventDefault();
9658
9890
  let i = activeIndex < 0 ? 0 : activeIndex;
9659
- if (e.key === "Home") i = 0;
9660
- else if (e.key === "End") i = n - 1;
9661
- else {
9891
+ if (e.key === "Home") i = items.findIndex((it2) => !it2.disabled);
9892
+ else if (e.key === "End") {
9893
+ for (let k = n - 1; k >= 0; k--) {
9894
+ if (!items[k].disabled) {
9895
+ i = k;
9896
+ break;
9897
+ }
9898
+ }
9899
+ } else {
9662
9900
  const dir = e.key === nextKey ? 1 : -1;
9663
- i = (i + dir + n) % n;
9901
+ let guard = 0;
9902
+ do {
9903
+ i = (i + dir + n) % n;
9904
+ } while (items[i]?.disabled && ++guard <= n);
9664
9905
  }
9665
9906
  const it = items[i];
9666
- if (!it) return;
9907
+ if (!it || it.disabled) return;
9667
9908
  select(it.value);
9668
9909
  const btns = listRef.current?.querySelectorAll('[role="tab"]');
9669
- if (btns && btns[i]) btns[i].focus();
9910
+ if (btns && btns[i]) {
9911
+ btns[i].focus();
9912
+ btns[i].scrollIntoView?.({ inline: "nearest", block: "nearest" });
9913
+ }
9670
9914
  }
9671
9915
  return /* @__PURE__ */ jsxs("div", { className: `twc-tabs ${className}`, "data-variant": variant, "data-tone": tone, "data-orientation": orientation, ...rest, children: [
9672
9916
  __twcStyles,
@@ -9679,10 +9923,14 @@ function Tabs({
9679
9923
  className: "twc-tab",
9680
9924
  role: "tab",
9681
9925
  "aria-selected": it.value === active,
9926
+ "aria-disabled": it.disabled || void 0,
9927
+ disabled: it.disabled || void 0,
9682
9928
  "aria-controls": it.value === active && panelRendered ? panelId : void 0,
9683
- tabIndex: it.value === active ? 0 : -1,
9929
+ tabIndex: it.value === active && !it.disabled ? 0 : -1,
9684
9930
  "data-active": it.value === active || void 0,
9685
- onClick: () => select(it.value),
9931
+ onClick: () => {
9932
+ if (!it.disabled) select(it.value);
9933
+ },
9686
9934
  children: [
9687
9935
  it.icon,
9688
9936
  it.label,
@@ -9745,10 +9993,12 @@ function Tag({
9745
9993
  leftIcon,
9746
9994
  tone = "neutral",
9747
9995
  variant = "soft",
9996
+ removeLabel,
9748
9997
  className = "",
9749
9998
  ...rest
9750
9999
  }) {
9751
10000
  const __twcStyles = useScopedStyles("twc-tag-styles", TAG_CSS);
10001
+ const _removeLabel = removeLabel ?? (typeof children === "string" ? `Remove ${children}` : "Remove");
9752
10002
  return /* @__PURE__ */ jsxs("span", { className: `twc-tag ${className}`, "data-tone": tone, "data-variant": variant, "data-no-remove": !onRemove || void 0, ...rest, children: [
9753
10003
  __twcStyles,
9754
10004
  leftIcon,
@@ -9756,7 +10006,7 @@ function Tag({
9756
10006
  onRemove ? /* @__PURE__ */ jsx("button", { className: "twc-tag__remove", onClick: (e) => {
9757
10007
  e.stopPropagation();
9758
10008
  onRemove(e);
9759
- }, "aria-label": "Remove", type: "button", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
10009
+ }, "aria-label": _removeLabel, type: "button", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
9760
10010
  ] });
9761
10011
  }
9762
10012
  function Textarea({
@@ -9802,7 +10052,7 @@ function Textarea({
9802
10052
  .twc-textarea__el[aria-invalid="true"] { border-color: var(--color-danger); }
9803
10053
  .twc-textarea__el:disabled { background: var(--color-surface-sunken); opacity: 0.7; cursor: not-allowed; }
9804
10054
  `);
9805
- const autoId = React23__default.useId();
10055
+ const autoId = React24__default.useId();
9806
10056
  const fieldId = id || autoId;
9807
10057
  const descId = `${fieldId}-desc`;
9808
10058
  const invalid = Boolean(error);
@@ -9940,19 +10190,19 @@ function Toast({
9940
10190
  }) {
9941
10191
  const resolvedTone = tone === "neutral" ? "default" : tone;
9942
10192
  const __twcStyles = useScopedStyles("twc-toast-styles", TOAST_CSS);
9943
- const onCloseRef = React23__default.useRef(onClose);
9944
- React23__default.useEffect(() => {
10193
+ const onCloseRef = React24__default.useRef(onClose);
10194
+ React24__default.useEffect(() => {
9945
10195
  onCloseRef.current = onClose;
9946
10196
  }, [onClose]);
9947
- const timer = React23__default.useRef();
9948
- const stop = React23__default.useCallback(() => clearTimeout(timer.current), []);
9949
- const start = React23__default.useCallback(() => {
10197
+ const timer = React24__default.useRef();
10198
+ const stop = React24__default.useCallback(() => clearTimeout(timer.current), []);
10199
+ const start = React24__default.useCallback(() => {
9950
10200
  stop();
9951
10201
  if (duration && duration !== Infinity && onCloseRef.current) {
9952
10202
  timer.current = setTimeout(() => onCloseRef.current && onCloseRef.current(), duration);
9953
10203
  }
9954
10204
  }, [duration, stop]);
9955
- React23__default.useEffect(() => {
10205
+ React24__default.useEffect(() => {
9956
10206
  start();
9957
10207
  return stop;
9958
10208
  }, [start, stop]);
@@ -9996,30 +10246,30 @@ function Toast({
9996
10246
  }
9997
10247
  function ToastViewport({ children, limit, className = "", ...rest }) {
9998
10248
  const __twcStyles = useScopedStyles("twc-toast-styles", TOAST_CSS);
9999
- const shown = limit && limit > 0 ? React23__default.Children.toArray(children).slice(-limit) : children;
10249
+ const shown = limit && limit > 0 ? React24__default.Children.toArray(children).slice(-limit) : children;
10000
10250
  return /* @__PURE__ */ jsxs("div", { className: `twc-toast-viewport ${className}`, ...rest, children: [
10001
10251
  __twcStyles,
10002
10252
  shown
10003
10253
  ] });
10004
10254
  }
10005
- var ToastContext = React23__default.createContext(null);
10255
+ var ToastContext = React24__default.createContext(null);
10006
10256
  function useToast() {
10007
- const ctx = React23__default.useContext(ToastContext);
10257
+ const ctx = React24__default.useContext(ToastContext);
10008
10258
  if (!ctx) throw new Error("useToast must be used within a <ToastProvider>.");
10009
10259
  return ctx;
10010
10260
  }
10011
10261
  function ToastProvider({ children, limit = 4, duration = 4500, ...viewportProps }) {
10012
- const [toasts, setToasts] = React23__default.useState([]);
10013
- const idRef = React23__default.useRef(0);
10014
- const limitRef = React23__default.useRef(limit);
10015
- React23__default.useEffect(() => {
10262
+ const [toasts, setToasts] = React24__default.useState([]);
10263
+ const idRef = React24__default.useRef(0);
10264
+ const limitRef = React24__default.useRef(limit);
10265
+ React24__default.useEffect(() => {
10016
10266
  limitRef.current = limit;
10017
10267
  }, [limit]);
10018
- const dismiss = React23__default.useCallback((id) => {
10268
+ const dismiss = React24__default.useCallback((id) => {
10019
10269
  setToasts((s) => s.filter((t) => t.id !== id));
10020
10270
  }, []);
10021
- const clear = React23__default.useCallback(() => setToasts([]), []);
10022
- const api = React23__default.useMemo(() => {
10271
+ const clear = React24__default.useCallback(() => setToasts([]), []);
10272
+ const api = React24__default.useMemo(() => {
10023
10273
  const push = (opts) => {
10024
10274
  const id = idRef.current += 1;
10025
10275
  const next = typeof opts === "string" ? { title: opts } : opts && typeof opts === "object" ? opts : {};
@@ -10040,7 +10290,7 @@ function ToastProvider({ children, limit = 4, duration = 4500, ...viewportProps
10040
10290
  toast.show = withTone("default");
10041
10291
  return { toast, dismiss, clear };
10042
10292
  }, [dismiss, clear]);
10043
- const value = React23__default.useMemo(() => ({ ...api, toasts }), [api, toasts]);
10293
+ const value = React24__default.useMemo(() => ({ ...api, toasts }), [api, toasts]);
10044
10294
  return /* @__PURE__ */ jsxs(ToastContext.Provider, { value, children: [
10045
10295
  children,
10046
10296
  /* @__PURE__ */ jsx(ToastViewport, { limit, ...viewportProps, children: toasts.map((t) => /* @__PURE__ */ jsx(
@@ -10080,7 +10330,7 @@ var TREE_CSS = `
10080
10330
  .twc-tree__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
10081
10331
  .twc-tree__badge { flex: none; font-size: 11px; color: var(--color-text-subtle); }
10082
10332
  `;
10083
- function Node({ node, depth, expanded, selectedId, tabbableId, rowRefs, onToggle, onSelect, onRowFocus }) {
10333
+ function Node({ node, depth, posInSet, setSize, expanded, selectedId, tabbableId, rowRefs, onToggle, onSelect, onRowFocus }) {
10084
10334
  const hasChildren = Array.isArray(node.children) && node.children.length > 0;
10085
10335
  const open = expanded.has(node.id);
10086
10336
  return /* @__PURE__ */ jsxs("li", { role: "none", children: [
@@ -10091,6 +10341,8 @@ function Node({ node, depth, expanded, selectedId, tabbableId, rowRefs, onToggle
10091
10341
  className: "twc-tree__row",
10092
10342
  role: "treeitem",
10093
10343
  "aria-level": depth + 1,
10344
+ "aria-posinset": posInSet,
10345
+ "aria-setsize": setSize,
10094
10346
  "aria-selected": selectedId === node.id,
10095
10347
  "data-selected": selectedId === node.id || void 0,
10096
10348
  "data-tree-id": node.id,
@@ -10114,11 +10366,13 @@ function Node({ node, depth, expanded, selectedId, tabbableId, rowRefs, onToggle
10114
10366
  ]
10115
10367
  }
10116
10368
  ),
10117
- hasChildren && open ? /* @__PURE__ */ jsx("ul", { className: "twc-tree__group twc-tree__group--child", role: "group", children: node.children.map((c) => /* @__PURE__ */ jsx(
10369
+ hasChildren && open ? /* @__PURE__ */ jsx("ul", { className: "twc-tree__group twc-tree__group--child", role: "group", children: node.children.map((c, i) => /* @__PURE__ */ jsx(
10118
10370
  Node,
10119
10371
  {
10120
10372
  node: c,
10121
10373
  depth: depth + 1,
10374
+ posInSet: i + 1,
10375
+ setSize: node.children.length,
10122
10376
  expanded,
10123
10377
  selectedId,
10124
10378
  tabbableId,
@@ -10144,12 +10398,13 @@ function TreeView({
10144
10398
  }) {
10145
10399
  const nodes = items;
10146
10400
  const __twcStyles = useScopedStyles("twc-tree-styles", TREE_CSS);
10147
- const [expInternal, setExpInternal] = React23__default.useState(() => new Set(defaultExpanded));
10401
+ const [expInternal, setExpInternal] = React24__default.useState(() => new Set(defaultExpanded));
10148
10402
  const expanded = expandedProp !== void 0 ? new Set(expandedProp) : expInternal;
10149
- const [selInternal, setSelInternal] = React23__default.useState(defaultSelectedId);
10403
+ const [selInternal, setSelInternal] = React24__default.useState(defaultSelectedId);
10150
10404
  const selectedId = selectedProp !== void 0 ? selectedProp : selInternal;
10151
- const [focusId, setFocusId] = React23__default.useState(null);
10152
- const rowRefs = React23__default.useRef(/* @__PURE__ */ new Map());
10405
+ const [focusId, setFocusId] = React24__default.useState(null);
10406
+ const rowRefs = React24__default.useRef(/* @__PURE__ */ new Map());
10407
+ const taRef = React24__default.useRef({ str: "", t: 0 });
10153
10408
  const toggle = (id) => {
10154
10409
  const n = new Set(expanded);
10155
10410
  n.has(id) ? n.delete(id) : n.add(id);
@@ -10163,10 +10418,12 @@ function TreeView({
10163
10418
  const visible = [];
10164
10419
  const parentOf = /* @__PURE__ */ new Map();
10165
10420
  const hasKids = /* @__PURE__ */ new Map();
10421
+ const labelText = /* @__PURE__ */ new Map();
10166
10422
  const walk = (nodes2, parentId) => {
10167
10423
  for (const n of nodes2) {
10168
10424
  visible.push(n.id);
10169
10425
  parentOf.set(n.id, parentId);
10426
+ if (typeof n.label === "string") labelText.set(n.id, n.label);
10170
10427
  const kids = Array.isArray(n.children) && n.children.length > 0;
10171
10428
  hasKids.set(n.id, kids);
10172
10429
  if (kids && expanded.has(n.id)) walk(n.children, n.id);
@@ -10204,17 +10461,36 @@ function TreeView({
10204
10461
  return;
10205
10462
  }
10206
10463
  next = parentOf.get(id);
10464
+ } else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey && /\S/.test(e.key)) {
10465
+ const now = Date.now();
10466
+ taRef.current.str = now - taRef.current.t > 500 ? e.key : taRef.current.str + e.key;
10467
+ taRef.current.t = now;
10468
+ const q = taRef.current.str.toLowerCase();
10469
+ const single = q.length > 1 && [...q].every((c) => c === q[0]);
10470
+ const needle = single ? q[0] : q;
10471
+ for (let k = 1; k <= visible.length; k++) {
10472
+ const cand = visible[(i + k) % visible.length];
10473
+ const lbl = labelText.get(cand);
10474
+ if (lbl && lbl.toLowerCase().startsWith(needle)) {
10475
+ e.preventDefault();
10476
+ focusRow(cand);
10477
+ break;
10478
+ }
10479
+ }
10480
+ return;
10207
10481
  } else return;
10208
10482
  e.preventDefault();
10209
10483
  if (next != null) focusRow(next);
10210
10484
  };
10211
10485
  return /* @__PURE__ */ jsxs("div", { className: `twc-tree ${className}`, role: "tree", onKeyDown, ...rest, children: [
10212
10486
  __twcStyles,
10213
- /* @__PURE__ */ jsx("ul", { className: "twc-tree__group", role: "none", children: nodes.map((n) => /* @__PURE__ */ jsx(
10487
+ /* @__PURE__ */ jsx("ul", { className: "twc-tree__group", role: "none", children: nodes.map((n, i) => /* @__PURE__ */ jsx(
10214
10488
  Node,
10215
10489
  {
10216
10490
  node: n,
10217
10491
  depth: 0,
10492
+ posInSet: i + 1,
10493
+ setSize: nodes.length,
10218
10494
  expanded,
10219
10495
  selectedId,
10220
10496
  tabbableId,
@@ -10228,12 +10504,22 @@ function TreeView({
10228
10504
  ] });
10229
10505
  }
10230
10506
  var SHELL_CSS = `
10231
- .twc-shell { display: flex; overflow: hidden; background: var(--color-bg); color: var(--color-text); font-family: var(--font-sans); }
10507
+ .twc-shell { position: relative; display: flex; overflow: hidden; background: var(--color-bg); color: var(--color-text); font-family: var(--font-sans); }
10508
+ .twc-shell__skip { position: absolute; inset-inline-start: var(--space-3); inset-block-start: var(--space-3); z-index: 100;
10509
+ padding: var(--space-2) var(--space-4); background: var(--color-surface); color: var(--color-text);
10510
+ border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-md); font-family: var(--font-sans);
10511
+ transform: translateY(-200%); transition: transform var(--duration-fast) var(--ease-standard); }
10512
+ .twc-shell__skip:focus-visible { transform: translateY(0); outline: none; box-shadow: var(--ring); }
10232
10513
  .twc-shell__main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; height: 100%; }
10233
10514
  .twc-shell__header { flex: none; display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
10234
10515
  min-height: 60px; padding-inline: var(--space-5); border-bottom: var(--border-thin) solid var(--color-border); background: var(--color-surface); }
10235
10516
  .twc-shell__content { flex: 1 1 auto; min-height: 0; overflow: auto; }
10236
10517
  .twc-shell__content[data-padded="true"] { padding: var(--space-6) var(--space-5); }
10518
+ /* Mobile: stack the shell so the sidebar (rendered as an off-canvas overlay) no
10519
+ longer reserves a column \u2014 the main content spans the full width. */
10520
+ @media (max-width: 720px) {
10521
+ .twc-shell { flex-direction: column; }
10522
+ }
10237
10523
  `;
10238
10524
  function AppShell({
10239
10525
  sidebar,
@@ -10241,17 +10527,27 @@ function AppShell({
10241
10527
  children,
10242
10528
  height = "100dvh",
10243
10529
  padded = true,
10530
+ mainId = "twc-main",
10531
+ skipLinkLabel = "Skip to content",
10532
+ sidebarOpen,
10533
+ onSidebarOpenChange,
10244
10534
  className = "",
10245
10535
  style,
10246
10536
  ...rest
10247
10537
  }) {
10248
10538
  const __twcStyles = useScopedStyles("twc-shell-styles", SHELL_CSS);
10539
+ const wiredSidebar = React24__default.isValidElement(sidebar) && (sidebarOpen !== void 0 || onSidebarOpenChange !== void 0) ? React24__default.cloneElement(sidebar, {
10540
+ overlay: sidebar.props.overlay !== void 0 ? sidebar.props.overlay : true,
10541
+ open: sidebar.props.open !== void 0 ? sidebar.props.open : sidebarOpen,
10542
+ onOpenChange: sidebar.props.onOpenChange !== void 0 ? sidebar.props.onOpenChange : onSidebarOpenChange
10543
+ }) : sidebar;
10249
10544
  return /* @__PURE__ */ jsxs("div", { className: `twc-shell ${className}`.trim(), style: { height, ...style }, ...rest, children: [
10250
10545
  __twcStyles,
10251
- sidebar,
10546
+ skipLinkLabel != null && skipLinkLabel !== false ? /* @__PURE__ */ jsx("a", { className: "twc-shell__skip", href: `#${mainId}`, children: skipLinkLabel }) : null,
10547
+ wiredSidebar,
10252
10548
  /* @__PURE__ */ jsxs("div", { className: "twc-shell__main", children: [
10253
10549
  header != null ? /* @__PURE__ */ jsx("header", { className: "twc-shell__header", children: header }) : null,
10254
- /* @__PURE__ */ jsx("main", { className: "twc-shell__content", "data-padded": padded ? "true" : void 0, children })
10550
+ /* @__PURE__ */ jsx("main", { className: "twc-shell__content", id: mainId, tabIndex: -1, "data-padded": padded ? "true" : void 0, children })
10255
10551
  ] })
10256
10552
  ] });
10257
10553
  }
@@ -10270,7 +10566,7 @@ function bgValue(bg) {
10270
10566
  if (BG[bg]) return `var(${BG[bg]})`;
10271
10567
  return String(bg).startsWith("--") ? `var(${bg})` : bg;
10272
10568
  }
10273
- function safeHref4(url) {
10569
+ function safeHref5(url) {
10274
10570
  if (url == null) return void 0;
10275
10571
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
10276
10572
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -10315,11 +10611,11 @@ function Box({
10315
10611
  boxShadow: shadow ? `var(--shadow-${shadow})` : void 0,
10316
10612
  ...style
10317
10613
  };
10318
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref4(rest.href);
10614
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref5(rest.href);
10319
10615
  return /* @__PURE__ */ jsx(Tag2, { className: `twc-box ${className}`.trim(), style: s, ...rest, children });
10320
10616
  }
10321
10617
  var SIZES = { sm: 640, md: 768, lg: 1024, xl: 1280, full: "100%" };
10322
- function safeHref5(url) {
10618
+ function safeHref6(url) {
10323
10619
  if (url == null) return void 0;
10324
10620
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
10325
10621
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -10334,7 +10630,7 @@ function Container({
10334
10630
  ...rest
10335
10631
  }) {
10336
10632
  const max = SIZES[size] ?? size;
10337
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref5(rest.href);
10633
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref6(rest.href);
10338
10634
  return /* @__PURE__ */ jsx(
10339
10635
  Tag2,
10340
10636
  {
@@ -10359,7 +10655,8 @@ function space(v) {
10359
10655
  function len(v) {
10360
10656
  return typeof v === "number" ? `${v}px` : v;
10361
10657
  }
10362
- function safeHref6(url) {
10658
+ var BP = { sm: 640, md: 768, lg: 1024, xl: 1280 };
10659
+ function safeHref7(url) {
10363
10660
  if (url == null) return void 0;
10364
10661
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
10365
10662
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -10369,29 +10666,54 @@ function Grid({
10369
10666
  columns,
10370
10667
  minChildWidth,
10371
10668
  gap = 4,
10669
+ rowGap,
10670
+ columnGap,
10372
10671
  align,
10373
10672
  justify,
10673
+ alignContent,
10674
+ justifyContent,
10374
10675
  className = "",
10375
10676
  style,
10376
10677
  children,
10377
10678
  ...rest
10378
10679
  }) {
10379
- const templateColumns = minChildWidth ? `repeat(auto-fill, minmax(min(${len(minChildWidth)}, 100%), 1fr))` : `repeat(${columns || 1}, minmax(0, 1fr))`;
10380
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref6(rest.href);
10381
- return /* @__PURE__ */ jsx(
10680
+ const responsive = columns != null && typeof columns === "object";
10681
+ const uid = React24__default.useId();
10682
+ const gridId = responsive ? `g${uid.replace(/[^a-zA-Z0-9]/g, "")}` : null;
10683
+ let css = "";
10684
+ if (responsive) {
10685
+ const base = columns.base ?? 1;
10686
+ const sel = `[data-twc-grid-id="${gridId}"]`;
10687
+ css = `${sel} { --twc-grid-cols: ${base}; }`;
10688
+ for (const bp of ["sm", "md", "lg", "xl"]) {
10689
+ if (columns[bp] != null) css += `
10690
+ @media (min-width: ${BP[bp]}px) { ${sel} { --twc-grid-cols: ${columns[bp]}; } }`;
10691
+ }
10692
+ }
10693
+ const __twcStyles = useScopedStyles(gridId ? `twc-grid-${gridId}` : "twc-grid", css);
10694
+ const templateColumns = minChildWidth ? `repeat(auto-fill, minmax(min(${len(minChildWidth)}, 100%), 1fr))` : responsive ? `repeat(var(--twc-grid-cols, ${columns.base ?? 1}), minmax(0, 1fr))` : `repeat(${columns || 1}, minmax(0, 1fr))`;
10695
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref7(rest.href);
10696
+ return /* @__PURE__ */ jsxs(
10382
10697
  Tag2,
10383
10698
  {
10384
10699
  className: `twc-grid ${className}`.trim(),
10700
+ "data-twc-grid-id": gridId || void 0,
10385
10701
  style: {
10386
10702
  display: "grid",
10387
10703
  gridTemplateColumns: templateColumns,
10388
- gap: space(gap),
10704
+ rowGap: space(rowGap ?? gap),
10705
+ columnGap: space(columnGap ?? gap),
10389
10706
  alignItems: align,
10390
10707
  justifyItems: justify,
10708
+ alignContent,
10709
+ justifyContent,
10391
10710
  ...style
10392
10711
  },
10393
10712
  ...rest,
10394
- children
10713
+ children: [
10714
+ responsive ? __twcStyles : null,
10715
+ children
10716
+ ]
10395
10717
  }
10396
10718
  );
10397
10719
  }
@@ -10400,7 +10722,7 @@ function space2(v) {
10400
10722
  if (typeof v === "number") return `var(--space-${String(v).replace(".", "-")})`;
10401
10723
  return v;
10402
10724
  }
10403
- function safeHref7(url) {
10725
+ function safeHref8(url) {
10404
10726
  if (url == null) return void 0;
10405
10727
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
10406
10728
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -10413,12 +10735,21 @@ function Stack({
10413
10735
  justify,
10414
10736
  wrap = false,
10415
10737
  inline = false,
10738
+ p,
10739
+ px,
10740
+ py,
10741
+ pt,
10742
+ pr,
10743
+ pb,
10744
+ pl,
10745
+ divider,
10416
10746
  className = "",
10417
10747
  style,
10418
10748
  children,
10419
10749
  ...rest
10420
10750
  }) {
10421
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref7(rest.href);
10751
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref8(rest.href);
10752
+ const kids = divider != null ? React24__default.Children.toArray(children).flatMap((child, i, arr) => i < arr.length - 1 ? [child, /* @__PURE__ */ jsx(React24__default.Fragment, { children: divider }, `twc-stack-div-${i}`)] : [child]) : children;
10422
10753
  return /* @__PURE__ */ jsx(
10423
10754
  Tag2,
10424
10755
  {
@@ -10430,11 +10761,15 @@ function Stack({
10430
10761
  alignItems: align,
10431
10762
  justifyContent: justify,
10432
10763
  flexWrap: wrap ? "wrap" : void 0,
10764
+ paddingTop: space2(pt ?? py ?? p),
10765
+ paddingRight: space2(pr ?? px ?? p),
10766
+ paddingBottom: space2(pb ?? py ?? p),
10767
+ paddingLeft: space2(pl ?? px ?? p),
10433
10768
  minWidth: 0,
10434
10769
  ...style
10435
10770
  },
10436
10771
  ...rest,
10437
- children
10772
+ children: kids
10438
10773
  }
10439
10774
  );
10440
10775
  }
@@ -10446,22 +10781,64 @@ var CODE_CSS = `
10446
10781
  border: var(--border-thin) solid var(--color-border);
10447
10782
  white-space: normal; overflow-wrap: anywhere; word-break: break-word;
10448
10783
  }
10784
+ .twc-code[data-block="true"] {
10785
+ display: block; position: relative; white-space: pre; overflow-x: auto;
10786
+ padding: 12px 14px; padding-inline-end: 40px; line-height: 1.6; font-size: 0.8125em;
10787
+ overflow-wrap: normal; word-break: normal;
10788
+ }
10789
+ .twc-code__copy {
10790
+ position: absolute; top: 6px; inset-inline-end: 6px; display: inline-grid; place-items: center;
10791
+ width: 26px; height: 26px; border: none; border-radius: var(--radius-sm);
10792
+ background: var(--color-surface); color: var(--color-text-subtle); cursor: pointer;
10793
+ transition: color var(--duration-fast), background-color var(--duration-fast);
10794
+ }
10795
+ .twc-code__copy:hover { color: var(--color-text); }
10796
+ .twc-code__copy:focus-visible { outline: none; box-shadow: var(--ring); }
10797
+ .twc-code__copy svg { width: 15px; height: 15px; display: block; }
10449
10798
  `;
10450
- function safeHref8(url) {
10799
+ function safeHref9(url) {
10451
10800
  if (url == null) return void 0;
10452
10801
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
10453
10802
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
10454
10803
  }
10455
- function Code({ as: Tag2 = "code", className = "", children, ...rest }) {
10804
+ function Code({
10805
+ as,
10806
+ block = false,
10807
+ copyable = false,
10808
+ copyLabel = "Copy code",
10809
+ copiedLabel = "Copied",
10810
+ className = "",
10811
+ children,
10812
+ ...rest
10813
+ }) {
10456
10814
  const __twcStyles = useScopedStyles("twc-code-styles", CODE_CSS);
10457
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref8(rest.href);
10458
- return /* @__PURE__ */ jsxs(Tag2, { className: `twc-code ${className}`.trim(), ...rest, children: [
10815
+ const Tag2 = as ?? (block ? "pre" : "code");
10816
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref9(rest.href);
10817
+ const rootRef = React24__default.useRef(null);
10818
+ const [copied, setCopied] = React24__default.useState(false);
10819
+ const timerRef = React24__default.useRef(null);
10820
+ React24__default.useEffect(() => () => clearTimeout(timerRef.current), []);
10821
+ const doCopy = () => {
10822
+ if (typeof navigator === "undefined" || !navigator.clipboard) return;
10823
+ const text = typeof children === "string" ? children : rootRef.current?.textContent ?? "";
10824
+ navigator.clipboard.writeText(text).then(() => {
10825
+ setCopied(true);
10826
+ clearTimeout(timerRef.current);
10827
+ timerRef.current = setTimeout(() => setCopied(false), 2e3);
10828
+ }).catch(() => {
10829
+ });
10830
+ };
10831
+ return /* @__PURE__ */ jsxs(Tag2, { ref: rootRef, className: `twc-code ${className}`.trim(), "data-block": block || void 0, ...rest, children: [
10459
10832
  __twcStyles,
10833
+ copyable ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-code__copy", "aria-label": copied ? copiedLabel : copyLabel, onClick: doCopy, children: copied ? /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m20 6-11 11-5-5" }) }) : /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
10834
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
10835
+ /* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
10836
+ ] }) }) : null,
10460
10837
  children
10461
10838
  ] });
10462
10839
  }
10463
10840
  var LEVEL_SIZE = { 1: "4xl", 2: "2xl", 3: "xl", 4: "lg", 5: "base", 6: "sm" };
10464
- function safeHref9(url) {
10841
+ function safeHref10(url) {
10465
10842
  if (url == null) return void 0;
10466
10843
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
10467
10844
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -10470,15 +10847,18 @@ function Heading({
10470
10847
  as,
10471
10848
  level = 2,
10472
10849
  size,
10850
+ display = false,
10473
10851
  align,
10852
+ truncate,
10853
+ lineClamp,
10474
10854
  className = "",
10475
10855
  style,
10476
10856
  children,
10477
10857
  ...rest
10478
10858
  }) {
10479
10859
  const Tag2 = as || `h${level}`;
10480
- const sz = size || LEVEL_SIZE[level] || "2xl";
10481
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref9(rest.href);
10860
+ const sz = size || (display ? "display" : LEVEL_SIZE[level]) || "2xl";
10861
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref10(rest.href);
10482
10862
  return /* @__PURE__ */ jsx(
10483
10863
  Tag2,
10484
10864
  {
@@ -10492,6 +10872,7 @@ function Heading({
10492
10872
  letterSpacing: "-0.02em",
10493
10873
  fontSize: `var(--text-${sz})`,
10494
10874
  textAlign: align,
10875
+ ...lineClamp != null ? { display: "-webkit-box", WebkitBoxOrient: "vertical", WebkitLineClamp: lineClamp, overflow: "hidden" } : truncate ? { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", minWidth: 0 } : null,
10495
10876
  ...style
10496
10877
  },
10497
10878
  ...rest,
@@ -10510,9 +10891,11 @@ var TONE = {
10510
10891
  success: "--color-success",
10511
10892
  warning: "--color-warning-subtle-fg",
10512
10893
  info: "--color-info-subtle-fg",
10513
- neutral: "--color-text-muted"
10894
+ neutral: "--color-text-muted",
10895
+ // Adopt the surrounding color (e.g. inside a solid Button/Badge/Alert or a link).
10896
+ inherit: "inherit"
10514
10897
  };
10515
- function safeHref10(url) {
10898
+ function safeHref11(url) {
10516
10899
  if (url == null) return void 0;
10517
10900
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
10518
10901
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -10523,12 +10906,15 @@ function Text({
10523
10906
  tone = "default",
10524
10907
  weight,
10525
10908
  align,
10909
+ truncate,
10910
+ lineClamp,
10526
10911
  className = "",
10527
10912
  style,
10528
10913
  children,
10529
10914
  ...rest
10530
10915
  }) {
10531
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref10(rest.href);
10916
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref11(rest.href);
10917
+ const toneToken = TONE[tone] || TONE.default;
10532
10918
  return /* @__PURE__ */ jsx(
10533
10919
  Tag2,
10534
10920
  {
@@ -10538,9 +10924,10 @@ function Text({
10538
10924
  fontFamily: "var(--font-sans)",
10539
10925
  lineHeight: 1.6,
10540
10926
  fontSize: `var(--text-${size})`,
10541
- color: `var(${TONE[tone] || TONE.default})`,
10927
+ color: toneToken.startsWith("--") ? `var(${toneToken})` : toneToken,
10542
10928
  fontWeight: weight ? `var(--font-${weight})` : void 0,
10543
10929
  textAlign: align,
10930
+ ...lineClamp != null ? { display: "-webkit-box", WebkitBoxOrient: "vertical", WebkitLineClamp: lineClamp, overflow: "hidden" } : truncate ? { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", minWidth: 0 } : null,
10544
10931
  ...style
10545
10932
  },
10546
10933
  ...rest,
@@ -10548,58 +10935,68 @@ function Text({
10548
10935
  }
10549
10936
  );
10550
10937
  }
10551
- var canUseDOM = typeof window !== "undefined" && typeof document !== "undefined";
10552
- var useIsomorphicLayoutEffect = canUseDOM ? React23__default.useLayoutEffect : React23__default.useEffect;
10938
+ var canUseDOM2 = typeof window !== "undefined" && typeof document !== "undefined";
10939
+ var useIsomorphicLayoutEffect = canUseDOM2 ? React24__default.useLayoutEffect : React24__default.useEffect;
10553
10940
  function useMounted() {
10554
- const [mounted, setMounted] = React23__default.useState(false);
10555
- React23__default.useEffect(() => {
10941
+ const [mounted, setMounted] = React24__default.useState(false);
10942
+ React24__default.useEffect(() => {
10556
10943
  setMounted(true);
10557
10944
  }, []);
10558
10945
  return mounted;
10559
10946
  }
10560
10947
  function usePrevious(value) {
10561
- const ref = React23__default.useRef(void 0);
10562
- React23__default.useEffect(() => {
10948
+ const ref = React24__default.useRef(void 0);
10949
+ React24__default.useEffect(() => {
10563
10950
  ref.current = value;
10564
10951
  }, [value]);
10565
10952
  return ref.current;
10566
10953
  }
10567
10954
  function useToggle(initial = false) {
10568
- const [on, setOn] = React23__default.useState(initial);
10569
- const toggle = React23__default.useCallback((next) => {
10955
+ const [on, setOn] = React24__default.useState(initial);
10956
+ const toggle = React24__default.useCallback((next) => {
10570
10957
  setOn((prev) => typeof next === "boolean" ? next : !prev);
10571
10958
  }, []);
10572
10959
  return [on, toggle, setOn];
10573
10960
  }
10574
10961
  function useDisclosure(initial = false) {
10575
- const [open, setOpen] = React23__default.useState(initial);
10576
- const onOpen = React23__default.useCallback(() => setOpen(true), []);
10577
- const onClose = React23__default.useCallback(() => setOpen(false), []);
10578
- const onToggle = React23__default.useCallback(() => setOpen((p) => !p), []);
10962
+ const [open, setOpen] = React24__default.useState(initial);
10963
+ const onOpen = React24__default.useCallback(() => setOpen(true), []);
10964
+ const onClose = React24__default.useCallback(() => setOpen(false), []);
10965
+ const onToggle = React24__default.useCallback(() => setOpen((p) => !p), []);
10579
10966
  return { open, onOpen, onClose, onToggle, setOpen };
10580
10967
  }
10581
10968
  function useControllableState({ value, defaultValue, onChange } = {}) {
10582
10969
  const isControlled = value !== void 0;
10583
- const [uncontrolled, setUncontrolled] = React23__default.useState(defaultValue);
10970
+ const [uncontrolled, setUncontrolled] = React24__default.useState(defaultValue);
10584
10971
  const current = isControlled ? value : uncontrolled;
10585
- const ref = React23__default.useRef({ current, isControlled, onChange });
10972
+ const ref = React24__default.useRef({ current, isControlled, onChange });
10586
10973
  useIsomorphicLayoutEffect(() => {
10587
10974
  ref.current = { current, isControlled, onChange };
10588
10975
  });
10589
- const setValue = React23__default.useCallback((next) => {
10976
+ const wasControlled = React24__default.useRef(isControlled);
10977
+ React24__default.useEffect(() => {
10978
+ if (wasControlled.current !== isControlled) {
10979
+ warnOnce(
10980
+ "useControllableState:switch",
10981
+ `useControllableState: a value is switching from ${wasControlled.current ? "controlled" : "uncontrolled"} to ${isControlled ? "controlled" : "uncontrolled"}. Decide between controlled (\`value\`) and uncontrolled (\`defaultValue\`) for the component's lifetime.`
10982
+ );
10983
+ wasControlled.current = isControlled;
10984
+ }
10985
+ });
10986
+ const setValue = React24__default.useCallback((next) => {
10590
10987
  const { current: cur, isControlled: ctrl, onChange: cb } = ref.current;
10591
10988
  const resolved = typeof next === "function" ? next(cur) : next;
10592
10989
  if (resolved === cur) return;
10593
10990
  if (!ctrl) setUncontrolled(resolved);
10594
10991
  if (cb) cb(resolved);
10595
10992
  }, []);
10596
- return [current, setValue];
10993
+ return [current, setValue, isControlled];
10597
10994
  }
10598
- function useMediaQuery(query) {
10599
- const get = () => canUseDOM ? window.matchMedia(query).matches : false;
10600
- const [matches3, setMatches] = React23__default.useState(get);
10601
- React23__default.useEffect(() => {
10602
- if (!canUseDOM) return void 0;
10995
+ function useMediaQuery(query, { defaultValue = false, initializeWithValue = false } = {}) {
10996
+ const get = () => canUseDOM2 ? window.matchMedia(query).matches : defaultValue;
10997
+ const [matches3, setMatches] = React24__default.useState(initializeWithValue ? get : defaultValue);
10998
+ useIsomorphicLayoutEffect(() => {
10999
+ if (!canUseDOM2) return void 0;
10603
11000
  const mql = window.matchMedia(query);
10604
11001
  const onChange = () => setMatches(mql.matches);
10605
11002
  onChange();
@@ -10612,10 +11009,10 @@ function usePrefersReducedMotion() {
10612
11009
  return useMediaQuery("(prefers-reduced-motion: reduce)");
10613
11010
  }
10614
11011
  function useColorScheme({ storageKey = "twico-theme", attribute = "class", element, disableTransitionsOnChange = true } = {}) {
10615
- const getTarget = () => element || (canUseDOM ? document.documentElement : null);
10616
- const firstApply = React23__default.useRef(true);
11012
+ const getTarget = () => element || (canUseDOM2 ? document.documentElement : null);
11013
+ const firstApply = React24__default.useRef(true);
10617
11014
  const read = () => {
10618
- if (!canUseDOM) return "light";
11015
+ if (!canUseDOM2) return "light";
10619
11016
  try {
10620
11017
  const stored = window.localStorage.getItem(storageKey);
10621
11018
  if (stored === "light" || stored === "dark") return stored;
@@ -10623,12 +11020,12 @@ function useColorScheme({ storageKey = "twico-theme", attribute = "class", eleme
10623
11020
  }
10624
11021
  return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
10625
11022
  };
10626
- const [theme, setThemeState] = React23__default.useState(read);
10627
- const apply = React23__default.useCallback(
11023
+ const [theme, setThemeState] = React24__default.useState(read);
11024
+ const apply = React24__default.useCallback(
10628
11025
  (t) => {
10629
11026
  const target = getTarget();
10630
11027
  if (!target) return;
10631
- const skip = firstApply.current || !disableTransitionsOnChange || !canUseDOM;
11028
+ const skip = firstApply.current || !disableTransitionsOnChange || !canUseDOM2;
10632
11029
  firstApply.current = false;
10633
11030
  let css;
10634
11031
  if (!skip) {
@@ -10650,26 +11047,26 @@ function useColorScheme({ storageKey = "twico-theme", attribute = "class", eleme
10650
11047
  useIsomorphicLayoutEffect(() => {
10651
11048
  apply(theme);
10652
11049
  }, [theme, apply]);
10653
- const themeRef = React23__default.useRef(theme);
11050
+ const themeRef = React24__default.useRef(theme);
10654
11051
  useIsomorphicLayoutEffect(() => {
10655
11052
  themeRef.current = theme;
10656
11053
  }, [theme]);
10657
- const setTheme = React23__default.useCallback(
11054
+ const setTheme = React24__default.useCallback(
10658
11055
  (t) => {
10659
11056
  setThemeState(t);
10660
11057
  try {
10661
- if (canUseDOM) window.localStorage.setItem(storageKey, t);
11058
+ if (canUseDOM2) window.localStorage.setItem(storageKey, t);
10662
11059
  } catch (e) {
10663
11060
  }
10664
- if (canUseDOM) window.dispatchEvent(new Event("twico:colorscheme"));
11061
+ if (canUseDOM2) window.dispatchEvent(new Event("twico:colorscheme"));
10665
11062
  },
10666
11063
  [storageKey]
10667
11064
  );
10668
- const toggle = React23__default.useCallback(() => {
11065
+ const toggle = React24__default.useCallback(() => {
10669
11066
  setTheme(themeRef.current === "dark" ? "light" : "dark");
10670
11067
  }, [setTheme]);
10671
- React23__default.useEffect(() => {
10672
- if (!canUseDOM) return void 0;
11068
+ React24__default.useEffect(() => {
11069
+ if (!canUseDOM2) return void 0;
10673
11070
  const sync = () => setThemeState(read());
10674
11071
  const onStorage = (e) => {
10675
11072
  if (e.key === storageKey) sync();
@@ -10684,15 +11081,15 @@ function useColorScheme({ storageKey = "twico-theme", attribute = "class", eleme
10684
11081
  return { theme, setTheme, toggle, isDark: theme === "dark" };
10685
11082
  }
10686
11083
  function useEventListener(eventName, handler, element, options) {
10687
- const saved = React23__default.useRef(handler);
11084
+ const saved = React24__default.useRef(handler);
10688
11085
  useIsomorphicLayoutEffect(() => {
10689
11086
  saved.current = handler;
10690
11087
  }, [handler]);
10691
11088
  const capture = typeof options === "boolean" ? options : options && options.capture;
10692
11089
  const passive = typeof options === "object" && options ? options.passive : void 0;
10693
11090
  const once = typeof options === "object" && options ? options.once : void 0;
10694
- React23__default.useEffect(() => {
10695
- const target = element && element.current || element || (canUseDOM ? window : null);
11091
+ React24__default.useEffect(() => {
11092
+ const target = element && element.current || element || (canUseDOM2 ? window : null);
10696
11093
  if (!target || !target.addEventListener) return void 0;
10697
11094
  const opts = typeof options === "boolean" ? options : { capture, passive, once };
10698
11095
  const listener = (e) => saved.current(e);
@@ -10701,12 +11098,12 @@ function useEventListener(eventName, handler, element, options) {
10701
11098
  }, [eventName, element, capture, passive, once]);
10702
11099
  }
10703
11100
  function useClickOutside(ref, handler, events = ["mousedown", "touchstart"]) {
10704
- const saved = React23__default.useRef(handler);
11101
+ const saved = React24__default.useRef(handler);
10705
11102
  useIsomorphicLayoutEffect(() => {
10706
11103
  saved.current = handler;
10707
11104
  }, [handler]);
10708
- React23__default.useEffect(() => {
10709
- if (!canUseDOM) return void 0;
11105
+ React24__default.useEffect(() => {
11106
+ if (!canUseDOM2) return void 0;
10710
11107
  const listener = (e) => {
10711
11108
  const el = ref && ref.current;
10712
11109
  if (!el || el.contains(e.target)) return;
@@ -10732,7 +11129,7 @@ function useKeyPress(key, handler, options = {}) {
10732
11129
  }
10733
11130
  function useLocalStorage(key, initialValue) {
10734
11131
  const read = () => {
10735
- if (!canUseDOM) return initialValue;
11132
+ if (!canUseDOM2) return initialValue;
10736
11133
  try {
10737
11134
  const item = window.localStorage.getItem(key);
10738
11135
  return item ? JSON.parse(item) : initialValue;
@@ -10740,13 +11137,13 @@ function useLocalStorage(key, initialValue) {
10740
11137
  return initialValue;
10741
11138
  }
10742
11139
  };
10743
- const [stored, setStored] = React23__default.useState(read);
10744
- const setValue = React23__default.useCallback(
11140
+ const [stored, setStored] = React24__default.useState(read);
11141
+ const setValue = React24__default.useCallback(
10745
11142
  (value) => {
10746
11143
  setStored((prev) => {
10747
11144
  const next = typeof value === "function" ? value(prev) : value;
10748
11145
  try {
10749
- if (canUseDOM) window.localStorage.setItem(key, JSON.stringify(next));
11146
+ if (canUseDOM2) window.localStorage.setItem(key, JSON.stringify(next));
10750
11147
  } catch (e) {
10751
11148
  }
10752
11149
  return next;
@@ -10757,9 +11154,9 @@ function useLocalStorage(key, initialValue) {
10757
11154
  return [stored, setValue];
10758
11155
  }
10759
11156
  function useCopyToClipboard(timeout = 1500) {
10760
- const [copied, setCopied] = React23__default.useState(false);
10761
- const copy = React23__default.useCallback(async (text) => {
10762
- if (!canUseDOM || !navigator.clipboard) {
11157
+ const [copied, setCopied] = React24__default.useState(false);
11158
+ const copy = React24__default.useCallback(async (text) => {
11159
+ if (!canUseDOM2 || !navigator.clipboard) {
10763
11160
  setCopied(false);
10764
11161
  return false;
10765
11162
  }
@@ -10772,7 +11169,7 @@ function useCopyToClipboard(timeout = 1500) {
10772
11169
  return false;
10773
11170
  }
10774
11171
  }, []);
10775
- React23__default.useEffect(() => {
11172
+ React24__default.useEffect(() => {
10776
11173
  if (!copied) return void 0;
10777
11174
  const t = setTimeout(() => setCopied(false), timeout);
10778
11175
  return () => clearTimeout(t);
@@ -10780,23 +11177,23 @@ function useCopyToClipboard(timeout = 1500) {
10780
11177
  return { copied, copy };
10781
11178
  }
10782
11179
  function useDebouncedValue(value, delay = 200) {
10783
- const [debounced, setDebounced] = React23__default.useState(value);
10784
- React23__default.useEffect(() => {
11180
+ const [debounced, setDebounced] = React24__default.useState(value);
11181
+ React24__default.useEffect(() => {
10785
11182
  const t = setTimeout(() => setDebounced(value), delay);
10786
11183
  return () => clearTimeout(t);
10787
11184
  }, [value, delay]);
10788
11185
  return debounced;
10789
11186
  }
10790
11187
  function useDebouncedCallback(callback, delay = 200) {
10791
- const saved = React23__default.useRef(callback);
10792
- const timer = React23__default.useRef(null);
11188
+ const saved = React24__default.useRef(callback);
11189
+ const timer = React24__default.useRef(null);
10793
11190
  useIsomorphicLayoutEffect(() => {
10794
11191
  saved.current = callback;
10795
11192
  }, [callback]);
10796
- React23__default.useEffect(() => () => {
11193
+ React24__default.useEffect(() => () => {
10797
11194
  if (timer.current) clearTimeout(timer.current);
10798
11195
  }, []);
10799
- return React23__default.useCallback(
11196
+ return React24__default.useCallback(
10800
11197
  (...args) => {
10801
11198
  if (timer.current) clearTimeout(timer.current);
10802
11199
  timer.current = setTimeout(() => saved.current(...args), delay);
@@ -10805,34 +11202,34 @@ function useDebouncedCallback(callback, delay = 200) {
10805
11202
  );
10806
11203
  }
10807
11204
  function useInterval(callback, delay) {
10808
- const saved = React23__default.useRef(callback);
11205
+ const saved = React24__default.useRef(callback);
10809
11206
  useIsomorphicLayoutEffect(() => {
10810
11207
  saved.current = callback;
10811
11208
  }, [callback]);
10812
- React23__default.useEffect(() => {
11209
+ React24__default.useEffect(() => {
10813
11210
  if (delay == null) return void 0;
10814
11211
  const id = setInterval(() => saved.current(), delay);
10815
11212
  return () => clearInterval(id);
10816
11213
  }, [delay]);
10817
11214
  }
10818
11215
  function useTimeout(callback, delay) {
10819
- const saved = React23__default.useRef(callback);
11216
+ const saved = React24__default.useRef(callback);
10820
11217
  useIsomorphicLayoutEffect(() => {
10821
11218
  saved.current = callback;
10822
11219
  }, [callback]);
10823
- React23__default.useEffect(() => {
11220
+ React24__default.useEffect(() => {
10824
11221
  if (delay == null) return void 0;
10825
11222
  const id = setTimeout(() => saved.current(), delay);
10826
11223
  return () => clearTimeout(id);
10827
11224
  }, [delay]);
10828
11225
  }
10829
11226
  function useWindowSize() {
10830
- const [size, setSize] = React23__default.useState(() => ({
10831
- width: canUseDOM ? window.innerWidth : 0,
10832
- height: canUseDOM ? window.innerHeight : 0
11227
+ const [size, setSize] = React24__default.useState(() => ({
11228
+ width: canUseDOM2 ? window.innerWidth : 0,
11229
+ height: canUseDOM2 ? window.innerHeight : 0
10833
11230
  }));
10834
- React23__default.useEffect(() => {
10835
- if (!canUseDOM) return void 0;
11231
+ React24__default.useEffect(() => {
11232
+ if (!canUseDOM2) return void 0;
10836
11233
  const onResize = () => setSize({ width: window.innerWidth, height: window.innerHeight });
10837
11234
  onResize();
10838
11235
  window.addEventListener("resize", onResize);
@@ -10841,8 +11238,8 @@ function useWindowSize() {
10841
11238
  return size;
10842
11239
  }
10843
11240
  function useHover(ref) {
10844
- const [hovered, setHovered] = React23__default.useState(false);
10845
- React23__default.useEffect(() => {
11241
+ const [hovered, setHovered] = React24__default.useState(false);
11242
+ React24__default.useEffect(() => {
10846
11243
  const el = ref && ref.current;
10847
11244
  if (!el) return void 0;
10848
11245
  const on = () => setHovered(true);
@@ -10858,10 +11255,10 @@ function useHover(ref) {
10858
11255
  }
10859
11256
  function useIntersectionObserver(ref, options = {}) {
10860
11257
  const { root = null, rootMargin = "0px", threshold = 0 } = options;
10861
- const [entry, setEntry] = React23__default.useState(null);
10862
- React23__default.useEffect(() => {
11258
+ const [entry, setEntry] = React24__default.useState(null);
11259
+ React24__default.useEffect(() => {
10863
11260
  const el = ref && ref.current;
10864
- if (!canUseDOM || !el || typeof IntersectionObserver === "undefined") return void 0;
11261
+ if (!canUseDOM2 || !el || typeof IntersectionObserver === "undefined") return void 0;
10865
11262
  const obs = new IntersectionObserver(([e]) => setEntry(e), { root, rootMargin, threshold });
10866
11263
  obs.observe(el);
10867
11264
  return () => obs.disconnect();
@@ -10872,7 +11269,7 @@ var __scrollLockCount = 0;
10872
11269
  var __scrollLockSaved = "";
10873
11270
  function useScrollLock(locked = true) {
10874
11271
  useIsomorphicLayoutEffect(() => {
10875
- if (!canUseDOM || !locked) return void 0;
11272
+ if (!canUseDOM2 || !locked) return void 0;
10876
11273
  if (__scrollLockCount === 0) {
10877
11274
  __scrollLockSaved = document.body.style.overflow;
10878
11275
  document.body.style.overflow = "hidden";
@@ -10887,10 +11284,12 @@ function useScrollLock(locked = true) {
10887
11284
  }, [locked]);
10888
11285
  }
10889
11286
  function useId(prefix = "twc") {
10890
- const raw = React23__default.useId();
11287
+ const raw = React24__default.useId();
10891
11288
  return prefix ? `${prefix}-${raw.replace(/:/g, "")}` : raw;
10892
11289
  }
11290
+ var useFocusTrap2 = useFocusTrap;
11291
+ var usePortal2 = usePortal;
10893
11292
 
10894
- export { Accordion, Alert, AppShell, Avatar, AvatarMenu, Badge, Box, Breadcrumb, Button, Card, Carousel, Chart, Checkbox, Code, ColorPicker, Combobox, CommandPalette, Container, Currency, CurrencyField, Datatable, DatePicker, DateRangePicker, Dialog, Divider, Drawer, EmptyState, Field, FileUpload, Grid, Heading, IconButton, Input, Kanban, List, Menu, MultiSelect, Navbar, Pagination, Popover, Progress, Radio, Rating, Select, Sidebar, Skeleton, Slider, Spinner, Stack, Stat, Stepper, Switch, Table, Tabs, Tag, Text, Textarea, Timeline, Toast, ToastProvider, ToastViewport, Tooltip, TreeView, runDatatableQuery, useClickOutside, useColorScheme, useControllableState, useCopyToClipboard, useDebouncedCallback, useDebouncedValue, useDisclosure, useEventListener, useHover, useId, useIntersectionObserver, useInterval, useIsomorphicLayoutEffect, useKeyPress, useLocalStorage, useMediaQuery, useMounted, usePrefersReducedMotion, usePrevious, useScrollLock, useTimeout, useToast, useToggle, useWindowSize };
11293
+ export { Accordion, Alert, AppShell, Avatar, AvatarMenu, Badge, Box, Breadcrumb, Button, Card, Carousel, Chart, Checkbox, Code, ColorPicker, Combobox, CommandPalette, Container, Currency, CurrencyField, Datatable, DatePicker, DateRangePicker, Dialog, Divider, Drawer, EmptyState, Field, FileUpload, Grid, Heading, IconButton, Input, Kanban, List, Menu, MultiSelect, Navbar, Pagination, Popover, Progress, Radio, Rating, Select, Sidebar, Skeleton, Slider, Spinner, Stack, Stat, Stepper, Switch, Table, Tabs, Tag, Text, Textarea, Timeline, Toast, ToastProvider, ToastViewport, Tooltip, TreeView, runDatatableQuery, useClickOutside, useColorScheme, useControllableState, useCopyToClipboard, useDebouncedCallback, useDebouncedValue, useDisclosure, useEventListener, useFocusTrap2 as useFocusTrap, useHover, useId, useIntersectionObserver, useInterval, useIsomorphicLayoutEffect, useKeyPress, useLocalStorage, useMediaQuery, useMounted, usePortal2 as usePortal, usePrefersReducedMotion, usePrevious, useScrollLock, useTimeout, useToast, useToggle, useWindowSize };
10895
11294
  //# sourceMappingURL=index.mjs.map
10896
11295
  //# sourceMappingURL=index.mjs.map