twico-ui 1.3.2 → 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.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var React23 = require('react');
4
+ var React24 = require('react');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var reactDom = require('react-dom');
7
7
 
@@ -23,12 +23,12 @@ function _interopNamespace(e) {
23
23
  return Object.freeze(n);
24
24
  }
25
25
 
26
- var React23__namespace = /*#__PURE__*/_interopNamespace(React23);
26
+ var React24__namespace = /*#__PURE__*/_interopNamespace(React24);
27
27
 
28
28
  // components/navigation/Accordion.jsx
29
- var SUPPORTS_STYLE_HOIST = parseInt(String(React23__namespace.version), 10) >= 19;
29
+ var SUPPORTS_STYLE_HOIST = parseInt(String(React24__namespace.version), 10) >= 19;
30
30
  function useScopedStyles(id, css) {
31
- React23__namespace.useInsertionEffect(() => {
31
+ React24__namespace.useInsertionEffect(() => {
32
32
  if (SUPPORTS_STYLE_HOIST) return;
33
33
  if (typeof document === "undefined" || document.getElementById(id)) return;
34
34
  const el = document.createElement("style");
@@ -36,7 +36,7 @@ function useScopedStyles(id, css) {
36
36
  el.textContent = css;
37
37
  document.head.appendChild(el);
38
38
  }, [id, css]);
39
- return SUPPORTS_STYLE_HOIST ? React23__namespace.createElement("style", { href: id, precedence: "twc-ui" }, css) : null;
39
+ return SUPPORTS_STYLE_HOIST ? React24__namespace.createElement("style", { href: id, precedence: "twc-ui" }, css) : null;
40
40
  }
41
41
  var ACCORDION_CSS = `
42
42
  .twc-accordion { display: flex; flex-direction: column; font-family: var(--font-sans);
@@ -50,7 +50,9 @@ var ACCORDION_CSS = `
50
50
  color: var(--color-text); text-align: start;
51
51
  transition: background-color var(--duration-fast) var(--ease-standard);
52
52
  }
53
- .twc-accordion__trigger:hover { background: var(--color-surface-sunken); }
53
+ .twc-accordion__heading { margin: 0; font: inherit; }
54
+ .twc-accordion__trigger:hover:not(:disabled) { background: var(--color-surface-sunken); }
55
+ .twc-accordion__trigger:disabled { opacity: 0.45; cursor: not-allowed; }
54
56
  .twc-accordion__trigger:focus-visible { outline: none; box-shadow: var(--ring); }
55
57
  .twc-accordion__label { flex: 1; }
56
58
  .twc-accordion__chevron { flex: none; color: var(--color-text-subtle); transition: transform var(--duration-base) var(--ease-spring); }
@@ -69,14 +71,19 @@ function Accordion({
69
71
  defaultOpen = [],
70
72
  open: openProp,
71
73
  onOpenChange,
74
+ headingLevel = 3,
72
75
  className = "",
76
+ onKeyDown: onKeyDownProp,
73
77
  ...rest
74
78
  }) {
75
79
  const __twcStyles = useScopedStyles("twc-accordion-styles", ACCORDION_CSS);
76
- const [internal, setInternal] = React23__namespace.default.useState(() => new Set(defaultOpen));
80
+ const rootRef = React24__namespace.default.useRef(null);
81
+ const [internal, setInternal] = React24__namespace.default.useState(() => new Set(defaultOpen));
77
82
  const open = openProp !== void 0 ? new Set(openProp) : internal;
78
- const baseId = React23__namespace.default.useId();
83
+ const baseId = React24__namespace.default.useId();
79
84
  function toggle(val) {
85
+ const item = items.find((x) => x.value === val);
86
+ if (item?.disabled) return;
80
87
  const next = new Set(open);
81
88
  if (next.has(val)) next.delete(val);
82
89
  else {
@@ -86,18 +93,47 @@ function Accordion({
86
93
  if (openProp === void 0) setInternal(next);
87
94
  onOpenChange?.([...next]);
88
95
  }
89
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-accordion ${className}`, ...rest, children: [
96
+ function handleKeyDown(e) {
97
+ onKeyDownProp?.(e);
98
+ if (!(e.target instanceof HTMLElement) || !e.target.classList.contains("twc-accordion__trigger")) return;
99
+ const triggers = Array.from(rootRef.current.querySelectorAll(".twc-accordion__trigger")).filter((b) => !b.disabled);
100
+ const i = triggers.indexOf(e.target);
101
+ if (i < 0) return;
102
+ const len2 = triggers.length;
103
+ let next;
104
+ switch (e.key) {
105
+ case "ArrowDown":
106
+ next = (i + 1) % len2;
107
+ break;
108
+ case "ArrowUp":
109
+ next = (i - 1 + len2) % len2;
110
+ break;
111
+ case "Home":
112
+ next = 0;
113
+ break;
114
+ case "End":
115
+ next = len2 - 1;
116
+ break;
117
+ default:
118
+ return;
119
+ }
120
+ e.preventDefault();
121
+ triggers[next].focus();
122
+ }
123
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: `twc-accordion ${className}`, onKeyDown: handleKeyDown, ...rest, children: [
90
124
  __twcStyles,
91
125
  items.map((it, i) => {
92
126
  const isOpen = open.has(it.value);
93
127
  const triggerId = `${baseId}-trigger-${i}`;
94
128
  const panelId = `${baseId}-panel-${i}`;
129
+ const lvl = Math.min(6, Math.max(1, it.headingLevel ?? headingLevel));
130
+ const Heading2 = `h${lvl}`;
95
131
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-accordion__item", children: [
96
- /* @__PURE__ */ jsxRuntime.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: [
132
+ /* @__PURE__ */ jsxRuntime.jsx(Heading2, { className: "twc-accordion__heading", children: /* @__PURE__ */ jsxRuntime.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: [
97
133
  it.icon,
98
134
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-accordion__label", children: it.label }),
99
135
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-accordion__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) }) })
100
- ] }),
136
+ ] }) }),
101
137
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-accordion__panel", id: panelId, role: "region", "aria-labelledby": triggerId, "data-open": isOpen || void 0, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-accordion__panel-inner", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-accordion__content", children: it.content }) }) })
102
138
  ] }, it.value);
103
139
  })
@@ -153,11 +189,15 @@ function Alert({
153
189
  title,
154
190
  icon,
155
191
  onClose,
192
+ live,
193
+ closeLabel = "Dismiss",
156
194
  className = "",
157
195
  ...rest
158
196
  }) {
159
197
  const __twcStyles = useScopedStyles("twc-alert-styles", ALERT_CSS);
160
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-alert ${className}`, "data-tone": tone, "data-variant": variant, role: "alert", ...rest, children: [
198
+ const resolvedLive = live ?? (tone === "danger" || tone === "warning" ? "assertive" : tone === "success" || tone === "info" ? "polite" : "off");
199
+ const liveProps = resolvedLive === "assertive" ? { role: "alert" } : resolvedLive === "polite" ? { role: "status" } : {};
200
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-alert ${className}`, "data-tone": tone, "data-variant": variant, ...liveProps, ...rest, children: [
161
201
  __twcStyles,
162
202
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-alert__icon", "aria-hidden": "true", children: icon || /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
163
203
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
@@ -167,7 +207,7 @@ function Alert({
167
207
  title ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-alert__title", children: title }) : null,
168
208
  children ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-alert__desc", children }) : null
169
209
  ] }),
170
- onClose ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: "twc-alert__close", onClick: onClose, "aria-label": "Dismiss", type: "button", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
210
+ onClose ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: "twc-alert__close", onClick: onClose, "aria-label": closeLabel, type: "button", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
171
211
  ] });
172
212
  }
173
213
  var AVATAR_CSS = `
@@ -208,22 +248,29 @@ function initials(name) {
208
248
  function safeSrc(url) {
209
249
  if (url == null) return void 0;
210
250
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
211
- return s.startsWith("javascript:") || s.startsWith("vbscript:") ? void 0 : url;
251
+ if (s.startsWith("javascript:") || s.startsWith("vbscript:")) return void 0;
252
+ if (s.startsWith("data:") && !s.startsWith("data:image/")) return void 0;
253
+ return url;
212
254
  }
255
+ var STATUS_LABELS = { online: "Online", busy: "Busy", away: "Away", offline: "Offline" };
213
256
  function Avatar({
214
257
  src,
215
258
  name,
216
259
  size = "md",
217
260
  square = false,
218
261
  status,
262
+ statusLabel,
263
+ statusLabels,
219
264
  ring = false,
220
265
  className = "",
221
266
  ...rest
222
267
  }) {
223
268
  const __twcStyles = useScopedStyles("twc-avatar-styles", AVATAR_CSS);
224
- const [errored, setErrored] = React23__namespace.default.useState(false);
269
+ const [errored, setErrored] = React24__namespace.default.useState(false);
225
270
  const cleanSrc = safeSrc(src);
226
271
  const showImg = cleanSrc && !errored;
272
+ const _statusLabel = status ? statusLabel ?? statusLabels?.[status] ?? STATUS_LABELS[status] : void 0;
273
+ const baseName = name || "avatar";
227
274
  return /* @__PURE__ */ jsxRuntime.jsxs(
228
275
  "span",
229
276
  {
@@ -231,12 +278,12 @@ function Avatar({
231
278
  "data-size": size,
232
279
  "data-square": square || void 0,
233
280
  role: "img",
234
- "aria-label": name || "avatar",
281
+ "aria-label": _statusLabel ? `${baseName}, ${_statusLabel}` : baseName,
235
282
  ...rest,
236
283
  children: [
237
284
  __twcStyles,
238
285
  showImg ? /* @__PURE__ */ jsxRuntime.jsx("img", { className: "twc-avatar__img", src: cleanSrc, alt: name || "", onError: () => setErrored(true) }, cleanSrc) : initials(name),
239
- status ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-avatar__status", "data-status": status }) : null
286
+ status ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-avatar__status", "data-status": status, title: _statusLabel }) : null
240
287
  ]
241
288
  }
242
289
  );
@@ -277,6 +324,11 @@ var MENU_CSS = `
277
324
  .twc-menu__item-label { flex: 1 1 auto; min-width: 0; }
278
325
  .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); }
279
326
  `;
327
+ var safeHref = (url) => {
328
+ if (url == null) return void 0;
329
+ const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
330
+ return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
331
+ };
280
332
  function Menu({
281
333
  trigger,
282
334
  items,
@@ -286,26 +338,29 @@ function Menu({
286
338
  open: openProp,
287
339
  defaultOpen = false,
288
340
  onOpenChange,
341
+ "aria-label": ariaLabel,
342
+ "aria-labelledby": ariaLabelledby,
289
343
  className = "",
290
344
  ...rest
291
345
  }) {
292
346
  const __twcStyles = useScopedStyles("twc-menu-styles", MENU_CSS);
293
- const [openState, setOpenState] = React23__namespace.default.useState(defaultOpen);
294
- const [render, setRender] = React23__namespace.default.useState(false);
295
- const [pos, setPos] = React23__namespace.default.useState(null);
296
- const [active, setActive] = React23__namespace.default.useState(-1);
297
- const wrapRef = React23__namespace.default.useRef(null);
298
- const menuRef = React23__namespace.default.useRef(null);
299
- const menuId = React23__namespace.default.useId();
347
+ const [openState, setOpenState] = React24__namespace.default.useState(defaultOpen);
348
+ const [render, setRender] = React24__namespace.default.useState(false);
349
+ const [pos, setPos] = React24__namespace.default.useState(null);
350
+ const [active, setActive] = React24__namespace.default.useState(-1);
351
+ const wrapRef = React24__namespace.default.useRef(null);
352
+ const menuRef = React24__namespace.default.useRef(null);
353
+ const menuId = React24__namespace.default.useId();
354
+ const headerId = `${menuId}-header`;
300
355
  const controlled = openProp !== void 0;
301
356
  const open = controlled ? !!openProp : openState;
302
- const openRef = React23__namespace.default.useRef(open);
357
+ const openRef = React24__namespace.default.useRef(open);
303
358
  openRef.current = open;
304
- const controlledRef = React23__namespace.default.useRef(controlled);
359
+ const controlledRef = React24__namespace.default.useRef(controlled);
305
360
  controlledRef.current = controlled;
306
- const onOpenChangeRef = React23__namespace.default.useRef(onOpenChange);
361
+ const onOpenChangeRef = React24__namespace.default.useRef(onOpenChange);
307
362
  onOpenChangeRef.current = onOpenChange;
308
- const setOpen = React23__namespace.default.useCallback((next) => {
363
+ const setOpen = React24__namespace.default.useCallback((next) => {
309
364
  const value = typeof next === "function" ? next(openRef.current) : next;
310
365
  if (value === openRef.current) return;
311
366
  if (!controlledRef.current) setOpenState(value);
@@ -313,7 +368,7 @@ function Menu({
313
368
  }, []);
314
369
  const RD = { createPortal: typeof reactDom.createPortal === "function" ? reactDom.createPortal : typeof window !== "undefined" && window.ReactDOM && window.ReactDOM.createPortal };
315
370
  const interactiveIdx = items.map((it, i) => !it.separator && !it.heading ? i : -1).filter((i) => i >= 0);
316
- const place = React23__namespace.default.useCallback(() => {
371
+ const place = React24__namespace.default.useCallback(() => {
317
372
  const t = wrapRef.current;
318
373
  if (!t) return;
319
374
  const r = t.getBoundingClientRect();
@@ -328,7 +383,7 @@ function Menu({
328
383
  const avail = (flip ? r.top : vh - r.bottom) - gap - M;
329
384
  setPos({ top, bottom, left, width: w, flip, maxHeight: Math.max(120, avail) });
330
385
  }, [align, width]);
331
- React23__namespace.default.useEffect(() => {
386
+ React24__namespace.default.useEffect(() => {
332
387
  if (!open) return;
333
388
  place();
334
389
  const onMove = () => place();
@@ -346,7 +401,7 @@ function Menu({
346
401
  document.removeEventListener("mousedown", onDown);
347
402
  };
348
403
  }, [open, place]);
349
- React23__namespace.default.useEffect(() => {
404
+ React24__namespace.default.useEffect(() => {
350
405
  if (open) {
351
406
  setRender(true);
352
407
  return;
@@ -392,8 +447,12 @@ function Menu({
392
447
  e.preventDefault();
393
448
  const it = items[active];
394
449
  if (it && !it.disabled) {
395
- it.onClick?.();
396
- setOpen(false);
450
+ const el = typeof document !== "undefined" ? document.getElementById(`${menuId}-item-${active}`) : null;
451
+ if (el && el.tagName === "A") el.click();
452
+ else {
453
+ it.onClick?.();
454
+ setOpen(false);
455
+ }
397
456
  }
398
457
  }
399
458
  }
@@ -407,29 +466,32 @@ function Menu({
407
466
  "data-align": align,
408
467
  "data-flip": pos.flip || void 0,
409
468
  role: "menu",
469
+ "aria-label": ariaLabel,
470
+ "aria-labelledby": ariaLabelledby ?? (ariaLabel ? void 0 : header ? headerId : void 0),
410
471
  style: { top: pos.top, bottom: pos.bottom, left: pos.left, minWidth: pos.width, width: pos.width, maxHeight: pos.maxHeight },
411
472
  children: [
412
473
  __twcStyles,
413
- header ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-menu__header", children: header }) : null,
474
+ header ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-menu__header", id: headerId, children: header }) : null,
414
475
  items.map((it, i) => {
415
476
  if (it.separator) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-menu__sep", role: "separator" }, `s${i}`);
416
477
  if (it.label && it.heading) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-menu__label", children: it.label }, `h${i}`);
478
+ const href = !it.disabled ? safeHref(it.href) : void 0;
479
+ const Tag2 = href ? "a" : "button";
417
480
  return /* @__PURE__ */ jsxRuntime.jsxs(
418
- "button",
481
+ Tag2,
419
482
  {
420
- type: "button",
421
483
  id: `${menuId}-item-${i}`,
422
484
  className: "twc-menu__item",
423
485
  role: "menuitem",
424
486
  tabIndex: -1,
425
487
  "data-danger": it.danger || void 0,
426
488
  "data-active": active === i || void 0,
427
- disabled: it.disabled,
428
489
  onMouseEnter: () => setActive(i),
429
490
  onClick: () => {
430
491
  it.onClick?.();
431
492
  setOpen(false);
432
493
  },
494
+ ...Tag2 === "button" ? { type: "button", disabled: it.disabled } : { href, target: it.target, rel: it.rel },
433
495
  children: [
434
496
  it.icon,
435
497
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-menu__item-label", children: it.label }),
@@ -443,7 +505,7 @@ function Menu({
443
505
  }
444
506
  ) : null;
445
507
  const activeDescId = open && active >= 0 ? `${menuId}-item-${active}` : void 0;
446
- const triggerEl = React23__namespace.default.isValidElement(trigger) ? React23__namespace.default.cloneElement(trigger, {
508
+ const triggerEl = React24__namespace.default.isValidElement(trigger) ? React24__namespace.default.cloneElement(trigger, {
447
509
  onClick: (e) => {
448
510
  trigger.props.onClick?.(e);
449
511
  toggle();
@@ -526,7 +588,7 @@ function AvatarMenu({
526
588
  ]
527
589
  }
528
590
  );
529
- return /* @__PURE__ */ jsxRuntime.jsx(Menu, { className, trigger, items, header, align, width: 240, ...rest });
591
+ return /* @__PURE__ */ jsxRuntime.jsx(Menu, { className, trigger, items, header, align, width: 240, "aria-label": `${name || "Account"} menu`, ...rest });
530
592
  }
531
593
  var BADGE_CSS = `
532
594
  .twc-badge {
@@ -593,7 +655,7 @@ var BREADCRUMB_CSS = `
593
655
  .twc-breadcrumb__ellipsis { border: none; background: transparent; cursor: pointer; color: var(--color-text-subtle); padding: 3px 7px; border-radius: var(--radius-sm); font: inherit; }
594
656
  .twc-breadcrumb__ellipsis:hover { background: var(--color-surface-sunken); color: var(--color-text); }
595
657
  `;
596
- function safeHref(url) {
658
+ function safeHref2(url) {
597
659
  if (url == null) return void 0;
598
660
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
599
661
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -607,7 +669,7 @@ function Breadcrumb({
607
669
  ...rest
608
670
  }) {
609
671
  const __twcStyles = useScopedStyles("twc-breadcrumb-styles", BREADCRUMB_CSS);
610
- const [expanded, setExpanded] = React23__namespace.default.useState(false);
672
+ const [expanded, setExpanded] = React24__namespace.default.useState(false);
611
673
  const sep = separator || /* @__PURE__ */ jsxRuntime.jsx(ChevronSep, {});
612
674
  let display = items;
613
675
  if (maxItems > 0 && items.length > maxItems && !expanded) {
@@ -620,7 +682,7 @@ function Breadcrumb({
620
682
  __twcStyles,
621
683
  display.map((it, i) => {
622
684
  const last = i === display.length - 1;
623
- return /* @__PURE__ */ jsxRuntime.jsxs(React23__namespace.default.Fragment, { children: [
685
+ return /* @__PURE__ */ jsxRuntime.jsxs(React24__namespace.default.Fragment, { children: [
624
686
  it.ellipsis ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: "twc-breadcrumb__ellipsis", "aria-label": "Show more", onClick: () => setExpanded(true), children: "\u2026" }) : last ? /* @__PURE__ */ jsxRuntime.jsxs(
625
687
  "span",
626
688
  {
@@ -636,7 +698,7 @@ function Breadcrumb({
636
698
  "a",
637
699
  {
638
700
  className: "twc-breadcrumb__item",
639
- href: safeHref(it.href) || "#",
701
+ href: safeHref2(it.href) || "#",
640
702
  onClick: it.onClick,
641
703
  children: [
642
704
  it.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: { display: "inline-flex" }, children: it.icon }) : null,
@@ -739,7 +801,7 @@ var CSS2 = `
739
801
  animation: twico-ripple var(--duration-slow) var(--ease-out) forwards;
740
802
  }
741
803
  `;
742
- function safeHref2(url) {
804
+ function safeHref3(url) {
743
805
  if (url == null) return void 0;
744
806
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
745
807
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -761,7 +823,7 @@ function Button({
761
823
  ...rest
762
824
  }) {
763
825
  const __twcStyles = useScopedStyles("twc-btn-styles", CSS2);
764
- const [ripples, setRipples] = React23__namespace.default.useState([]);
826
+ const [ripples, setRipples] = React24__namespace.default.useState([]);
765
827
  const Tag2 = as;
766
828
  const inert = Tag2 === "a" && (disabled || loading);
767
829
  function handleClick(e) {
@@ -790,7 +852,7 @@ function Button({
790
852
  "data-block": fullWidth || void 0,
791
853
  disabled: Tag2 === "button" ? disabled || loading : void 0,
792
854
  type: Tag2 === "button" ? "button" : void 0,
793
- href: inert ? void 0 : safeHref2(href),
855
+ href: inert ? void 0 : safeHref3(href),
794
856
  "aria-disabled": inert || void 0,
795
857
  tabIndex: inert ? -1 : void 0,
796
858
  "aria-busy": loading || void 0,
@@ -898,6 +960,15 @@ var CAROUSEL_CSS = `
898
960
  .twc-carousel__dot { width: 8px; height: 8px; border-radius: var(--radius-full); border: none; padding: 0; cursor: pointer;
899
961
  background: var(--color-border-strong); transition: width var(--duration-base) var(--ease-spring), background-color var(--duration-fast); }
900
962
  .twc-carousel__dot[data-active="true"] { width: 22px; background: var(--color-primary); }
963
+ .twc-carousel__pause { position: absolute; top: 12px; inset-inline-end: 12px; z-index: 2;
964
+ display: grid; place-items: center; width: 34px; height: 34px; border-radius: var(--radius-full);
965
+ background: color-mix(in srgb, var(--color-surface) 88%, transparent); color: var(--color-text);
966
+ border: var(--border-thin) solid var(--color-border); box-shadow: var(--shadow-sm); cursor: pointer;
967
+ backdrop-filter: blur(6px); transition: background-color var(--duration-fast) var(--ease-standard); }
968
+ .twc-carousel__pause:hover { background: var(--color-surface); }
969
+ .twc-carousel__pause svg { width: 15px; height: 15px; display: block; }
970
+ .twc-carousel__live { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
971
+ overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
901
972
  `;
902
973
  function Carousel({
903
974
  children,
@@ -906,35 +977,76 @@ function Carousel({
906
977
  onIndexChange,
907
978
  showArrows = true,
908
979
  showDots = true,
980
+ showPauseButton = true,
909
981
  loop = true,
910
982
  autoPlay = false,
911
983
  interval = 4e3,
984
+ label,
985
+ pauseLabel = "Pause",
986
+ playLabel = "Play",
912
987
  className = "",
988
+ onKeyDown: onKeyDownProp,
989
+ "aria-label": ariaLabelProp,
990
+ "aria-labelledby": ariaLabelledbyProp,
913
991
  ...rest
914
992
  }) {
915
993
  const __twcStyles = useScopedStyles("twc-carousel-styles", CAROUSEL_CSS);
916
- const slides = React23__namespace.default.Children.toArray(children);
994
+ const slides = React24__namespace.default.Children.toArray(children);
917
995
  const count = slides.length;
918
- const [internal, setInternal] = React23__namespace.default.useState(defaultIndex);
996
+ const [internal, setInternal] = React24__namespace.default.useState(defaultIndex);
919
997
  const index = indexProp !== void 0 ? indexProp : internal;
920
- const [paused, setPaused] = React23__namespace.default.useState(false);
921
- const setIndex = React23__namespace.default.useCallback((i) => {
998
+ const [paused, setPaused] = React24__namespace.default.useState(false);
999
+ const [userPaused, setUserPaused] = React24__namespace.default.useState(false);
1000
+ const [prefersReduced, setPrefersReduced] = React24__namespace.default.useState(false);
1001
+ React24__namespace.default.useEffect(() => {
1002
+ if (typeof window === "undefined" || !window.matchMedia) return void 0;
1003
+ const mql = window.matchMedia("(prefers-reduced-motion: reduce)");
1004
+ const on = () => setPrefersReduced(mql.matches);
1005
+ on();
1006
+ mql.addEventListener("change", on);
1007
+ return () => mql.removeEventListener("change", on);
1008
+ }, []);
1009
+ const setIndex = React24__namespace.default.useCallback((i) => {
922
1010
  if (indexProp === void 0) setInternal(i);
923
1011
  onIndexChange?.(i);
924
1012
  }, [indexProp, onIndexChange]);
925
- const go = React23__namespace.default.useCallback((i) => {
1013
+ const go = React24__namespace.default.useCallback((i) => {
926
1014
  setIndex(loop ? (i + count) % count : Math.min(Math.max(i, 0), count - 1));
927
1015
  }, [count, loop, setIndex]);
928
- React23__namespace.default.useEffect(() => {
929
- if (!autoPlay || paused || count <= 1) return;
1016
+ const autoRotating = autoPlay && !paused && !userPaused && !prefersReduced && count > 1;
1017
+ React24__namespace.default.useEffect(() => {
1018
+ if (!autoRotating) return void 0;
930
1019
  const t = setInterval(() => {
931
1020
  const next = loop ? (index + 1) % count : index + 1 >= count ? index : index + 1;
932
1021
  if (next !== index) setIndex(next);
933
1022
  }, interval);
934
1023
  return () => clearInterval(t);
935
- }, [autoPlay, paused, count, interval, loop, index, setIndex]);
1024
+ }, [autoRotating, count, interval, loop, index, setIndex]);
936
1025
  const atStart = !loop && index === 0;
937
1026
  const atEnd = !loop && index === count - 1;
1027
+ const handleKeyDown = (e) => {
1028
+ onKeyDownProp?.(e);
1029
+ if (e.defaultPrevented) return;
1030
+ if (e.target.closest && e.target.closest('input, textarea, select, [contenteditable="true"]')) return;
1031
+ switch (e.key) {
1032
+ case "ArrowLeft":
1033
+ go(index - 1);
1034
+ break;
1035
+ case "ArrowRight":
1036
+ go(index + 1);
1037
+ break;
1038
+ case "Home":
1039
+ go(0);
1040
+ break;
1041
+ case "End":
1042
+ go(count - 1);
1043
+ break;
1044
+ default:
1045
+ return;
1046
+ }
1047
+ e.preventDefault();
1048
+ };
1049
+ const ariaLabel = ariaLabelledbyProp ? void 0 : ariaLabelProp ?? label ?? "Carousel";
938
1050
  return /* @__PURE__ */ jsxRuntime.jsxs(
939
1051
  "div",
940
1052
  {
@@ -943,12 +1055,17 @@ function Carousel({
943
1055
  onMouseLeave: () => setPaused(false),
944
1056
  onFocusCapture: () => setPaused(true),
945
1057
  onBlurCapture: () => setPaused(false),
1058
+ onKeyDown: handleKeyDown,
946
1059
  role: "region",
947
1060
  "aria-roledescription": "carousel",
1061
+ "aria-label": ariaLabel,
1062
+ "aria-labelledby": ariaLabelledbyProp,
948
1063
  ...rest,
949
1064
  children: [
950
1065
  __twcStyles,
951
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-carousel__viewport", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-carousel__track", style: { transform: `translateX(-${index * 100}%)` }, children: slides.map((s, i) => /* @__PURE__ */ jsxRuntime.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)) }) }),
1066
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-carousel__viewport", tabIndex: 0, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-carousel__track", style: { transform: `translateX(-${index * 100}%)` }, children: slides.map((s, i) => /* @__PURE__ */ jsxRuntime.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)) }) }),
1067
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-carousel__live", "aria-live": autoRotating ? "off" : "polite", "aria-atomic": "true", children: count > 1 ? `Slide ${index + 1} of ${count}` : null }),
1068
+ autoPlay && showPauseButton && count > 1 ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-carousel__pause", "aria-label": userPaused ? playLabel : pauseLabel, onClick: () => setUserPaused((v) => !v), children: userPaused ? /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 5v14l11-7z" }) }) : /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 5h4v14H6zM14 5h4v14h-4z" }) }) }) : null,
952
1069
  showArrows && count > 1 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
953
1070
  /* @__PURE__ */ jsxRuntime.jsx("button", { className: "twc-carousel__arrow", "data-dir": "prev", "aria-label": "Previous", disabled: atStart, onClick: () => go(index - 1), children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) }) }),
954
1071
  /* @__PURE__ */ jsxRuntime.jsx("button", { className: "twc-carousel__arrow", "data-dir": "next", "aria-label": "Next", disabled: atEnd, onClick: () => go(index + 1), children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) }) })
@@ -971,6 +1088,7 @@ var CHART_CSS = `
971
1088
  .twc-chart__leg { display: inline-flex; align-items: center; gap: 6px; }
972
1089
  .twc-chart__leg-sw { width: 10px; height: 10px; border-radius: 3px; }
973
1090
  @keyframes twc-chart-grow { from { transform: scaleY(0); } to { transform: scaleY(1); } }
1091
+ .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; }
974
1092
  `;
975
1093
  var SERIES_COLORS = ["var(--brand-500)", "var(--sky-500)", "var(--emerald-500)", "var(--amber-500)", "var(--rose-500)"];
976
1094
  function Chart({
@@ -985,10 +1103,14 @@ function Chart({
985
1103
  valueFormat,
986
1104
  ariaLabel,
987
1105
  "aria-label": ariaLabelProp,
1106
+ tableFallback = true,
1107
+ caption,
988
1108
  className = "",
989
1109
  ...rest
990
1110
  }) {
991
1111
  const __twcStyles = useScopedStyles("twc-chart-styles", CHART_CSS);
1112
+ const uid = React24__namespace.default.useId();
1113
+ const tableId = tableFallback ? `${uid}-table` : void 0;
992
1114
  const keys = series || ["value"];
993
1115
  const palette = colors && colors.length ? colors : SERIES_COLORS;
994
1116
  const W = 600, H = height, padL = showAxis ? 40 : 8, padR = 8, padT = 12, padB = showAxis ? 26 : 8;
@@ -1001,7 +1123,7 @@ function Chart({
1001
1123
  const svgAriaLabel = ariaLabelProp ?? ariaLabel ?? `${type} chart`;
1002
1124
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-chart ${className}`, ...rest, children: [
1003
1125
  __twcStyles,
1004
- /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: `0 0 ${W} ${H}`, role: "img", "aria-label": svgAriaLabel, preserveAspectRatio: "none", children: [
1126
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: `0 0 ${W} ${H}`, role: "img", "aria-label": svgAriaLabel, "aria-describedby": tableId, preserveAspectRatio: "none", children: [
1005
1127
  showGrid ? Array.from({ length: ticks + 1 }).map((_, i) => {
1006
1128
  const gy = padT + innerH / ticks * i;
1007
1129
  return /* @__PURE__ */ jsxRuntime.jsx("line", { className: "twc-chart__grid", x1: padL, y1: gy, x2: W - padR, y2: gy }, i);
@@ -1051,6 +1173,17 @@ function Chart({
1051
1173
  return /* @__PURE__ */ jsxRuntime.jsx("text", { className: "twc-chart__axis", x: cx, y: H - 8, textAnchor: "middle", children: d.label }, i);
1052
1174
  }) : null
1053
1175
  ] }),
1176
+ tableFallback ? /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "twc-chart__sr", id: tableId, children: [
1177
+ /* @__PURE__ */ jsxRuntime.jsx("caption", { children: caption ?? svgAriaLabel }),
1178
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
1179
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col" }),
1180
+ keys.map((k) => /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: k }, k))
1181
+ ] }) }),
1182
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: data.map((d, i) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
1183
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "row", children: d.label }),
1184
+ keys.map((k) => /* @__PURE__ */ jsxRuntime.jsx("td", { children: fmt(Number(d[k]) || 0) }, k))
1185
+ ] }, i)) })
1186
+ ] }) : null,
1054
1187
  showLegend && keys.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-chart__legend", children: keys.map((k, si) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-chart__leg", children: [
1055
1188
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-chart__leg-sw", style: { background: palette[si % palette.length] } }),
1056
1189
  k
@@ -1123,12 +1256,12 @@ function Checkbox({
1123
1256
  .twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
1124
1257
  .twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
1125
1258
  `);
1126
- const autoId = React23__namespace.default.useId();
1259
+ const autoId = React24__namespace.default.useId();
1127
1260
  const fieldId = id || autoId;
1128
1261
  const errId = `${fieldId}-error`;
1129
1262
  const invalid = Boolean(error);
1130
- const ref = React23__namespace.default.useRef(null);
1131
- React23__namespace.default.useEffect(() => {
1263
+ const ref = React24__namespace.default.useRef(null);
1264
+ React24__namespace.default.useEffect(() => {
1132
1265
  if (ref.current) ref.current.indeterminate = indeterminate;
1133
1266
  }, [indeterminate]);
1134
1267
  const describedBy = [rest["aria-describedby"], error ? errId : null].filter(Boolean).join(" ") || void 0;
@@ -1265,20 +1398,20 @@ function ColorPicker({
1265
1398
  }) {
1266
1399
  const __twcStyles0 = useScopedStyles("twc-field-styles", FIELD_CSS);
1267
1400
  const __twcStyles1 = useScopedStyles("twc-colorpicker-styles", COLORPICKER_CSS);
1268
- const [internal, setInternal] = React23__namespace.default.useState(defaultValue);
1401
+ const [internal, setInternal] = React24__namespace.default.useState(defaultValue);
1269
1402
  const hex = (value !== void 0 ? value : internal) || "#000000";
1270
- const lastValidRef = React23__namespace.default.useRef(hex);
1403
+ const lastValidRef = React24__namespace.default.useRef(hex);
1271
1404
  if (/^#[0-9a-f]{6}$/i.test(hex)) lastValidRef.current = hex;
1272
- const [open, setOpen] = React23__namespace.default.useState(false);
1273
- const [hsv, setHsv] = React23__namespace.default.useState(() => hexToHsv(hex) || { h: 239, s: 60, v: 94 });
1274
- const [coords, setCoords] = React23__namespace.default.useState(null);
1275
- const wrapRef = React23__namespace.default.useRef(null);
1276
- const triggerRef = React23__namespace.default.useRef(null);
1277
- const popRef = React23__namespace.default.useRef(null);
1278
- const areaRef = React23__namespace.default.useRef(null);
1279
- const hueRef = React23__namespace.default.useRef(null);
1405
+ const [open, setOpen] = React24__namespace.default.useState(false);
1406
+ const [hsv, setHsv] = React24__namespace.default.useState(() => hexToHsv(hex) || { h: 239, s: 60, v: 94 });
1407
+ const [coords, setCoords] = React24__namespace.default.useState(null);
1408
+ const wrapRef = React24__namespace.default.useRef(null);
1409
+ const triggerRef = React24__namespace.default.useRef(null);
1410
+ const popRef = React24__namespace.default.useRef(null);
1411
+ const areaRef = React24__namespace.default.useRef(null);
1412
+ const hueRef = React24__namespace.default.useRef(null);
1280
1413
  const POP_W = 240;
1281
- const place = React23__namespace.default.useCallback(() => {
1414
+ const place = React24__namespace.default.useCallback(() => {
1282
1415
  const el = triggerRef.current;
1283
1416
  if (!el) return;
1284
1417
  const r = el.getBoundingClientRect();
@@ -1289,7 +1422,7 @@ function ColorPicker({
1289
1422
  left = Math.max(8, left);
1290
1423
  setCoords({ left, top: flip ? void 0 : Math.round(r.bottom + 6), bottom: flip ? Math.round(vh - r.top + 6) : void 0 });
1291
1424
  }, []);
1292
- React23__namespace.default.useEffect(() => {
1425
+ React24__namespace.default.useEffect(() => {
1293
1426
  if (!open) return void 0;
1294
1427
  place();
1295
1428
  const onMove = () => place();
@@ -1300,17 +1433,17 @@ function ColorPicker({
1300
1433
  window.removeEventListener("resize", onMove);
1301
1434
  };
1302
1435
  }, [open, place]);
1303
- const labelId = React23__namespace.default.useId();
1436
+ const labelId = React24__namespace.default.useId();
1304
1437
  const descId = `${labelId}-desc`;
1305
1438
  const invalid = Boolean(error);
1306
- React23__namespace.default.useEffect(() => {
1439
+ React24__namespace.default.useEffect(() => {
1307
1440
  if (disabled) setOpen(false);
1308
1441
  }, [disabled]);
1309
- React23__namespace.default.useEffect(() => {
1442
+ React24__namespace.default.useEffect(() => {
1310
1443
  const v = hexToHsv(hex);
1311
1444
  if (v && hsvToHex(v.h, v.s, v.v).toLowerCase() !== hsvToHex(hsv.h, hsv.s, hsv.v).toLowerCase()) setHsv(v);
1312
1445
  }, [hex]);
1313
- React23__namespace.default.useEffect(() => {
1446
+ React24__namespace.default.useEffect(() => {
1314
1447
  if (!open) return;
1315
1448
  const onDown = (e) => {
1316
1449
  if (wrapRef.current && wrapRef.current.contains(e.target)) return;
@@ -1327,8 +1460,8 @@ function ColorPicker({
1327
1460
  document.removeEventListener("keydown", onKey);
1328
1461
  };
1329
1462
  }, [open]);
1330
- const prevOpen = React23__namespace.default.useRef(false);
1331
- React23__namespace.default.useEffect(() => {
1463
+ const prevOpen = React24__namespace.default.useRef(false);
1464
+ React24__namespace.default.useEffect(() => {
1332
1465
  let id;
1333
1466
  if (!prevOpen.current && open) {
1334
1467
  id = setTimeout(() => areaRef.current?.focus({ preventScroll: true }), 20);
@@ -1648,29 +1781,29 @@ function Combobox({
1648
1781
  ...rest
1649
1782
  }) {
1650
1783
  const __twcStyles = useScopedStyles("twc-combo-styles", COMBO_CSS);
1651
- const groups = React23__namespace.default.useMemo(() => normalizeGroups(options), [options]);
1652
- const flat = React23__namespace.default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
1653
- const autoId = React23__namespace.default.useId();
1784
+ const groups = React24__namespace.default.useMemo(() => normalizeGroups(options), [options]);
1785
+ const flat = React24__namespace.default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
1786
+ const autoId = React24__namespace.default.useId();
1654
1787
  const fieldId = id || autoId;
1655
- const [internal, setInternal] = React23__namespace.default.useState(defaultValue);
1788
+ const [internal, setInternal] = React24__namespace.default.useState(defaultValue);
1656
1789
  const current = value !== void 0 ? value : internal;
1657
1790
  const selected = flat.find((o) => o.value === current);
1658
- const [open, setOpen] = React23__namespace.default.useState(false);
1659
- const [query, setQuery] = React23__namespace.default.useState("");
1660
- const [active, setActive] = React23__namespace.default.useState(0);
1661
- const [coords, setCoords] = React23__namespace.default.useState(null);
1662
- const wrapRef = React23__namespace.default.useRef(null);
1663
- const controlRef = React23__namespace.default.useRef(null);
1664
- const inputRef = React23__namespace.default.useRef(null);
1665
- const popRef = React23__namespace.default.useRef(null);
1666
- const listRef = React23__namespace.default.useRef(null);
1667
- const activeRef = React23__namespace.default.useRef(null);
1668
- const fGroups = React23__namespace.default.useMemo(
1791
+ const [open, setOpen] = React24__namespace.default.useState(false);
1792
+ const [query, setQuery] = React24__namespace.default.useState("");
1793
+ const [active, setActive] = React24__namespace.default.useState(0);
1794
+ const [coords, setCoords] = React24__namespace.default.useState(null);
1795
+ const wrapRef = React24__namespace.default.useRef(null);
1796
+ const controlRef = React24__namespace.default.useRef(null);
1797
+ const inputRef = React24__namespace.default.useRef(null);
1798
+ const popRef = React24__namespace.default.useRef(null);
1799
+ const listRef = React24__namespace.default.useRef(null);
1800
+ const activeRef = React24__namespace.default.useRef(null);
1801
+ const fGroups = React24__namespace.default.useMemo(
1669
1802
  () => groups.map((g) => ({ group: g.group, options: g.options.filter((o) => matches(o, query.trim())) })).filter((g) => g.options.length),
1670
1803
  [groups, query]
1671
1804
  );
1672
- const visible = React23__namespace.default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
1673
- const place = React23__namespace.default.useCallback(() => {
1805
+ const visible = React24__namespace.default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
1806
+ const place = React24__namespace.default.useCallback(() => {
1674
1807
  const el = controlRef.current;
1675
1808
  if (!el) return;
1676
1809
  const r = el.getBoundingClientRect();
@@ -1685,7 +1818,7 @@ function Combobox({
1685
1818
  flip
1686
1819
  });
1687
1820
  }, [placement, minWidth]);
1688
- React23__namespace.default.useEffect(() => {
1821
+ React24__namespace.default.useEffect(() => {
1689
1822
  if (!open || !portal) return;
1690
1823
  place();
1691
1824
  const onMove = () => place();
@@ -1696,7 +1829,7 @@ function Combobox({
1696
1829
  window.removeEventListener("resize", onMove);
1697
1830
  };
1698
1831
  }, [open, portal, place]);
1699
- React23__namespace.default.useEffect(() => {
1832
+ React24__namespace.default.useEffect(() => {
1700
1833
  if (!open) return;
1701
1834
  const onDown = (e) => {
1702
1835
  if (wrapRef.current && wrapRef.current.contains(e.target)) return;
@@ -1706,10 +1839,10 @@ function Combobox({
1706
1839
  document.addEventListener("mousedown", onDown);
1707
1840
  return () => document.removeEventListener("mousedown", onDown);
1708
1841
  }, [open]);
1709
- React23__namespace.default.useEffect(() => {
1842
+ React24__namespace.default.useEffect(() => {
1710
1843
  setActive(0);
1711
1844
  }, [query]);
1712
- React23__namespace.default.useEffect(() => {
1845
+ React24__namespace.default.useEffect(() => {
1713
1846
  if (open) ensureVisible(listRef.current, activeRef.current);
1714
1847
  }, [active, open]);
1715
1848
  function openMenu() {
@@ -1752,7 +1885,7 @@ function Combobox({
1752
1885
  const descId = `${fieldId}-desc`;
1753
1886
  const describedBy = error || hint ? descId : void 0;
1754
1887
  let counter = -1;
1755
- const popInner = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__list", ref: listRef, children: visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__empty", children: "No results found" }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxRuntime.jsxs(React23__namespace.default.Fragment, { children: [
1888
+ const popInner = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__list", ref: listRef, children: visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__empty", children: "No results found" }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxRuntime.jsxs(React24__namespace.default.Fragment, { children: [
1756
1889
  g.group ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__group", children: g.group }) : null,
1757
1890
  g.options.map((o) => {
1758
1891
  counter += 1;
@@ -1890,6 +2023,52 @@ function Combobox({
1890
2023
  error ? /* @__PURE__ */ jsxRuntime.jsx("span", { id: descId, className: "twc-field__error", children: error }) : hint ? /* @__PURE__ */ jsxRuntime.jsx("span", { id: descId, className: "twc-field__hint", children: hint }) : null
1891
2024
  ] });
1892
2025
  }
2026
+ var canUseDOM = typeof window !== "undefined" && typeof document !== "undefined";
2027
+ 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"])';
2028
+ function useFocusTrap(ref, active = true, { restoreFocus = true } = {}) {
2029
+ React24__namespace.default.useEffect(() => {
2030
+ if (!active || !canUseDOM) return void 0;
2031
+ const node = ref.current;
2032
+ if (!node) return void 0;
2033
+ const prevFocused = document.activeElement;
2034
+ const first = node.querySelector(FOCUSABLE);
2035
+ (first || node).focus();
2036
+ return () => {
2037
+ if (restoreFocus && prevFocused && typeof prevFocused.focus === "function") prevFocused.focus();
2038
+ };
2039
+ }, [active]);
2040
+ React24__namespace.default.useEffect(() => {
2041
+ if (!active || !canUseDOM) return void 0;
2042
+ const node = ref.current;
2043
+ const onKey = (e) => {
2044
+ if (e.key !== "Tab" || !node) return;
2045
+ const f = Array.from(node.querySelectorAll(FOCUSABLE)).filter((el) => el.offsetParent !== null);
2046
+ if (!f.length) {
2047
+ e.preventDefault();
2048
+ node.focus();
2049
+ return;
2050
+ }
2051
+ const first = f[0], last = f[f.length - 1], ae = document.activeElement;
2052
+ if (e.shiftKey) {
2053
+ if (ae === first || ae === node || !node.contains(ae)) {
2054
+ e.preventDefault();
2055
+ last.focus();
2056
+ }
2057
+ } else if (ae === last || !node.contains(ae)) {
2058
+ e.preventDefault();
2059
+ first.focus();
2060
+ }
2061
+ };
2062
+ document.addEventListener("keydown", onKey);
2063
+ return () => document.removeEventListener("keydown", onKey);
2064
+ }, [active]);
2065
+ }
2066
+ function usePortal() {
2067
+ return React24__namespace.default.useCallback((node) => {
2068
+ if (typeof document === "undefined") return null;
2069
+ return typeof reactDom.createPortal === "function" ? reactDom.createPortal(node, document.body) : node;
2070
+ }, []);
2071
+ }
1893
2072
  var COMMAND_CSS = `
1894
2073
  .twc-cmdk__overlay { position: fixed; inset: 0; z-index: var(--z-modal); background: var(--color-overlay); backdrop-filter: blur(3px);
1895
2074
  display: flex; align-items: flex-start; justify-content: center; padding-top: 12vh; }
@@ -1935,14 +2114,15 @@ function CommandPalette({
1935
2114
  ...rest
1936
2115
  }) {
1937
2116
  const __twcStyles = useScopedStyles("twc-cmdk-styles", COMMAND_CSS);
1938
- const [query, setQuery] = React23__namespace.default.useState("");
1939
- const [active, setActive] = React23__namespace.default.useState(0);
1940
- const inputRef = React23__namespace.default.useRef(null);
1941
- const listRef = React23__namespace.default.useRef(null);
1942
- const paletteRef = React23__namespace.default.useRef(null);
1943
- const baseId = React23__namespace.default.useId();
1944
- const [mounted, setMounted] = React23__namespace.default.useState(open);
1945
- React23__namespace.default.useEffect(() => {
2117
+ const renderPortal = usePortal();
2118
+ const [query, setQuery] = React24__namespace.default.useState("");
2119
+ const [active, setActive] = React24__namespace.default.useState(0);
2120
+ const inputRef = React24__namespace.default.useRef(null);
2121
+ const listRef = React24__namespace.default.useRef(null);
2122
+ const paletteRef = React24__namespace.default.useRef(null);
2123
+ const baseId = React24__namespace.default.useId();
2124
+ const [mounted, setMounted] = React24__namespace.default.useState(open);
2125
+ React24__namespace.default.useEffect(() => {
1946
2126
  if (open) {
1947
2127
  setMounted(true);
1948
2128
  return;
@@ -1950,7 +2130,7 @@ function CommandPalette({
1950
2130
  const t = setTimeout(() => setMounted(false), 170);
1951
2131
  return () => clearTimeout(t);
1952
2132
  }, [open]);
1953
- React23__namespace.default.useEffect(() => {
2133
+ React24__namespace.default.useEffect(() => {
1954
2134
  if (!open) return void 0;
1955
2135
  const prev = document.body.style.overflow;
1956
2136
  document.body.style.overflow = "hidden";
@@ -1958,58 +2138,26 @@ function CommandPalette({
1958
2138
  document.body.style.overflow = prev;
1959
2139
  };
1960
2140
  }, [open]);
1961
- React23__namespace.default.useEffect(() => {
2141
+ React24__namespace.default.useEffect(() => {
1962
2142
  if (open) {
1963
2143
  setQuery("");
1964
2144
  setActive(0);
1965
- const t = setTimeout(() => inputRef.current?.focus(), 30);
1966
- return () => clearTimeout(t);
1967
2145
  }
1968
2146
  }, [open]);
1969
- React23__namespace.default.useEffect(() => {
1970
- if (!open) return;
1971
- const prevFocused = document.activeElement;
1972
- return () => {
1973
- if (prevFocused && typeof prevFocused.focus === "function") prevFocused.focus();
1974
- };
1975
- }, [open]);
1976
- React23__namespace.default.useEffect(() => {
1977
- if (!open) return;
1978
- const focusables = (node) => node ? Array.from(
1979
- node.querySelectorAll(
1980
- '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"])'
1981
- )
1982
- ).filter((el) => el.offsetParent !== null) : [];
2147
+ useFocusTrap(paletteRef, open && mounted);
2148
+ React24__namespace.default.useEffect(() => {
2149
+ if (!open) return void 0;
1983
2150
  const onKey = (e) => {
1984
2151
  if (e.key === "Escape") {
1985
2152
  e.preventDefault();
1986
2153
  onClose?.();
1987
- return;
1988
- }
1989
- if (e.key !== "Tab") return;
1990
- const node = paletteRef.current;
1991
- const f = focusables(node);
1992
- if (!f.length) {
1993
- e.preventDefault();
1994
- node?.focus();
1995
- return;
1996
- }
1997
- const first = f[0], last = f[f.length - 1], ae = document.activeElement;
1998
- if (e.shiftKey) {
1999
- if (ae === first || ae === node || !node.contains(ae)) {
2000
- e.preventDefault();
2001
- last.focus();
2002
- }
2003
- } else if (ae === last || !node.contains(ae)) {
2004
- e.preventDefault();
2005
- first.focus();
2006
2154
  }
2007
2155
  };
2008
2156
  document.addEventListener("keydown", onKey);
2009
2157
  return () => document.removeEventListener("keydown", onKey);
2010
2158
  }, [open, onClose]);
2011
2159
  const q = query.trim().toLowerCase();
2012
- const filtered = React23__namespace.default.useMemo(() => commands.filter(
2160
+ const filtered = React24__namespace.default.useMemo(() => commands.filter(
2013
2161
  (c) => !q || c.label.toLowerCase().includes(q) || (c.keywords || "").toLowerCase().includes(q) || (c.group || "").toLowerCase().includes(q)
2014
2162
  ), [commands, q]);
2015
2163
  const groups = [];
@@ -2024,7 +2172,7 @@ function CommandPalette({
2024
2172
  g.items.push(c);
2025
2173
  flat.push(c);
2026
2174
  });
2027
- React23__namespace.default.useEffect(() => {
2175
+ React24__namespace.default.useEffect(() => {
2028
2176
  setActive(0);
2029
2177
  }, [query]);
2030
2178
  const run = (cmd) => {
@@ -2044,11 +2192,11 @@ function CommandPalette({
2044
2192
  if (cmd) run(cmd);
2045
2193
  }
2046
2194
  }
2047
- React23__namespace.default.useEffect(() => {
2195
+ React24__namespace.default.useEffect(() => {
2048
2196
  const node = listRef.current?.querySelector('[data-active="true"]');
2049
2197
  if (node) node.scrollIntoView({ block: "nearest" });
2050
2198
  }, [active]);
2051
- if (!mounted || typeof document === "undefined") return null;
2199
+ if (!mounted) return null;
2052
2200
  const state = open ? "open" : "closed";
2053
2201
  const listId = `${baseId}-list`;
2054
2202
  const optionId = (i) => `${baseId}-opt-${i}`;
@@ -2114,8 +2262,7 @@ function CommandPalette({
2114
2262
  ] }, g.key || "_")) })
2115
2263
  ] })
2116
2264
  ] });
2117
- const RD = typeof reactDom.createPortal === "function" ? reactDom.createPortal : null;
2118
- return RD ? RD(overlay, document.body) : overlay;
2265
+ return renderPortal(overlay);
2119
2266
  }
2120
2267
  var CURRENCIES = {
2121
2268
  USD: { code: "USD", symbol: "$", precision: 2, label: "US Dollar" },
@@ -2218,11 +2365,11 @@ function Currency({
2218
2365
  const prec = precision != null ? precision : meta.precision;
2219
2366
  const sym = symbol != null ? symbol : meta.symbol;
2220
2367
  const cur = code != null ? code : meta.code;
2221
- const autoId = React23__namespace.default.useId();
2368
+ const autoId = React24__namespace.default.useId();
2222
2369
  const fieldId = id || autoId;
2223
2370
  const invalid = Boolean(error);
2224
2371
  const controlled = value !== void 0;
2225
- const [internal, setInternal] = React23__namespace.default.useState(() => clampPrecision(String(defaultValue ?? ""), prec));
2372
+ const [internal, setInternal] = React24__namespace.default.useState(() => clampPrecision(String(defaultValue ?? ""), prec));
2226
2373
  const shown = controlled ? clampPrecision(String(value ?? ""), prec) : internal;
2227
2374
  const describedBy = [error ? `${fieldId}-error` : hint ? `${fieldId}-hint` : null, rest["aria-describedby"]].filter(Boolean).join(" ") || void 0;
2228
2375
  function handleChange(e) {
@@ -2396,32 +2543,32 @@ function Select({
2396
2543
  ...rest
2397
2544
  }) {
2398
2545
  const __twcStyles = useScopedStyles("twc-select-styles", SELECT_CSS);
2399
- const groups = React23__namespace.default.useMemo(() => normalizeGroups2(options), [options]);
2400
- const flat = React23__namespace.default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
2401
- const autoId = React23__namespace.default.useId();
2546
+ const groups = React24__namespace.default.useMemo(() => normalizeGroups2(options), [options]);
2547
+ const flat = React24__namespace.default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
2548
+ const autoId = React24__namespace.default.useId();
2402
2549
  const fieldId = id || autoId;
2403
- const [internal, setInternal] = React23__namespace.default.useState(defaultValue);
2550
+ const [internal, setInternal] = React24__namespace.default.useState(defaultValue);
2404
2551
  const current = value !== void 0 ? value : internal;
2405
- const [open, setOpen] = React23__namespace.default.useState(false);
2406
- const [render, setRender] = React23__namespace.default.useState(false);
2407
- const [active, setActive] = React23__namespace.default.useState(0);
2408
- const [coords, setCoords] = React23__namespace.default.useState(null);
2409
- const [query, setQuery] = React23__namespace.default.useState("");
2410
- const wrapRef = React23__namespace.default.useRef(null);
2411
- const triggerRef = React23__namespace.default.useRef(null);
2412
- const popRef = React23__namespace.default.useRef(null);
2413
- const listRef = React23__namespace.default.useRef(null);
2414
- const activeRef = React23__namespace.default.useRef(null);
2415
- const searchRef = React23__namespace.default.useRef(null);
2552
+ const [open, setOpen] = React24__namespace.default.useState(false);
2553
+ const [render, setRender] = React24__namespace.default.useState(false);
2554
+ const [active, setActive] = React24__namespace.default.useState(0);
2555
+ const [coords, setCoords] = React24__namespace.default.useState(null);
2556
+ const [query, setQuery] = React24__namespace.default.useState("");
2557
+ const wrapRef = React24__namespace.default.useRef(null);
2558
+ const triggerRef = React24__namespace.default.useRef(null);
2559
+ const popRef = React24__namespace.default.useRef(null);
2560
+ const listRef = React24__namespace.default.useRef(null);
2561
+ const activeRef = React24__namespace.default.useRef(null);
2562
+ const searchRef = React24__namespace.default.useRef(null);
2416
2563
  const showSearch = searchable === void 0 ? flat.length > 5 : searchable;
2417
- const fGroups = React23__namespace.default.useMemo(() => {
2564
+ const fGroups = React24__namespace.default.useMemo(() => {
2418
2565
  const q = query.trim().toLowerCase();
2419
2566
  if (!q) return groups;
2420
2567
  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);
2421
2568
  }, [groups, query]);
2422
- const visible = React23__namespace.default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
2569
+ const visible = React24__namespace.default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
2423
2570
  const selected = flat.find((o) => o.value === current);
2424
- const place = React23__namespace.default.useCallback(() => {
2571
+ const place = React24__namespace.default.useCallback(() => {
2425
2572
  const el = triggerRef.current;
2426
2573
  if (!el) return;
2427
2574
  const r = el.getBoundingClientRect();
@@ -2436,7 +2583,7 @@ function Select({
2436
2583
  flip
2437
2584
  });
2438
2585
  }, [placement, minWidth]);
2439
- React23__namespace.default.useEffect(() => {
2586
+ React24__namespace.default.useEffect(() => {
2440
2587
  if (!open || !portal) return;
2441
2588
  place();
2442
2589
  const onMove = () => place();
@@ -2447,7 +2594,7 @@ function Select({
2447
2594
  window.removeEventListener("resize", onMove);
2448
2595
  };
2449
2596
  }, [open, portal, place]);
2450
- React23__namespace.default.useEffect(() => {
2597
+ React24__namespace.default.useEffect(() => {
2451
2598
  if (!open) return;
2452
2599
  const idx = flat.findIndex((o) => o.value === current);
2453
2600
  setActive(idx >= 0 ? idx : 0);
@@ -2463,13 +2610,13 @@ function Select({
2463
2610
  document.addEventListener("mousedown", onDown);
2464
2611
  return () => document.removeEventListener("mousedown", onDown);
2465
2612
  }, [open]);
2466
- React23__namespace.default.useEffect(() => {
2613
+ React24__namespace.default.useEffect(() => {
2467
2614
  setActive(0);
2468
2615
  }, [query]);
2469
- React23__namespace.default.useEffect(() => {
2616
+ React24__namespace.default.useEffect(() => {
2470
2617
  if (open) ensureVisible2(listRef.current, activeRef.current);
2471
2618
  }, [active, open]);
2472
- React23__namespace.default.useEffect(() => {
2619
+ React24__namespace.default.useEffect(() => {
2473
2620
  if (open) {
2474
2621
  setRender(true);
2475
2622
  return;
@@ -2477,8 +2624,8 @@ function Select({
2477
2624
  const t = setTimeout(() => setRender(false), 170);
2478
2625
  return () => clearTimeout(t);
2479
2626
  }, [open]);
2480
- const prevOpen = React23__namespace.default.useRef(false);
2481
- React23__namespace.default.useEffect(() => {
2627
+ const prevOpen = React24__namespace.default.useRef(false);
2628
+ React24__namespace.default.useEffect(() => {
2482
2629
  if (prevOpen.current && !open) {
2483
2630
  const ae = typeof document !== "undefined" ? document.activeElement : null;
2484
2631
  if (popRef.current && ae && popRef.current.contains(ae)) triggerRef.current?.focus();
@@ -2551,7 +2698,7 @@ function Select({
2551
2698
  }
2552
2699
  )
2553
2700
  ] }) : null,
2554
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__list", ref: listRef, children: visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__empty", children: "No results found" }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxRuntime.jsxs(React23__namespace.default.Fragment, { children: [
2701
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__list", ref: listRef, children: visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__empty", children: "No results found" }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxRuntime.jsxs(React24__namespace.default.Fragment, { children: [
2555
2702
  g.group ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__group", children: g.group }) : null,
2556
2703
  g.options.map((o) => {
2557
2704
  counter += 1;
@@ -2725,19 +2872,19 @@ function CurrencyField({
2725
2872
  ...rest
2726
2873
  }) {
2727
2874
  const __twcStyles = useScopedStyles("twc-curf-styles", CURF_CSS);
2728
- const autoId = React23__namespace.default.useId();
2875
+ const autoId = React24__namespace.default.useId();
2729
2876
  const fieldId = id || autoId;
2730
2877
  const invalid = Boolean(error);
2731
2878
  const curControlled = currency !== void 0;
2732
- const [curInternal, setCurInternal] = React23__namespace.default.useState(defaultCurrency);
2879
+ const [curInternal, setCurInternal] = React24__namespace.default.useState(defaultCurrency);
2733
2880
  const cur = curControlled ? currency : curInternal;
2734
2881
  const meta = CURRENCIES[cur] || CURRENCIES.USD;
2735
2882
  const prec = meta.precision;
2736
2883
  const valControlled = value !== void 0;
2737
- const [valInternal, setValInternal] = React23__namespace.default.useState(() => clampPrecision(String(defaultValue ?? ""), prec));
2884
+ const [valInternal, setValInternal] = React24__namespace.default.useState(() => clampPrecision(String(defaultValue ?? ""), prec));
2738
2885
  const shown = valControlled ? clampPrecision(String(value ?? ""), prec) : valInternal;
2739
2886
  const describedBy = [error ? `${fieldId}-error` : hint ? `${fieldId}-hint` : null, rest["aria-describedby"]].filter(Boolean).join(" ") || void 0;
2740
- const options = React23__namespace.default.useMemo(() => {
2887
+ const options = React24__namespace.default.useMemo(() => {
2741
2888
  if (!currencies) return CURRENCY_OPTIONS;
2742
2889
  return currencies.map((c) => typeof c === "string" ? { value: c, label: `${c} \u2014 ${(CURRENCIES[c] || {}).label || c}` } : c);
2743
2890
  }, [currencies]);
@@ -2872,12 +3019,12 @@ function Input({
2872
3019
  ...rest
2873
3020
  }) {
2874
3021
  const __twcStyles = useScopedStyles("twc-field-styles", FIELD_CSS2);
2875
- const autoId = React23__namespace.default.useId();
3022
+ const autoId = React24__namespace.default.useId();
2876
3023
  const fieldId = id || autoId;
2877
3024
  const descId = `${fieldId}-desc`;
2878
3025
  const invalid = Boolean(error);
2879
3026
  const isPassword = type === "password";
2880
- const [revealed, setRevealed] = React23__namespace.default.useState(false);
3027
+ const [revealed, setRevealed] = React24__namespace.default.useState(false);
2881
3028
  const effectiveType = isPassword && revealed ? "text" : type;
2882
3029
  const suffix = rightIcon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-input__affix", children: rightIcon }) : isPassword ? /* @__PURE__ */ jsxRuntime.jsx(
2883
3030
  "button",
@@ -3058,28 +3205,28 @@ function MultiSelect({
3058
3205
  ...rest
3059
3206
  }) {
3060
3207
  const __twcStyles = useScopedStyles("twc-ms-styles", MULTI_CSS);
3061
- const groups = React23__namespace.default.useMemo(() => normalizeGroups3(options), [options]);
3062
- const flat = React23__namespace.default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
3063
- const autoId = React23__namespace.default.useId();
3208
+ const groups = React24__namespace.default.useMemo(() => normalizeGroups3(options), [options]);
3209
+ const flat = React24__namespace.default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
3210
+ const autoId = React24__namespace.default.useId();
3064
3211
  const fieldId = id || autoId;
3065
- const [internal, setInternal] = React23__namespace.default.useState(defaultValue);
3212
+ const [internal, setInternal] = React24__namespace.default.useState(defaultValue);
3066
3213
  const selected = value !== void 0 ? value : internal;
3067
- const [open, setOpen] = React23__namespace.default.useState(false);
3068
- const [query, setQuery] = React23__namespace.default.useState("");
3069
- const [active, setActive] = React23__namespace.default.useState(0);
3070
- const [coords, setCoords] = React23__namespace.default.useState(null);
3071
- const wrapRef = React23__namespace.default.useRef(null);
3072
- const controlRef = React23__namespace.default.useRef(null);
3073
- const inputRef = React23__namespace.default.useRef(null);
3074
- const popRef = React23__namespace.default.useRef(null);
3075
- const listRef = React23__namespace.default.useRef(null);
3076
- const activeRef = React23__namespace.default.useRef(null);
3077
- const fGroups = React23__namespace.default.useMemo(
3214
+ const [open, setOpen] = React24__namespace.default.useState(false);
3215
+ const [query, setQuery] = React24__namespace.default.useState("");
3216
+ const [active, setActive] = React24__namespace.default.useState(0);
3217
+ const [coords, setCoords] = React24__namespace.default.useState(null);
3218
+ const wrapRef = React24__namespace.default.useRef(null);
3219
+ const controlRef = React24__namespace.default.useRef(null);
3220
+ const inputRef = React24__namespace.default.useRef(null);
3221
+ const popRef = React24__namespace.default.useRef(null);
3222
+ const listRef = React24__namespace.default.useRef(null);
3223
+ const activeRef = React24__namespace.default.useRef(null);
3224
+ const fGroups = React24__namespace.default.useMemo(
3078
3225
  () => groups.map((g) => ({ group: g.group, options: g.options.filter((o) => matches2(o, query.trim())) })).filter((g) => g.options.length),
3079
3226
  [groups, query]
3080
3227
  );
3081
- const visible = React23__namespace.default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
3082
- const place = React23__namespace.default.useCallback(() => {
3228
+ const visible = React24__namespace.default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
3229
+ const place = React24__namespace.default.useCallback(() => {
3083
3230
  const el = controlRef.current;
3084
3231
  if (!el) return;
3085
3232
  const r = el.getBoundingClientRect();
@@ -3094,7 +3241,7 @@ function MultiSelect({
3094
3241
  flip
3095
3242
  });
3096
3243
  }, [placement, minWidth]);
3097
- React23__namespace.default.useEffect(() => {
3244
+ React24__namespace.default.useEffect(() => {
3098
3245
  if (!open || !portal) return;
3099
3246
  place();
3100
3247
  const onMove = () => place();
@@ -3105,7 +3252,7 @@ function MultiSelect({
3105
3252
  window.removeEventListener("resize", onMove);
3106
3253
  };
3107
3254
  }, [open, portal, place]);
3108
- React23__namespace.default.useEffect(() => {
3255
+ React24__namespace.default.useEffect(() => {
3109
3256
  if (!open) return;
3110
3257
  const onDown = (e) => {
3111
3258
  if (wrapRef.current && wrapRef.current.contains(e.target)) return;
@@ -3116,10 +3263,10 @@ function MultiSelect({
3116
3263
  document.addEventListener("mousedown", onDown);
3117
3264
  return () => document.removeEventListener("mousedown", onDown);
3118
3265
  }, [open]);
3119
- React23__namespace.default.useEffect(() => {
3266
+ React24__namespace.default.useEffect(() => {
3120
3267
  setActive(0);
3121
3268
  }, [query]);
3122
- React23__namespace.default.useEffect(() => {
3269
+ React24__namespace.default.useEffect(() => {
3123
3270
  if (open) ensureVisible3(listRef.current, activeRef.current);
3124
3271
  }, [active, open]);
3125
3272
  function commit(next) {
@@ -3156,7 +3303,7 @@ function MultiSelect({
3156
3303
  const descId = `${fieldId}-desc`;
3157
3304
  const describedBy = error || hint ? descId : void 0;
3158
3305
  let counter = -1;
3159
- const popInner = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__list", id: listboxId, ref: listRef, role: "listbox", "aria-multiselectable": "true", children: visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__empty", children: "No results found" }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxRuntime.jsxs(React23__namespace.default.Fragment, { children: [
3306
+ const popInner = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__list", id: listboxId, ref: listRef, role: "listbox", "aria-multiselectable": "true", children: visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__empty", children: "No results found" }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxRuntime.jsxs(React24__namespace.default.Fragment, { children: [
3160
3307
  g.group ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-pop__group", children: g.group }) : null,
3161
3308
  g.options.map((o) => {
3162
3309
  counter += 1;
@@ -3300,6 +3447,15 @@ function MultiSelect({
3300
3447
  error ? /* @__PURE__ */ jsxRuntime.jsx("span", { id: descId, className: "twc-field__error", children: error }) : hint ? /* @__PURE__ */ jsxRuntime.jsx("span", { id: descId, className: "twc-field__hint", children: hint }) : null
3301
3448
  ] });
3302
3449
  }
3450
+
3451
+ // components/_warn.js
3452
+ var seen = /* @__PURE__ */ new Set();
3453
+ function warnOnce(key, message) {
3454
+ if (typeof process !== "undefined" && process.env && process.env.NODE_ENV === "production") return;
3455
+ if (seen.has(key)) return;
3456
+ seen.add(key);
3457
+ if (typeof console !== "undefined" && console.warn) console.warn(message);
3458
+ }
3303
3459
  var PAGINATION_CSS = `
3304
3460
  .twc-pagination { display: inline-flex; align-items: center; gap: 4px; font-family: var(--font-sans); }
3305
3461
  .twc-page {
@@ -3362,15 +3518,18 @@ function Pagination({
3362
3518
  siblings = 1,
3363
3519
  boundaries = 1,
3364
3520
  size = "md",
3365
- showJumper = false,
3521
+ showJumper,
3366
3522
  showPageJumper,
3367
3523
  jumperLabel = "Go to",
3368
3524
  className = "",
3369
3525
  ...rest
3370
3526
  }) {
3527
+ if (process.env.NODE_ENV !== "production" && showJumper !== void 0 && showPageJumper === void 0) {
3528
+ warnOnce("Pagination.showJumper", "Pagination: `showJumper` is deprecated and will be removed in 2.0 \u2014 use `showPageJumper`.");
3529
+ }
3371
3530
  const jumperEnabled = showPageJumper ?? showJumper;
3372
3531
  const __twcStyles = useScopedStyles("twc-pagination-styles", PAGINATION_CSS);
3373
- const [internal, setInternal] = React23__namespace.default.useState(defaultPage);
3532
+ const [internal, setInternal] = React24__namespace.default.useState(defaultPage);
3374
3533
  const page = pageProp !== void 0 ? pageProp : internal;
3375
3534
  const pages = buildPages(page, total, siblings, boundaries);
3376
3535
  const go = (p) => {
@@ -3378,7 +3537,7 @@ function Pagination({
3378
3537
  if (pageProp === void 0) setInternal(p);
3379
3538
  onChange?.(p);
3380
3539
  };
3381
- const [jump, setJump] = React23__namespace.default.useState("");
3540
+ const [jump, setJump] = React24__namespace.default.useState("");
3382
3541
  const submitJump = () => {
3383
3542
  const n = parseInt(jump, 10);
3384
3543
  if (!Number.isNaN(n)) go(Math.min(Math.max(n, 1), total));
@@ -3801,6 +3960,7 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
3801
3960
  .twc-dt__sw[data-on="true"]::after { transform: translateX(14px); }
3802
3961
  .twc-dt__panel-head { display: flex; align-items: center; justify-content: space-between; padding: 6px 8px 8px; }
3803
3962
  .twc-dt__panel-title { font-size: var(--text-xs); font-weight: 700; letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--color-text-subtle); }
3963
+ .twc-dt__panel-count { font-weight: 600; color: var(--color-text-muted); text-transform: none; letter-spacing: 0; margin-inline-start: 6px; font-variant-numeric: tabular-nums; }
3804
3964
  .twc-dt__link { border: none; background: transparent; color: var(--color-primary); font-family: inherit; font-size: var(--text-xs); font-weight: 600; cursor: pointer; padding: 2px 4px; border-radius: var(--radius-sm); }
3805
3965
  .twc-dt__link:hover { background: var(--color-primary-subtle); }
3806
3966
 
@@ -3988,9 +4148,9 @@ function runDatatableQuery(rows, query, options = {}) {
3988
4148
  return { rows: page, total, filtered: out };
3989
4149
  }
3990
4150
  function useFloating() {
3991
- const [pos, setPos] = React23__namespace.default.useState(null);
3992
- const cfg = React23__namespace.default.useRef(null);
3993
- const place = React23__namespace.default.useCallback(() => {
4151
+ const [pos, setPos] = React24__namespace.default.useState(null);
4152
+ const cfg = React24__namespace.default.useRef(null);
4153
+ const place = React24__namespace.default.useCallback(() => {
3994
4154
  const c = cfg.current;
3995
4155
  if (!c || !c.el || !c.el.isConnected) return null;
3996
4156
  const r = c.el.getBoundingClientRect();
@@ -4001,17 +4161,17 @@ function useFloating() {
4001
4161
  const top = r.bottom + 6;
4002
4162
  return { top, left, width: c.width, anchorX: r.left + r.width / 2, maxHeight: Math.max(180, vh - top - M) };
4003
4163
  }, []);
4004
- const open = React23__namespace.default.useCallback((el, align = "left", width = 220) => {
4164
+ const open = React24__namespace.default.useCallback((el, align = "left", width = 220) => {
4005
4165
  cfg.current = { el, align, width };
4006
4166
  const p = place();
4007
4167
  if (p) setPos(p);
4008
4168
  }, [place]);
4009
- const close = React23__namespace.default.useCallback(() => {
4169
+ const close = React24__namespace.default.useCallback(() => {
4010
4170
  cfg.current = null;
4011
4171
  setPos(null);
4012
4172
  }, []);
4013
4173
  const isOpen = pos != null;
4014
- React23__namespace.default.useEffect(() => {
4174
+ React24__namespace.default.useEffect(() => {
4015
4175
  if (!isOpen) return void 0;
4016
4176
  const update = () => {
4017
4177
  const p = place();
@@ -4035,9 +4195,9 @@ function Caret({ pos }) {
4035
4195
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__caret", style: { left } });
4036
4196
  }
4037
4197
  function EditCell({ col, value, options, onChange, onCommit, onCommitValue, onCancel, onKeyDown }) {
4038
- const ref = React23__namespace.default.useRef(null);
4198
+ const ref = React24__namespace.default.useRef(null);
4039
4199
  const isSelect = col.editType === "select" || options && col.editType !== "text";
4040
- React23__namespace.default.useEffect(() => {
4200
+ React24__namespace.default.useEffect(() => {
4041
4201
  if (isSelect) {
4042
4202
  const t = setTimeout(() => ref.current?.querySelector(".twc-sel__trigger")?.click(), 0);
4043
4203
  return () => clearTimeout(t);
@@ -4198,7 +4358,7 @@ function Datatable({
4198
4358
  loading = false,
4199
4359
  rowKey,
4200
4360
  checkboxSelection = false,
4201
- density: densityProp = "standard",
4361
+ density: densityProp = "comfortable",
4202
4362
  pageSize = 10,
4203
4363
  pageSizeOptions = [5, 10, 25, 50],
4204
4364
  height = 440,
@@ -4206,7 +4366,9 @@ function Datatable({
4206
4366
  rowCount,
4207
4367
  onServerChange,
4208
4368
  batchActions = [],
4209
- showExport = true,
4369
+ showExport = false,
4370
+ showDensity = false,
4371
+ showPivot = false,
4210
4372
  exportFilename = "export",
4211
4373
  aggregationValues = null,
4212
4374
  disableColumnReorder = false,
@@ -4238,7 +4400,7 @@ function Datatable({
4238
4400
  ...rest
4239
4401
  }) {
4240
4402
  const __twcStyles = useScopedStyles("twc-dt-styles", DT_CSS);
4241
- const cols = React23__namespace.default.useMemo(() => {
4403
+ const cols = React24__namespace.default.useMemo(() => {
4242
4404
  const out = columns.map((c) => {
4243
4405
  const isActions = c.type === "actions";
4244
4406
  return {
@@ -4273,7 +4435,7 @@ function Datatable({
4273
4435
  }
4274
4436
  return out;
4275
4437
  }, [columns, rowPinning]);
4276
- const _autoKey = React23__namespace.default.useRef();
4438
+ const _autoKey = React24__namespace.default.useRef();
4277
4439
  if (!_autoKey.current) _autoKey.current = { map: /* @__PURE__ */ new WeakMap(), n: 0 };
4278
4440
  const keyOf = rowKey || ((r, i) => {
4279
4441
  if (r != null && r.id != null) return r.id;
@@ -4288,17 +4450,17 @@ function Datatable({
4288
4450
  }
4289
4451
  return i;
4290
4452
  });
4291
- const [sort, setSort] = React23__namespace.default.useState(null);
4292
- const [filters, setFilters] = React23__namespace.default.useState([]);
4293
- const [hidden, setHidden] = React23__namespace.default.useState(() => /* @__PURE__ */ new Set());
4294
- const [showRowNum, setShowRowNum] = React23__namespace.default.useState(rowNumbers);
4295
- const [wrapped, setWrapped] = React23__namespace.default.useState(() => new Set((columns || []).filter((c) => c.wrapText).map((c) => c.field)));
4453
+ const [sort, setSort] = React24__namespace.default.useState(null);
4454
+ const [filters, setFilters] = React24__namespace.default.useState([]);
4455
+ const [hidden, setHidden] = React24__namespace.default.useState(() => /* @__PURE__ */ new Set());
4456
+ const [showRowNum, setShowRowNum] = React24__namespace.default.useState(rowNumbers);
4457
+ const [wrapped, setWrapped] = React24__namespace.default.useState(() => new Set((columns || []).filter((c) => c.wrapText).map((c) => c.field)));
4296
4458
  const toggleWrap = (field) => setWrapped((w) => {
4297
4459
  const n = new Set(w);
4298
4460
  n.has(field) ? n.delete(field) : n.add(field);
4299
4461
  return n;
4300
4462
  });
4301
- const [pins, setPins] = React23__namespace.default.useState(() => {
4463
+ const [pins, setPins] = React24__namespace.default.useState(() => {
4302
4464
  const left = [], right = [];
4303
4465
  columns.forEach((c) => {
4304
4466
  if (c.pinned === "left") left.push(c.field);
@@ -4306,34 +4468,34 @@ function Datatable({
4306
4468
  });
4307
4469
  return { left, right };
4308
4470
  });
4309
- const [density, setDensity] = React23__namespace.default.useState(densityProp);
4310
- const [quick, setQuick] = React23__namespace.default.useState("");
4311
- const [selected, setSelected] = React23__namespace.default.useState(() => /* @__PURE__ */ new Set());
4312
- const [activeRow, setActiveRow] = React23__namespace.default.useState(null);
4313
- const [activeCell, setActiveCell] = React23__namespace.default.useState(null);
4314
- const [page, setPage] = React23__namespace.default.useState(0);
4315
- const [rowsPerPage, setRowsPerPage] = React23__namespace.default.useState(pageSize > 0 ? pageSize : 10);
4316
- const [colQuery, setColQuery] = React23__namespace.default.useState("");
4317
- const [widths, setWidths] = React23__namespace.default.useState({});
4318
- const [order, setOrder] = React23__namespace.default.useState(() => columns.map((c) => c.field));
4319
- const [drag, setDrag] = React23__namespace.default.useState({ from: null, over: null, after: false });
4320
- const [aggOn, setAggOn] = React23__namespace.default.useState(showAggregation);
4321
- const [focus, setFocus] = React23__namespace.default.useState({ r: 0, c: 0 });
4322
- const gridRef = React23__namespace.default.useRef(null);
4323
- const [groupBy, setGroupBy] = React23__namespace.default.useState(rowGrouping || []);
4324
- const [collapsed, setCollapsed] = React23__namespace.default.useState(() => /* @__PURE__ */ new Set());
4325
- const [pinnedRows, setPinnedRows] = React23__namespace.default.useState({ top: [], bottom: [] });
4326
- const [headH, setHeadH] = React23__namespace.default.useState(41);
4327
- const theadRef = React23__namespace.default.useRef(null);
4328
- const [rowOrder, setRowOrder] = React23__namespace.default.useState(null);
4329
- const [rowHeights, setRowHeights] = React23__namespace.default.useState({});
4330
- const [rowDrag, setRowDrag] = React23__namespace.default.useState({ from: null, over: null, after: false });
4331
- const [rowGrab, setRowGrab] = React23__namespace.default.useState(null);
4332
- const [reorderMsg, setReorderMsg] = React23__namespace.default.useState("");
4333
- const rowFocusRef = React23__namespace.default.useRef(null);
4334
- const rootRef = React23__namespace.default.useRef(null);
4335
- const [compact, setCompact] = React23__namespace.default.useState(false);
4336
- React23__namespace.default.useEffect(() => {
4471
+ const [density, setDensity] = React24__namespace.default.useState(densityProp);
4472
+ const [quick, setQuick] = React24__namespace.default.useState("");
4473
+ const [selected, setSelected] = React24__namespace.default.useState(() => /* @__PURE__ */ new Set());
4474
+ const [activeRow, setActiveRow] = React24__namespace.default.useState(null);
4475
+ const [activeCell, setActiveCell] = React24__namespace.default.useState(null);
4476
+ const [page, setPage] = React24__namespace.default.useState(0);
4477
+ const [rowsPerPage, setRowsPerPage] = React24__namespace.default.useState(pageSize > 0 ? pageSize : 10);
4478
+ const [colQuery, setColQuery] = React24__namespace.default.useState("");
4479
+ const [widths, setWidths] = React24__namespace.default.useState({});
4480
+ const [order, setOrder] = React24__namespace.default.useState(() => columns.map((c) => c.field));
4481
+ const [drag, setDrag] = React24__namespace.default.useState({ from: null, over: null, after: false });
4482
+ const [aggOn, setAggOn] = React24__namespace.default.useState(showAggregation);
4483
+ const [focus, setFocus] = React24__namespace.default.useState({ r: 0, c: 0 });
4484
+ const gridRef = React24__namespace.default.useRef(null);
4485
+ const [groupBy, setGroupBy] = React24__namespace.default.useState(rowGrouping || []);
4486
+ const [collapsed, setCollapsed] = React24__namespace.default.useState(() => /* @__PURE__ */ new Set());
4487
+ const [pinnedRows, setPinnedRows] = React24__namespace.default.useState({ top: [], bottom: [] });
4488
+ const [headH, setHeadH] = React24__namespace.default.useState(41);
4489
+ const theadRef = React24__namespace.default.useRef(null);
4490
+ const [rowOrder, setRowOrder] = React24__namespace.default.useState(null);
4491
+ const [rowHeights, setRowHeights] = React24__namespace.default.useState({});
4492
+ const [rowDrag, setRowDrag] = React24__namespace.default.useState({ from: null, over: null, after: false });
4493
+ const [rowGrab, setRowGrab] = React24__namespace.default.useState(null);
4494
+ const [reorderMsg, setReorderMsg] = React24__namespace.default.useState("");
4495
+ const rowFocusRef = React24__namespace.default.useRef(null);
4496
+ const rootRef = React24__namespace.default.useRef(null);
4497
+ const [compact, setCompact] = React24__namespace.default.useState(false);
4498
+ React24__namespace.default.useEffect(() => {
4337
4499
  const el = rootRef.current;
4338
4500
  if (!el) return void 0;
4339
4501
  const measure = () => setCompact((el.clientWidth || 0) < 720);
@@ -4346,11 +4508,11 @@ function Datatable({
4346
4508
  else if (typeof window !== "undefined") window.removeEventListener("resize", measure);
4347
4509
  };
4348
4510
  }, []);
4349
- const scrollRef = React23__namespace.default.useRef(null);
4350
- const [scrollTop, setScrollTop] = React23__namespace.default.useState(0);
4351
- const [viewportH, setViewportH] = React23__namespace.default.useState(0);
4352
- const [pivotOn, setPivotOn] = React23__namespace.default.useState(pivotMode);
4353
- const [aggConfig, setAggConfig] = React23__namespace.default.useState(() => {
4511
+ const scrollRef = React24__namespace.default.useRef(null);
4512
+ const [scrollTop, setScrollTop] = React24__namespace.default.useState(0);
4513
+ const [viewportH, setViewportH] = React24__namespace.default.useState(0);
4514
+ const [pivotOn, setPivotOn] = React24__namespace.default.useState(pivotMode);
4515
+ const [aggConfig, setAggConfig] = React24__namespace.default.useState(() => {
4354
4516
  const m = {};
4355
4517
  (columns || []).forEach((c) => {
4356
4518
  if (typeof c.aggregation === "string") m[c.field] = c.aggregation;
@@ -4358,13 +4520,13 @@ function Datatable({
4358
4520
  return m;
4359
4521
  });
4360
4522
  const aggOf = (c) => aggConfig[c.field] || (typeof c.aggregation === "function" ? c.aggregation : null);
4361
- const [pivotConfig, setPivotConfig] = React23__namespace.default.useState(() => ({
4523
+ const [pivotConfig, setPivotConfig] = React24__namespace.default.useState(() => ({
4362
4524
  rows: pivot && pivot.rows || [],
4363
4525
  columns: pivot && pivot.columns || [],
4364
4526
  values: pivot && pivot.values || []
4365
4527
  }));
4366
4528
  const pivotActive = pivotOn && pivotConfig.rows.length > 0 && pivotConfig.values.length > 0;
4367
- React23__namespace.default.useEffect(() => {
4529
+ React24__namespace.default.useEffect(() => {
4368
4530
  setOrder((prev) => {
4369
4531
  const fields = columns.map((c) => c.field);
4370
4532
  const kept = prev.filter((f) => fields.includes(f));
@@ -4372,32 +4534,32 @@ function Datatable({
4372
4534
  return [...kept, ...added];
4373
4535
  });
4374
4536
  }, [columns]);
4375
- React23__namespace.default.useEffect(() => {
4537
+ React24__namespace.default.useEffect(() => {
4376
4538
  setDensity(densityProp);
4377
4539
  }, [densityProp]);
4378
- React23__namespace.default.useEffect(() => {
4540
+ React24__namespace.default.useEffect(() => {
4379
4541
  setAggOn(showAggregation);
4380
4542
  }, [showAggregation]);
4381
4543
  const rowGroupingKey = (rowGrouping || []).join("\0");
4382
- const rowGroupingKeyRef = React23__namespace.default.useRef(rowGroupingKey);
4383
- React23__namespace.default.useEffect(() => {
4544
+ const rowGroupingKeyRef = React24__namespace.default.useRef(rowGroupingKey);
4545
+ React24__namespace.default.useEffect(() => {
4384
4546
  if (rowGroupingKeyRef.current === rowGroupingKey) return;
4385
4547
  rowGroupingKeyRef.current = rowGroupingKey;
4386
4548
  setGroupBy(rowGrouping || []);
4387
4549
  }, [rowGroupingKey]);
4388
4550
  const widthOf = (c) => widths[c.field] ?? c.width ?? 160;
4389
- const [colMenu, setColMenu] = React23__namespace.default.useState(null);
4551
+ const [colMenu, setColMenu] = React24__namespace.default.useState(null);
4390
4552
  const [menuPos, openMenu, closeMenu] = useFloating();
4391
- const [panel, setPanel] = React23__namespace.default.useState(null);
4553
+ const [panel, setPanel] = React24__namespace.default.useState(null);
4392
4554
  const [panelPos, openPanel, closePanel] = useFloating();
4393
- const [rowMenu, setRowMenu] = React23__namespace.default.useState(null);
4555
+ const [rowMenu, setRowMenu] = React24__namespace.default.useState(null);
4394
4556
  const [rowMenuPos, openRowMenu, closeRowMenu] = useFloating();
4395
- const [exportOpen, setExportOpen] = React23__namespace.default.useState(false);
4557
+ const [exportOpen, setExportOpen] = React24__namespace.default.useState(false);
4396
4558
  const [exportPos, openExport, closeExport] = useFloating();
4397
- const menuTriggerRef = React23__namespace.default.useRef(null);
4398
- const colMenuRef = React23__namespace.default.useRef(null);
4399
- const rowMenuRef = React23__namespace.default.useRef(null);
4400
- const exportMenuRef = React23__namespace.default.useRef(null);
4559
+ const menuTriggerRef = React24__namespace.default.useRef(null);
4560
+ const colMenuRef = React24__namespace.default.useRef(null);
4561
+ const rowMenuRef = React24__namespace.default.useRef(null);
4562
+ const exportMenuRef = React24__namespace.default.useRef(null);
4401
4563
  function focusFirstItem(container) {
4402
4564
  if (!container) return;
4403
4565
  const first = container.querySelector('[role="menuitem"]:not([disabled])');
@@ -4436,16 +4598,16 @@ function Datatable({
4436
4598
  restoreTriggerFocus();
4437
4599
  }
4438
4600
  }
4439
- React23__namespace.default.useEffect(() => {
4601
+ React24__namespace.default.useEffect(() => {
4440
4602
  if (colMenu) focusFirstItem(colMenuRef.current);
4441
4603
  }, [colMenu]);
4442
- React23__namespace.default.useEffect(() => {
4604
+ React24__namespace.default.useEffect(() => {
4443
4605
  if (rowMenu) focusFirstItem(rowMenuRef.current);
4444
4606
  }, [rowMenu]);
4445
- React23__namespace.default.useEffect(() => {
4607
+ React24__namespace.default.useEffect(() => {
4446
4608
  if (exportOpen) focusFirstItem(exportMenuRef.current);
4447
4609
  }, [exportOpen]);
4448
- React23__namespace.default.useEffect(() => {
4610
+ React24__namespace.default.useEffect(() => {
4449
4611
  if (!colMenu && !panel && !rowMenu) return;
4450
4612
  const closeAll = () => {
4451
4613
  setColMenu(null);
@@ -4468,7 +4630,7 @@ function Datatable({
4468
4630
  document.removeEventListener("keydown", onKey);
4469
4631
  };
4470
4632
  }, [colMenu, panel, rowMenu]);
4471
- React23__namespace.default.useEffect(() => {
4633
+ React24__namespace.default.useEffect(() => {
4472
4634
  if (!exportOpen) return;
4473
4635
  const close = () => {
4474
4636
  setExportOpen(false);
@@ -4487,9 +4649,9 @@ function Datatable({
4487
4649
  document.removeEventListener("keydown", onKey);
4488
4650
  };
4489
4651
  }, [exportOpen]);
4490
- const colByField = React23__namespace.default.useMemo(() => Object.fromEntries(cols.map((c) => [c.field, c])), [cols]);
4652
+ const colByField = React24__namespace.default.useMemo(() => Object.fromEntries(cols.map((c) => [c.field, c])), [cols]);
4491
4653
  const visibleCols = cols.filter((c) => !hidden.has(c.field));
4492
- const ordered = React23__namespace.default.useMemo(() => {
4654
+ const ordered = React24__namespace.default.useMemo(() => {
4493
4655
  const orderIdx = (f) => {
4494
4656
  const i = order.indexOf(f);
4495
4657
  return i === -1 ? 9999 : i;
@@ -4524,7 +4686,7 @@ function Datatable({
4524
4686
  }
4525
4687
  return {};
4526
4688
  };
4527
- const processed = React23__namespace.default.useMemo(() => {
4689
+ const processed = React24__namespace.default.useMemo(() => {
4528
4690
  if (serverMode) {
4529
4691
  if (rowOrder) {
4530
4692
  const idx = new Map(rowOrder.map((k, i) => [k, i]));
@@ -4563,10 +4725,10 @@ function Datatable({
4563
4725
  const totalRows = serverMode ? serverTotal : processed.length;
4564
4726
  const totalPages = paginated ? Math.max(1, Math.ceil(totalRows / rowsPerPage)) : 1;
4565
4727
  const paged = !paginated || serverMode ? processed : processed.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage);
4566
- React23__namespace.default.useEffect(() => {
4728
+ React24__namespace.default.useEffect(() => {
4567
4729
  if (page > totalPages - 1) setPage(0);
4568
4730
  }, [totalPages]);
4569
- const activeGroupBy = React23__namespace.default.useMemo(() => groupBy.filter((f) => colByField[f]), [groupBy, colByField]);
4731
+ const activeGroupBy = React24__namespace.default.useMemo(() => groupBy.filter((f) => colByField[f]), [groupBy, colByField]);
4570
4732
  function subtotalText(rowsIn) {
4571
4733
  const parts = [];
4572
4734
  for (const c of ordered) {
@@ -4593,7 +4755,7 @@ function Datatable({
4593
4755
  if (agg === "max") return Math.max(...nums);
4594
4756
  return null;
4595
4757
  }
4596
- const displayItems = React23__namespace.default.useMemo(() => {
4758
+ const displayItems = React24__namespace.default.useMemo(() => {
4597
4759
  if (!activeGroupBy.length) return null;
4598
4760
  const build = (rowsIn, depth, prefix) => {
4599
4761
  if (depth >= activeGroupBy.length) return rowsIn.map((row) => ({ kind: "leaf", row }));
@@ -4635,7 +4797,7 @@ function Datatable({
4635
4797
  return { top, bottom };
4636
4798
  });
4637
4799
  }
4638
- React23__namespace.default.useEffect(() => {
4800
+ React24__namespace.default.useEffect(() => {
4639
4801
  if (!rowPinning) return;
4640
4802
  const measure = () => {
4641
4803
  if (theadRef.current) setHeadH(theadRef.current.offsetHeight || 41);
@@ -4649,12 +4811,12 @@ function Datatable({
4649
4811
  const pinnedTopRows = canPinRows ? pinnedRows.top.map((k) => leafRows.find((r, i) => keyOf(r, i) === k)).filter(Boolean) : [];
4650
4812
  const pinnedBottomRows = canPinRows ? pinnedRows.bottom.map((k) => leafRows.find((r, i) => keyOf(r, i) === k)).filter(Boolean) : [];
4651
4813
  const middleRows = canPinRows ? leafRows.filter((r, i) => !pinSideOf(keyOf(r, i))) : leafRows;
4652
- const keyIndex = React23__namespace.default.useMemo(() => {
4814
+ const keyIndex = React24__namespace.default.useMemo(() => {
4653
4815
  const m = /* @__PURE__ */ new Map();
4654
4816
  leafRows.forEach((r, i) => m.set(keyOf(r, i), i));
4655
4817
  return m;
4656
4818
  }, [leafRows]);
4657
- const keyIndexMid = React23__namespace.default.useMemo(() => {
4819
+ const keyIndexMid = React24__namespace.default.useMemo(() => {
4658
4820
  const m = /* @__PURE__ */ new Map();
4659
4821
  middleRows.forEach((r, i) => m.set(keyOf(r, keyIndex.get(keyOf(r)) ?? i), i));
4660
4822
  return m;
@@ -4739,19 +4901,19 @@ function Datatable({
4739
4901
  setReorderMsg("Reorder cancelled.");
4740
4902
  }
4741
4903
  }
4742
- React23__namespace.default.useEffect(() => {
4904
+ React24__namespace.default.useEffect(() => {
4743
4905
  if (rowFocusRef.current == null) return;
4744
4906
  const key = rowFocusRef.current;
4745
4907
  rowFocusRef.current = null;
4746
4908
  const root = gridRef.current;
4747
4909
  if (!root) return;
4748
- const sel = typeof CSS !== "undefined" && CSS.escape ? CSS.escape(String(key)) : String(key).replace(/"/g, '\\"');
4910
+ const sel = typeof CSS !== "undefined" && CSS.escape ? CSS.escape(String(key)) : String(key).replace(/[\\"]/g, "\\$&");
4749
4911
  const el = root.querySelector(`.twc-dt__row-handle[data-row-key="${sel}"]`);
4750
4912
  if (el) el.focus();
4751
4913
  });
4752
4914
  const estRowH = rowHeight ?? (density === "compact" ? 36 : density === "comfortable" ? 56 : 44);
4753
4915
  const virtualizing = virtualized && !paginated && !activeGroupBy.length && !loading;
4754
- React23__namespace.default.useEffect(() => {
4916
+ React24__namespace.default.useEffect(() => {
4755
4917
  if (!virtualizing) return;
4756
4918
  const el = scrollRef.current;
4757
4919
  if (!el) return;
@@ -4761,13 +4923,13 @@ function Datatable({
4761
4923
  if (ro) ro.observe(el);
4762
4924
  return () => ro && ro.disconnect();
4763
4925
  }, [virtualizing, height]);
4764
- const onScrollVirtual = React23__namespace.default.useCallback((e) => {
4926
+ const onScrollVirtual = React24__namespace.default.useCallback((e) => {
4765
4927
  setScrollTop(e.currentTarget.scrollTop);
4766
4928
  }, []);
4767
4929
  const vh = viewportH || (typeof height === "number" ? height : 440);
4768
- const rowHRef = React23__namespace.default.useRef(/* @__PURE__ */ new Map());
4769
- const [measureTick, setMeasureTick] = React23__namespace.default.useState(0);
4770
- const offsets = React23__namespace.default.useMemo(() => {
4930
+ const rowHRef = React24__namespace.default.useRef(/* @__PURE__ */ new Map());
4931
+ const [measureTick, setMeasureTick] = React24__namespace.default.useState(0);
4932
+ const offsets = React24__namespace.default.useMemo(() => {
4771
4933
  if (!virtualizing) return null;
4772
4934
  const total = middleRows.length;
4773
4935
  const arr = new Float64Array(total + 1);
@@ -4777,7 +4939,7 @@ function Datatable({
4777
4939
  }
4778
4940
  return arr;
4779
4941
  }, [virtualizing, middleRows, estRowH, measureTick]);
4780
- const vWindow = React23__namespace.default.useMemo(() => {
4942
+ const vWindow = React24__namespace.default.useMemo(() => {
4781
4943
  if (!virtualizing || !offsets) return null;
4782
4944
  const total = middleRows.length;
4783
4945
  const totalH = offsets[total];
@@ -4806,7 +4968,7 @@ function Datatable({
4806
4968
  if (start > end) start = end;
4807
4969
  return { start, end, padTop: offsets[start], padBottom: Math.max(0, totalH - offsets[end]) };
4808
4970
  }, [virtualizing, offsets, middleRows.length, vh, scrollTop, overscan]);
4809
- React23__namespace.default.useLayoutEffect(() => {
4971
+ React24__namespace.default.useLayoutEffect(() => {
4810
4972
  if (!virtualizing) return;
4811
4973
  const el = scrollRef.current;
4812
4974
  if (!el) return;
@@ -4821,9 +4983,9 @@ function Datatable({
4821
4983
  }
4822
4984
  if (changed) setMeasureTick((t) => t + 1);
4823
4985
  });
4824
- const onServerChangeRef = React23__namespace.default.useRef(onServerChange);
4986
+ const onServerChangeRef = React24__namespace.default.useRef(onServerChange);
4825
4987
  onServerChangeRef.current = onServerChange;
4826
- React23__namespace.default.useEffect(() => {
4988
+ React24__namespace.default.useEffect(() => {
4827
4989
  if (!serverMode) return;
4828
4990
  const t = setTimeout(() => {
4829
4991
  onServerChangeRef.current?.({
@@ -4858,7 +5020,7 @@ function Datatable({
4858
5020
  return n;
4859
5021
  });
4860
5022
  }
4861
- const movableMidFields = React23__namespace.default.useMemo(
5023
+ const movableMidFields = React24__namespace.default.useMemo(
4862
5024
  () => ordered.filter((c) => !pins.left.includes(c.field) && !pins.right.includes(c.field)).map((c) => c.field),
4863
5025
  [ordered, pins]
4864
5026
  );
@@ -4889,7 +5051,7 @@ function Datatable({
4889
5051
  }
4890
5052
  return [...set].sort((a, b) => a.localeCompare(b)).map((v) => ({ value: v, label: v }));
4891
5053
  }
4892
- const [resizing, setResizing] = React23__namespace.default.useState(false);
5054
+ const [resizing, setResizing] = React24__namespace.default.useState(false);
4893
5055
  function startResize(e, field) {
4894
5056
  e.preventDefault();
4895
5057
  e.stopPropagation();
@@ -4996,7 +5158,7 @@ function Datatable({
4996
5158
  if (!agg) return null;
4997
5159
  if (aggregationValues && col.field in aggregationValues) {
4998
5160
  const pre = aggregationValues[col.field];
4999
- if (pre && typeof pre === "object" && !React23__namespace.default.isValidElement(pre)) {
5161
+ if (pre && typeof pre === "object" && !React24__namespace.default.isValidElement(pre)) {
5000
5162
  if (typeof agg === "string" && agg in pre) return pre[agg];
5001
5163
  } else {
5002
5164
  return pre;
@@ -5114,14 +5276,14 @@ function Datatable({
5114
5276
  focusCell(r, c);
5115
5277
  }
5116
5278
  }
5117
- React23__namespace.default.useEffect(() => {
5279
+ React24__namespace.default.useEffect(() => {
5118
5280
  setFocus((f) => ({ r: Math.min(f.r, Math.max(0, leafRows.length - 1)), c: Math.min(f.c, Math.max(0, ordered.length - 1)) }));
5119
5281
  }, [leafRows.length, ordered.length, page]);
5120
- const selectedRows = React23__namespace.default.useMemo(() => rows.filter((r, i) => selected.has(keyOf(r, i))), [rows, selected]);
5282
+ const selectedRows = React24__namespace.default.useMemo(() => rows.filter((r, i) => selected.has(keyOf(r, i))), [rows, selected]);
5121
5283
  function clearSelection() {
5122
5284
  setSelected(/* @__PURE__ */ new Set());
5123
5285
  }
5124
- const [editing, setEditing] = React23__namespace.default.useState(null);
5286
+ const [editing, setEditing] = React24__namespace.default.useState(null);
5125
5287
  const isColEditable = (c) => c.type !== "actions" && (c.editable ?? (editMode && c.editable !== false));
5126
5288
  function beginEdit(rowK, col, row) {
5127
5289
  if (!isColEditable(col)) return;
@@ -5156,17 +5318,17 @@ function Datatable({
5156
5318
  cancelEdit();
5157
5319
  }
5158
5320
  }
5159
- const batchEditableCols = React23__namespace.default.useMemo(
5321
+ const batchEditableCols = React24__namespace.default.useMemo(
5160
5322
  () => cols.filter((c) => c.type !== "actions" && (c.editable ?? (editMode && c.editable !== false))),
5161
5323
  [cols, editMode]
5162
5324
  );
5163
- const [batchEdit, setBatchEdit] = React23__namespace.default.useState(null);
5325
+ const [batchEdit, setBatchEdit] = React24__namespace.default.useState(null);
5164
5326
  const [batchEditPos, openBatchEdit, closeBatchEdit] = useFloating();
5165
5327
  function openBatchEditor(el) {
5166
5328
  setBatchEdit({ fields: {}, values: {} });
5167
5329
  openBatchEdit(el, "left", 320);
5168
5330
  }
5169
- React23__namespace.default.useEffect(() => {
5331
+ React24__namespace.default.useEffect(() => {
5170
5332
  if (!batchEdit) return;
5171
5333
  const close = () => {
5172
5334
  setBatchEdit(null);
@@ -5185,7 +5347,7 @@ function Datatable({
5185
5347
  document.removeEventListener("keydown", onKey);
5186
5348
  };
5187
5349
  }, [batchEdit]);
5188
- React23__namespace.default.useEffect(() => {
5350
+ React24__namespace.default.useEffect(() => {
5189
5351
  if (batchEdit && selected.size === 0) {
5190
5352
  setBatchEdit(null);
5191
5353
  closeBatchEdit();
@@ -5222,7 +5384,7 @@ function Datatable({
5222
5384
  setBatchEdit(null);
5223
5385
  closeBatchEdit();
5224
5386
  }
5225
- React23__namespace.default.useEffect(() => {
5387
+ React24__namespace.default.useEffect(() => {
5226
5388
  if (!editing) return;
5227
5389
  const onDown = (e) => {
5228
5390
  if (e.target.closest(".twc-dt__editor-wrap") || e.target.closest(".twc-pop")) return;
@@ -5295,6 +5457,8 @@ function Datatable({
5295
5457
  };
5296
5458
  const shownColRows = cols.filter((c) => c.field !== "__pinactions__" && c.headerName.toLowerCase().includes(colQuery.trim().toLowerCase())).sort((a, b) => orderIdxOf(a.field) - orderIdxOf(b.field));
5297
5459
  const rowNumMatch = rowNumbers && "row number".includes(colQuery.trim().toLowerCase());
5460
+ const manageableCols = cols.filter((c) => c.field !== "__pinactions__");
5461
+ const visibleColCount = manageableCols.filter((c) => !hidden.has(c.field)).length;
5298
5462
  const rppOptions = Array.from(new Set([...pageSizeOptions || [], pageSize].filter((n) => n > 0))).sort((a, b) => a - b).map((n) => ({ value: String(n), label: String(n) }));
5299
5463
  const totalCols = ordered.length + (checkboxSelection ? 1 : 0) + (showRowNum ? 1 : 0);
5300
5464
  function renderGroupRow(item) {
@@ -5492,12 +5656,12 @@ function Datatable({
5492
5656
  const vlabel = (v) => v.label || (colByField[v.field]?.headerName || v.field);
5493
5657
  const rowFieldLabel = rFields.map((f) => colByField[f]?.headerName || f).join(" / ");
5494
5658
  const leafPaths = [];
5495
- const seen = /* @__PURE__ */ new Set();
5659
+ const seen2 = /* @__PURE__ */ new Set();
5496
5660
  for (const r of rows) {
5497
5661
  const path = colPathOf(r);
5498
5662
  const key = path.join("\0");
5499
- if (!seen.has(key)) {
5500
- seen.add(key);
5663
+ if (!seen2.has(key)) {
5664
+ seen2.add(key);
5501
5665
  leafPaths.push(path);
5502
5666
  }
5503
5667
  }
@@ -5657,11 +5821,11 @@ function Datatable({
5657
5821
  ]
5658
5822
  }
5659
5823
  ),
5660
- /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "twc-dt__tbtn", "data-tip": "Change row density", onClick: () => setDensity((d) => d === "compact" ? "standard" : d === "standard" ? "comfortable" : "compact"), children: [
5824
+ showDensity ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "twc-dt__tbtn", "data-tip": "Change row density", onClick: () => setDensity((d) => d === "compact" ? "standard" : d === "standard" ? "comfortable" : "compact"), children: [
5661
5825
  /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.density }),
5662
5826
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__tlabel", children: density[0].toUpperCase() + density.slice(1) })
5663
- ] }),
5664
- /* @__PURE__ */ jsxRuntime.jsxs(
5827
+ ] }) : null,
5828
+ showAggregation ? /* @__PURE__ */ jsxRuntime.jsxs(
5665
5829
  "button",
5666
5830
  {
5667
5831
  type: "button",
@@ -5686,8 +5850,8 @@ function Datatable({
5686
5850
  aggOn && hasAggregation ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__tbadge", children: ordered.filter((c) => aggOf(c)).length }) : null
5687
5851
  ]
5688
5852
  }
5689
- ),
5690
- /* @__PURE__ */ jsxRuntime.jsxs(
5853
+ ) : null,
5854
+ showPivot || pivotMode || pivot != null || pivotActive ? /* @__PURE__ */ jsxRuntime.jsxs(
5691
5855
  "button",
5692
5856
  {
5693
5857
  type: "button",
@@ -5712,7 +5876,7 @@ function Datatable({
5712
5876
  pivotActive ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__tdot", "aria-label": "on", role: "img" }) : null
5713
5877
  ]
5714
5878
  }
5715
- ),
5879
+ ) : null,
5716
5880
  showExport ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__export", children: [
5717
5881
  /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "twc-dt__export-main", "data-tip": "Export to CSV", onClick: () => exportData("csv"), "aria-label": "Export to CSV", children: [
5718
5882
  /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.download }),
@@ -6025,7 +6189,7 @@ function Datatable({
6025
6189
  } }) })
6026
6190
  ] }) : null
6027
6191
  ] }),
6028
- paginated ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__footer-row", "data-pager": "true", children: /* @__PURE__ */ jsxRuntime.jsx(Pagination, { size: "sm", page: page + 1, total: totalPages, boundaries: 3, showJumper: showPageJumper && totalPages > 5, onChange: (p) => setPage(p - 1) }) }) : null
6192
+ paginated ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__footer-row", "data-pager": "true", children: /* @__PURE__ */ jsxRuntime.jsx(Pagination, { size: "sm", page: page + 1, total: totalPages, boundaries: 3, showPageJumper: showPageJumper && totalPages > 5, onChange: (p) => setPage(p - 1) }) }) : null
6029
6193
  ] }) : null,
6030
6194
  exportOpen && exportPos ? /* @__PURE__ */ jsxRuntime.jsxs(
6031
6195
  "div",
@@ -6281,7 +6445,14 @@ function Datatable({
6281
6445
  ) : null,
6282
6446
  panel === "columns" && panelPos ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__pop twc-dt__cols", style: { top: panelPos.top, left: panelPos.left }, role: "dialog", "aria-label": "Column settings", children: [
6283
6447
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__panel-head", children: [
6284
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__panel-title", children: "Columns" }),
6448
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__panel-title", children: [
6449
+ "Columns ",
6450
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__panel-count", title: `${visibleColCount} of ${manageableCols.length} columns shown`, children: [
6451
+ visibleColCount,
6452
+ "/",
6453
+ manageableCols.length
6454
+ ] })
6455
+ ] }),
6285
6456
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6286
6457
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__link", onClick: () => setHidden(/* @__PURE__ */ new Set()), children: "Show all" }),
6287
6458
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__link", onClick: () => setHidden(new Set(cols.filter((c) => c.hideable).map((c) => c.field))), children: "Hide all" })
@@ -6735,23 +6906,23 @@ function DatePicker({
6735
6906
  }) {
6736
6907
  const __twcStyles0 = useScopedStyles("twc-field-styles", FIELD_CSS3);
6737
6908
  const __twcStyles1 = useScopedStyles("twc-datepicker-styles", DATEPICKER_CSS);
6738
- const autoId = React23__namespace.default.useId();
6909
+ const autoId = React24__namespace.default.useId();
6739
6910
  const fieldId = id || autoId;
6740
6911
  const descId = `${fieldId}-desc`;
6741
6912
  const invalid = Boolean(error);
6742
- const [internal, setInternal] = React23__namespace.default.useState(defaultValue);
6913
+ const [internal, setInternal] = React24__namespace.default.useState(defaultValue);
6743
6914
  const selected = value !== void 0 ? value : internal;
6744
- const [open, setOpen] = React23__namespace.default.useState(false);
6745
- const [view, setView] = React23__namespace.default.useState(selected || /* @__PURE__ */ new Date());
6746
- const [mode, setMode] = React23__namespace.default.useState("days");
6747
- const [focusDate, setFocusDate] = React23__namespace.default.useState(null);
6748
- const [coords, setCoords] = React23__namespace.default.useState(null);
6749
- const wrapRef = React23__namespace.default.useRef(null);
6750
- const triggerRef = React23__namespace.default.useRef(null);
6751
- const popRef = React23__namespace.default.useRef(null);
6752
- const gridRef = React23__namespace.default.useRef(null);
6915
+ const [open, setOpen] = React24__namespace.default.useState(false);
6916
+ const [view, setView] = React24__namespace.default.useState(selected || /* @__PURE__ */ new Date());
6917
+ const [mode, setMode] = React24__namespace.default.useState("days");
6918
+ const [focusDate, setFocusDate] = React24__namespace.default.useState(null);
6919
+ const [coords, setCoords] = React24__namespace.default.useState(null);
6920
+ const wrapRef = React24__namespace.default.useRef(null);
6921
+ const triggerRef = React24__namespace.default.useRef(null);
6922
+ const popRef = React24__namespace.default.useRef(null);
6923
+ const gridRef = React24__namespace.default.useRef(null);
6753
6924
  const POP_W = 280;
6754
- const place = React23__namespace.default.useCallback(() => {
6925
+ const place = React24__namespace.default.useCallback(() => {
6755
6926
  const el = triggerRef.current;
6756
6927
  if (!el) return;
6757
6928
  const r = el.getBoundingClientRect();
@@ -6762,7 +6933,7 @@ function DatePicker({
6762
6933
  left = Math.max(8, left);
6763
6934
  setCoords({ left, top: flip ? void 0 : Math.round(r.bottom + 6), bottom: flip ? Math.round(vh - r.top + 6) : void 0 });
6764
6935
  }, []);
6765
- React23__namespace.default.useEffect(() => {
6936
+ React24__namespace.default.useEffect(() => {
6766
6937
  if (!open) return void 0;
6767
6938
  place();
6768
6939
  const onMove = () => place();
@@ -6773,7 +6944,7 @@ function DatePicker({
6773
6944
  window.removeEventListener("resize", onMove);
6774
6945
  };
6775
6946
  }, [open, place]);
6776
- React23__namespace.default.useEffect(() => {
6947
+ React24__namespace.default.useEffect(() => {
6777
6948
  if (!open) return;
6778
6949
  setView(selected || /* @__PURE__ */ new Date());
6779
6950
  setMode("days");
@@ -6793,8 +6964,8 @@ function DatePicker({
6793
6964
  document.removeEventListener("keydown", onKey);
6794
6965
  };
6795
6966
  }, [open]);
6796
- const prevOpen = React23__namespace.default.useRef(false);
6797
- React23__namespace.default.useEffect(() => {
6967
+ const prevOpen = React24__namespace.default.useRef(false);
6968
+ React24__namespace.default.useEffect(() => {
6798
6969
  let id2;
6799
6970
  if (!prevOpen.current && open) {
6800
6971
  id2 = setTimeout(() => gridRef.current?.querySelector('[tabindex="0"]')?.focus({ preventScroll: true }), 30);
@@ -6805,9 +6976,9 @@ function DatePicker({
6805
6976
  prevOpen.current = open;
6806
6977
  return () => clearTimeout(id2);
6807
6978
  }, [open]);
6808
- const months = React23__namespace.default.useMemo(() => locale === void 0 ? MONTHS : monthNames(locale), [locale]);
6809
- const monthsShort = React23__namespace.default.useMemo(() => locale === void 0 ? MONTHS.map((n) => n.slice(0, 3)) : monthShortNames(locale), [locale]);
6810
- const dows = React23__namespace.default.useMemo(
6979
+ const months = React24__namespace.default.useMemo(() => locale === void 0 ? MONTHS : monthNames(locale), [locale]);
6980
+ const monthsShort = React24__namespace.default.useMemo(() => locale === void 0 ? MONTHS.map((n) => n.slice(0, 3)) : monthShortNames(locale), [locale]);
6981
+ const dows = React24__namespace.default.useMemo(
6811
6982
  () => locale === void 0 ? Array.from({ length: 7 }, (_, i) => DOW[(i + weekStartsOn) % 7]) : weekdayNames(locale, weekStartsOn),
6812
6983
  [locale, weekStartsOn]
6813
6984
  );
@@ -6835,7 +7006,7 @@ function DatePicker({
6835
7006
  };
6836
7007
  const cells = Array.from({ length: 42 }, (_, i) => new Date(gridStart.getFullYear(), gridStart.getMonth(), gridStart.getDate() + i));
6837
7008
  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);
6838
- React23__namespace.default.useEffect(() => {
7009
+ React24__namespace.default.useEffect(() => {
6839
7010
  if (!open || mode !== "days" || !focusDate) return;
6840
7011
  gridRef.current?.querySelector(`[data-key="${keyOf(focusDate)}"]`)?.focus();
6841
7012
  }, [focusDate, open, mode]);
@@ -7058,23 +7229,23 @@ function DateRangePicker({
7058
7229
  }) {
7059
7230
  const __twcStyles0 = useScopedStyles("twc-field-styles", FIELD_CSS4);
7060
7231
  const __twcStyles1 = useScopedStyles("twc-drp-styles", RANGE_CSS);
7061
- const [internal, setInternal] = React23__namespace.default.useState(defaultValue);
7232
+ const [internal, setInternal] = React24__namespace.default.useState(defaultValue);
7062
7233
  const range = value !== void 0 ? value : internal;
7063
- const [open, setOpen] = React23__namespace.default.useState(false);
7064
- const [view, setView] = React23__namespace.default.useState(range.start || /* @__PURE__ */ new Date());
7065
- const [hover, setHover] = React23__namespace.default.useState(null);
7066
- const [coords, setCoords] = React23__namespace.default.useState(null);
7067
- const wrapRef = React23__namespace.default.useRef(null);
7068
- const triggerRef = React23__namespace.default.useRef(null);
7069
- const popRef = React23__namespace.default.useRef(null);
7070
- const labelId = React23__namespace.default.useId();
7234
+ const [open, setOpen] = React24__namespace.default.useState(false);
7235
+ const [view, setView] = React24__namespace.default.useState(range.start || /* @__PURE__ */ new Date());
7236
+ const [hover, setHover] = React24__namespace.default.useState(null);
7237
+ const [coords, setCoords] = React24__namespace.default.useState(null);
7238
+ const wrapRef = React24__namespace.default.useRef(null);
7239
+ const triggerRef = React24__namespace.default.useRef(null);
7240
+ const popRef = React24__namespace.default.useRef(null);
7241
+ const labelId = React24__namespace.default.useId();
7071
7242
  const descId = `${labelId}-desc`;
7072
7243
  const invalid = Boolean(error);
7073
- React23__namespace.default.useEffect(() => {
7244
+ React24__namespace.default.useEffect(() => {
7074
7245
  if (disabled) setOpen(false);
7075
7246
  }, [disabled]);
7076
7247
  const POP_W = 420;
7077
- const place = React23__namespace.default.useCallback(() => {
7248
+ const place = React24__namespace.default.useCallback(() => {
7078
7249
  const el = triggerRef.current;
7079
7250
  if (!el) return;
7080
7251
  const r = el.getBoundingClientRect();
@@ -7085,7 +7256,7 @@ function DateRangePicker({
7085
7256
  left = Math.max(8, left);
7086
7257
  setCoords({ left, top: flip ? void 0 : Math.round(r.bottom + 6), bottom: flip ? Math.round(vh - r.top + 6) : void 0 });
7087
7258
  }, []);
7088
- React23__namespace.default.useEffect(() => {
7259
+ React24__namespace.default.useEffect(() => {
7089
7260
  if (!open) return void 0;
7090
7261
  place();
7091
7262
  const onMove = () => place();
@@ -7096,7 +7267,7 @@ function DateRangePicker({
7096
7267
  window.removeEventListener("resize", onMove);
7097
7268
  };
7098
7269
  }, [open, place]);
7099
- React23__namespace.default.useEffect(() => {
7270
+ React24__namespace.default.useEffect(() => {
7100
7271
  if (!open) return;
7101
7272
  const onDown = (e) => {
7102
7273
  if (wrapRef.current && wrapRef.current.contains(e.target)) return;
@@ -7134,8 +7305,8 @@ function DateRangePicker({
7134
7305
  setView(start);
7135
7306
  setOpen(false);
7136
7307
  };
7137
- const months = React23__namespace.default.useMemo(() => locale === void 0 ? MONTHS2 : monthNames2(locale), [locale]);
7138
- const dows = React23__namespace.default.useMemo(
7308
+ const months = React24__namespace.default.useMemo(() => locale === void 0 ? MONTHS2 : monthNames2(locale), [locale]);
7309
+ const dows = React24__namespace.default.useMemo(
7139
7310
  () => locale === void 0 ? Array.from({ length: 7 }, (_, i) => DOW2[(i + weekStartsOn) % 7]) : weekdayNames2(locale, weekStartsOn),
7140
7311
  [locale, weekStartsOn]
7141
7312
  );
@@ -7316,13 +7487,14 @@ function Dialog({
7316
7487
  className = "",
7317
7488
  ...rest
7318
7489
  }) {
7319
- const autoId = React23__namespace.default.useId();
7490
+ const autoId = React24__namespace.default.useId();
7320
7491
  const titleId = `${autoId}-title`;
7321
7492
  const descId = `${autoId}-desc`;
7322
- const dialogRef = React23__namespace.default.useRef(null);
7493
+ const dialogRef = React24__namespace.default.useRef(null);
7323
7494
  const __twcStyles = useScopedStyles("twc-dialog-styles", DIALOG_CSS);
7324
- const [mounted, setMounted] = React23__namespace.default.useState(open);
7325
- React23__namespace.default.useEffect(() => {
7495
+ const renderPortal = usePortal();
7496
+ const [mounted, setMounted] = React24__namespace.default.useState(open);
7497
+ React24__namespace.default.useEffect(() => {
7326
7498
  if (open) {
7327
7499
  setMounted(true);
7328
7500
  return;
@@ -7330,7 +7502,7 @@ function Dialog({
7330
7502
  const t = setTimeout(() => setMounted(false), 170);
7331
7503
  return () => clearTimeout(t);
7332
7504
  }, [open]);
7333
- React23__namespace.default.useEffect(() => {
7505
+ React24__namespace.default.useEffect(() => {
7334
7506
  if (!open) return void 0;
7335
7507
  const prev = document.body.style.overflow;
7336
7508
  document.body.style.overflow = "hidden";
@@ -7338,48 +7510,13 @@ function Dialog({
7338
7510
  document.body.style.overflow = prev;
7339
7511
  };
7340
7512
  }, [open]);
7341
- React23__namespace.default.useEffect(() => {
7342
- if (!open || !mounted) return void 0;
7343
- const node = dialogRef.current;
7344
- const prevFocused = document.activeElement;
7345
- const first = node?.querySelector(
7346
- 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
7347
- );
7348
- (first || node)?.focus();
7349
- return () => {
7350
- if (prevFocused && typeof prevFocused.focus === "function") prevFocused.focus();
7351
- };
7352
- }, [open, mounted]);
7353
- React23__namespace.default.useEffect(() => {
7354
- if (!open) return;
7355
- const node = dialogRef.current;
7356
- const focusables = () => node ? Array.from(
7357
- node.querySelectorAll(
7358
- 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
7359
- )
7360
- ).filter((el) => el.offsetParent !== null) : [];
7513
+ useFocusTrap(dialogRef, open && mounted);
7514
+ React24__namespace.default.useEffect(() => {
7515
+ if (!open) return void 0;
7361
7516
  const onKey = (e) => {
7362
7517
  if (e.key === "Escape") {
7363
7518
  e.preventDefault();
7364
7519
  onClose?.();
7365
- return;
7366
- }
7367
- if (e.key !== "Tab") return;
7368
- const f = focusables();
7369
- if (!f.length) {
7370
- e.preventDefault();
7371
- node?.focus();
7372
- return;
7373
- }
7374
- const first = f[0], last = f[f.length - 1], ae = document.activeElement;
7375
- if (e.shiftKey) {
7376
- if (ae === first || ae === node || !node.contains(ae)) {
7377
- e.preventDefault();
7378
- last.focus();
7379
- }
7380
- } else if (ae === last || !node.contains(ae)) {
7381
- e.preventDefault();
7382
- first.focus();
7383
7520
  }
7384
7521
  };
7385
7522
  document.addEventListener("keydown", onKey);
@@ -7403,9 +7540,7 @@ function Dialog({
7403
7540
  footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dialog__footer", children: footer }) : null
7404
7541
  ] })
7405
7542
  ] });
7406
- if (typeof document === "undefined") return null;
7407
- const RD = typeof reactDom.createPortal === "function" ? reactDom.createPortal : null;
7408
- return RD ? RD(overlay, document.body) : overlay;
7543
+ return renderPortal(overlay);
7409
7544
  }
7410
7545
  var DIVIDER_CSS = `
7411
7546
  .twc-divider { border: none; background: var(--color-divider); }
@@ -7420,6 +7555,10 @@ var DIVIDER_CSS = `
7420
7555
  so ::before/::after land on the correct inline edge under RTL \u2014 no physical override needed. */
7421
7556
  .twc-divider-label[data-align="start"]::before { flex: 0 0 var(--space-6); }
7422
7557
  .twc-divider-label[data-align="end"]::after { flex: 0 0 var(--space-6); }
7558
+ /* Vertical labeled divider: stack the two segments above/below the label. */
7559
+ .twc-divider-label[data-orientation="vertical"] { flex-direction: column; align-self: stretch; min-height: 1em; margin: 0 var(--space-3); }
7560
+ .twc-divider-label[data-orientation="vertical"]::before,
7561
+ .twc-divider-label[data-orientation="vertical"]::after { width: 1px; height: auto; flex: 1; }
7423
7562
  `;
7424
7563
  function Divider({
7425
7564
  orientation = "horizontal",
@@ -7432,7 +7571,7 @@ function Divider({
7432
7571
  const __twcStyles = useScopedStyles("twc-divider-styles", DIVIDER_CSS);
7433
7572
  const resolvedAlign = align === "left" ? "start" : align === "right" ? "end" : align;
7434
7573
  if (children) {
7435
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-divider-label ${className}`, "data-align": resolvedAlign, role: "separator", ...rest, children: [
7574
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-divider-label ${className}`, "data-align": resolvedAlign, "data-orientation": orientation, role: "separator", "aria-orientation": orientation, ...rest, children: [
7436
7575
  __twcStyles,
7437
7576
  children
7438
7577
  ] });
@@ -7519,13 +7658,14 @@ function Drawer({
7519
7658
  style,
7520
7659
  ...rest
7521
7660
  }) {
7522
- const autoId = React23__namespace.default.useId();
7661
+ const autoId = React24__namespace.default.useId();
7523
7662
  const titleId = `${autoId}-title`;
7524
7663
  const descId = `${autoId}-desc`;
7525
- const panelRef = React23__namespace.default.useRef(null);
7664
+ const panelRef = React24__namespace.default.useRef(null);
7526
7665
  const __twcStyles = useScopedStyles("twc-drawer-styles", DRAWER_CSS);
7527
- const [mounted, setMounted] = React23__namespace.default.useState(open);
7528
- React23__namespace.default.useEffect(() => {
7666
+ const renderPortal = usePortal();
7667
+ const [mounted, setMounted] = React24__namespace.default.useState(open);
7668
+ React24__namespace.default.useEffect(() => {
7529
7669
  if (open) {
7530
7670
  setMounted(true);
7531
7671
  return;
@@ -7533,7 +7673,7 @@ function Drawer({
7533
7673
  const t = setTimeout(() => setMounted(false), 170);
7534
7674
  return () => clearTimeout(t);
7535
7675
  }, [open]);
7536
- React23__namespace.default.useEffect(() => {
7676
+ React24__namespace.default.useEffect(() => {
7537
7677
  if (!open) return void 0;
7538
7678
  const prev = document.body.style.overflow;
7539
7679
  document.body.style.overflow = "hidden";
@@ -7541,48 +7681,13 @@ function Drawer({
7541
7681
  document.body.style.overflow = prev;
7542
7682
  };
7543
7683
  }, [open]);
7544
- React23__namespace.default.useEffect(() => {
7545
- if (!open || !mounted) return void 0;
7546
- const node = panelRef.current;
7547
- const prevFocused = document.activeElement;
7548
- const first = node?.querySelector(
7549
- 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
7550
- );
7551
- (first || node)?.focus();
7552
- return () => {
7553
- if (prevFocused && typeof prevFocused.focus === "function") prevFocused.focus();
7554
- };
7555
- }, [open, mounted]);
7556
- React23__namespace.default.useEffect(() => {
7557
- if (!open) return;
7558
- const node = panelRef.current;
7559
- const focusables = () => node ? Array.from(
7560
- node.querySelectorAll(
7561
- 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
7562
- )
7563
- ).filter((el) => el.offsetParent !== null) : [];
7684
+ useFocusTrap(panelRef, open && mounted);
7685
+ React24__namespace.default.useEffect(() => {
7686
+ if (!open) return void 0;
7564
7687
  const onKey = (e) => {
7565
7688
  if (e.key === "Escape") {
7566
7689
  e.preventDefault();
7567
7690
  onClose?.();
7568
- return;
7569
- }
7570
- if (e.key !== "Tab") return;
7571
- const f = focusables();
7572
- if (!f.length) {
7573
- e.preventDefault();
7574
- node?.focus();
7575
- return;
7576
- }
7577
- const first = f[0], last = f[f.length - 1], ae = document.activeElement;
7578
- if (e.shiftKey) {
7579
- if (ae === first || ae === node || !node.contains(ae)) {
7580
- e.preventDefault();
7581
- last.focus();
7582
- }
7583
- } else if (ae === last || !node.contains(ae)) {
7584
- e.preventDefault();
7585
- first.focus();
7586
7691
  }
7587
7692
  };
7588
7693
  document.addEventListener("keydown", onKey);
@@ -7610,9 +7715,7 @@ function Drawer({
7610
7715
  footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-drawer__footer", children: footer }) : null
7611
7716
  ] })
7612
7717
  ] });
7613
- if (typeof document === "undefined") return null;
7614
- const RD = typeof reactDom.createPortal === "function" ? reactDom.createPortal : null;
7615
- return RD ? RD(overlay, document.body) : overlay;
7718
+ return renderPortal(overlay);
7616
7719
  }
7617
7720
  var EMPTY_CSS = `
7618
7721
  .twc-empty { display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--space-3);
@@ -7630,11 +7733,14 @@ function EmptyState({
7630
7733
  title,
7631
7734
  description,
7632
7735
  actions,
7633
- bordered = false,
7736
+ bordered,
7634
7737
  border,
7635
7738
  className = "",
7636
7739
  ...rest
7637
7740
  }) {
7741
+ if (process.env.NODE_ENV !== "production" && bordered !== void 0 && border === void 0) {
7742
+ warnOnce("EmptyState.bordered", "EmptyState: `bordered` is deprecated and will be removed in 2.0 \u2014 use `border`.");
7743
+ }
7638
7744
  const hasBorder = border ?? bordered;
7639
7745
  const __twcStyles = useScopedStyles("twc-empty-styles", EMPTY_CSS);
7640
7746
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-empty ${className}`, "data-bordered": hasBorder || void 0, ...rest, children: [
@@ -7665,7 +7771,7 @@ function Field({
7665
7771
  ...rest
7666
7772
  }) {
7667
7773
  const __twcStyles = useScopedStyles("twc-field-styles", FIELD_CSS5);
7668
- const autoId = React23__namespace.default.useId();
7774
+ const autoId = React24__namespace.default.useId();
7669
7775
  const fieldId = id || autoId;
7670
7776
  const descId = `${fieldId}-desc`;
7671
7777
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-field ${className}`, "data-size": size, ...rest, children: [
@@ -7745,11 +7851,11 @@ function FileUpload({
7745
7851
  ...rest
7746
7852
  }) {
7747
7853
  const __twcStyles = useScopedStyles("twc-upload-styles", UPLOAD_CSS);
7748
- const [internal, setInternal] = React23__namespace.default.useState(defaultValue);
7854
+ const [internal, setInternal] = React24__namespace.default.useState(defaultValue);
7749
7855
  const files = value !== void 0 ? value : internal;
7750
- const [drag, setDrag] = React23__namespace.default.useState(false);
7751
- const inputRef = React23__namespace.default.useRef(null);
7752
- const autoId = React23__namespace.default.useId();
7856
+ const [drag, setDrag] = React24__namespace.default.useState(false);
7857
+ const inputRef = React24__namespace.default.useRef(null);
7858
+ const autoId = React24__namespace.default.useId();
7753
7859
  const fieldId = id || autoId;
7754
7860
  const descId = `${fieldId}-desc`;
7755
7861
  const invalid = Boolean(error);
@@ -7947,19 +8053,20 @@ function Kanban({
7947
8053
  defaultCards,
7948
8054
  onCardMove,
7949
8055
  renderCard,
8056
+ getCardLabel,
7950
8057
  className = "",
7951
8058
  ...rest
7952
8059
  }) {
7953
8060
  const __twcStyles = useScopedStyles("twc-kanban-styles", KANBAN_CSS);
7954
- const [internal, setInternal] = React23__namespace.default.useState(cards ?? defaultCards ?? []);
8061
+ const [internal, setInternal] = React24__namespace.default.useState(cards ?? defaultCards ?? []);
7955
8062
  const items = cards !== void 0 ? cards : internal;
7956
- const [drag, setDrag] = React23__namespace.default.useState(null);
7957
- const [overCol, setOverCol] = React23__namespace.default.useState(null);
7958
- const [grab, setGrab] = React23__namespace.default.useState(null);
7959
- const [announce, setAnnounce] = React23__namespace.default.useState("");
7960
- const rootRef = React23__namespace.default.useRef(null);
7961
- const focusIdRef = React23__namespace.default.useRef(null);
7962
- React23__namespace.default.useEffect(() => {
8063
+ const [drag, setDrag] = React24__namespace.default.useState(null);
8064
+ const [overCol, setOverCol] = React24__namespace.default.useState(null);
8065
+ const [grab, setGrab] = React24__namespace.default.useState(null);
8066
+ const [announce, setAnnounce] = React24__namespace.default.useState("");
8067
+ const rootRef = React24__namespace.default.useRef(null);
8068
+ const focusIdRef = React24__namespace.default.useRef(null);
8069
+ React24__namespace.default.useEffect(() => {
7963
8070
  if (focusIdRef.current == null) return void 0;
7964
8071
  const raf = requestAnimationFrame(() => {
7965
8072
  const id = focusIdRef.current;
@@ -8011,7 +8118,7 @@ function Kanban({
8011
8118
  }
8012
8119
  };
8013
8120
  const keyTargetCol = grab ? columns[grab.targetIdx]?.id : null;
8014
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-kanban ${className}`, ref: rootRef, ...rest, children: [
8121
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-kanban ${className}`, ref: rootRef, role: "group", "aria-label": "Board", ...rest, children: [
8015
8122
  __twcStyles,
8016
8123
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-kanban__sr", role: "status", "aria-live": "polite", children: announce }),
8017
8124
  columns.map((col, colIdx) => {
@@ -8021,7 +8128,7 @@ function Kanban({
8021
8128
  {
8022
8129
  className: "twc-kanban__col",
8023
8130
  role: "group",
8024
- "aria-label": typeof col.title === "string" ? col.title : void 0,
8131
+ "aria-label": col.ariaLabel ?? colTitle(col),
8025
8132
  "data-over": overCol === col.id || keyTargetCol === col.id || void 0,
8026
8133
  onDragOver: (e) => {
8027
8134
  e.preventDefault();
@@ -8052,6 +8159,8 @@ function Kanban({
8052
8159
  tabIndex: 0,
8053
8160
  "aria-roledescription": "draggable card",
8054
8161
  "data-card-id": card.id,
8162
+ "aria-label": getCardLabel?.(card) ?? (typeof card.ariaLabel === "string" ? card.ariaLabel : cardTitle(card)),
8163
+ "aria-pressed": grab && grab.id === card.id || void 0,
8055
8164
  "data-grabbed": grab && grab.id === card.id || void 0,
8056
8165
  onKeyDown: (e) => handleCardKey(e, card, colIdx),
8057
8166
  onBlur: () => {
@@ -8105,7 +8214,7 @@ var LIST_CSS = `
8105
8214
  `;
8106
8215
  function List({ items, plain = false, className = "", ...rest }) {
8107
8216
  const __twcStyles = useScopedStyles("twc-list-styles", LIST_CSS);
8108
- const safeHref11 = (url) => {
8217
+ const safeHref12 = (url) => {
8109
8218
  if (url == null) return void 0;
8110
8219
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
8111
8220
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -8113,7 +8222,7 @@ function List({ items, plain = false, className = "", ...rest }) {
8113
8222
  return /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: `twc-list ${className}`, "data-plain": plain || void 0, ...rest, children: [
8114
8223
  __twcStyles,
8115
8224
  items.map((it, i) => {
8116
- const href = safeHref11(it.href);
8225
+ const href = safeHref12(it.href);
8117
8226
  const interactive = Boolean(it.onClick || href);
8118
8227
  const Tag2 = href ? "a" : interactive ? "button" : "div";
8119
8228
  const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -8167,7 +8276,7 @@ button.twc-navbar__brand, a.twc-navbar__brand { cursor: pointer; }
8167
8276
  .twc-navbar__menu-btn { display: inline-grid; }
8168
8277
  }
8169
8278
  `;
8170
- function safeHref3(url) {
8279
+ function safeHref4(url) {
8171
8280
  if (url == null) return void 0;
8172
8281
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
8173
8282
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -8180,16 +8289,19 @@ function Navbar({
8180
8289
  actions,
8181
8290
  sticky = true,
8182
8291
  onMenuClick,
8292
+ menuOpen,
8293
+ menuControls,
8294
+ navLabel = "Primary",
8183
8295
  className = "",
8184
8296
  ...rest
8185
8297
  }) {
8186
8298
  const __twcStyles = useScopedStyles("twc-navbar-styles", NAVBAR_CSS);
8187
8299
  return /* @__PURE__ */ jsxRuntime.jsxs("header", { className: `twc-navbar ${className}`, "data-sticky": sticky || void 0, ...rest, children: [
8188
8300
  __twcStyles,
8189
- onMenuClick ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-navbar__menu-btn", "aria-label": "Open menu", onClick: onMenuClick, children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 6h16M4 12h16M4 18h16" }) }) }) : null,
8190
- brand ? brandHref ? /* @__PURE__ */ jsxRuntime.jsx("a", { className: "twc-navbar__brand", href: safeHref3(brandHref), children: brand }) : onBrandClick ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-navbar__brand", onClick: onBrandClick, children: brand }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-navbar__brand", children: brand }) : null,
8191
- /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "twc-navbar__links", children: links.map((l, i) => {
8192
- const href = safeHref3(l.href);
8301
+ onMenuClick ? /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 6h16M4 12h16M4 18h16" }) }) }) : null,
8302
+ brand ? brandHref ? /* @__PURE__ */ jsxRuntime.jsx("a", { className: "twc-navbar__brand", href: safeHref4(brandHref), children: brand }) : onBrandClick ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-navbar__brand", onClick: onBrandClick, children: brand }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-navbar__brand", children: brand }) : null,
8303
+ /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "twc-navbar__links", "aria-label": navLabel, children: links.map((l, i) => {
8304
+ const href = safeHref4(l.href);
8193
8305
  const inner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8194
8306
  l.icon,
8195
8307
  l.label
@@ -8257,21 +8369,21 @@ function Popover({
8257
8369
  ...rest
8258
8370
  }) {
8259
8371
  const __twcStyles = useScopedStyles("twc-popover-styles", POPOVER_CSS);
8260
- const [openState, setOpenState] = React23__namespace.default.useState(defaultOpen);
8261
- const [render, setRender] = React23__namespace.default.useState(false);
8262
- const [pos, setPos] = React23__namespace.default.useState(null);
8263
- const wrapRef = React23__namespace.default.useRef(null);
8264
- const popRef = React23__namespace.default.useRef(null);
8265
- const popId = React23__namespace.default.useId();
8372
+ const [openState, setOpenState] = React24__namespace.default.useState(defaultOpen);
8373
+ const [render, setRender] = React24__namespace.default.useState(false);
8374
+ const [pos, setPos] = React24__namespace.default.useState(null);
8375
+ const wrapRef = React24__namespace.default.useRef(null);
8376
+ const popRef = React24__namespace.default.useRef(null);
8377
+ const popId = React24__namespace.default.useId();
8266
8378
  const controlled = openProp !== void 0;
8267
8379
  const open = controlled ? !!openProp : openState;
8268
- const openRef = React23__namespace.default.useRef(open);
8380
+ const openRef = React24__namespace.default.useRef(open);
8269
8381
  openRef.current = open;
8270
- const controlledRef = React23__namespace.default.useRef(controlled);
8382
+ const controlledRef = React24__namespace.default.useRef(controlled);
8271
8383
  controlledRef.current = controlled;
8272
- const onOpenChangeRef = React23__namespace.default.useRef(onOpenChange);
8384
+ const onOpenChangeRef = React24__namespace.default.useRef(onOpenChange);
8273
8385
  onOpenChangeRef.current = onOpenChange;
8274
- const setOpen = React23__namespace.default.useCallback((next) => {
8386
+ const setOpen = React24__namespace.default.useCallback((next) => {
8275
8387
  const value = typeof next === "function" ? next(openRef.current) : next;
8276
8388
  if (value === openRef.current) return;
8277
8389
  if (!controlledRef.current) setOpenState(value);
@@ -8279,7 +8391,7 @@ function Popover({
8279
8391
  }, []);
8280
8392
  const toggle = () => setOpen((o) => !o);
8281
8393
  const RD = { createPortal: typeof reactDom.createPortal === "function" ? reactDom.createPortal : typeof window !== "undefined" && window.ReactDOM && window.ReactDOM.createPortal };
8282
- const place = React23__namespace.default.useCallback(() => {
8394
+ const place = React24__namespace.default.useCallback(() => {
8283
8395
  const t = wrapRef.current;
8284
8396
  if (!t) return;
8285
8397
  const r = t.getBoundingClientRect();
@@ -8310,7 +8422,7 @@ function Popover({
8310
8422
  arrow = { top: Math.min(Math.max(cy - top - 5.5, 8), ph - 18), [onRight ? "left" : "right"]: -6 };
8311
8423
  setPos({ top, left, width: w, flip: false, arrow });
8312
8424
  }, [placement, align, width]);
8313
- React23__namespace.default.useEffect(() => {
8425
+ React24__namespace.default.useEffect(() => {
8314
8426
  if (!open) return;
8315
8427
  place();
8316
8428
  const onMove = () => place();
@@ -8333,7 +8445,7 @@ function Popover({
8333
8445
  document.removeEventListener("keydown", onKey);
8334
8446
  };
8335
8447
  }, [open, place]);
8336
- React23__namespace.default.useEffect(() => {
8448
+ React24__namespace.default.useEffect(() => {
8337
8449
  if (open) {
8338
8450
  setRender(true);
8339
8451
  return;
@@ -8341,12 +8453,12 @@ function Popover({
8341
8453
  const t = setTimeout(() => setRender(false), 170);
8342
8454
  return () => clearTimeout(t);
8343
8455
  }, [open]);
8344
- React23__namespace.default.useEffect(() => {
8456
+ React24__namespace.default.useEffect(() => {
8345
8457
  if (render && open) place();
8346
8458
  }, [render, place]);
8347
- const restoreRef = React23__namespace.default.useRef(null);
8348
- const needFocusRef = React23__namespace.default.useRef(false);
8349
- React23__namespace.default.useEffect(() => {
8459
+ const restoreRef = React24__namespace.default.useRef(null);
8460
+ const needFocusRef = React24__namespace.default.useRef(false);
8461
+ React24__namespace.default.useEffect(() => {
8350
8462
  if (open) {
8351
8463
  restoreRef.current = document.activeElement;
8352
8464
  needFocusRef.current = true;
@@ -8357,7 +8469,7 @@ function Popover({
8357
8469
  needFocusRef.current = false;
8358
8470
  if (prev && typeof prev.focus === "function" && popRef.current?.contains(document.activeElement)) prev.focus();
8359
8471
  }, [open]);
8360
- React23__namespace.default.useEffect(() => {
8472
+ React24__namespace.default.useEffect(() => {
8361
8473
  if (open && render && pos && needFocusRef.current) {
8362
8474
  needFocusRef.current = false;
8363
8475
  popRef.current?.focus({ preventScroll: true });
@@ -8385,7 +8497,7 @@ function Popover({
8385
8497
  ]
8386
8498
  }
8387
8499
  ) : null;
8388
- const triggerEl = React23__namespace.default.isValidElement(trigger) ? React23__namespace.default.cloneElement(trigger, {
8500
+ const triggerEl = React24__namespace.default.isValidElement(trigger) ? React24__namespace.default.cloneElement(trigger, {
8389
8501
  onClick: (e) => {
8390
8502
  trigger.props.onClick?.(e);
8391
8503
  toggle();
@@ -8424,9 +8536,12 @@ function Progress({
8424
8536
  size = "md",
8425
8537
  indeterminate = false,
8426
8538
  showLabel = false,
8539
+ label,
8427
8540
  className = "",
8428
8541
  ...rest
8429
8542
  }) {
8543
+ const labelId = React24__namespace.default.useId();
8544
+ const { "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...restProps } = rest;
8430
8545
  const __twcStyles = useScopedStyles("twc-progress-styles", `
8431
8546
  .twc-progress-wrap { display: flex; flex-direction: column; gap: 6px; font-family: var(--font-sans); }
8432
8547
  .twc-progress {
@@ -8465,14 +8580,14 @@ function Progress({
8465
8580
  return (
8466
8581
  // Single-root contract: className and ...rest (style, id, handlers, …) share the outer
8467
8582
  // wrapper; role="progressbar" + aria-value* stay on the inner track.
8468
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-progress-wrap ${className}`, ...rest, children: [
8583
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-progress-wrap ${className}`, ...restProps, children: [
8469
8584
  __twcStyles,
8470
- showLabel && !indeterminate ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-progress__meta", children: [
8471
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Progress" }),
8472
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
8585
+ (showLabel || label != null) && !indeterminate ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-progress__meta", children: [
8586
+ /* @__PURE__ */ jsxRuntime.jsx("span", { id: labelId, children: label ?? "Progress" }),
8587
+ showLabel ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
8473
8588
  Math.round(pct),
8474
8589
  "%"
8475
- ] })
8590
+ ] }) : null
8476
8591
  ] }) : null,
8477
8592
  /* @__PURE__ */ jsxRuntime.jsx(
8478
8593
  "div",
@@ -8485,6 +8600,8 @@ function Progress({
8485
8600
  "aria-valuenow": indeterminate ? void 0 : Math.round(pct),
8486
8601
  "aria-valuemin": 0,
8487
8602
  "aria-valuemax": 100,
8603
+ "aria-label": ariaLabel,
8604
+ "aria-labelledby": ariaLabelledby ?? (label != null ? labelId : void 0),
8488
8605
  children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-progress__bar", style: indeterminate ? void 0 : { width: `${pct}%` } })
8489
8606
  }
8490
8607
  )
@@ -8546,7 +8663,7 @@ function Radio({
8546
8663
  .twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
8547
8664
  .twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
8548
8665
  `);
8549
- const autoId = React23__namespace.default.useId();
8666
+ const autoId = React24__namespace.default.useId();
8550
8667
  const fieldId = id || autoId;
8551
8668
  const errId = `${fieldId}-error`;
8552
8669
  const invalid = Boolean(error);
@@ -8624,12 +8741,12 @@ function Rating({
8624
8741
  ...rest
8625
8742
  }) {
8626
8743
  const __twcStyles = useScopedStyles("twc-rating-styles", RATING_CSS);
8627
- const [internal, setInternal] = React23__namespace.default.useState(defaultValue);
8628
- const [hover, setHover] = React23__namespace.default.useState(0);
8744
+ const [internal, setInternal] = React24__namespace.default.useState(defaultValue);
8745
+ const [hover, setHover] = React24__namespace.default.useState(0);
8629
8746
  const val = value !== void 0 ? value : internal;
8630
8747
  const shown = hover || val;
8631
8748
  const interactive = !readOnly && !disabled;
8632
- const btnRefs = React23__namespace.default.useRef([]);
8749
+ const btnRefs = React24__namespace.default.useRef([]);
8633
8750
  const tabStar = Math.min(count, Math.max(1, Math.round(val) || 1));
8634
8751
  const set = (v) => {
8635
8752
  if (!interactive) return;
@@ -8723,12 +8840,12 @@ function Tooltip({
8723
8840
  ...rest
8724
8841
  }) {
8725
8842
  const __twcStyles = useScopedStyles("twc-tooltip-styles", TOOLTIP_CSS);
8726
- const id = React23__namespace.default.useId();
8727
- const [show, setShow] = React23__namespace.default.useState(false);
8728
- const [coords, setCoords] = React23__namespace.default.useState(null);
8729
- const timer = React23__namespace.default.useRef(null);
8730
- const wrapRef = React23__namespace.default.useRef(null);
8731
- const tipRef = React23__namespace.default.useRef(null);
8843
+ const id = React24__namespace.default.useId();
8844
+ const [show, setShow] = React24__namespace.default.useState(false);
8845
+ const [coords, setCoords] = React24__namespace.default.useState(null);
8846
+ const timer = React24__namespace.default.useRef(null);
8847
+ const wrapRef = React24__namespace.default.useRef(null);
8848
+ const tipRef = React24__namespace.default.useRef(null);
8732
8849
  const open = () => {
8733
8850
  clearTimeout(timer.current);
8734
8851
  timer.current = setTimeout(() => setShow(true), delay);
@@ -8737,8 +8854,8 @@ function Tooltip({
8737
8854
  clearTimeout(timer.current);
8738
8855
  setShow(false);
8739
8856
  };
8740
- React23__namespace.default.useEffect(() => () => clearTimeout(timer.current), []);
8741
- const place = React23__namespace.default.useCallback(() => {
8857
+ React24__namespace.default.useEffect(() => () => clearTimeout(timer.current), []);
8858
+ const place = React24__namespace.default.useCallback(() => {
8742
8859
  const el = wrapRef.current;
8743
8860
  if (!el) return;
8744
8861
  const r = el.getBoundingClientRect();
@@ -8754,10 +8871,10 @@ function Tooltip({
8754
8871
  else if (placement === "right") setCoords({ ...base, top: clampY(cy), left: Math.round(r.right + gap) });
8755
8872
  else setCoords({ ...base, left: clampX(cx), bottom: Math.round(vh - r.top + gap) });
8756
8873
  }, [placement]);
8757
- React23__namespace.default.useEffect(() => {
8874
+ React24__namespace.default.useEffect(() => {
8758
8875
  place();
8759
8876
  }, [place]);
8760
- React23__namespace.default.useEffect(() => {
8877
+ React24__namespace.default.useEffect(() => {
8761
8878
  if (!show) return void 0;
8762
8879
  place();
8763
8880
  const onMove = () => place();
@@ -8768,7 +8885,7 @@ function Tooltip({
8768
8885
  window.removeEventListener("resize", onMove);
8769
8886
  };
8770
8887
  }, [show, place]);
8771
- React23__namespace.default.useEffect(() => {
8888
+ React24__namespace.default.useEffect(() => {
8772
8889
  if (!show) return;
8773
8890
  const onKeyDown = (e) => {
8774
8891
  if (e.key === "Escape") {
@@ -8780,7 +8897,7 @@ function Tooltip({
8780
8897
  return () => document.removeEventListener("keydown", onKeyDown);
8781
8898
  }, [show]);
8782
8899
  const describedBy = show ? id : void 0;
8783
- const trigger = React23__namespace.default.isValidElement(children) && children.type !== React23__namespace.default.Fragment ? React23__namespace.default.cloneElement(children, {
8900
+ const trigger = React24__namespace.default.isValidElement(children) && children.type !== React24__namespace.default.Fragment ? React24__namespace.default.cloneElement(children, {
8784
8901
  "aria-describedby": [children.props["aria-describedby"], describedBy].filter(Boolean).join(" ") || void 0
8785
8902
  }) : /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-describedby": describedBy, children });
8786
8903
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -8836,6 +8953,7 @@ var SIDEBAR_CSS = `
8836
8953
  .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;
8837
8954
  transition: font-size var(--duration-base) var(--ease-standard), gap var(--duration-base) var(--ease-standard); }
8838
8955
  .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; }
8956
+ .twc-sidebar__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
8839
8957
  .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;
8840
8958
  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; }
8841
8959
  .twc-sidebar[data-collapsed="true"] .twc-sidebar__section { max-height: 0; padding-top: 0; padding-bottom: 0; opacity: 0; visibility: hidden;
@@ -8877,6 +8995,23 @@ var SIDEBAR_CSS = `
8877
8995
  .twc-sidebar[data-collapsed="true"] .twc-sidebar__foot { display: flex; flex-direction: column; align-items: center; padding: var(--space-2) 0; }
8878
8996
  .twc-sidebar[data-collapsed="true"] .twc-sidebar__collapse { width: auto; padding: 11px; gap: 0; margin: 0; }
8879
8997
  .twc-sidebar[data-collapsed="true"] .twc-sidebar__collapse span { display: none; }
8998
+
8999
+ /* Off-canvas overlay mode (mobile): the rail becomes a slide-over drawer behind a
9000
+ scrim, mirroring Drawer.jsx. Logical inset + a --_off var slide it in from the
9001
+ inline-start edge (mirrored under dir="rtl"). */
9002
+ .twc-sidebar__overlay { position: fixed; inset: 0; z-index: var(--z-modal); background: var(--color-overlay); backdrop-filter: blur(2px); }
9003
+ .twc-sidebar__overlay[data-state="open"] { animation: twico-fade-in var(--duration-base) var(--ease-out); }
9004
+ .twc-sidebar__overlay[data-state="closed"] { animation: twc-sidebar-fade-out var(--duration-exit) var(--ease-in) forwards; pointer-events: none; }
9005
+ @keyframes twc-sidebar-fade-out { from { opacity: 1; } to { opacity: 0; } }
9006
+ .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%; }
9007
+ [dir="rtl"] .twc-sidebar--overlay { inset-inline-start: auto; inset-inline-end: 0; --_off: 100%; }
9008
+ .twc-sidebar--overlay[data-state="open"] { animation: twc-sidebar-in var(--duration-base) var(--ease-out); }
9009
+ .twc-sidebar--overlay[data-state="closed"] { animation: twc-sidebar-out var(--duration-exit) var(--ease-in) forwards; }
9010
+ @keyframes twc-sidebar-in { from { transform: translateX(var(--_off)); } to { transform: translateX(0); } }
9011
+ @keyframes twc-sidebar-out { from { transform: translateX(0); } to { transform: translateX(var(--_off)); } }
9012
+ @media (prefers-reduced-motion: reduce) {
9013
+ .twc-sidebar__overlay[data-state], .twc-sidebar--overlay[data-state] { animation-duration: 1ms; }
9014
+ }
8880
9015
  `;
8881
9016
  function Sidebar({
8882
9017
  brand,
@@ -8886,63 +9021,149 @@ function Sidebar({
8886
9021
  defaultCollapsed = false,
8887
9022
  collapsible = true,
8888
9023
  onCollapsedChange,
9024
+ overlay = false,
9025
+ open: openProp,
9026
+ defaultOpen = false,
9027
+ onOpenChange,
9028
+ navLabel = "Main",
8889
9029
  className = "",
8890
9030
  ...rest
8891
9031
  }) {
8892
9032
  const __twcStyles = useScopedStyles("twc-sidebar-styles", SIDEBAR_CSS);
8893
- const [internal, setInternal] = React23__namespace.default.useState(defaultCollapsed);
9033
+ const navId = React24__namespace.default.useId();
9034
+ const panelRef = React24__namespace.default.useRef(null);
9035
+ const renderPortal = usePortal();
9036
+ const [internal, setInternal] = React24__namespace.default.useState(defaultCollapsed);
8894
9037
  const collapsed = collapsedProp !== void 0 ? collapsedProp : internal;
8895
9038
  const toggle = () => {
8896
9039
  const next = !collapsed;
8897
9040
  if (collapsedProp === void 0) setInternal(next);
8898
9041
  onCollapsedChange?.(next);
8899
9042
  };
8900
- const safeHref11 = (url) => {
9043
+ const [openInternal, setOpenInternal] = React24__namespace.default.useState(defaultOpen);
9044
+ const open = openProp !== void 0 ? openProp : openInternal;
9045
+ const setOpen = (next) => {
9046
+ if (openProp === void 0) setOpenInternal(next);
9047
+ onOpenChange?.(next);
9048
+ };
9049
+ const [mounted, setMounted] = React24__namespace.default.useState(open);
9050
+ React24__namespace.default.useEffect(() => {
9051
+ if (!overlay) return void 0;
9052
+ if (open) {
9053
+ setMounted(true);
9054
+ return void 0;
9055
+ }
9056
+ const t = setTimeout(() => setMounted(false), 170);
9057
+ return () => clearTimeout(t);
9058
+ }, [overlay, open]);
9059
+ React24__namespace.default.useEffect(() => {
9060
+ if (!overlay || !open) return void 0;
9061
+ const prev = document.body.style.overflow;
9062
+ document.body.style.overflow = "hidden";
9063
+ return () => {
9064
+ document.body.style.overflow = prev;
9065
+ };
9066
+ }, [overlay, open]);
9067
+ useFocusTrap(panelRef, overlay && open && mounted);
9068
+ React24__namespace.default.useEffect(() => {
9069
+ if (!overlay || !open) return void 0;
9070
+ const onKey = (e) => {
9071
+ if (e.key === "Escape") {
9072
+ e.preventDefault();
9073
+ if (openProp === void 0) setOpenInternal(false);
9074
+ onOpenChange?.(false);
9075
+ }
9076
+ };
9077
+ document.addEventListener("keydown", onKey);
9078
+ return () => document.removeEventListener("keydown", onKey);
9079
+ }, [overlay, open, openProp, onOpenChange]);
9080
+ const safeHref12 = (url) => {
8901
9081
  if (url == null) return void 0;
8902
9082
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
8903
9083
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
8904
9084
  };
8905
- return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: `twc-sidebar ${className}`, "data-collapsed": collapsed || void 0, ...rest, children: [
9085
+ const renderItem = (it, i) => {
9086
+ const href = safeHref12(it.href);
9087
+ const labelStr = typeof it.label === "string" ? it.label : void 0;
9088
+ const inner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9089
+ it.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-sidebar__ic", "aria-hidden": "true", children: it.icon }) : labelStr != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-sidebar__ic twc-sidebar__ic--initial", "aria-hidden": "true", children: labelStr.charAt(0) }) : null,
9090
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-sidebar__label", children: it.label }),
9091
+ it.badge != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-sidebar__badge", children: it.badge }) : null
9092
+ ] });
9093
+ const common = {
9094
+ className: "twc-sidebar__item",
9095
+ "data-active": it.active || void 0,
9096
+ "aria-current": it.active ? "page" : void 0,
9097
+ onClick: it.onClick,
9098
+ "aria-label": collapsed && labelStr != null ? labelStr : void 0
9099
+ };
9100
+ const node = href != null ? /* @__PURE__ */ jsxRuntime.jsx("a", { href, ...common, children: inner }) : /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", ...common, children: inner });
9101
+ return collapsed && labelStr != null ? /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { label: labelStr, placement: "right", style: { display: "block" }, children: node }) : node;
9102
+ };
9103
+ const groups = [];
9104
+ let group = { sid: null, section: null, entries: [] };
9105
+ let secN = 0;
9106
+ for (let i = 0; i < items.length; i++) {
9107
+ const it = items[i];
9108
+ if (it.section) {
9109
+ if (group.entries.length || group.section != null) groups.push(group);
9110
+ secN += 1;
9111
+ group = { sid: `${navId}-sec-${secN}`, section: it.section, entries: [] };
9112
+ } else {
9113
+ group.entries.push({ it, i });
9114
+ }
9115
+ }
9116
+ if (group.entries.length || group.section != null) groups.push(group);
9117
+ const body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8906
9118
  __twcStyles,
8907
9119
  brand ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-sidebar__head", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-sidebar__brand", children: brand }) }) : null,
8908
- /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "twc-sidebar__nav", children: items.map(
8909
- (it, i) => it.section ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-sidebar__section", children: it.section }, i) : (() => {
8910
- const href = safeHref11(it.href);
8911
- const labelStr = typeof it.label === "string" ? it.label : void 0;
8912
- const inner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8913
- it.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-sidebar__ic", "aria-hidden": "true", children: it.icon }) : labelStr != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-sidebar__ic twc-sidebar__ic--initial", "aria-hidden": "true", children: labelStr.charAt(0) }) : null,
8914
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-sidebar__label", children: it.label }),
8915
- it.badge != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-sidebar__badge", children: it.badge }) : null
8916
- ] });
8917
- const common = {
8918
- className: "twc-sidebar__item",
8919
- "data-active": it.active || void 0,
8920
- "aria-current": it.active ? "page" : void 0,
8921
- onClick: it.onClick,
8922
- "aria-label": collapsed && labelStr != null ? labelStr : void 0
8923
- };
8924
- const node = href != null ? /* @__PURE__ */ jsxRuntime.jsx("a", { href, ...common, children: inner }, i) : /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", ...common, children: inner }, i);
8925
- return collapsed && labelStr != null ? /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { label: labelStr, placement: "right", style: { display: "block" }, children: node }, i) : node;
8926
- })()
8927
- ) }),
9120
+ /* @__PURE__ */ jsxRuntime.jsx("nav", { id: navId, className: "twc-sidebar__nav", "aria-label": navLabel, children: groups.map((g, gi) => /* @__PURE__ */ jsxRuntime.jsxs(React24__namespace.default.Fragment, { children: [
9121
+ g.section != null ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-sidebar__section", id: g.sid, children: g.section }) : null,
9122
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "twc-sidebar__list", ...g.section != null ? { "aria-labelledby": g.sid } : {}, children: g.entries.map(({ it, i }) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: renderItem(it) }, i)) })
9123
+ ] }, gi)) }),
8928
9124
  footer || collapsible ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-sidebar__foot", children: [
8929
9125
  footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-sidebar__foot-user", children: footer }) : null,
8930
- collapsible ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "twc-sidebar__collapse", onClick: toggle, "aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar", children: [
9126
+ collapsible ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "twc-sidebar__collapse", onClick: toggle, "aria-expanded": !collapsed, "aria-controls": navId, "aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar", children: [
8931
9127
  /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) }),
8932
9128
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Collapse" })
8933
9129
  ] }) : null
8934
9130
  ] }) : null
8935
9131
  ] });
9132
+ if (!overlay) {
9133
+ return /* @__PURE__ */ jsxRuntime.jsx("aside", { className: `twc-sidebar ${className}`, "data-collapsed": collapsed || void 0, ...rest, children: body });
9134
+ }
9135
+ if (!mounted) return null;
9136
+ const state = open ? "open" : "closed";
9137
+ const drawer = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-sidebar__overlay", "data-state": state, onMouseDown: (e) => {
9138
+ if (e.target === e.currentTarget) setOpen(false);
9139
+ }, children: /* @__PURE__ */ jsxRuntime.jsx(
9140
+ "aside",
9141
+ {
9142
+ ref: panelRef,
9143
+ className: `twc-sidebar twc-sidebar--overlay ${className}`,
9144
+ "data-state": state,
9145
+ "data-collapsed": collapsed || void 0,
9146
+ role: "dialog",
9147
+ "aria-modal": "true",
9148
+ tabIndex: -1,
9149
+ "aria-label": navLabel || "Navigation",
9150
+ ...rest,
9151
+ children: body
9152
+ }
9153
+ ) });
9154
+ return renderPortal(drawer);
8936
9155
  }
8937
9156
  function Skeleton({
8938
9157
  variant = "text",
8939
9158
  width,
8940
9159
  height,
8941
9160
  lines = 1,
9161
+ label,
8942
9162
  className = "",
8943
9163
  style,
8944
9164
  ...rest
8945
9165
  }) {
9166
+ const a11y = label != null ? { role: "status", "aria-live": "polite", "aria-busy": true } : { "aria-hidden": true };
8946
9167
  const __twcStyles = useScopedStyles("twc-skeleton-styles", `
8947
9168
  .twc-skeleton {
8948
9169
  position: relative; overflow: hidden;
@@ -8958,25 +9179,31 @@ function Skeleton({
8958
9179
  .twc-skeleton[data-variant="rect"] { border-radius: var(--radius-md); }
8959
9180
  .twc-skeleton__group { display: flex; flex-direction: column; gap: 8px; }
8960
9181
  .twc-skeleton__group .twc-skeleton:last-child { width: 70%; }
9182
+ .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; }
8961
9183
  /* The shimmer signals loading \u2014 keep it animating even under reduced motion. */
8962
9184
  @media (prefers-reduced-motion: reduce) {
8963
9185
  .twc-skeleton::after { animation-duration: 1.4s !important; animation-iteration-count: infinite !important; }
8964
9186
  }
8965
9187
  `);
8966
9188
  if (variant === "text" && lines > 1) {
8967
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-skeleton__group ${className}`, style: { height, ...style }, ...rest, children: [
9189
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-skeleton__group ${className}`, style: { height, ...style }, ...a11y, ...rest, children: [
8968
9190
  __twcStyles,
9191
+ label != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-skeleton__sr", children: label }) : null,
8969
9192
  Array.from({ length: lines }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-skeleton", "data-variant": "text", style: { width: width || "100%" } }, i))
8970
9193
  ] });
8971
9194
  }
8972
- return /* @__PURE__ */ jsxRuntime.jsx(
9195
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8973
9196
  "span",
8974
9197
  {
8975
9198
  className: `twc-skeleton ${className}`,
8976
9199
  "data-variant": variant,
8977
9200
  style: { width, height, ...style },
9201
+ ...a11y,
8978
9202
  ...rest,
8979
- children: __twcStyles
9203
+ children: [
9204
+ __twcStyles,
9205
+ label != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-skeleton__sr", children: label }) : null
9206
+ ]
8980
9207
  }
8981
9208
  );
8982
9209
  }
@@ -9043,12 +9270,12 @@ function Slider({
9043
9270
  const max = Number.isFinite(maxProp) && maxProp > min ? maxProp : min + 1;
9044
9271
  const step = Number.isFinite(stepProp) && stepProp > 0 ? stepProp : 1;
9045
9272
  const __twcStyles = useScopedStyles("twc-slider-styles", SLIDER_CSS);
9046
- const autoId = React23__namespace.default.useId();
9273
+ const autoId = React24__namespace.default.useId();
9047
9274
  const fieldId = id || autoId;
9048
- const [internal, setInternal] = React23__namespace.default.useState(defaultValue);
9275
+ const [internal, setInternal] = React24__namespace.default.useState(defaultValue);
9049
9276
  const val = value !== void 0 ? value : internal;
9050
- const trackRef = React23__namespace.default.useRef(null);
9051
- const [dragging, setDragging] = React23__namespace.default.useState(false);
9277
+ const trackRef = React24__namespace.default.useRef(null);
9278
+ const [dragging, setDragging] = React24__namespace.default.useState(false);
9052
9279
  const pct = (val - min) / (max - min) * 100;
9053
9280
  const fmt = (v) => formatValue ? formatValue(v) : v;
9054
9281
  const clampSnap = (raw) => {
@@ -9066,8 +9293,8 @@ function Slider({
9066
9293
  const ratio = Math.min(1, Math.max(0, (clientX - r.left) / r.width));
9067
9294
  return clampSnap(min + ratio * (max - min));
9068
9295
  };
9069
- const dragCleanupRef = React23__namespace.default.useRef(null);
9070
- React23__namespace.default.useEffect(() => () => dragCleanupRef.current?.(), []);
9296
+ const dragCleanupRef = React24__namespace.default.useRef(null);
9297
+ React24__namespace.default.useEffect(() => () => dragCleanupRef.current?.(), []);
9071
9298
  function onPointerDown(e) {
9072
9299
  if (disabled) return;
9073
9300
  e.preventDefault();
@@ -9089,7 +9316,7 @@ function Slider({
9089
9316
  }
9090
9317
  function onKeyDown(e) {
9091
9318
  if (disabled) return;
9092
- let next = val;
9319
+ let next;
9093
9320
  if (e.key === "ArrowRight" || e.key === "ArrowUp") next = clampSnap(val + step);
9094
9321
  else if (e.key === "ArrowLeft" || e.key === "ArrowDown") next = clampSnap(val - step);
9095
9322
  else if (e.key === "Home") next = min;
@@ -9142,12 +9369,15 @@ function Slider({
9142
9369
  function Spinner({
9143
9370
  size = "md",
9144
9371
  color,
9145
- tone = "current",
9372
+ tone,
9146
9373
  label = "Loading",
9147
9374
  className = "",
9148
9375
  ...rest
9149
9376
  }) {
9150
- const resolvedColor = color ?? tone;
9377
+ if (process.env.NODE_ENV !== "production" && tone !== void 0 && color === void 0) {
9378
+ warnOnce("Spinner.tone", "Spinner: `tone` is deprecated and will be removed in 2.0 \u2014 use `color`.");
9379
+ }
9380
+ const resolvedColor = color ?? tone ?? "current";
9151
9381
  const __twcStyles = useScopedStyles("twc-spinner-styles", `
9152
9382
  .twc-spinner {
9153
9383
  --_sz: 24px; --_bw: 2.5px;
@@ -9263,6 +9493,7 @@ var STEPPER_CSS = `
9263
9493
  .twc-stepper[data-orientation="vertical"] .twc-step__col { display: flex; flex-direction: column; align-items: center; }
9264
9494
  .twc-step[data-state="complete"] .twc-step__connector, .twc-step[data-state="active"] .twc-step__connector { background: var(--_accent); }
9265
9495
  .twc-stepper[data-orientation="vertical"] .twc-step__vbody { padding-bottom: var(--space-2); }
9496
+ .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; }
9266
9497
  `;
9267
9498
  var CheckIcon = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6 9 17l-5-5" }) });
9268
9499
  var BangIcon = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 8v5M12 17h.01" }) });
@@ -9278,7 +9509,7 @@ function Stepper({
9278
9509
  ...rest
9279
9510
  }) {
9280
9511
  const __twcStyles = useScopedStyles("twc-stepper-styles", STEPPER_CSS);
9281
- const [activeInternal, setActiveInternal] = React23__namespace.default.useState(defaultActive);
9512
+ const [activeInternal, setActiveInternal] = React24__namespace.default.useState(defaultActive);
9282
9513
  const active = activeProp !== void 0 ? activeProp : activeInternal;
9283
9514
  const handleStep = (i) => {
9284
9515
  if (activeProp === void 0) setActiveInternal(i);
@@ -9290,11 +9521,12 @@ function Stepper({
9290
9521
  if (i === active) return "active";
9291
9522
  return "upcoming";
9292
9523
  };
9293
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-stepper ${className}`, "data-orientation": orientation, "data-tone": tone, ...rest, children: [
9524
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-stepper ${className}`, "data-orientation": orientation, "data-tone": tone, role: "group", "aria-label": "Progress", ...rest, children: [
9294
9525
  __twcStyles,
9295
9526
  steps.map((step, i) => {
9296
9527
  const state = stateOf(i, step);
9297
9528
  const last = i === steps.length - 1;
9529
+ const srText = `Step ${i + 1} of ${steps.length}${state === "complete" ? ", completed" : state === "error" ? ", error" : state === "active" ? ", current" : ", upcoming"}. `;
9298
9530
  const isClickable = clickable && i <= active;
9299
9531
  const interactive = isClickable ? {
9300
9532
  role: "button",
@@ -9316,8 +9548,10 @@ function Stepper({
9316
9548
  "data-state": state,
9317
9549
  "data-clickable": isClickable || void 0,
9318
9550
  "aria-current": state === "active" ? "step" : void 0,
9551
+ "aria-invalid": state === "error" ? "true" : void 0,
9319
9552
  ...interactive,
9320
9553
  children: [
9554
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-step__sr", children: srText }),
9321
9555
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-step__col", children: [
9322
9556
  indicator,
9323
9557
  !last ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-step__connector" }) : null
@@ -9338,8 +9572,10 @@ function Stepper({
9338
9572
  "data-state": state,
9339
9573
  "data-clickable": isClickable || void 0,
9340
9574
  "aria-current": state === "active" ? "step" : void 0,
9575
+ "aria-invalid": state === "error" ? "true" : void 0,
9341
9576
  ...interactive,
9342
9577
  children: [
9578
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-step__sr", children: srText }),
9343
9579
  indicator,
9344
9580
  !last ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-step__connector" }) : null,
9345
9581
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-step__body", children: [
@@ -9405,7 +9641,7 @@ function Switch({
9405
9641
  .twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
9406
9642
  .twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
9407
9643
  `);
9408
- const autoId = React23__namespace.default.useId();
9644
+ const autoId = React24__namespace.default.useId();
9409
9645
  const fieldId = id || autoId;
9410
9646
  const errId = `${fieldId}-error`;
9411
9647
  const invalid = Boolean(error);
@@ -9489,14 +9725,14 @@ function Table({
9489
9725
  ...rest
9490
9726
  }) {
9491
9727
  const __twcStyles = useScopedStyles("twc-table-styles", TABLE_CSS);
9492
- const cols = React23__namespace.default.useMemo(
9728
+ const cols = React24__namespace.default.useMemo(
9493
9729
  () => (columns || []).map((c) => ({ ...c, header: c.headerName, render: c.renderCell })),
9494
9730
  [columns]
9495
9731
  );
9496
9732
  const dataRows = rowsProp || [];
9497
- const [internalSort, setInternalSort] = React23__namespace.default.useState(defaultSort || { field: null, dir: "asc" });
9733
+ const [internalSort, setInternalSort] = React24__namespace.default.useState(defaultSort || { field: null, dir: "asc" });
9498
9734
  const sort = (sortProp !== void 0 ? sortProp : internalSort) || { field: null, dir: "asc" };
9499
- const rows = React23__namespace.default.useMemo(() => {
9735
+ const rows = React24__namespace.default.useMemo(() => {
9500
9736
  if (!sortable || !sort.field) return dataRows;
9501
9737
  const col = cols.find((c) => c.field === sort.field);
9502
9738
  if (!col) return dataRows;
@@ -9588,6 +9824,13 @@ var TABS_CSS = `
9588
9824
  .twc-tabs[data-variant="pill"] .twc-tabs__indicator {
9589
9825
  top: 4px; bottom: 4px; height: auto; background: var(--color-surface); box-shadow: var(--shadow-sm); border-radius: var(--radius-md);
9590
9826
  }
9827
+ .twc-tab[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
9828
+ /* Horizontal tablist scrolls when tabs overflow (vertical orientation untouched). Making
9829
+ overflow-x non-visible makes overflow-y compute to auto, which would clip the bottom:-1px
9830
+ indicator \u2014 so pin the horizontal indicator to bottom:0 (the list border-bottom is the baseline). */
9831
+ .twc-tabs:not([data-orientation="vertical"]) .twc-tabs__list { overflow-x: auto; scrollbar-width: none; }
9832
+ .twc-tabs:not([data-orientation="vertical"]) .twc-tabs__list::-webkit-scrollbar { display: none; }
9833
+ .twc-tabs:not([data-orientation="vertical"]) .twc-tabs__indicator { bottom: 0; }
9591
9834
  .twc-tabs__panel { padding-top: var(--space-4); }
9592
9835
 
9593
9836
  /* Vertical orientation */
@@ -9622,24 +9865,27 @@ function Tabs({
9622
9865
  }) {
9623
9866
  const vertical = orientation === "vertical";
9624
9867
  const __twcStyles = useScopedStyles("twc-tabs-styles", TABS_CSS);
9625
- const [internal, setInternal] = React23__namespace.default.useState(defaultValue ?? items[0]?.value);
9868
+ const [internal, setInternal] = React24__namespace.default.useState(defaultValue ?? items[0]?.value);
9626
9869
  const active = value ?? internal;
9627
- const listRef = React23__namespace.default.useRef(null);
9628
- const [ind, setInd] = React23__namespace.default.useState({ left: 0, width: 0, top: 0, height: 0 });
9629
- const baseId = React23__namespace.default.useId();
9870
+ const listRef = React24__namespace.default.useRef(null);
9871
+ const [ind, setInd] = React24__namespace.default.useState({ left: 0, width: 0, top: 0, height: 0 });
9872
+ const baseId = React24__namespace.default.useId();
9630
9873
  const tabIdAt = (i) => `${baseId}-tab-${i}`;
9631
9874
  const panelId = `${baseId}-panel`;
9632
9875
  const activeIndex = items.findIndex((it) => it.value === active);
9633
- const updateIndicator = React23__namespace.default.useCallback(() => {
9876
+ const updateIndicator = React24__namespace.default.useCallback(() => {
9634
9877
  const list = listRef.current;
9635
9878
  if (!list) return;
9636
9879
  const el = list.querySelector('[data-active="true"]');
9637
- if (el) setInd({ left: el.offsetLeft, width: el.offsetWidth, top: el.offsetTop, height: el.offsetHeight });
9638
- }, []);
9639
- React23__namespace.default.useEffect(() => {
9880
+ if (el) {
9881
+ setInd({ left: el.offsetLeft, width: el.offsetWidth, top: el.offsetTop, height: el.offsetHeight });
9882
+ if (!vertical) el.scrollIntoView?.({ inline: "nearest", block: "nearest" });
9883
+ }
9884
+ }, [vertical]);
9885
+ React24__namespace.default.useEffect(() => {
9640
9886
  updateIndicator();
9641
9887
  }, [active, updateIndicator, items, orientation]);
9642
- React23__namespace.default.useEffect(() => {
9888
+ React24__namespace.default.useEffect(() => {
9643
9889
  const r = () => updateIndicator();
9644
9890
  window.addEventListener("resize", r);
9645
9891
  if (typeof document !== "undefined" && document.fonts && document.fonts.ready) {
@@ -9660,20 +9906,32 @@ function Tabs({
9660
9906
  const keys = [prevKey, nextKey, "Home", "End"];
9661
9907
  if (!keys.includes(e.key)) return;
9662
9908
  const n = items.length;
9663
- if (!n) return;
9909
+ if (!n || items.every((it2) => it2.disabled)) return;
9664
9910
  e.preventDefault();
9665
9911
  let i = activeIndex < 0 ? 0 : activeIndex;
9666
- if (e.key === "Home") i = 0;
9667
- else if (e.key === "End") i = n - 1;
9668
- else {
9912
+ if (e.key === "Home") i = items.findIndex((it2) => !it2.disabled);
9913
+ else if (e.key === "End") {
9914
+ for (let k = n - 1; k >= 0; k--) {
9915
+ if (!items[k].disabled) {
9916
+ i = k;
9917
+ break;
9918
+ }
9919
+ }
9920
+ } else {
9669
9921
  const dir = e.key === nextKey ? 1 : -1;
9670
- i = (i + dir + n) % n;
9922
+ let guard = 0;
9923
+ do {
9924
+ i = (i + dir + n) % n;
9925
+ } while (items[i]?.disabled && ++guard <= n);
9671
9926
  }
9672
9927
  const it = items[i];
9673
- if (!it) return;
9928
+ if (!it || it.disabled) return;
9674
9929
  select(it.value);
9675
9930
  const btns = listRef.current?.querySelectorAll('[role="tab"]');
9676
- if (btns && btns[i]) btns[i].focus();
9931
+ if (btns && btns[i]) {
9932
+ btns[i].focus();
9933
+ btns[i].scrollIntoView?.({ inline: "nearest", block: "nearest" });
9934
+ }
9677
9935
  }
9678
9936
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-tabs ${className}`, "data-variant": variant, "data-tone": tone, "data-orientation": orientation, ...rest, children: [
9679
9937
  __twcStyles,
@@ -9686,10 +9944,14 @@ function Tabs({
9686
9944
  className: "twc-tab",
9687
9945
  role: "tab",
9688
9946
  "aria-selected": it.value === active,
9947
+ "aria-disabled": it.disabled || void 0,
9948
+ disabled: it.disabled || void 0,
9689
9949
  "aria-controls": it.value === active && panelRendered ? panelId : void 0,
9690
- tabIndex: it.value === active ? 0 : -1,
9950
+ tabIndex: it.value === active && !it.disabled ? 0 : -1,
9691
9951
  "data-active": it.value === active || void 0,
9692
- onClick: () => select(it.value),
9952
+ onClick: () => {
9953
+ if (!it.disabled) select(it.value);
9954
+ },
9693
9955
  children: [
9694
9956
  it.icon,
9695
9957
  it.label,
@@ -9752,10 +10014,12 @@ function Tag({
9752
10014
  leftIcon,
9753
10015
  tone = "neutral",
9754
10016
  variant = "soft",
10017
+ removeLabel,
9755
10018
  className = "",
9756
10019
  ...rest
9757
10020
  }) {
9758
10021
  const __twcStyles = useScopedStyles("twc-tag-styles", TAG_CSS);
10022
+ const _removeLabel = removeLabel ?? (typeof children === "string" ? `Remove ${children}` : "Remove");
9759
10023
  return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `twc-tag ${className}`, "data-tone": tone, "data-variant": variant, "data-no-remove": !onRemove || void 0, ...rest, children: [
9760
10024
  __twcStyles,
9761
10025
  leftIcon,
@@ -9763,7 +10027,7 @@ function Tag({
9763
10027
  onRemove ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: "twc-tag__remove", onClick: (e) => {
9764
10028
  e.stopPropagation();
9765
10029
  onRemove(e);
9766
- }, "aria-label": "Remove", type: "button", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
10030
+ }, "aria-label": _removeLabel, type: "button", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
9767
10031
  ] });
9768
10032
  }
9769
10033
  function Textarea({
@@ -9809,7 +10073,7 @@ function Textarea({
9809
10073
  .twc-textarea__el[aria-invalid="true"] { border-color: var(--color-danger); }
9810
10074
  .twc-textarea__el:disabled { background: var(--color-surface-sunken); opacity: 0.7; cursor: not-allowed; }
9811
10075
  `);
9812
- const autoId = React23__namespace.default.useId();
10076
+ const autoId = React24__namespace.default.useId();
9813
10077
  const fieldId = id || autoId;
9814
10078
  const descId = `${fieldId}-desc`;
9815
10079
  const invalid = Boolean(error);
@@ -9947,19 +10211,19 @@ function Toast({
9947
10211
  }) {
9948
10212
  const resolvedTone = tone === "neutral" ? "default" : tone;
9949
10213
  const __twcStyles = useScopedStyles("twc-toast-styles", TOAST_CSS);
9950
- const onCloseRef = React23__namespace.default.useRef(onClose);
9951
- React23__namespace.default.useEffect(() => {
10214
+ const onCloseRef = React24__namespace.default.useRef(onClose);
10215
+ React24__namespace.default.useEffect(() => {
9952
10216
  onCloseRef.current = onClose;
9953
10217
  }, [onClose]);
9954
- const timer = React23__namespace.default.useRef();
9955
- const stop = React23__namespace.default.useCallback(() => clearTimeout(timer.current), []);
9956
- const start = React23__namespace.default.useCallback(() => {
10218
+ const timer = React24__namespace.default.useRef();
10219
+ const stop = React24__namespace.default.useCallback(() => clearTimeout(timer.current), []);
10220
+ const start = React24__namespace.default.useCallback(() => {
9957
10221
  stop();
9958
10222
  if (duration && duration !== Infinity && onCloseRef.current) {
9959
10223
  timer.current = setTimeout(() => onCloseRef.current && onCloseRef.current(), duration);
9960
10224
  }
9961
10225
  }, [duration, stop]);
9962
- React23__namespace.default.useEffect(() => {
10226
+ React24__namespace.default.useEffect(() => {
9963
10227
  start();
9964
10228
  return stop;
9965
10229
  }, [start, stop]);
@@ -10003,30 +10267,30 @@ function Toast({
10003
10267
  }
10004
10268
  function ToastViewport({ children, limit, className = "", ...rest }) {
10005
10269
  const __twcStyles = useScopedStyles("twc-toast-styles", TOAST_CSS);
10006
- const shown = limit && limit > 0 ? React23__namespace.default.Children.toArray(children).slice(-limit) : children;
10270
+ const shown = limit && limit > 0 ? React24__namespace.default.Children.toArray(children).slice(-limit) : children;
10007
10271
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-toast-viewport ${className}`, ...rest, children: [
10008
10272
  __twcStyles,
10009
10273
  shown
10010
10274
  ] });
10011
10275
  }
10012
- var ToastContext = React23__namespace.default.createContext(null);
10276
+ var ToastContext = React24__namespace.default.createContext(null);
10013
10277
  function useToast() {
10014
- const ctx = React23__namespace.default.useContext(ToastContext);
10278
+ const ctx = React24__namespace.default.useContext(ToastContext);
10015
10279
  if (!ctx) throw new Error("useToast must be used within a <ToastProvider>.");
10016
10280
  return ctx;
10017
10281
  }
10018
10282
  function ToastProvider({ children, limit = 4, duration = 4500, ...viewportProps }) {
10019
- const [toasts, setToasts] = React23__namespace.default.useState([]);
10020
- const idRef = React23__namespace.default.useRef(0);
10021
- const limitRef = React23__namespace.default.useRef(limit);
10022
- React23__namespace.default.useEffect(() => {
10283
+ const [toasts, setToasts] = React24__namespace.default.useState([]);
10284
+ const idRef = React24__namespace.default.useRef(0);
10285
+ const limitRef = React24__namespace.default.useRef(limit);
10286
+ React24__namespace.default.useEffect(() => {
10023
10287
  limitRef.current = limit;
10024
10288
  }, [limit]);
10025
- const dismiss = React23__namespace.default.useCallback((id) => {
10289
+ const dismiss = React24__namespace.default.useCallback((id) => {
10026
10290
  setToasts((s) => s.filter((t) => t.id !== id));
10027
10291
  }, []);
10028
- const clear = React23__namespace.default.useCallback(() => setToasts([]), []);
10029
- const api = React23__namespace.default.useMemo(() => {
10292
+ const clear = React24__namespace.default.useCallback(() => setToasts([]), []);
10293
+ const api = React24__namespace.default.useMemo(() => {
10030
10294
  const push = (opts) => {
10031
10295
  const id = idRef.current += 1;
10032
10296
  const next = typeof opts === "string" ? { title: opts } : opts && typeof opts === "object" ? opts : {};
@@ -10047,7 +10311,7 @@ function ToastProvider({ children, limit = 4, duration = 4500, ...viewportProps
10047
10311
  toast.show = withTone("default");
10048
10312
  return { toast, dismiss, clear };
10049
10313
  }, [dismiss, clear]);
10050
- const value = React23__namespace.default.useMemo(() => ({ ...api, toasts }), [api, toasts]);
10314
+ const value = React24__namespace.default.useMemo(() => ({ ...api, toasts }), [api, toasts]);
10051
10315
  return /* @__PURE__ */ jsxRuntime.jsxs(ToastContext.Provider, { value, children: [
10052
10316
  children,
10053
10317
  /* @__PURE__ */ jsxRuntime.jsx(ToastViewport, { limit, ...viewportProps, children: toasts.map((t) => /* @__PURE__ */ jsxRuntime.jsx(
@@ -10087,7 +10351,7 @@ var TREE_CSS = `
10087
10351
  .twc-tree__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
10088
10352
  .twc-tree__badge { flex: none; font-size: 11px; color: var(--color-text-subtle); }
10089
10353
  `;
10090
- function Node({ node, depth, expanded, selectedId, tabbableId, rowRefs, onToggle, onSelect, onRowFocus }) {
10354
+ function Node({ node, depth, posInSet, setSize, expanded, selectedId, tabbableId, rowRefs, onToggle, onSelect, onRowFocus }) {
10091
10355
  const hasChildren = Array.isArray(node.children) && node.children.length > 0;
10092
10356
  const open = expanded.has(node.id);
10093
10357
  return /* @__PURE__ */ jsxRuntime.jsxs("li", { role: "none", children: [
@@ -10098,6 +10362,8 @@ function Node({ node, depth, expanded, selectedId, tabbableId, rowRefs, onToggle
10098
10362
  className: "twc-tree__row",
10099
10363
  role: "treeitem",
10100
10364
  "aria-level": depth + 1,
10365
+ "aria-posinset": posInSet,
10366
+ "aria-setsize": setSize,
10101
10367
  "aria-selected": selectedId === node.id,
10102
10368
  "data-selected": selectedId === node.id || void 0,
10103
10369
  "data-tree-id": node.id,
@@ -10121,11 +10387,13 @@ function Node({ node, depth, expanded, selectedId, tabbableId, rowRefs, onToggle
10121
10387
  ]
10122
10388
  }
10123
10389
  ),
10124
- hasChildren && open ? /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "twc-tree__group twc-tree__group--child", role: "group", children: node.children.map((c) => /* @__PURE__ */ jsxRuntime.jsx(
10390
+ hasChildren && open ? /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "twc-tree__group twc-tree__group--child", role: "group", children: node.children.map((c, i) => /* @__PURE__ */ jsxRuntime.jsx(
10125
10391
  Node,
10126
10392
  {
10127
10393
  node: c,
10128
10394
  depth: depth + 1,
10395
+ posInSet: i + 1,
10396
+ setSize: node.children.length,
10129
10397
  expanded,
10130
10398
  selectedId,
10131
10399
  tabbableId,
@@ -10151,12 +10419,13 @@ function TreeView({
10151
10419
  }) {
10152
10420
  const nodes = items;
10153
10421
  const __twcStyles = useScopedStyles("twc-tree-styles", TREE_CSS);
10154
- const [expInternal, setExpInternal] = React23__namespace.default.useState(() => new Set(defaultExpanded));
10422
+ const [expInternal, setExpInternal] = React24__namespace.default.useState(() => new Set(defaultExpanded));
10155
10423
  const expanded = expandedProp !== void 0 ? new Set(expandedProp) : expInternal;
10156
- const [selInternal, setSelInternal] = React23__namespace.default.useState(defaultSelectedId);
10424
+ const [selInternal, setSelInternal] = React24__namespace.default.useState(defaultSelectedId);
10157
10425
  const selectedId = selectedProp !== void 0 ? selectedProp : selInternal;
10158
- const [focusId, setFocusId] = React23__namespace.default.useState(null);
10159
- const rowRefs = React23__namespace.default.useRef(/* @__PURE__ */ new Map());
10426
+ const [focusId, setFocusId] = React24__namespace.default.useState(null);
10427
+ const rowRefs = React24__namespace.default.useRef(/* @__PURE__ */ new Map());
10428
+ const taRef = React24__namespace.default.useRef({ str: "", t: 0 });
10160
10429
  const toggle = (id) => {
10161
10430
  const n = new Set(expanded);
10162
10431
  n.has(id) ? n.delete(id) : n.add(id);
@@ -10170,10 +10439,12 @@ function TreeView({
10170
10439
  const visible = [];
10171
10440
  const parentOf = /* @__PURE__ */ new Map();
10172
10441
  const hasKids = /* @__PURE__ */ new Map();
10442
+ const labelText = /* @__PURE__ */ new Map();
10173
10443
  const walk = (nodes2, parentId) => {
10174
10444
  for (const n of nodes2) {
10175
10445
  visible.push(n.id);
10176
10446
  parentOf.set(n.id, parentId);
10447
+ if (typeof n.label === "string") labelText.set(n.id, n.label);
10177
10448
  const kids = Array.isArray(n.children) && n.children.length > 0;
10178
10449
  hasKids.set(n.id, kids);
10179
10450
  if (kids && expanded.has(n.id)) walk(n.children, n.id);
@@ -10211,17 +10482,36 @@ function TreeView({
10211
10482
  return;
10212
10483
  }
10213
10484
  next = parentOf.get(id);
10485
+ } else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey && /\S/.test(e.key)) {
10486
+ const now = Date.now();
10487
+ taRef.current.str = now - taRef.current.t > 500 ? e.key : taRef.current.str + e.key;
10488
+ taRef.current.t = now;
10489
+ const q = taRef.current.str.toLowerCase();
10490
+ const single = q.length > 1 && [...q].every((c) => c === q[0]);
10491
+ const needle = single ? q[0] : q;
10492
+ for (let k = 1; k <= visible.length; k++) {
10493
+ const cand = visible[(i + k) % visible.length];
10494
+ const lbl = labelText.get(cand);
10495
+ if (lbl && lbl.toLowerCase().startsWith(needle)) {
10496
+ e.preventDefault();
10497
+ focusRow(cand);
10498
+ break;
10499
+ }
10500
+ }
10501
+ return;
10214
10502
  } else return;
10215
10503
  e.preventDefault();
10216
10504
  if (next != null) focusRow(next);
10217
10505
  };
10218
10506
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-tree ${className}`, role: "tree", onKeyDown, ...rest, children: [
10219
10507
  __twcStyles,
10220
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "twc-tree__group", role: "none", children: nodes.map((n) => /* @__PURE__ */ jsxRuntime.jsx(
10508
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "twc-tree__group", role: "none", children: nodes.map((n, i) => /* @__PURE__ */ jsxRuntime.jsx(
10221
10509
  Node,
10222
10510
  {
10223
10511
  node: n,
10224
10512
  depth: 0,
10513
+ posInSet: i + 1,
10514
+ setSize: nodes.length,
10225
10515
  expanded,
10226
10516
  selectedId,
10227
10517
  tabbableId,
@@ -10235,12 +10525,22 @@ function TreeView({
10235
10525
  ] });
10236
10526
  }
10237
10527
  var SHELL_CSS = `
10238
- .twc-shell { display: flex; overflow: hidden; background: var(--color-bg); color: var(--color-text); font-family: var(--font-sans); }
10528
+ .twc-shell { position: relative; display: flex; overflow: hidden; background: var(--color-bg); color: var(--color-text); font-family: var(--font-sans); }
10529
+ .twc-shell__skip { position: absolute; inset-inline-start: var(--space-3); inset-block-start: var(--space-3); z-index: 100;
10530
+ padding: var(--space-2) var(--space-4); background: var(--color-surface); color: var(--color-text);
10531
+ border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-md); font-family: var(--font-sans);
10532
+ transform: translateY(-200%); transition: transform var(--duration-fast) var(--ease-standard); }
10533
+ .twc-shell__skip:focus-visible { transform: translateY(0); outline: none; box-shadow: var(--ring); }
10239
10534
  .twc-shell__main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; height: 100%; }
10240
10535
  .twc-shell__header { flex: none; display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
10241
10536
  min-height: 60px; padding-inline: var(--space-5); border-bottom: var(--border-thin) solid var(--color-border); background: var(--color-surface); }
10242
10537
  .twc-shell__content { flex: 1 1 auto; min-height: 0; overflow: auto; }
10243
10538
  .twc-shell__content[data-padded="true"] { padding: var(--space-6) var(--space-5); }
10539
+ /* Mobile: stack the shell so the sidebar (rendered as an off-canvas overlay) no
10540
+ longer reserves a column \u2014 the main content spans the full width. */
10541
+ @media (max-width: 720px) {
10542
+ .twc-shell { flex-direction: column; }
10543
+ }
10244
10544
  `;
10245
10545
  function AppShell({
10246
10546
  sidebar,
@@ -10248,17 +10548,27 @@ function AppShell({
10248
10548
  children,
10249
10549
  height = "100dvh",
10250
10550
  padded = true,
10551
+ mainId = "twc-main",
10552
+ skipLinkLabel = "Skip to content",
10553
+ sidebarOpen,
10554
+ onSidebarOpenChange,
10251
10555
  className = "",
10252
10556
  style,
10253
10557
  ...rest
10254
10558
  }) {
10255
10559
  const __twcStyles = useScopedStyles("twc-shell-styles", SHELL_CSS);
10560
+ const wiredSidebar = React24__namespace.default.isValidElement(sidebar) && (sidebarOpen !== void 0 || onSidebarOpenChange !== void 0) ? React24__namespace.default.cloneElement(sidebar, {
10561
+ overlay: sidebar.props.overlay !== void 0 ? sidebar.props.overlay : true,
10562
+ open: sidebar.props.open !== void 0 ? sidebar.props.open : sidebarOpen,
10563
+ onOpenChange: sidebar.props.onOpenChange !== void 0 ? sidebar.props.onOpenChange : onSidebarOpenChange
10564
+ }) : sidebar;
10256
10565
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-shell ${className}`.trim(), style: { height, ...style }, ...rest, children: [
10257
10566
  __twcStyles,
10258
- sidebar,
10567
+ skipLinkLabel != null && skipLinkLabel !== false ? /* @__PURE__ */ jsxRuntime.jsx("a", { className: "twc-shell__skip", href: `#${mainId}`, children: skipLinkLabel }) : null,
10568
+ wiredSidebar,
10259
10569
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-shell__main", children: [
10260
10570
  header != null ? /* @__PURE__ */ jsxRuntime.jsx("header", { className: "twc-shell__header", children: header }) : null,
10261
- /* @__PURE__ */ jsxRuntime.jsx("main", { className: "twc-shell__content", "data-padded": padded ? "true" : void 0, children })
10571
+ /* @__PURE__ */ jsxRuntime.jsx("main", { className: "twc-shell__content", id: mainId, tabIndex: -1, "data-padded": padded ? "true" : void 0, children })
10262
10572
  ] })
10263
10573
  ] });
10264
10574
  }
@@ -10277,7 +10587,7 @@ function bgValue(bg) {
10277
10587
  if (BG[bg]) return `var(${BG[bg]})`;
10278
10588
  return String(bg).startsWith("--") ? `var(${bg})` : bg;
10279
10589
  }
10280
- function safeHref4(url) {
10590
+ function safeHref5(url) {
10281
10591
  if (url == null) return void 0;
10282
10592
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
10283
10593
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -10322,11 +10632,11 @@ function Box({
10322
10632
  boxShadow: shadow ? `var(--shadow-${shadow})` : void 0,
10323
10633
  ...style
10324
10634
  };
10325
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref4(rest.href);
10635
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref5(rest.href);
10326
10636
  return /* @__PURE__ */ jsxRuntime.jsx(Tag2, { className: `twc-box ${className}`.trim(), style: s, ...rest, children });
10327
10637
  }
10328
10638
  var SIZES = { sm: 640, md: 768, lg: 1024, xl: 1280, full: "100%" };
10329
- function safeHref5(url) {
10639
+ function safeHref6(url) {
10330
10640
  if (url == null) return void 0;
10331
10641
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
10332
10642
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -10341,7 +10651,7 @@ function Container({
10341
10651
  ...rest
10342
10652
  }) {
10343
10653
  const max = SIZES[size] ?? size;
10344
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref5(rest.href);
10654
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref6(rest.href);
10345
10655
  return /* @__PURE__ */ jsxRuntime.jsx(
10346
10656
  Tag2,
10347
10657
  {
@@ -10366,7 +10676,8 @@ function space(v) {
10366
10676
  function len(v) {
10367
10677
  return typeof v === "number" ? `${v}px` : v;
10368
10678
  }
10369
- function safeHref6(url) {
10679
+ var BP = { sm: 640, md: 768, lg: 1024, xl: 1280 };
10680
+ function safeHref7(url) {
10370
10681
  if (url == null) return void 0;
10371
10682
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
10372
10683
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -10376,29 +10687,54 @@ function Grid({
10376
10687
  columns,
10377
10688
  minChildWidth,
10378
10689
  gap = 4,
10690
+ rowGap,
10691
+ columnGap,
10379
10692
  align,
10380
10693
  justify,
10694
+ alignContent,
10695
+ justifyContent,
10381
10696
  className = "",
10382
10697
  style,
10383
10698
  children,
10384
10699
  ...rest
10385
10700
  }) {
10386
- const templateColumns = minChildWidth ? `repeat(auto-fill, minmax(min(${len(minChildWidth)}, 100%), 1fr))` : `repeat(${columns || 1}, minmax(0, 1fr))`;
10387
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref6(rest.href);
10388
- return /* @__PURE__ */ jsxRuntime.jsx(
10701
+ const responsive = columns != null && typeof columns === "object";
10702
+ const uid = React24__namespace.default.useId();
10703
+ const gridId = responsive ? `g${uid.replace(/[^a-zA-Z0-9]/g, "")}` : null;
10704
+ let css = "";
10705
+ if (responsive) {
10706
+ const base = columns.base ?? 1;
10707
+ const sel = `[data-twc-grid-id="${gridId}"]`;
10708
+ css = `${sel} { --twc-grid-cols: ${base}; }`;
10709
+ for (const bp of ["sm", "md", "lg", "xl"]) {
10710
+ if (columns[bp] != null) css += `
10711
+ @media (min-width: ${BP[bp]}px) { ${sel} { --twc-grid-cols: ${columns[bp]}; } }`;
10712
+ }
10713
+ }
10714
+ const __twcStyles = useScopedStyles(gridId ? `twc-grid-${gridId}` : "twc-grid", css);
10715
+ 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))`;
10716
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref7(rest.href);
10717
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10389
10718
  Tag2,
10390
10719
  {
10391
10720
  className: `twc-grid ${className}`.trim(),
10721
+ "data-twc-grid-id": gridId || void 0,
10392
10722
  style: {
10393
10723
  display: "grid",
10394
10724
  gridTemplateColumns: templateColumns,
10395
- gap: space(gap),
10725
+ rowGap: space(rowGap ?? gap),
10726
+ columnGap: space(columnGap ?? gap),
10396
10727
  alignItems: align,
10397
10728
  justifyItems: justify,
10729
+ alignContent,
10730
+ justifyContent,
10398
10731
  ...style
10399
10732
  },
10400
10733
  ...rest,
10401
- children
10734
+ children: [
10735
+ responsive ? __twcStyles : null,
10736
+ children
10737
+ ]
10402
10738
  }
10403
10739
  );
10404
10740
  }
@@ -10407,7 +10743,7 @@ function space2(v) {
10407
10743
  if (typeof v === "number") return `var(--space-${String(v).replace(".", "-")})`;
10408
10744
  return v;
10409
10745
  }
10410
- function safeHref7(url) {
10746
+ function safeHref8(url) {
10411
10747
  if (url == null) return void 0;
10412
10748
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
10413
10749
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -10420,12 +10756,21 @@ function Stack({
10420
10756
  justify,
10421
10757
  wrap = false,
10422
10758
  inline = false,
10759
+ p,
10760
+ px,
10761
+ py,
10762
+ pt,
10763
+ pr,
10764
+ pb,
10765
+ pl,
10766
+ divider,
10423
10767
  className = "",
10424
10768
  style,
10425
10769
  children,
10426
10770
  ...rest
10427
10771
  }) {
10428
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref7(rest.href);
10772
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref8(rest.href);
10773
+ const kids = divider != null ? React24__namespace.default.Children.toArray(children).flatMap((child, i, arr) => i < arr.length - 1 ? [child, /* @__PURE__ */ jsxRuntime.jsx(React24__namespace.default.Fragment, { children: divider }, `twc-stack-div-${i}`)] : [child]) : children;
10429
10774
  return /* @__PURE__ */ jsxRuntime.jsx(
10430
10775
  Tag2,
10431
10776
  {
@@ -10437,11 +10782,15 @@ function Stack({
10437
10782
  alignItems: align,
10438
10783
  justifyContent: justify,
10439
10784
  flexWrap: wrap ? "wrap" : void 0,
10785
+ paddingTop: space2(pt ?? py ?? p),
10786
+ paddingRight: space2(pr ?? px ?? p),
10787
+ paddingBottom: space2(pb ?? py ?? p),
10788
+ paddingLeft: space2(pl ?? px ?? p),
10440
10789
  minWidth: 0,
10441
10790
  ...style
10442
10791
  },
10443
10792
  ...rest,
10444
- children
10793
+ children: kids
10445
10794
  }
10446
10795
  );
10447
10796
  }
@@ -10453,22 +10802,64 @@ var CODE_CSS = `
10453
10802
  border: var(--border-thin) solid var(--color-border);
10454
10803
  white-space: normal; overflow-wrap: anywhere; word-break: break-word;
10455
10804
  }
10805
+ .twc-code[data-block="true"] {
10806
+ display: block; position: relative; white-space: pre; overflow-x: auto;
10807
+ padding: 12px 14px; padding-inline-end: 40px; line-height: 1.6; font-size: 0.8125em;
10808
+ overflow-wrap: normal; word-break: normal;
10809
+ }
10810
+ .twc-code__copy {
10811
+ position: absolute; top: 6px; inset-inline-end: 6px; display: inline-grid; place-items: center;
10812
+ width: 26px; height: 26px; border: none; border-radius: var(--radius-sm);
10813
+ background: var(--color-surface); color: var(--color-text-subtle); cursor: pointer;
10814
+ transition: color var(--duration-fast), background-color var(--duration-fast);
10815
+ }
10816
+ .twc-code__copy:hover { color: var(--color-text); }
10817
+ .twc-code__copy:focus-visible { outline: none; box-shadow: var(--ring); }
10818
+ .twc-code__copy svg { width: 15px; height: 15px; display: block; }
10456
10819
  `;
10457
- function safeHref8(url) {
10820
+ function safeHref9(url) {
10458
10821
  if (url == null) return void 0;
10459
10822
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
10460
10823
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
10461
10824
  }
10462
- function Code({ as: Tag2 = "code", className = "", children, ...rest }) {
10825
+ function Code({
10826
+ as,
10827
+ block = false,
10828
+ copyable = false,
10829
+ copyLabel = "Copy code",
10830
+ copiedLabel = "Copied",
10831
+ className = "",
10832
+ children,
10833
+ ...rest
10834
+ }) {
10463
10835
  const __twcStyles = useScopedStyles("twc-code-styles", CODE_CSS);
10464
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref8(rest.href);
10465
- return /* @__PURE__ */ jsxRuntime.jsxs(Tag2, { className: `twc-code ${className}`.trim(), ...rest, children: [
10836
+ const Tag2 = as ?? (block ? "pre" : "code");
10837
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref9(rest.href);
10838
+ const rootRef = React24__namespace.default.useRef(null);
10839
+ const [copied, setCopied] = React24__namespace.default.useState(false);
10840
+ const timerRef = React24__namespace.default.useRef(null);
10841
+ React24__namespace.default.useEffect(() => () => clearTimeout(timerRef.current), []);
10842
+ const doCopy = () => {
10843
+ if (typeof navigator === "undefined" || !navigator.clipboard) return;
10844
+ const text = typeof children === "string" ? children : rootRef.current?.textContent ?? "";
10845
+ navigator.clipboard.writeText(text).then(() => {
10846
+ setCopied(true);
10847
+ clearTimeout(timerRef.current);
10848
+ timerRef.current = setTimeout(() => setCopied(false), 2e3);
10849
+ }).catch(() => {
10850
+ });
10851
+ };
10852
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tag2, { ref: rootRef, className: `twc-code ${className}`.trim(), "data-block": block || void 0, ...rest, children: [
10466
10853
  __twcStyles,
10854
+ copyable ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-code__copy", "aria-label": copied ? copiedLabel : copyLabel, onClick: doCopy, children: copied ? /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m20 6-11 11-5-5" }) }) : /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
10855
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
10856
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
10857
+ ] }) }) : null,
10467
10858
  children
10468
10859
  ] });
10469
10860
  }
10470
10861
  var LEVEL_SIZE = { 1: "4xl", 2: "2xl", 3: "xl", 4: "lg", 5: "base", 6: "sm" };
10471
- function safeHref9(url) {
10862
+ function safeHref10(url) {
10472
10863
  if (url == null) return void 0;
10473
10864
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
10474
10865
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -10477,15 +10868,18 @@ function Heading({
10477
10868
  as,
10478
10869
  level = 2,
10479
10870
  size,
10871
+ display = false,
10480
10872
  align,
10873
+ truncate,
10874
+ lineClamp,
10481
10875
  className = "",
10482
10876
  style,
10483
10877
  children,
10484
10878
  ...rest
10485
10879
  }) {
10486
10880
  const Tag2 = as || `h${level}`;
10487
- const sz = size || LEVEL_SIZE[level] || "2xl";
10488
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref9(rest.href);
10881
+ const sz = size || (display ? "display" : LEVEL_SIZE[level]) || "2xl";
10882
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref10(rest.href);
10489
10883
  return /* @__PURE__ */ jsxRuntime.jsx(
10490
10884
  Tag2,
10491
10885
  {
@@ -10499,6 +10893,7 @@ function Heading({
10499
10893
  letterSpacing: "-0.02em",
10500
10894
  fontSize: `var(--text-${sz})`,
10501
10895
  textAlign: align,
10896
+ ...lineClamp != null ? { display: "-webkit-box", WebkitBoxOrient: "vertical", WebkitLineClamp: lineClamp, overflow: "hidden" } : truncate ? { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", minWidth: 0 } : null,
10502
10897
  ...style
10503
10898
  },
10504
10899
  ...rest,
@@ -10517,9 +10912,11 @@ var TONE = {
10517
10912
  success: "--color-success",
10518
10913
  warning: "--color-warning-subtle-fg",
10519
10914
  info: "--color-info-subtle-fg",
10520
- neutral: "--color-text-muted"
10915
+ neutral: "--color-text-muted",
10916
+ // Adopt the surrounding color (e.g. inside a solid Button/Badge/Alert or a link).
10917
+ inherit: "inherit"
10521
10918
  };
10522
- function safeHref10(url) {
10919
+ function safeHref11(url) {
10523
10920
  if (url == null) return void 0;
10524
10921
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
10525
10922
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -10530,12 +10927,15 @@ function Text({
10530
10927
  tone = "default",
10531
10928
  weight,
10532
10929
  align,
10930
+ truncate,
10931
+ lineClamp,
10533
10932
  className = "",
10534
10933
  style,
10535
10934
  children,
10536
10935
  ...rest
10537
10936
  }) {
10538
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref10(rest.href);
10937
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref11(rest.href);
10938
+ const toneToken = TONE[tone] || TONE.default;
10539
10939
  return /* @__PURE__ */ jsxRuntime.jsx(
10540
10940
  Tag2,
10541
10941
  {
@@ -10545,9 +10945,10 @@ function Text({
10545
10945
  fontFamily: "var(--font-sans)",
10546
10946
  lineHeight: 1.6,
10547
10947
  fontSize: `var(--text-${size})`,
10548
- color: `var(${TONE[tone] || TONE.default})`,
10948
+ color: toneToken.startsWith("--") ? `var(${toneToken})` : toneToken,
10549
10949
  fontWeight: weight ? `var(--font-${weight})` : void 0,
10550
10950
  textAlign: align,
10951
+ ...lineClamp != null ? { display: "-webkit-box", WebkitBoxOrient: "vertical", WebkitLineClamp: lineClamp, overflow: "hidden" } : truncate ? { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", minWidth: 0 } : null,
10551
10952
  ...style
10552
10953
  },
10553
10954
  ...rest,
@@ -10555,58 +10956,68 @@ function Text({
10555
10956
  }
10556
10957
  );
10557
10958
  }
10558
- var canUseDOM = typeof window !== "undefined" && typeof document !== "undefined";
10559
- var useIsomorphicLayoutEffect = canUseDOM ? React23__namespace.default.useLayoutEffect : React23__namespace.default.useEffect;
10959
+ var canUseDOM2 = typeof window !== "undefined" && typeof document !== "undefined";
10960
+ var useIsomorphicLayoutEffect = canUseDOM2 ? React24__namespace.default.useLayoutEffect : React24__namespace.default.useEffect;
10560
10961
  function useMounted() {
10561
- const [mounted, setMounted] = React23__namespace.default.useState(false);
10562
- React23__namespace.default.useEffect(() => {
10962
+ const [mounted, setMounted] = React24__namespace.default.useState(false);
10963
+ React24__namespace.default.useEffect(() => {
10563
10964
  setMounted(true);
10564
10965
  }, []);
10565
10966
  return mounted;
10566
10967
  }
10567
10968
  function usePrevious(value) {
10568
- const ref = React23__namespace.default.useRef(void 0);
10569
- React23__namespace.default.useEffect(() => {
10969
+ const ref = React24__namespace.default.useRef(void 0);
10970
+ React24__namespace.default.useEffect(() => {
10570
10971
  ref.current = value;
10571
10972
  }, [value]);
10572
10973
  return ref.current;
10573
10974
  }
10574
10975
  function useToggle(initial = false) {
10575
- const [on, setOn] = React23__namespace.default.useState(initial);
10576
- const toggle = React23__namespace.default.useCallback((next) => {
10976
+ const [on, setOn] = React24__namespace.default.useState(initial);
10977
+ const toggle = React24__namespace.default.useCallback((next) => {
10577
10978
  setOn((prev) => typeof next === "boolean" ? next : !prev);
10578
10979
  }, []);
10579
10980
  return [on, toggle, setOn];
10580
10981
  }
10581
10982
  function useDisclosure(initial = false) {
10582
- const [open, setOpen] = React23__namespace.default.useState(initial);
10583
- const onOpen = React23__namespace.default.useCallback(() => setOpen(true), []);
10584
- const onClose = React23__namespace.default.useCallback(() => setOpen(false), []);
10585
- const onToggle = React23__namespace.default.useCallback(() => setOpen((p) => !p), []);
10983
+ const [open, setOpen] = React24__namespace.default.useState(initial);
10984
+ const onOpen = React24__namespace.default.useCallback(() => setOpen(true), []);
10985
+ const onClose = React24__namespace.default.useCallback(() => setOpen(false), []);
10986
+ const onToggle = React24__namespace.default.useCallback(() => setOpen((p) => !p), []);
10586
10987
  return { open, onOpen, onClose, onToggle, setOpen };
10587
10988
  }
10588
10989
  function useControllableState({ value, defaultValue, onChange } = {}) {
10589
10990
  const isControlled = value !== void 0;
10590
- const [uncontrolled, setUncontrolled] = React23__namespace.default.useState(defaultValue);
10991
+ const [uncontrolled, setUncontrolled] = React24__namespace.default.useState(defaultValue);
10591
10992
  const current = isControlled ? value : uncontrolled;
10592
- const ref = React23__namespace.default.useRef({ current, isControlled, onChange });
10993
+ const ref = React24__namespace.default.useRef({ current, isControlled, onChange });
10593
10994
  useIsomorphicLayoutEffect(() => {
10594
10995
  ref.current = { current, isControlled, onChange };
10595
10996
  });
10596
- const setValue = React23__namespace.default.useCallback((next) => {
10997
+ const wasControlled = React24__namespace.default.useRef(isControlled);
10998
+ React24__namespace.default.useEffect(() => {
10999
+ if (wasControlled.current !== isControlled) {
11000
+ warnOnce(
11001
+ "useControllableState:switch",
11002
+ `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.`
11003
+ );
11004
+ wasControlled.current = isControlled;
11005
+ }
11006
+ });
11007
+ const setValue = React24__namespace.default.useCallback((next) => {
10597
11008
  const { current: cur, isControlled: ctrl, onChange: cb } = ref.current;
10598
11009
  const resolved = typeof next === "function" ? next(cur) : next;
10599
11010
  if (resolved === cur) return;
10600
11011
  if (!ctrl) setUncontrolled(resolved);
10601
11012
  if (cb) cb(resolved);
10602
11013
  }, []);
10603
- return [current, setValue];
11014
+ return [current, setValue, isControlled];
10604
11015
  }
10605
- function useMediaQuery(query) {
10606
- const get = () => canUseDOM ? window.matchMedia(query).matches : false;
10607
- const [matches3, setMatches] = React23__namespace.default.useState(get);
10608
- React23__namespace.default.useEffect(() => {
10609
- if (!canUseDOM) return void 0;
11016
+ function useMediaQuery(query, { defaultValue = false, initializeWithValue = false } = {}) {
11017
+ const get = () => canUseDOM2 ? window.matchMedia(query).matches : defaultValue;
11018
+ const [matches3, setMatches] = React24__namespace.default.useState(initializeWithValue ? get : defaultValue);
11019
+ useIsomorphicLayoutEffect(() => {
11020
+ if (!canUseDOM2) return void 0;
10610
11021
  const mql = window.matchMedia(query);
10611
11022
  const onChange = () => setMatches(mql.matches);
10612
11023
  onChange();
@@ -10619,10 +11030,10 @@ function usePrefersReducedMotion() {
10619
11030
  return useMediaQuery("(prefers-reduced-motion: reduce)");
10620
11031
  }
10621
11032
  function useColorScheme({ storageKey = "twico-theme", attribute = "class", element, disableTransitionsOnChange = true } = {}) {
10622
- const getTarget = () => element || (canUseDOM ? document.documentElement : null);
10623
- const firstApply = React23__namespace.default.useRef(true);
11033
+ const getTarget = () => element || (canUseDOM2 ? document.documentElement : null);
11034
+ const firstApply = React24__namespace.default.useRef(true);
10624
11035
  const read = () => {
10625
- if (!canUseDOM) return "light";
11036
+ if (!canUseDOM2) return "light";
10626
11037
  try {
10627
11038
  const stored = window.localStorage.getItem(storageKey);
10628
11039
  if (stored === "light" || stored === "dark") return stored;
@@ -10630,12 +11041,12 @@ function useColorScheme({ storageKey = "twico-theme", attribute = "class", eleme
10630
11041
  }
10631
11042
  return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
10632
11043
  };
10633
- const [theme, setThemeState] = React23__namespace.default.useState(read);
10634
- const apply = React23__namespace.default.useCallback(
11044
+ const [theme, setThemeState] = React24__namespace.default.useState(read);
11045
+ const apply = React24__namespace.default.useCallback(
10635
11046
  (t) => {
10636
11047
  const target = getTarget();
10637
11048
  if (!target) return;
10638
- const skip = firstApply.current || !disableTransitionsOnChange || !canUseDOM;
11049
+ const skip = firstApply.current || !disableTransitionsOnChange || !canUseDOM2;
10639
11050
  firstApply.current = false;
10640
11051
  let css;
10641
11052
  if (!skip) {
@@ -10657,26 +11068,26 @@ function useColorScheme({ storageKey = "twico-theme", attribute = "class", eleme
10657
11068
  useIsomorphicLayoutEffect(() => {
10658
11069
  apply(theme);
10659
11070
  }, [theme, apply]);
10660
- const themeRef = React23__namespace.default.useRef(theme);
11071
+ const themeRef = React24__namespace.default.useRef(theme);
10661
11072
  useIsomorphicLayoutEffect(() => {
10662
11073
  themeRef.current = theme;
10663
11074
  }, [theme]);
10664
- const setTheme = React23__namespace.default.useCallback(
11075
+ const setTheme = React24__namespace.default.useCallback(
10665
11076
  (t) => {
10666
11077
  setThemeState(t);
10667
11078
  try {
10668
- if (canUseDOM) window.localStorage.setItem(storageKey, t);
11079
+ if (canUseDOM2) window.localStorage.setItem(storageKey, t);
10669
11080
  } catch (e) {
10670
11081
  }
10671
- if (canUseDOM) window.dispatchEvent(new Event("twico:colorscheme"));
11082
+ if (canUseDOM2) window.dispatchEvent(new Event("twico:colorscheme"));
10672
11083
  },
10673
11084
  [storageKey]
10674
11085
  );
10675
- const toggle = React23__namespace.default.useCallback(() => {
11086
+ const toggle = React24__namespace.default.useCallback(() => {
10676
11087
  setTheme(themeRef.current === "dark" ? "light" : "dark");
10677
11088
  }, [setTheme]);
10678
- React23__namespace.default.useEffect(() => {
10679
- if (!canUseDOM) return void 0;
11089
+ React24__namespace.default.useEffect(() => {
11090
+ if (!canUseDOM2) return void 0;
10680
11091
  const sync = () => setThemeState(read());
10681
11092
  const onStorage = (e) => {
10682
11093
  if (e.key === storageKey) sync();
@@ -10691,15 +11102,15 @@ function useColorScheme({ storageKey = "twico-theme", attribute = "class", eleme
10691
11102
  return { theme, setTheme, toggle, isDark: theme === "dark" };
10692
11103
  }
10693
11104
  function useEventListener(eventName, handler, element, options) {
10694
- const saved = React23__namespace.default.useRef(handler);
11105
+ const saved = React24__namespace.default.useRef(handler);
10695
11106
  useIsomorphicLayoutEffect(() => {
10696
11107
  saved.current = handler;
10697
11108
  }, [handler]);
10698
11109
  const capture = typeof options === "boolean" ? options : options && options.capture;
10699
11110
  const passive = typeof options === "object" && options ? options.passive : void 0;
10700
11111
  const once = typeof options === "object" && options ? options.once : void 0;
10701
- React23__namespace.default.useEffect(() => {
10702
- const target = element && element.current || element || (canUseDOM ? window : null);
11112
+ React24__namespace.default.useEffect(() => {
11113
+ const target = element && element.current || element || (canUseDOM2 ? window : null);
10703
11114
  if (!target || !target.addEventListener) return void 0;
10704
11115
  const opts = typeof options === "boolean" ? options : { capture, passive, once };
10705
11116
  const listener = (e) => saved.current(e);
@@ -10708,12 +11119,12 @@ function useEventListener(eventName, handler, element, options) {
10708
11119
  }, [eventName, element, capture, passive, once]);
10709
11120
  }
10710
11121
  function useClickOutside(ref, handler, events = ["mousedown", "touchstart"]) {
10711
- const saved = React23__namespace.default.useRef(handler);
11122
+ const saved = React24__namespace.default.useRef(handler);
10712
11123
  useIsomorphicLayoutEffect(() => {
10713
11124
  saved.current = handler;
10714
11125
  }, [handler]);
10715
- React23__namespace.default.useEffect(() => {
10716
- if (!canUseDOM) return void 0;
11126
+ React24__namespace.default.useEffect(() => {
11127
+ if (!canUseDOM2) return void 0;
10717
11128
  const listener = (e) => {
10718
11129
  const el = ref && ref.current;
10719
11130
  if (!el || el.contains(e.target)) return;
@@ -10739,7 +11150,7 @@ function useKeyPress(key, handler, options = {}) {
10739
11150
  }
10740
11151
  function useLocalStorage(key, initialValue) {
10741
11152
  const read = () => {
10742
- if (!canUseDOM) return initialValue;
11153
+ if (!canUseDOM2) return initialValue;
10743
11154
  try {
10744
11155
  const item = window.localStorage.getItem(key);
10745
11156
  return item ? JSON.parse(item) : initialValue;
@@ -10747,13 +11158,13 @@ function useLocalStorage(key, initialValue) {
10747
11158
  return initialValue;
10748
11159
  }
10749
11160
  };
10750
- const [stored, setStored] = React23__namespace.default.useState(read);
10751
- const setValue = React23__namespace.default.useCallback(
11161
+ const [stored, setStored] = React24__namespace.default.useState(read);
11162
+ const setValue = React24__namespace.default.useCallback(
10752
11163
  (value) => {
10753
11164
  setStored((prev) => {
10754
11165
  const next = typeof value === "function" ? value(prev) : value;
10755
11166
  try {
10756
- if (canUseDOM) window.localStorage.setItem(key, JSON.stringify(next));
11167
+ if (canUseDOM2) window.localStorage.setItem(key, JSON.stringify(next));
10757
11168
  } catch (e) {
10758
11169
  }
10759
11170
  return next;
@@ -10764,9 +11175,9 @@ function useLocalStorage(key, initialValue) {
10764
11175
  return [stored, setValue];
10765
11176
  }
10766
11177
  function useCopyToClipboard(timeout = 1500) {
10767
- const [copied, setCopied] = React23__namespace.default.useState(false);
10768
- const copy = React23__namespace.default.useCallback(async (text) => {
10769
- if (!canUseDOM || !navigator.clipboard) {
11178
+ const [copied, setCopied] = React24__namespace.default.useState(false);
11179
+ const copy = React24__namespace.default.useCallback(async (text) => {
11180
+ if (!canUseDOM2 || !navigator.clipboard) {
10770
11181
  setCopied(false);
10771
11182
  return false;
10772
11183
  }
@@ -10779,7 +11190,7 @@ function useCopyToClipboard(timeout = 1500) {
10779
11190
  return false;
10780
11191
  }
10781
11192
  }, []);
10782
- React23__namespace.default.useEffect(() => {
11193
+ React24__namespace.default.useEffect(() => {
10783
11194
  if (!copied) return void 0;
10784
11195
  const t = setTimeout(() => setCopied(false), timeout);
10785
11196
  return () => clearTimeout(t);
@@ -10787,23 +11198,23 @@ function useCopyToClipboard(timeout = 1500) {
10787
11198
  return { copied, copy };
10788
11199
  }
10789
11200
  function useDebouncedValue(value, delay = 200) {
10790
- const [debounced, setDebounced] = React23__namespace.default.useState(value);
10791
- React23__namespace.default.useEffect(() => {
11201
+ const [debounced, setDebounced] = React24__namespace.default.useState(value);
11202
+ React24__namespace.default.useEffect(() => {
10792
11203
  const t = setTimeout(() => setDebounced(value), delay);
10793
11204
  return () => clearTimeout(t);
10794
11205
  }, [value, delay]);
10795
11206
  return debounced;
10796
11207
  }
10797
11208
  function useDebouncedCallback(callback, delay = 200) {
10798
- const saved = React23__namespace.default.useRef(callback);
10799
- const timer = React23__namespace.default.useRef(null);
11209
+ const saved = React24__namespace.default.useRef(callback);
11210
+ const timer = React24__namespace.default.useRef(null);
10800
11211
  useIsomorphicLayoutEffect(() => {
10801
11212
  saved.current = callback;
10802
11213
  }, [callback]);
10803
- React23__namespace.default.useEffect(() => () => {
11214
+ React24__namespace.default.useEffect(() => () => {
10804
11215
  if (timer.current) clearTimeout(timer.current);
10805
11216
  }, []);
10806
- return React23__namespace.default.useCallback(
11217
+ return React24__namespace.default.useCallback(
10807
11218
  (...args) => {
10808
11219
  if (timer.current) clearTimeout(timer.current);
10809
11220
  timer.current = setTimeout(() => saved.current(...args), delay);
@@ -10812,34 +11223,34 @@ function useDebouncedCallback(callback, delay = 200) {
10812
11223
  );
10813
11224
  }
10814
11225
  function useInterval(callback, delay) {
10815
- const saved = React23__namespace.default.useRef(callback);
11226
+ const saved = React24__namespace.default.useRef(callback);
10816
11227
  useIsomorphicLayoutEffect(() => {
10817
11228
  saved.current = callback;
10818
11229
  }, [callback]);
10819
- React23__namespace.default.useEffect(() => {
11230
+ React24__namespace.default.useEffect(() => {
10820
11231
  if (delay == null) return void 0;
10821
11232
  const id = setInterval(() => saved.current(), delay);
10822
11233
  return () => clearInterval(id);
10823
11234
  }, [delay]);
10824
11235
  }
10825
11236
  function useTimeout(callback, delay) {
10826
- const saved = React23__namespace.default.useRef(callback);
11237
+ const saved = React24__namespace.default.useRef(callback);
10827
11238
  useIsomorphicLayoutEffect(() => {
10828
11239
  saved.current = callback;
10829
11240
  }, [callback]);
10830
- React23__namespace.default.useEffect(() => {
11241
+ React24__namespace.default.useEffect(() => {
10831
11242
  if (delay == null) return void 0;
10832
11243
  const id = setTimeout(() => saved.current(), delay);
10833
11244
  return () => clearTimeout(id);
10834
11245
  }, [delay]);
10835
11246
  }
10836
11247
  function useWindowSize() {
10837
- const [size, setSize] = React23__namespace.default.useState(() => ({
10838
- width: canUseDOM ? window.innerWidth : 0,
10839
- height: canUseDOM ? window.innerHeight : 0
11248
+ const [size, setSize] = React24__namespace.default.useState(() => ({
11249
+ width: canUseDOM2 ? window.innerWidth : 0,
11250
+ height: canUseDOM2 ? window.innerHeight : 0
10840
11251
  }));
10841
- React23__namespace.default.useEffect(() => {
10842
- if (!canUseDOM) return void 0;
11252
+ React24__namespace.default.useEffect(() => {
11253
+ if (!canUseDOM2) return void 0;
10843
11254
  const onResize = () => setSize({ width: window.innerWidth, height: window.innerHeight });
10844
11255
  onResize();
10845
11256
  window.addEventListener("resize", onResize);
@@ -10848,8 +11259,8 @@ function useWindowSize() {
10848
11259
  return size;
10849
11260
  }
10850
11261
  function useHover(ref) {
10851
- const [hovered, setHovered] = React23__namespace.default.useState(false);
10852
- React23__namespace.default.useEffect(() => {
11262
+ const [hovered, setHovered] = React24__namespace.default.useState(false);
11263
+ React24__namespace.default.useEffect(() => {
10853
11264
  const el = ref && ref.current;
10854
11265
  if (!el) return void 0;
10855
11266
  const on = () => setHovered(true);
@@ -10865,10 +11276,10 @@ function useHover(ref) {
10865
11276
  }
10866
11277
  function useIntersectionObserver(ref, options = {}) {
10867
11278
  const { root = null, rootMargin = "0px", threshold = 0 } = options;
10868
- const [entry, setEntry] = React23__namespace.default.useState(null);
10869
- React23__namespace.default.useEffect(() => {
11279
+ const [entry, setEntry] = React24__namespace.default.useState(null);
11280
+ React24__namespace.default.useEffect(() => {
10870
11281
  const el = ref && ref.current;
10871
- if (!canUseDOM || !el || typeof IntersectionObserver === "undefined") return void 0;
11282
+ if (!canUseDOM2 || !el || typeof IntersectionObserver === "undefined") return void 0;
10872
11283
  const obs = new IntersectionObserver(([e]) => setEntry(e), { root, rootMargin, threshold });
10873
11284
  obs.observe(el);
10874
11285
  return () => obs.disconnect();
@@ -10879,7 +11290,7 @@ var __scrollLockCount = 0;
10879
11290
  var __scrollLockSaved = "";
10880
11291
  function useScrollLock(locked = true) {
10881
11292
  useIsomorphicLayoutEffect(() => {
10882
- if (!canUseDOM || !locked) return void 0;
11293
+ if (!canUseDOM2 || !locked) return void 0;
10883
11294
  if (__scrollLockCount === 0) {
10884
11295
  __scrollLockSaved = document.body.style.overflow;
10885
11296
  document.body.style.overflow = "hidden";
@@ -10894,9 +11305,11 @@ function useScrollLock(locked = true) {
10894
11305
  }, [locked]);
10895
11306
  }
10896
11307
  function useId(prefix = "twc") {
10897
- const raw = React23__namespace.default.useId();
11308
+ const raw = React24__namespace.default.useId();
10898
11309
  return prefix ? `${prefix}-${raw.replace(/:/g, "")}` : raw;
10899
11310
  }
11311
+ var useFocusTrap2 = useFocusTrap;
11312
+ var usePortal2 = usePortal;
10900
11313
 
10901
11314
  exports.Accordion = Accordion;
10902
11315
  exports.Alert = Alert;
@@ -10970,6 +11383,7 @@ exports.useDebouncedCallback = useDebouncedCallback;
10970
11383
  exports.useDebouncedValue = useDebouncedValue;
10971
11384
  exports.useDisclosure = useDisclosure;
10972
11385
  exports.useEventListener = useEventListener;
11386
+ exports.useFocusTrap = useFocusTrap2;
10973
11387
  exports.useHover = useHover;
10974
11388
  exports.useId = useId;
10975
11389
  exports.useIntersectionObserver = useIntersectionObserver;
@@ -10979,6 +11393,7 @@ exports.useKeyPress = useKeyPress;
10979
11393
  exports.useLocalStorage = useLocalStorage;
10980
11394
  exports.useMediaQuery = useMediaQuery;
10981
11395
  exports.useMounted = useMounted;
11396
+ exports.usePortal = usePortal2;
10982
11397
  exports.usePrefersReducedMotion = usePrefersReducedMotion;
10983
11398
  exports.usePrevious = usePrevious;
10984
11399
  exports.useScrollLock = useScrollLock;