twico-ui 1.6.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,22 +1,339 @@
1
1
  "use client";
2
- import * as React25 from 'react';
3
- import React25__default from 'react';
2
+ import * as React37 from 'react';
3
+ import React37__default from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
  import { createPortal } from 'react-dom';
6
6
 
7
- // components/navigation/Accordion.jsx
8
- var SUPPORTS_STYLE_HOIST = parseInt(String(React25.version), 10) >= 19;
7
+ // components/TwicoProvider.jsx
8
+ var SUPPORTS_STYLE_HOIST = parseInt(String(React37.version), 10) >= 19;
9
+ var NonceContext = React37.createContext(void 0);
9
10
  function useScopedStyles(id, css) {
10
- React25.useInsertionEffect(() => {
11
+ const nonce = React37.useContext(NonceContext);
12
+ React37.useInsertionEffect(() => {
11
13
  if (SUPPORTS_STYLE_HOIST) return;
12
- if (typeof document === "undefined" || document.getElementById(id)) return;
13
- const el = document.createElement("style");
14
- el.id = id;
15
- el.textContent = css;
16
- document.head.appendChild(el);
17
- }, [id, css]);
18
- return SUPPORTS_STYLE_HOIST ? React25.createElement("style", { href: id, precedence: "twc-ui" }, css) : null;
14
+ if (typeof document === "undefined") return;
15
+ if (!css) return;
16
+ let el = document.getElementById(id);
17
+ if (!el) {
18
+ el = document.createElement("style");
19
+ el.id = id;
20
+ if (nonce) {
21
+ el.setAttribute("nonce", nonce);
22
+ el.nonce = nonce;
23
+ }
24
+ document.head.appendChild(el);
25
+ }
26
+ if (el.textContent !== css) el.textContent = css;
27
+ }, [id, css, nonce]);
28
+ return SUPPORTS_STYLE_HOIST && css ? React37.createElement("style", { href: id, precedence: "twc-ui", nonce }, css) : null;
29
+ }
30
+
31
+ // components/TwicoProvider.jsx
32
+ function TwicoProvider({ nonce, children }) {
33
+ return React37__default.createElement(NonceContext.Provider, { value: nonce }, children);
34
+ }
35
+ var GROUPS = { colors: "color", space: "space", radius: "radius", font: "font", shadow: "shadow", motion: "" };
36
+ function createTheme(partial = {}) {
37
+ const vars = {};
38
+ for (const [group, prefix] of Object.entries(GROUPS)) {
39
+ const obj = partial[group];
40
+ if (!obj || typeof obj !== "object") continue;
41
+ for (const [key, value] of Object.entries(obj)) {
42
+ if (value == null) continue;
43
+ vars[`--${prefix ? `${prefix}-` : ""}${key}`] = String(value);
44
+ }
45
+ }
46
+ return vars;
47
+ }
48
+ function toVars(theme) {
49
+ if (!theme) return {};
50
+ return Object.keys(theme).some((k) => k.startsWith("--")) ? theme : createTheme(theme);
51
+ }
52
+ function ThemeProvider({ theme, mode = "inline", className = "", style, children, ...rest }) {
53
+ const vars = React37__default.useMemo(() => toVars(theme), [theme]);
54
+ const uid = React37__default.useId();
55
+ const scopeId = `twc-theme-${uid.replace(/[^a-zA-Z0-9]/g, "")}`;
56
+ const css = mode === "stylesheet" ? `[data-twc-theme="${scopeId}"] { ${Object.entries(vars).map(([k, v]) => `${k}: ${v};`).join(" ")} }` : "";
57
+ const __twcStyles = useScopedStyles(mode === "stylesheet" ? scopeId : "twc-theme-noop", css);
58
+ return /* @__PURE__ */ jsxs(
59
+ "div",
60
+ {
61
+ className: `twc-theme ${className}`.trim(),
62
+ "data-twc-theme": mode === "stylesheet" ? scopeId : void 0,
63
+ style: mode === "stylesheet" ? style : { ...vars, ...style },
64
+ ...rest,
65
+ children: [
66
+ mode === "stylesheet" ? __twcStyles : null,
67
+ children
68
+ ]
69
+ }
70
+ );
19
71
  }
72
+ var FORM_CSS = `
73
+ .twc-form { display: flex; flex-direction: column; gap: var(--space-4); font-family: var(--font-sans); }
74
+ .twc-form__fieldset { border: 0; margin: 0; padding: 0; min-width: 0; display: flex; flex-direction: column; gap: inherit; }
75
+ `;
76
+ var Form = React37__default.forwardRef(function Form2({
77
+ onSubmit,
78
+ preventDefault = true,
79
+ loading = false,
80
+ disabled = false,
81
+ gap,
82
+ className = "",
83
+ style,
84
+ children,
85
+ ...rest
86
+ }, ref) {
87
+ const __twcStyles = useScopedStyles("twc-form-styles", FORM_CSS);
88
+ const handleSubmit = (e) => {
89
+ if (preventDefault) e.preventDefault();
90
+ onSubmit?.(e);
91
+ };
92
+ return /* @__PURE__ */ jsxs(
93
+ "form",
94
+ {
95
+ ref,
96
+ className: `twc-form ${className}`.trim(),
97
+ onSubmit: handleSubmit,
98
+ style: gap != null ? { gap: `var(--space-${gap})`, ...style } : style,
99
+ ...rest,
100
+ children: [
101
+ __twcStyles,
102
+ /* @__PURE__ */ jsx("fieldset", { className: "twc-form__fieldset", disabled: loading || disabled || void 0, "aria-busy": loading || void 0, children })
103
+ ]
104
+ }
105
+ );
106
+ });
107
+ Form.displayName = "Form";
108
+ var VH_CSS = `
109
+ .twc-visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
110
+ `;
111
+ var VisuallyHidden = React37__default.forwardRef(function VisuallyHidden2({ as: Tag2 = "span", className = "", children, ...rest }, ref) {
112
+ const __twcStyles = useScopedStyles("twc-visually-hidden-styles", VH_CSS);
113
+ return /* @__PURE__ */ jsxs(Tag2, { ref, className: `twc-visually-hidden ${className}`.trim(), ...rest, children: [
114
+ __twcStyles,
115
+ children
116
+ ] });
117
+ });
118
+ VisuallyHidden.displayName = "VisuallyHidden";
119
+ var canUseDOM = typeof window !== "undefined" && typeof document !== "undefined";
120
+ var useIsoLayoutEffect = canUseDOM ? React37__default.useLayoutEffect : React37__default.useEffect;
121
+ 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"])';
122
+ function useFocusTrap(ref, active = true, { restoreFocus = true, initialFocus } = {}) {
123
+ React37__default.useEffect(() => {
124
+ if (!active || !canUseDOM) return void 0;
125
+ const node = ref.current;
126
+ if (!node) return void 0;
127
+ const prevFocused = document.activeElement;
128
+ const target = (typeof initialFocus === "function" ? initialFocus() : initialFocus && initialFocus.current) || node.querySelector(FOCUSABLE);
129
+ (target || node).focus();
130
+ return () => {
131
+ if (restoreFocus && prevFocused && typeof prevFocused.focus === "function") prevFocused.focus();
132
+ };
133
+ }, [active]);
134
+ React37__default.useEffect(() => {
135
+ if (!active || !canUseDOM) return void 0;
136
+ const node = ref.current;
137
+ const onKey = (e) => {
138
+ if (e.key !== "Tab" || !node) return;
139
+ const f = Array.from(node.querySelectorAll(FOCUSABLE)).filter((el) => el.offsetParent !== null);
140
+ if (!f.length) {
141
+ e.preventDefault();
142
+ node.focus();
143
+ return;
144
+ }
145
+ const first = f[0], last = f[f.length - 1], ae = document.activeElement;
146
+ if (e.shiftKey) {
147
+ if (ae === first || ae === node || !node.contains(ae)) {
148
+ e.preventDefault();
149
+ last.focus();
150
+ }
151
+ } else if (ae === last || !node.contains(ae)) {
152
+ e.preventDefault();
153
+ first.focus();
154
+ }
155
+ };
156
+ document.addEventListener("keydown", onKey);
157
+ return () => document.removeEventListener("keydown", onKey);
158
+ }, [active]);
159
+ }
160
+ function usePortal() {
161
+ return React37__default.useCallback((node) => {
162
+ if (typeof document === "undefined") return null;
163
+ return typeof createPortal === "function" ? createPortal(node, document.body) : node;
164
+ }, []);
165
+ }
166
+ var __scrollLockCount = 0;
167
+ var __scrollLockSaved = { overflow: "", paddingRight: "" };
168
+ function useScrollLock(locked = true) {
169
+ useIsoLayoutEffect(() => {
170
+ if (!canUseDOM || !locked) return void 0;
171
+ if (__scrollLockCount === 0) {
172
+ const b = document.body;
173
+ __scrollLockSaved = { overflow: b.style.overflow, paddingRight: b.style.paddingRight };
174
+ const gutter = window.innerWidth - document.documentElement.clientWidth;
175
+ b.style.overflow = "hidden";
176
+ if (gutter > 0) b.style.paddingRight = `${(parseFloat(getComputedStyle(b).paddingRight) || 0) + gutter}px`;
177
+ }
178
+ __scrollLockCount += 1;
179
+ return () => {
180
+ __scrollLockCount -= 1;
181
+ if (__scrollLockCount === 0) {
182
+ document.body.style.overflow = __scrollLockSaved.overflow;
183
+ document.body.style.paddingRight = __scrollLockSaved.paddingRight;
184
+ }
185
+ };
186
+ }, [locked]);
187
+ }
188
+ function useInertBackground(ref, active) {
189
+ React37__default.useEffect(() => {
190
+ if (!active || !canUseDOM) return void 0;
191
+ const node = ref.current;
192
+ if (!node) return void 0;
193
+ const changed = [];
194
+ Array.from(document.body.children).forEach((el) => {
195
+ if (el.contains(node) || el.hasAttribute("aria-hidden") || el.inert) return;
196
+ el.inert = true;
197
+ el.setAttribute("aria-hidden", "true");
198
+ changed.push(el);
199
+ });
200
+ return () => {
201
+ changed.forEach((el) => {
202
+ el.inert = false;
203
+ el.removeAttribute("aria-hidden");
204
+ });
205
+ };
206
+ }, [active]);
207
+ }
208
+
209
+ // components/layout/Portal.jsx
210
+ function Portal({ children }) {
211
+ const render = usePortal();
212
+ return render(children);
213
+ }
214
+ function getColorSchemeScript({ storageKey = "twico-theme", attribute = "class", defaultScheme } = {}) {
215
+ const k = JSON.stringify(storageKey);
216
+ const a = JSON.stringify(attribute);
217
+ const d = defaultScheme === "dark" || defaultScheme === "light" ? JSON.stringify(defaultScheme) : "null";
218
+ return `(function(){try{var k=${k},a=${a},d=${d},t=localStorage.getItem(k);if(t!=='light'){if(t!=='dark'){t=d?d:(window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light');}}if(a==='class'){document.documentElement.classList.toggle('dark',t==='dark');}else{document.documentElement.setAttribute(a,t);}}catch(e){}})();`;
219
+ }
220
+ function ColorSchemeScript({ storageKey = "twico-theme", attribute = "class", nonce, defaultScheme }) {
221
+ return React37__default.createElement("script", { nonce }, getColorSchemeScript({ storageKey, attribute, defaultScheme }));
222
+ }
223
+ var KBD_CSS = `
224
+ .twc-kbd { display: inline-flex; align-items: center; justify-content: center; min-width: 20px; padding: 2px 6px;
225
+ font-family: var(--font-mono); font-size: 11px; font-weight: var(--font-semibold); line-height: 1; color: var(--color-text-muted);
226
+ background: var(--color-surface-sunken); border: var(--border-thin) solid var(--color-border);
227
+ border-bottom-width: 2px; border-radius: var(--radius-sm); }
228
+ `;
229
+ var Kbd = React37__default.forwardRef(function Kbd2({ className = "", children, ...rest }, ref) {
230
+ const __twcStyles = useScopedStyles("twc-kbd-styles", KBD_CSS);
231
+ return /* @__PURE__ */ jsxs("kbd", { ref, className: `twc-kbd ${className}`.trim(), ...rest, children: [
232
+ __twcStyles,
233
+ children
234
+ ] });
235
+ });
236
+ Kbd.displayName = "Kbd";
237
+ var PRE_CSS = `
238
+ .twc-pre { margin: 0; padding: var(--space-4); overflow-x: auto; max-width: 100%;
239
+ font-family: var(--font-mono); font-size: var(--text-sm); line-height: var(--leading-normal);
240
+ color: var(--color-text); background: var(--color-surface-sunken);
241
+ border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-lg);
242
+ white-space: pre; -webkit-overflow-scrolling: touch; }
243
+ `;
244
+ var Pre = React37__default.forwardRef(function Pre2({ className = "", children, ...rest }, ref) {
245
+ const __twcStyles = useScopedStyles("twc-pre-styles", PRE_CSS);
246
+ return /* @__PURE__ */ jsxs("pre", { ref, className: `twc-pre ${className}`.trim(), ...rest, children: [
247
+ __twcStyles,
248
+ children
249
+ ] });
250
+ });
251
+ Pre.displayName = "Pre";
252
+ var ANCHOR_CSS = `
253
+ .twc-anchor { color: var(--color-primary); text-decoration: none; border-radius: var(--radius-sm);
254
+ transition: color var(--duration-fast) var(--ease-standard); }
255
+ .twc-anchor:hover { text-decoration: underline; color: var(--color-primary-hover, var(--color-primary)); }
256
+ .twc-anchor:focus-visible { outline: none; box-shadow: var(--ring); }
257
+ .twc-anchor__ext { display: inline-block; margin-inline-start: 3px; font-size: 0.85em; vertical-align: baseline; }
258
+ `;
259
+ function safeHref(url) {
260
+ if (url == null) return void 0;
261
+ const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
262
+ return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
263
+ }
264
+ var Anchor = React37__default.forwardRef(function Anchor2({ as: Tag2 = "a", href, external = false, className = "", children, ...rest }, ref) {
265
+ const __twcStyles = useScopedStyles("twc-anchor-styles", ANCHOR_CSS);
266
+ const extra = external ? { target: "_blank", rel: "noopener noreferrer" } : {};
267
+ return /* @__PURE__ */ jsxs(Tag2, { ref, className: `twc-anchor ${className}`.trim(), href: Tag2 === "a" ? safeHref(href) : href, ...extra, ...rest, children: [
268
+ __twcStyles,
269
+ children,
270
+ external ? /* @__PURE__ */ jsx("span", { className: "twc-anchor__ext", "aria-hidden": "true", children: "\u2197" }) : null
271
+ ] });
272
+ });
273
+ Anchor.displayName = "Anchor";
274
+ var LABEL_CSS = `
275
+ .twc-label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); display: inline-flex; gap: 4px; align-items: center; }
276
+ .twc-label[data-size="sm"] { font-size: var(--text-xs); }
277
+ .twc-label[data-size="lg"] { font-size: var(--text-base); }
278
+ .twc-label__req { color: var(--color-danger); }
279
+ `;
280
+ var Label = React37__default.forwardRef(function Label2({ htmlFor, required = false, size = "md", className = "", children, ...rest }, ref) {
281
+ const __twcStyles = useScopedStyles("twc-label-styles", LABEL_CSS);
282
+ return /* @__PURE__ */ jsxs("label", { ref, htmlFor, className: `twc-label ${className}`.trim(), "data-size": size, ...rest, children: [
283
+ __twcStyles,
284
+ children,
285
+ required ? /* @__PURE__ */ jsx("span", { className: "twc-label__req", "aria-hidden": "true", children: "*" }) : null
286
+ ] });
287
+ });
288
+ Label.displayName = "Label";
289
+ var IMAGE_CSS = `
290
+ .twc-image { display: block; max-width: 100%; }
291
+ .twc-image[data-fit] { width: 100%; height: 100%; }
292
+ `;
293
+ var Image = React37__default.forwardRef(function Image2({
294
+ src,
295
+ alt,
296
+ fit,
297
+ radius,
298
+ aspectRatio,
299
+ fallback,
300
+ loading = "lazy",
301
+ className = "",
302
+ style,
303
+ onError,
304
+ ...rest
305
+ }, ref) {
306
+ const __twcStyles = useScopedStyles("twc-image-styles", IMAGE_CSS);
307
+ const [failed, setFailed] = React37__default.useState(false);
308
+ const shownSrc = failed && fallback ? fallback : src;
309
+ const s = {
310
+ objectFit: fit,
311
+ borderRadius: radius ? `var(--radius-${radius})` : void 0,
312
+ aspectRatio,
313
+ ...style
314
+ };
315
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
316
+ __twcStyles,
317
+ /* @__PURE__ */ jsx(
318
+ "img",
319
+ {
320
+ ref,
321
+ src: shownSrc,
322
+ alt,
323
+ loading,
324
+ className: `twc-image ${className}`.trim(),
325
+ "data-fit": fit || void 0,
326
+ style: s,
327
+ onError: (e) => {
328
+ onError?.(e);
329
+ if (fallback && !failed) setFailed(true);
330
+ },
331
+ ...rest
332
+ }
333
+ )
334
+ ] });
335
+ });
336
+ Image.displayName = "Image";
20
337
  var ACCORDION_CSS = `
21
338
  .twc-accordion { display: flex; flex-direction: column; font-family: var(--font-sans);
22
339
  border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-lg); overflow: hidden; background: var(--color-surface); }
@@ -56,10 +373,10 @@ function Accordion({
56
373
  ...rest
57
374
  }) {
58
375
  const __twcStyles = useScopedStyles("twc-accordion-styles", ACCORDION_CSS);
59
- const rootRef = React25__default.useRef(null);
60
- const [internal, setInternal] = React25__default.useState(() => new Set(defaultOpen));
376
+ const rootRef = React37__default.useRef(null);
377
+ const [internal, setInternal] = React37__default.useState(() => new Set(defaultOpen));
61
378
  const open = openProp !== void 0 ? new Set(openProp) : internal;
62
- const baseId = React25__default.useId();
379
+ const baseId = React37__default.useId();
63
380
  function toggle(val) {
64
381
  const item = items.find((x) => x.value === val);
65
382
  if (item?.disabled) return;
@@ -106,9 +423,9 @@ function Accordion({
106
423
  const triggerId = `${baseId}-trigger-${i}`;
107
424
  const panelId = `${baseId}-panel-${i}`;
108
425
  const lvl = Math.min(6, Math.max(1, it.headingLevel ?? headingLevel));
109
- const Heading2 = `h${lvl}`;
426
+ const Heading3 = `h${lvl}`;
110
427
  return /* @__PURE__ */ jsxs("div", { className: "twc-accordion__item", children: [
111
- /* @__PURE__ */ jsx(Heading2, { className: "twc-accordion__heading", children: /* @__PURE__ */ jsxs("button", { type: "button", id: triggerId, className: "twc-accordion__trigger", "data-open": isOpen || void 0, disabled: it.disabled || void 0, "aria-disabled": it.disabled || void 0, "data-disabled": it.disabled || void 0, "aria-expanded": isOpen, "aria-controls": panelId, onClick: () => toggle(it.value), children: [
428
+ /* @__PURE__ */ jsx(Heading3, { className: "twc-accordion__heading", children: /* @__PURE__ */ jsxs("button", { type: "button", id: triggerId, className: "twc-accordion__trigger", "data-open": isOpen || void 0, disabled: it.disabled || void 0, "aria-disabled": it.disabled || void 0, "data-disabled": it.disabled || void 0, "aria-expanded": isOpen, "aria-controls": panelId, onClick: () => toggle(it.value), children: [
112
429
  it.icon,
113
430
  /* @__PURE__ */ jsx("span", { className: "twc-accordion__label", children: it.label }),
114
431
  /* @__PURE__ */ jsx("span", { className: "twc-accordion__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" }) }) })
@@ -245,7 +562,7 @@ function Avatar({
245
562
  ...rest
246
563
  }) {
247
564
  const __twcStyles = useScopedStyles("twc-avatar-styles", AVATAR_CSS);
248
- const [errored, setErrored] = React25__default.useState(false);
565
+ const [errored, setErrored] = React37__default.useState(false);
249
566
  const cleanSrc = safeSrc(src);
250
567
  const showImg = cleanSrc && !errored;
251
568
  const _statusLabel = status ? statusLabel ?? statusLabels?.[status] ?? STATUS_LABELS[status] : void 0;
@@ -303,7 +620,7 @@ var MENU_CSS = `
303
620
  .twc-menu__item-label { flex: 1 1 auto; min-width: 0; }
304
621
  .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); }
305
622
  `;
306
- var safeHref = (url) => {
623
+ var safeHref2 = (url) => {
307
624
  if (url == null) return void 0;
308
625
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
309
626
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -323,25 +640,25 @@ function Menu({
323
640
  ...rest
324
641
  }) {
325
642
  const __twcStyles = useScopedStyles("twc-menu-styles", MENU_CSS);
326
- const [openState, setOpenState] = React25__default.useState(defaultOpen);
327
- const [render, setRender] = React25__default.useState(false);
328
- const [pos, setPos] = React25__default.useState(null);
329
- const [active, setActive] = React25__default.useState(-1);
330
- const wrapRef = React25__default.useRef(null);
331
- const menuRef = React25__default.useRef(null);
332
- const typeBufRef = React25__default.useRef("");
333
- const typeTimerRef = React25__default.useRef(null);
334
- const menuId = React25__default.useId();
643
+ const [openState, setOpenState] = React37__default.useState(defaultOpen);
644
+ const [render, setRender] = React37__default.useState(false);
645
+ const [pos, setPos] = React37__default.useState(null);
646
+ const [active, setActive] = React37__default.useState(-1);
647
+ const wrapRef = React37__default.useRef(null);
648
+ const menuRef = React37__default.useRef(null);
649
+ const typeBufRef = React37__default.useRef("");
650
+ const typeTimerRef = React37__default.useRef(null);
651
+ const menuId = React37__default.useId();
335
652
  const headerId = `${menuId}-header`;
336
653
  const controlled = openProp !== void 0;
337
654
  const open = controlled ? !!openProp : openState;
338
- const openRef = React25__default.useRef(open);
655
+ const openRef = React37__default.useRef(open);
339
656
  openRef.current = open;
340
- const controlledRef = React25__default.useRef(controlled);
657
+ const controlledRef = React37__default.useRef(controlled);
341
658
  controlledRef.current = controlled;
342
- const onOpenChangeRef = React25__default.useRef(onOpenChange);
659
+ const onOpenChangeRef = React37__default.useRef(onOpenChange);
343
660
  onOpenChangeRef.current = onOpenChange;
344
- const setOpen = React25__default.useCallback((next) => {
661
+ const setOpen = React37__default.useCallback((next) => {
345
662
  const value = typeof next === "function" ? next(openRef.current) : next;
346
663
  if (value === openRef.current) return;
347
664
  if (!controlledRef.current) setOpenState(value);
@@ -349,7 +666,7 @@ function Menu({
349
666
  }, []);
350
667
  const RD = { createPortal: typeof createPortal === "function" ? createPortal : typeof window !== "undefined" && window.ReactDOM && window.ReactDOM.createPortal };
351
668
  const interactiveIdx = items.map((it, i) => !it.separator && !it.heading ? i : -1).filter((i) => i >= 0);
352
- const place = React25__default.useCallback(() => {
669
+ const place = React37__default.useCallback(() => {
353
670
  const t = wrapRef.current;
354
671
  if (!t) return;
355
672
  const r = t.getBoundingClientRect();
@@ -364,7 +681,7 @@ function Menu({
364
681
  const avail = (flip ? r.top : vh - r.bottom) - gap - M;
365
682
  setPos({ top, bottom, left, width: w, flip, maxHeight: Math.max(120, avail) });
366
683
  }, [align, width]);
367
- React25__default.useEffect(() => {
684
+ React37__default.useEffect(() => {
368
685
  if (!open) return;
369
686
  place();
370
687
  const onMove = () => place();
@@ -382,7 +699,7 @@ function Menu({
382
699
  document.removeEventListener("mousedown", onDown);
383
700
  };
384
701
  }, [open, place]);
385
- React25__default.useEffect(() => {
702
+ React37__default.useEffect(() => {
386
703
  if (open) {
387
704
  setRender(true);
388
705
  return;
@@ -475,7 +792,7 @@ function Menu({
475
792
  items.map((it, i) => {
476
793
  if (it.separator) return /* @__PURE__ */ jsx("div", { className: "twc-menu__sep", role: "separator" }, `s${i}`);
477
794
  if (it.label && it.heading) return /* @__PURE__ */ jsx("div", { className: "twc-menu__label", children: it.label }, `h${i}`);
478
- const href = !it.disabled ? safeHref(it.href) : void 0;
795
+ const href = !it.disabled ? safeHref2(it.href) : void 0;
479
796
  const Tag2 = href ? "a" : "button";
480
797
  return /* @__PURE__ */ jsxs(
481
798
  Tag2,
@@ -505,7 +822,7 @@ function Menu({
505
822
  }
506
823
  ) : null;
507
824
  const activeDescId = open && active >= 0 ? `${menuId}-item-${active}` : void 0;
508
- const triggerEl = React25__default.isValidElement(trigger) ? React25__default.cloneElement(trigger, {
825
+ const triggerEl = React37__default.isValidElement(trigger) ? React37__default.cloneElement(trigger, {
509
826
  onClick: (e) => {
510
827
  trigger.props.onClick?.(e);
511
828
  toggle();
@@ -656,7 +973,7 @@ a.twc-breadcrumb__item:hover, button.twc-breadcrumb__item:hover { color: var(--c
656
973
  .twc-breadcrumb__ellipsis { border: none; background: transparent; cursor: pointer; color: var(--color-text-subtle); padding: 3px 7px; border-radius: var(--radius-sm); font: inherit; }
657
974
  .twc-breadcrumb__ellipsis:hover { background: var(--color-surface-sunken); color: var(--color-text); }
658
975
  `;
659
- function safeHref2(url) {
976
+ function safeHref3(url) {
660
977
  if (url == null) return void 0;
661
978
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
662
979
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -670,7 +987,7 @@ function Breadcrumb({
670
987
  ...rest
671
988
  }) {
672
989
  const __twcStyles = useScopedStyles("twc-breadcrumb-styles", BREADCRUMB_CSS);
673
- const [expanded, setExpanded] = React25__default.useState(false);
990
+ const [expanded, setExpanded] = React37__default.useState(false);
674
991
  const sep = separator || /* @__PURE__ */ jsx(ChevronSep, {});
675
992
  let display = items;
676
993
  if (maxItems > 0 && items.length > maxItems && !expanded) {
@@ -683,7 +1000,7 @@ function Breadcrumb({
683
1000
  __twcStyles,
684
1001
  display.map((it, i) => {
685
1002
  const last = i === display.length - 1;
686
- return /* @__PURE__ */ jsxs(React25__default.Fragment, { children: [
1003
+ return /* @__PURE__ */ jsxs(React37__default.Fragment, { children: [
687
1004
  it.ellipsis ? /* @__PURE__ */ jsx("button", { className: "twc-breadcrumb__ellipsis", "aria-label": "Show more", onClick: () => setExpanded(true), children: "\u2026" }) : last ? /* @__PURE__ */ jsxs(
688
1005
  "span",
689
1006
  {
@@ -695,7 +1012,7 @@ function Breadcrumb({
695
1012
  it.label
696
1013
  ]
697
1014
  }
698
- ) : safeHref2(it.href) ? /* @__PURE__ */ jsxs("a", { className: "twc-breadcrumb__item", href: safeHref2(it.href), onClick: it.onClick, children: [
1015
+ ) : safeHref3(it.href) ? /* @__PURE__ */ jsxs("a", { className: "twc-breadcrumb__item", href: safeHref3(it.href), onClick: it.onClick, children: [
699
1016
  it.icon ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { display: "inline-flex" }, children: it.icon }) : null,
700
1017
  it.label
701
1018
  ] }) : it.onClick ? /* @__PURE__ */ jsxs("button", { type: "button", className: "twc-breadcrumb__item", onClick: it.onClick, children: [
@@ -803,7 +1120,7 @@ var CSS2 = `
803
1120
  animation: twico-ripple var(--duration-slow) var(--ease-out) forwards;
804
1121
  }
805
1122
  `;
806
- function safeHref3(url) {
1123
+ function safeHref4(url) {
807
1124
  if (url == null) return void 0;
808
1125
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
809
1126
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -825,7 +1142,7 @@ function Button({
825
1142
  ...rest
826
1143
  }) {
827
1144
  const __twcStyles = useScopedStyles("twc-btn-styles", CSS2);
828
- const [ripples, setRipples] = React25__default.useState([]);
1145
+ const [ripples, setRipples] = React37__default.useState([]);
829
1146
  const Tag2 = as;
830
1147
  const inert = Tag2 === "a" && (disabled || loading);
831
1148
  function handleClick(e) {
@@ -854,7 +1171,7 @@ function Button({
854
1171
  "data-block": fullWidth || void 0,
855
1172
  disabled: Tag2 === "button" ? disabled || loading : void 0,
856
1173
  type: Tag2 === "button" ? "button" : void 0,
857
- href: inert ? void 0 : safeHref3(href),
1174
+ href: inert ? void 0 : safeHref4(href),
858
1175
  "aria-disabled": inert || void 0,
859
1176
  tabIndex: inert ? -1 : void 0,
860
1177
  "aria-busy": loading || void 0,
@@ -880,6 +1197,122 @@ function Button({
880
1197
  }
881
1198
  );
882
1199
  }
1200
+ var UNITLESS = /* @__PURE__ */ new Set([
1201
+ "animationIterationCount",
1202
+ "aspectRatio",
1203
+ "borderImageOutset",
1204
+ "borderImageSlice",
1205
+ "borderImageWidth",
1206
+ "boxFlex",
1207
+ "boxFlexGroup",
1208
+ "boxOrdinalGroup",
1209
+ "columnCount",
1210
+ "columns",
1211
+ "flex",
1212
+ "flexGrow",
1213
+ "flexShrink",
1214
+ "flexPositive",
1215
+ "flexNegative",
1216
+ "flexOrder",
1217
+ "gridArea",
1218
+ "gridRow",
1219
+ "gridRowEnd",
1220
+ "gridRowSpan",
1221
+ "gridRowStart",
1222
+ "gridColumn",
1223
+ "gridColumnEnd",
1224
+ "gridColumnSpan",
1225
+ "gridColumnStart",
1226
+ "fontWeight",
1227
+ "lineClamp",
1228
+ "lineHeight",
1229
+ "opacity",
1230
+ "order",
1231
+ "orphans",
1232
+ "tabSize",
1233
+ "widows",
1234
+ "zIndex",
1235
+ "zoom",
1236
+ "fillOpacity",
1237
+ "floodOpacity",
1238
+ "stopOpacity",
1239
+ "strokeDasharray",
1240
+ "strokeDashoffset",
1241
+ "strokeMiterlimit",
1242
+ "strokeOpacity",
1243
+ "strokeWidth",
1244
+ "scale"
1245
+ ]);
1246
+ var isObject = (v) => v != null && typeof v === "object" && !Array.isArray(v);
1247
+ var isNestedKey = (k, v) => isObject(v) || k.charCodeAt(0) === 38 || k.charCodeAt(0) === 64 || k.charCodeAt(0) === 58;
1248
+ function kebab(prop) {
1249
+ if (prop.startsWith("--")) return prop;
1250
+ return prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
1251
+ }
1252
+ function cssValue(key, value) {
1253
+ if (typeof value !== "number") return String(value);
1254
+ if (value === 0 || key.startsWith("--") || UNITLESS.has(key)) return String(value);
1255
+ return `${value}px`;
1256
+ }
1257
+ function resolveSelector(key, scope) {
1258
+ if (key.includes("&")) return key.replace(/&/g, scope);
1259
+ if (key.charCodeAt(0) === 58) return `${scope}${key}`;
1260
+ return `${scope} ${key}`;
1261
+ }
1262
+ function compileSx(obj, selector) {
1263
+ if (!isObject(obj)) return "";
1264
+ let decls = "";
1265
+ let rules = "";
1266
+ for (const key of Object.keys(obj)) {
1267
+ const value = obj[key];
1268
+ if (isNestedKey(key, value)) {
1269
+ if (!isObject(value)) continue;
1270
+ if (key.charCodeAt(0) === 64) {
1271
+ const inner = compileSx(value, selector);
1272
+ if (inner) rules += `${key} { ${inner.trim()} }
1273
+ `;
1274
+ } else {
1275
+ rules += compileSx(value, resolveSelector(key, selector));
1276
+ }
1277
+ } else {
1278
+ decls += `${kebab(key)}: ${cssValue(key, value)}; `;
1279
+ }
1280
+ }
1281
+ let out = "";
1282
+ if (decls) out += `${selector} { ${decls.trimEnd()} }
1283
+ `;
1284
+ out += rules;
1285
+ return out;
1286
+ }
1287
+ function buildSx(sx, uid) {
1288
+ if (!isObject(sx)) return { flatStyle: void 0, css: "" };
1289
+ const scope = `[data-twc-sx="${uid}"]`;
1290
+ let flatStyle;
1291
+ let css = "";
1292
+ for (const key of Object.keys(sx)) {
1293
+ const value = sx[key];
1294
+ if (isNestedKey(key, value)) {
1295
+ if (!isObject(value)) continue;
1296
+ if (key.charCodeAt(0) === 64) {
1297
+ const inner = compileSx(value, scope);
1298
+ if (inner) css += `${key} { ${inner.trim()} }
1299
+ `;
1300
+ } else {
1301
+ css += compileSx(value, resolveSelector(key, scope));
1302
+ }
1303
+ } else {
1304
+ (flatStyle || (flatStyle = {}))[key] = value;
1305
+ }
1306
+ }
1307
+ return { flatStyle, css };
1308
+ }
1309
+ function useSx(sx) {
1310
+ const rawId = React37__default.useId();
1311
+ const uid = `sx${rawId.replace(/[^a-zA-Z0-9]/g, "")}`;
1312
+ const { flatStyle, css } = React37__default.useMemo(() => buildSx(sx, uid), [sx, uid]);
1313
+ const styleNode = useScopedStyles(`twc-sx-${uid}`, css);
1314
+ return { flatStyle, styleNode, sxAttr: css ? uid : void 0 };
1315
+ }
883
1316
  var CARD_CSS = `
884
1317
  .twc-card {
885
1318
  display: flex; flex-direction: column;
@@ -919,10 +1352,13 @@ function Card({
919
1352
  padding = "md",
920
1353
  interactive = false,
921
1354
  fullHeight = false,
1355
+ sx,
922
1356
  className = "",
1357
+ style,
923
1358
  ...rest
924
1359
  }) {
925
1360
  const __twcStyles = useScopedStyles("twc-card-styles", CARD_CSS);
1361
+ const { flatStyle, styleNode, sxAttr } = useSx(sx);
926
1362
  return /* @__PURE__ */ jsxs(
927
1363
  "div",
928
1364
  {
@@ -931,9 +1367,12 @@ function Card({
931
1367
  "data-pad": padding,
932
1368
  "data-interactive": interactive || void 0,
933
1369
  "data-full": fullHeight || void 0,
1370
+ "data-twc-sx": sxAttr,
1371
+ style: style || flatStyle ? { ...style, ...flatStyle } : void 0,
934
1372
  ...rest,
935
1373
  children: [
936
1374
  __twcStyles,
1375
+ styleNode,
937
1376
  title || subtitle || actions ? /* @__PURE__ */ jsxs("div", { className: "twc-card__header", children: [
938
1377
  /* @__PURE__ */ jsxs("div", { className: "twc-card__heading", children: [
939
1378
  title ? /* @__PURE__ */ jsx("div", { className: "twc-card__title", children: title }) : null,
@@ -999,14 +1438,14 @@ function Carousel({
999
1438
  ...rest
1000
1439
  }) {
1001
1440
  const __twcStyles = useScopedStyles("twc-carousel-styles", CAROUSEL_CSS);
1002
- const slides = React25__default.Children.toArray(children);
1441
+ const slides = React37__default.Children.toArray(children);
1003
1442
  const count = slides.length;
1004
- const [internal, setInternal] = React25__default.useState(defaultIndex);
1443
+ const [internal, setInternal] = React37__default.useState(defaultIndex);
1005
1444
  const index = indexProp !== void 0 ? indexProp : internal;
1006
- const [paused, setPaused] = React25__default.useState(false);
1007
- const [userPaused, setUserPaused] = React25__default.useState(false);
1008
- const [prefersReduced, setPrefersReduced] = React25__default.useState(false);
1009
- React25__default.useEffect(() => {
1445
+ const [paused, setPaused] = React37__default.useState(false);
1446
+ const [userPaused, setUserPaused] = React37__default.useState(false);
1447
+ const [prefersReduced, setPrefersReduced] = React37__default.useState(false);
1448
+ React37__default.useEffect(() => {
1010
1449
  if (typeof window === "undefined" || !window.matchMedia) return void 0;
1011
1450
  const mql = window.matchMedia("(prefers-reduced-motion: reduce)");
1012
1451
  const on = () => setPrefersReduced(mql.matches);
@@ -1014,15 +1453,15 @@ function Carousel({
1014
1453
  mql.addEventListener("change", on);
1015
1454
  return () => mql.removeEventListener("change", on);
1016
1455
  }, []);
1017
- const setIndex = React25__default.useCallback((i) => {
1456
+ const setIndex = React37__default.useCallback((i) => {
1018
1457
  if (indexProp === void 0) setInternal(i);
1019
1458
  onIndexChange?.(i);
1020
1459
  }, [indexProp, onIndexChange]);
1021
- const go = React25__default.useCallback((i) => {
1460
+ const go = React37__default.useCallback((i) => {
1022
1461
  setIndex(loop ? (i + count) % count : Math.min(Math.max(i, 0), count - 1));
1023
1462
  }, [count, loop, setIndex]);
1024
1463
  const autoRotating = autoPlay && !paused && !userPaused && !prefersReduced && count > 1;
1025
- React25__default.useEffect(() => {
1464
+ React37__default.useEffect(() => {
1026
1465
  if (!autoRotating) return void 0;
1027
1466
  const t = setInterval(() => {
1028
1467
  const next = loop ? (index + 1) % count : index + 1 >= count ? index : index + 1;
@@ -1117,7 +1556,7 @@ function Chart({
1117
1556
  ...rest
1118
1557
  }) {
1119
1558
  const __twcStyles = useScopedStyles("twc-chart-styles", CHART_CSS);
1120
- const uid = React25__default.useId();
1559
+ const uid = React37__default.useId();
1121
1560
  const tableId = tableFallback ? `${uid}-table` : void 0;
1122
1561
  const keys = series || ["value"];
1123
1562
  const palette = colors && colors.length ? colors : SERIES_COLORS;
@@ -1273,13 +1712,13 @@ function Checkbox({
1273
1712
  .twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
1274
1713
  .twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
1275
1714
  `);
1276
- const autoId = React25__default.useId();
1715
+ const autoId = React37__default.useId();
1277
1716
  const fieldId = id || autoId;
1278
1717
  const errId = `${fieldId}-error`;
1279
1718
  const invalid = Boolean(error);
1280
- const ref = React25__default.useRef(null);
1719
+ const ref = React37__default.useRef(null);
1281
1720
  const mixed = indeterminate && !checked;
1282
- React25__default.useEffect(() => {
1721
+ React37__default.useEffect(() => {
1283
1722
  if (ref.current) ref.current.indeterminate = mixed;
1284
1723
  }, [mixed]);
1285
1724
  if (process.env.NODE_ENV !== "production" && !label && !description && !rest["aria-label"] && !rest["aria-labelledby"]) {
@@ -1352,6 +1791,10 @@ var COLORPICKER_CSS = `
1352
1791
  .twc-cp__hue { position: relative; height: 12px; margin-top: var(--space-3); border-radius: var(--radius-full); cursor: pointer; touch-action: none;
1353
1792
  background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%); }
1354
1793
  .twc-cp__hue-knob { position: absolute; top: 50%; width: 16px; height: 16px; border-radius: var(--radius-full); background: #fff; box-shadow: var(--shadow-sm), inset 0 0 0 1px rgb(0 0 0 / 0.2); transform: translate(-50%, -50%); pointer-events: none; }
1794
+ .twc-cp__alpha { position: relative; height: 12px; margin-top: var(--space-2); border-radius: var(--radius-full); cursor: pointer; touch-action: none;
1795
+ background-image: linear-gradient(to right, transparent, var(--_solid, #000)), conic-gradient(#c8c8c8 0 25%, #fff 0 50%, #c8c8c8 0 75%, #fff 0);
1796
+ background-size: 100% 100%, 10px 10px; }
1797
+ .twc-cp__alpha:focus-visible { outline: none; box-shadow: var(--ring); }
1355
1798
  .twc-cp__foot { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-3); }
1356
1799
  .twc-cp__hex { flex: 1; min-width: 0; height: 32px; padding: 0 8px; font-family: var(--font-mono); font-size: var(--text-xs); text-transform: uppercase;
1357
1800
  color: var(--color-text); background: var(--color-surface); border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-sm); outline: none; }
@@ -1389,11 +1832,17 @@ function rgbToHex(r, g, b) {
1389
1832
  function hsvToHex(h, s, v) {
1390
1833
  return rgbToHex(...hsvToRgb(h, s, v));
1391
1834
  }
1835
+ function hsvaToHex8(h, s, v, a) {
1836
+ return rgbToHex(...hsvToRgb(h, s, v)) + Math.round(Math.min(1, Math.max(0, a)) * 255).toString(16).padStart(2, "0");
1837
+ }
1392
1838
  function hexToHsv(hex) {
1393
- const m = /^#?([0-9a-f]{6})$/i.exec(hex || "");
1839
+ let str = String(hex || "").replace(/^#/, "");
1840
+ if (/^[0-9a-f]{3}$/i.test(str)) str = str.split("").map((c) => c + c).join("");
1841
+ const m = /^([0-9a-f]{6})([0-9a-f]{2})?$/i.exec(str);
1394
1842
  if (!m) return null;
1395
1843
  const int = parseInt(m[1], 16);
1396
1844
  const r = (int >> 16) / 255, g = (int >> 8 & 255) / 255, b = (int & 255) / 255;
1845
+ const a = m[2] != null ? parseInt(m[2], 16) / 255 : 1;
1397
1846
  const max = Math.max(r, g, b), min = Math.min(r, g, b), d = max - min;
1398
1847
  let h = 0;
1399
1848
  if (d) {
@@ -1403,7 +1852,7 @@ function hexToHsv(hex) {
1403
1852
  h *= 60;
1404
1853
  if (h < 0) h += 360;
1405
1854
  }
1406
- return { h, s: max ? d / max * 100 : 0, v: max * 100 };
1855
+ return { h, s: max ? d / max * 100 : 0, v: max * 100, a };
1407
1856
  }
1408
1857
  var DEFAULT_PRESETS = ["#6366F1", "#0EA5E9", "#14B8A6", "#22C55E", "#F59E0B", "#F43F5E", "#8B5CF6", "#0F172A"];
1409
1858
  function ColorPicker({
@@ -1415,6 +1864,7 @@ function ColorPicker({
1415
1864
  defaultValue = "#6366F1",
1416
1865
  presets = DEFAULT_PRESETS,
1417
1866
  disabled = false,
1867
+ alpha = false,
1418
1868
  tone = "primary",
1419
1869
  onChange,
1420
1870
  className = "",
@@ -1422,20 +1872,22 @@ function ColorPicker({
1422
1872
  }) {
1423
1873
  const __twcStyles0 = useScopedStyles("twc-field-styles", FIELD_CSS);
1424
1874
  const __twcStyles1 = useScopedStyles("twc-colorpicker-styles", COLORPICKER_CSS);
1425
- const [internal, setInternal] = React25__default.useState(defaultValue);
1875
+ const [internal, setInternal] = React37__default.useState(defaultValue);
1426
1876
  const hex = (value !== void 0 ? value : internal) || "#000000";
1427
- const lastValidRef = React25__default.useRef(hex);
1428
- if (/^#[0-9a-f]{6}$/i.test(hex)) lastValidRef.current = hex;
1429
- const [open, setOpen] = React25__default.useState(false);
1430
- const [hsv, setHsv] = React25__default.useState(() => hexToHsv(hex) || { h: 239, s: 60, v: 94 });
1431
- const [coords, setCoords] = React25__default.useState(null);
1432
- const wrapRef = React25__default.useRef(null);
1433
- const triggerRef = React25__default.useRef(null);
1434
- const popRef = React25__default.useRef(null);
1435
- const areaRef = React25__default.useRef(null);
1436
- const hueRef = React25__default.useRef(null);
1877
+ const hexRe = alpha ? /^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i : /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
1878
+ const lastValidRef = React37__default.useRef(hex);
1879
+ if (hexRe.test(hex)) lastValidRef.current = hex;
1880
+ const [open, setOpen] = React37__default.useState(false);
1881
+ const [hsv, setHsv] = React37__default.useState(() => hexToHsv(hex) || { h: 239, s: 60, v: 94, a: 1 });
1882
+ const [coords, setCoords] = React37__default.useState(null);
1883
+ const wrapRef = React37__default.useRef(null);
1884
+ const triggerRef = React37__default.useRef(null);
1885
+ const popRef = React37__default.useRef(null);
1886
+ const areaRef = React37__default.useRef(null);
1887
+ const hueRef = React37__default.useRef(null);
1888
+ const alphaRef = React37__default.useRef(null);
1437
1889
  const POP_W = 240;
1438
- const place = React25__default.useCallback(() => {
1890
+ const place = React37__default.useCallback(() => {
1439
1891
  const el = triggerRef.current;
1440
1892
  if (!el) return;
1441
1893
  const r = el.getBoundingClientRect();
@@ -1446,7 +1898,7 @@ function ColorPicker({
1446
1898
  left = Math.max(8, left);
1447
1899
  setCoords({ left, top: flip ? void 0 : Math.round(r.bottom + 6), bottom: flip ? Math.round(vh - r.top + 6) : void 0 });
1448
1900
  }, []);
1449
- React25__default.useEffect(() => {
1901
+ React37__default.useEffect(() => {
1450
1902
  if (!open) return void 0;
1451
1903
  place();
1452
1904
  const onMove = () => place();
@@ -1457,17 +1909,17 @@ function ColorPicker({
1457
1909
  window.removeEventListener("resize", onMove);
1458
1910
  };
1459
1911
  }, [open, place]);
1460
- const labelId = React25__default.useId();
1912
+ const labelId = React37__default.useId();
1461
1913
  const descId = `${labelId}-desc`;
1462
1914
  const invalid = Boolean(error);
1463
- React25__default.useEffect(() => {
1915
+ React37__default.useEffect(() => {
1464
1916
  if (disabled) setOpen(false);
1465
1917
  }, [disabled]);
1466
- React25__default.useEffect(() => {
1918
+ React37__default.useEffect(() => {
1467
1919
  const v = hexToHsv(hex);
1468
1920
  if (v && hsvToHex(v.h, v.s, v.v).toLowerCase() !== hsvToHex(hsv.h, hsv.s, hsv.v).toLowerCase()) setHsv(v);
1469
1921
  }, [hex]);
1470
- React25__default.useEffect(() => {
1922
+ React37__default.useEffect(() => {
1471
1923
  if (!open) return;
1472
1924
  const onDown = (e) => {
1473
1925
  if (wrapRef.current && wrapRef.current.contains(e.target)) return;
@@ -1484,23 +1936,12 @@ function ColorPicker({
1484
1936
  document.removeEventListener("keydown", onKey);
1485
1937
  };
1486
1938
  }, [open]);
1487
- const prevOpen = React25__default.useRef(false);
1488
- React25__default.useEffect(() => {
1489
- let id;
1490
- if (!prevOpen.current && open) {
1491
- id = setTimeout(() => areaRef.current?.focus({ preventScroll: true }), 20);
1492
- } else if (prevOpen.current && !open) {
1493
- const ae = typeof document !== "undefined" ? document.activeElement : null;
1494
- if (!ae || ae === document.body) triggerRef.current?.focus();
1495
- }
1496
- prevOpen.current = open;
1497
- return () => clearTimeout(id);
1498
- }, [open]);
1939
+ useFocusTrap(popRef, open && !!coords, { initialFocus: areaRef });
1499
1940
  const commit = (next) => {
1500
- const h = hsvToHex(next.h, next.s, next.v);
1941
+ const out = alpha ? hsvaToHex8(next.h, next.s, next.v, next.a ?? 1) : hsvToHex(next.h, next.s, next.v);
1501
1942
  setHsv(next);
1502
- if (value === void 0) setInternal(h);
1503
- onChange?.(h);
1943
+ if (value === void 0) setInternal(out);
1944
+ onChange?.(out);
1504
1945
  };
1505
1946
  const dragArea = (e) => {
1506
1947
  const r = areaRef.current.getBoundingClientRect();
@@ -1544,6 +1985,21 @@ function ColorPicker({
1544
1985
  e.preventDefault();
1545
1986
  commit({ ...hsv, h });
1546
1987
  };
1988
+ const dragAlpha = (e) => {
1989
+ const r = alphaRef.current.getBoundingClientRect();
1990
+ const a = Math.min(1, Math.max(0, (e.clientX - r.left) / r.width));
1991
+ commit({ ...hsv, a });
1992
+ };
1993
+ const onAlphaKeyDown = (e) => {
1994
+ let a = hsv.a ?? 1;
1995
+ if (e.key === "ArrowRight" || e.key === "ArrowUp") a = Math.min(1, a + 0.01);
1996
+ else if (e.key === "ArrowLeft" || e.key === "ArrowDown") a = Math.max(0, a - 0.01);
1997
+ else if (e.key === "Home") a = 0;
1998
+ else if (e.key === "End") a = 1;
1999
+ else return;
2000
+ e.preventDefault();
2001
+ commit({ ...hsv, a: Math.round(a * 100) / 100 });
2002
+ };
1547
2003
  return /* @__PURE__ */ jsxs("div", { className: `twc-cp twc-field ${className}`, ref: wrapRef, ...rest, children: [
1548
2004
  __twcStyles0,
1549
2005
  __twcStyles1,
@@ -1588,6 +2044,7 @@ function ColorPicker({
1588
2044
  className: "twc-cp__pop",
1589
2045
  ref: popRef,
1590
2046
  role: "dialog",
2047
+ "aria-modal": "true",
1591
2048
  "aria-label": "Color picker",
1592
2049
  style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-tooltip)" },
1593
2050
  children: [
@@ -1629,6 +2086,23 @@ function ColorPicker({
1629
2086
  children: /* @__PURE__ */ jsx("span", { className: "twc-cp__hue-knob", style: { left: `${hsv.h / 360 * 100}%` } })
1630
2087
  }
1631
2088
  ),
2089
+ alpha ? /* @__PURE__ */ jsx(
2090
+ "div",
2091
+ {
2092
+ className: "twc-cp__alpha",
2093
+ ref: alphaRef,
2094
+ onPointerDown: startDrag(dragAlpha),
2095
+ role: "slider",
2096
+ tabIndex: 0,
2097
+ "aria-label": "Alpha",
2098
+ "aria-valuemin": 0,
2099
+ "aria-valuemax": 100,
2100
+ "aria-valuenow": Math.round((hsv.a ?? 1) * 100),
2101
+ onKeyDown: onAlphaKeyDown,
2102
+ style: { "--_solid": hsvToHex(hsv.h, hsv.s, hsv.v) },
2103
+ children: /* @__PURE__ */ jsx("span", { className: "twc-cp__hue-knob", style: { left: `${(hsv.a ?? 1) * 100}%` } })
2104
+ }
2105
+ ) : null,
1632
2106
  /* @__PURE__ */ jsxs("div", { className: "twc-cp__foot", children: [
1633
2107
  /* @__PURE__ */ jsx("span", { className: "twc-cp__swatch", style: { background: hex } }),
1634
2108
  /* @__PURE__ */ jsx(
@@ -1637,10 +2111,10 @@ function ColorPicker({
1637
2111
  className: "twc-cp__hex",
1638
2112
  "data-tone": tone,
1639
2113
  value: hex,
1640
- maxLength: 7,
2114
+ maxLength: alpha ? 9 : 7,
1641
2115
  "aria-label": "Hex color",
1642
- "aria-invalid": !/^#[0-9a-f]{6}$/i.test(hex) || void 0,
1643
- "data-invalid": !/^#[0-9a-f]{6}$/i.test(hex) || void 0,
2116
+ "aria-invalid": !hexRe.test(hex) || void 0,
2117
+ "data-invalid": !hexRe.test(hex) || void 0,
1644
2118
  onChange: (e) => {
1645
2119
  let v = e.target.value;
1646
2120
  if (!v.startsWith("#")) v = "#" + v;
@@ -1650,7 +2124,7 @@ function ColorPicker({
1650
2124
  if (p) setHsv(p);
1651
2125
  },
1652
2126
  onBlur: () => {
1653
- if (/^#[0-9a-f]{6}$/i.test(hex)) return;
2127
+ if (hexRe.test(hex)) return;
1654
2128
  const revert = lastValidRef.current;
1655
2129
  if (revert === hex) return;
1656
2130
  if (value === void 0) setInternal(revert);
@@ -1808,6 +2282,8 @@ function Combobox({
1808
2282
  loading = false,
1809
2283
  emptyText = "No results found",
1810
2284
  name,
2285
+ virtualized = false,
2286
+ overscan = 8,
1811
2287
  id,
1812
2288
  className = "",
1813
2289
  onFocus,
@@ -1815,29 +2291,51 @@ function Combobox({
1815
2291
  ...rest
1816
2292
  }) {
1817
2293
  const __twcStyles = useScopedStyles("twc-combo-styles", COMBO_CSS);
1818
- const groups = React25__default.useMemo(() => normalizeGroups(options), [options]);
1819
- const flat = React25__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
1820
- const autoId = React25__default.useId();
2294
+ const groups = React37__default.useMemo(() => normalizeGroups(options), [options]);
2295
+ const flat = React37__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
2296
+ const autoId = React37__default.useId();
1821
2297
  const fieldId = id || autoId;
1822
- const [internal, setInternal] = React25__default.useState(defaultValue);
2298
+ const [internal, setInternal] = React37__default.useState(defaultValue);
1823
2299
  const current = value !== void 0 ? value : internal;
1824
2300
  const selected = flat.find((o) => o.value === current);
1825
- const [open, setOpen] = React25__default.useState(false);
1826
- const [query, setQuery] = React25__default.useState("");
1827
- const [active, setActive] = React25__default.useState(0);
1828
- const [coords, setCoords] = React25__default.useState(null);
1829
- const wrapRef = React25__default.useRef(null);
1830
- const controlRef = React25__default.useRef(null);
1831
- const inputRef = React25__default.useRef(null);
1832
- const popRef = React25__default.useRef(null);
1833
- const listRef = React25__default.useRef(null);
1834
- const activeRef = React25__default.useRef(null);
1835
- const fGroups = React25__default.useMemo(() => {
2301
+ const [open, setOpen] = React37__default.useState(false);
2302
+ const [query, setQuery] = React37__default.useState("");
2303
+ const [active, setActive] = React37__default.useState(0);
2304
+ const [coords, setCoords] = React37__default.useState(null);
2305
+ const [scrollTop, setScrollTop] = React37__default.useState(0);
2306
+ const [listH, setListH] = React37__default.useState(260);
2307
+ const wrapRef = React37__default.useRef(null);
2308
+ const controlRef = React37__default.useRef(null);
2309
+ const inputRef = React37__default.useRef(null);
2310
+ const popRef = React37__default.useRef(null);
2311
+ const listRef = React37__default.useRef(null);
2312
+ const activeRef = React37__default.useRef(null);
2313
+ const fGroups = React37__default.useMemo(() => {
1836
2314
  const q = query.trim();
1837
2315
  const fn = filter === false ? null : typeof filter === "function" ? filter : matches;
1838
2316
  return groups.map((g) => ({ group: g.group, options: fn ? g.options.filter((o) => fn(o, q)) : g.options })).filter((g) => g.options.length);
1839
2317
  }, [groups, query, filter]);
1840
- const visible = React25__default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
2318
+ const visible = React37__default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
2319
+ const rowH = React37__default.useMemo(() => visible.some((o) => o.description) ? 48 : 36, [visible]);
2320
+ const GROUP_H = 30;
2321
+ const { rows, totalH } = React37__default.useMemo(() => {
2322
+ if (!virtualized) return { rows: [], totalH: 0 };
2323
+ const rows2 = [];
2324
+ let off = 0;
2325
+ let optIdx = -1;
2326
+ fGroups.forEach((g, gi) => {
2327
+ if (g.group) {
2328
+ rows2.push({ kind: "group", gi, label: g.group, top: off, h: GROUP_H });
2329
+ off += GROUP_H;
2330
+ }
2331
+ g.options.forEach((o) => {
2332
+ optIdx += 1;
2333
+ rows2.push({ kind: "option", o, idx: optIdx, top: off, h: rowH });
2334
+ off += rowH;
2335
+ });
2336
+ });
2337
+ return { rows: rows2, totalH: off };
2338
+ }, [virtualized, fGroups, rowH]);
1841
2339
  const nextEnabled = (from, dir) => {
1842
2340
  let i = from + dir;
1843
2341
  while (i >= 0 && i < visible.length) {
@@ -1846,7 +2344,7 @@ function Combobox({
1846
2344
  }
1847
2345
  return from;
1848
2346
  };
1849
- const place = React25__default.useCallback(() => {
2347
+ const place = React37__default.useCallback(() => {
1850
2348
  const el = controlRef.current;
1851
2349
  if (!el) return;
1852
2350
  const r = el.getBoundingClientRect();
@@ -1861,7 +2359,7 @@ function Combobox({
1861
2359
  flip
1862
2360
  });
1863
2361
  }, [placement, minWidth]);
1864
- React25__default.useEffect(() => {
2362
+ React37__default.useEffect(() => {
1865
2363
  if (!open || !portal) return;
1866
2364
  place();
1867
2365
  const onMove = () => place();
@@ -1872,7 +2370,7 @@ function Combobox({
1872
2370
  window.removeEventListener("resize", onMove);
1873
2371
  };
1874
2372
  }, [open, portal, place]);
1875
- React25__default.useEffect(() => {
2373
+ React37__default.useEffect(() => {
1876
2374
  if (!open) return;
1877
2375
  const onDown = (e) => {
1878
2376
  if (wrapRef.current && wrapRef.current.contains(e.target)) return;
@@ -1882,17 +2380,36 @@ function Combobox({
1882
2380
  document.addEventListener("mousedown", onDown);
1883
2381
  return () => document.removeEventListener("mousedown", onDown);
1884
2382
  }, [open]);
1885
- React25__default.useEffect(() => {
2383
+ React37__default.useEffect(() => {
1886
2384
  setActive(0);
1887
2385
  }, [query]);
1888
- React25__default.useEffect(() => {
2386
+ React37__default.useEffect(() => {
1889
2387
  if (!open) return;
1890
2388
  const idx = flat.findIndex((o) => o.value === current);
1891
2389
  setActive(idx >= 0 ? idx : 0);
1892
2390
  }, [open]);
1893
- React25__default.useEffect(() => {
1894
- if (open) ensureVisible(listRef.current, activeRef.current);
1895
- }, [active, open]);
2391
+ React37__default.useEffect(() => {
2392
+ if (!open || !virtualized) return;
2393
+ const el = listRef.current;
2394
+ if (el && el.clientHeight) setListH(el.clientHeight);
2395
+ }, [open, virtualized]);
2396
+ React37__default.useEffect(() => {
2397
+ if (!open) return;
2398
+ if (!virtualized) {
2399
+ ensureVisible(listRef.current, activeRef.current);
2400
+ return;
2401
+ }
2402
+ const el = listRef.current;
2403
+ if (!el) return;
2404
+ const row = rows.find((r) => r.kind === "option" && r.idx === active);
2405
+ if (!row) return;
2406
+ const vh = el.clientHeight || listH;
2407
+ let next = el.scrollTop;
2408
+ if (row.top < el.scrollTop) next = row.top;
2409
+ else if (row.top + row.h > el.scrollTop + vh) next = row.top + row.h - vh;
2410
+ if (next !== el.scrollTop) el.scrollTop = next;
2411
+ setScrollTop(next);
2412
+ }, [active, open, virtualized, rows, listH]);
1896
2413
  function openMenu() {
1897
2414
  if (disabled) return;
1898
2415
  setQuery("");
@@ -1937,45 +2454,60 @@ function Combobox({
1937
2454
  const activeId = open && visible[active] ? optionId(active) : void 0;
1938
2455
  const descId = `${fieldId}-desc`;
1939
2456
  const describedBy = error || hint ? descId : void 0;
2457
+ const renderOption = (o, idx) => {
2458
+ const isSel = o.value === current;
2459
+ return /* @__PURE__ */ jsxs(
2460
+ "button",
2461
+ {
2462
+ id: optionId(idx),
2463
+ type: "button",
2464
+ className: "twc-opt",
2465
+ role: "option",
2466
+ "aria-selected": isSel,
2467
+ ref: idx === active ? activeRef : null,
2468
+ disabled: o.disabled || void 0,
2469
+ "aria-disabled": o.disabled || void 0,
2470
+ "data-disabled": o.disabled || void 0,
2471
+ "data-selected": isSel || void 0,
2472
+ "data-active": idx === active || void 0,
2473
+ onMouseEnter: () => {
2474
+ if (!o.disabled) setActive(idx);
2475
+ },
2476
+ onMouseDown: (e) => e.preventDefault(),
2477
+ onClick: () => commit(o.value),
2478
+ children: [
2479
+ /* @__PURE__ */ jsxs("span", { className: "twc-opt__main", children: [
2480
+ /* @__PURE__ */ jsx("span", { className: "twc-opt__label", children: o.label }),
2481
+ o.description ? /* @__PURE__ */ jsx("span", { className: "twc-opt__desc", children: o.description }) : null
2482
+ ] }),
2483
+ isSel ? /* @__PURE__ */ jsx("span", { className: "twc-opt__check", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.6", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) }) }) : null
2484
+ ]
2485
+ },
2486
+ o.value
2487
+ );
2488
+ };
2489
+ let vTop = 0, vBottom = 0, vShown = rows;
2490
+ if (virtualized && rows.length) {
2491
+ const winTop = scrollTop - overscan * rowH;
2492
+ const winBottom = scrollTop + listH + overscan * rowH;
2493
+ vShown = rows.filter((r) => r.top + r.h > winTop && r.top < winBottom);
2494
+ vTop = vShown.length ? vShown[0].top : 0;
2495
+ vBottom = vShown.length ? totalH - (vShown[vShown.length - 1].top + vShown[vShown.length - 1].h) : totalH;
2496
+ }
1940
2497
  let counter = -1;
1941
- const popInner = /* @__PURE__ */ jsx("div", { className: "twc-pop__list", ref: listRef, children: loading ? /* @__PURE__ */ jsxs("div", { className: "twc-pop__loading", role: "status", children: [
2498
+ const popInner = /* @__PURE__ */ jsx("div", { className: "twc-pop__list", ref: listRef, onScroll: virtualized ? (e) => setScrollTop(e.currentTarget.scrollTop) : void 0, children: loading ? /* @__PURE__ */ jsxs("div", { className: "twc-pop__loading", role: "status", children: [
1942
2499
  /* @__PURE__ */ jsx("span", { className: "twc-pop__spinner", "aria-hidden": "true" }),
1943
2500
  "Loading\u2026"
1944
- ] }) : visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: emptyText }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React25__default.Fragment, { children: [
2501
+ ] }) : visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: emptyText }) : virtualized ? /* @__PURE__ */ jsxs(Fragment, { children: [
2502
+ vTop > 0 ? /* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { height: vTop } }) : null,
2503
+ vShown.map((r) => r.kind === "group" ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: r.label }, `g${r.gi}`) : renderOption(r.o, r.idx)),
2504
+ vBottom > 0 ? /* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { height: vBottom } }) : null
2505
+ ] }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React37__default.Fragment, { children: [
1945
2506
  g.group ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: g.group }) : null,
1946
2507
  g.options.map((o) => {
1947
2508
  counter += 1;
1948
2509
  const idx = counter;
1949
- const isSel = o.value === current;
1950
- return /* @__PURE__ */ jsxs(
1951
- "button",
1952
- {
1953
- id: optionId(idx),
1954
- type: "button",
1955
- className: "twc-opt",
1956
- role: "option",
1957
- "aria-selected": isSel,
1958
- ref: idx === active ? activeRef : null,
1959
- disabled: o.disabled || void 0,
1960
- "aria-disabled": o.disabled || void 0,
1961
- "data-disabled": o.disabled || void 0,
1962
- "data-selected": isSel || void 0,
1963
- "data-active": idx === active || void 0,
1964
- onMouseEnter: () => {
1965
- if (!o.disabled) setActive(idx);
1966
- },
1967
- onMouseDown: (e) => e.preventDefault(),
1968
- onClick: () => commit(o.value),
1969
- children: [
1970
- /* @__PURE__ */ jsxs("span", { className: "twc-opt__main", children: [
1971
- /* @__PURE__ */ jsx("span", { className: "twc-opt__label", children: o.label }),
1972
- o.description ? /* @__PURE__ */ jsx("span", { className: "twc-opt__desc", children: o.description }) : null
1973
- ] }),
1974
- isSel ? /* @__PURE__ */ jsx("span", { className: "twc-opt__check", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.6", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) }) }) : null
1975
- ]
1976
- },
1977
- o.value
1978
- );
2510
+ return renderOption(o, idx);
1979
2511
  })
1980
2512
  ] }, gi)) });
1981
2513
  const RD = { createPortal: typeof createPortal === "function" ? createPortal : typeof window !== "undefined" && window.ReactDOM && window.ReactDOM.createPortal };
@@ -2086,95 +2618,6 @@ function Combobox({
2086
2618
  error ? /* @__PURE__ */ jsx("span", { id: descId, className: "twc-field__error", children: error }) : hint ? /* @__PURE__ */ jsx("span", { id: descId, className: "twc-field__hint", children: hint }) : null
2087
2619
  ] });
2088
2620
  }
2089
- var canUseDOM = typeof window !== "undefined" && typeof document !== "undefined";
2090
- var useIsoLayoutEffect = canUseDOM ? React25__default.useLayoutEffect : React25__default.useEffect;
2091
- 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"])';
2092
- function useFocusTrap(ref, active = true, { restoreFocus = true } = {}) {
2093
- React25__default.useEffect(() => {
2094
- if (!active || !canUseDOM) return void 0;
2095
- const node = ref.current;
2096
- if (!node) return void 0;
2097
- const prevFocused = document.activeElement;
2098
- const first = node.querySelector(FOCUSABLE);
2099
- (first || node).focus();
2100
- return () => {
2101
- if (restoreFocus && prevFocused && typeof prevFocused.focus === "function") prevFocused.focus();
2102
- };
2103
- }, [active]);
2104
- React25__default.useEffect(() => {
2105
- if (!active || !canUseDOM) return void 0;
2106
- const node = ref.current;
2107
- const onKey = (e) => {
2108
- if (e.key !== "Tab" || !node) return;
2109
- const f = Array.from(node.querySelectorAll(FOCUSABLE)).filter((el) => el.offsetParent !== null);
2110
- if (!f.length) {
2111
- e.preventDefault();
2112
- node.focus();
2113
- return;
2114
- }
2115
- const first = f[0], last = f[f.length - 1], ae = document.activeElement;
2116
- if (e.shiftKey) {
2117
- if (ae === first || ae === node || !node.contains(ae)) {
2118
- e.preventDefault();
2119
- last.focus();
2120
- }
2121
- } else if (ae === last || !node.contains(ae)) {
2122
- e.preventDefault();
2123
- first.focus();
2124
- }
2125
- };
2126
- document.addEventListener("keydown", onKey);
2127
- return () => document.removeEventListener("keydown", onKey);
2128
- }, [active]);
2129
- }
2130
- function usePortal() {
2131
- return React25__default.useCallback((node) => {
2132
- if (typeof document === "undefined") return null;
2133
- return typeof createPortal === "function" ? createPortal(node, document.body) : node;
2134
- }, []);
2135
- }
2136
- var __scrollLockCount = 0;
2137
- var __scrollLockSaved = { overflow: "", paddingRight: "" };
2138
- function useScrollLock(locked = true) {
2139
- useIsoLayoutEffect(() => {
2140
- if (!canUseDOM || !locked) return void 0;
2141
- if (__scrollLockCount === 0) {
2142
- const b = document.body;
2143
- __scrollLockSaved = { overflow: b.style.overflow, paddingRight: b.style.paddingRight };
2144
- const gutter = window.innerWidth - document.documentElement.clientWidth;
2145
- b.style.overflow = "hidden";
2146
- if (gutter > 0) b.style.paddingRight = `${(parseFloat(getComputedStyle(b).paddingRight) || 0) + gutter}px`;
2147
- }
2148
- __scrollLockCount += 1;
2149
- return () => {
2150
- __scrollLockCount -= 1;
2151
- if (__scrollLockCount === 0) {
2152
- document.body.style.overflow = __scrollLockSaved.overflow;
2153
- document.body.style.paddingRight = __scrollLockSaved.paddingRight;
2154
- }
2155
- };
2156
- }, [locked]);
2157
- }
2158
- function useInertBackground(ref, active) {
2159
- React25__default.useEffect(() => {
2160
- if (!active || !canUseDOM) return void 0;
2161
- const node = ref.current;
2162
- if (!node) return void 0;
2163
- const changed = [];
2164
- Array.from(document.body.children).forEach((el) => {
2165
- if (el.contains(node) || el.hasAttribute("aria-hidden") || el.inert) return;
2166
- el.inert = true;
2167
- el.setAttribute("aria-hidden", "true");
2168
- changed.push(el);
2169
- });
2170
- return () => {
2171
- changed.forEach((el) => {
2172
- el.inert = false;
2173
- el.removeAttribute("aria-hidden");
2174
- });
2175
- };
2176
- }, [active]);
2177
- }
2178
2621
  var COMMAND_CSS = `
2179
2622
  .twc-cmdk__overlay { position: fixed; inset: 0; z-index: var(--z-modal); background: var(--color-overlay); backdrop-filter: blur(3px);
2180
2623
  display: flex; align-items: flex-start; justify-content: center; padding-top: 12vh; }
@@ -2222,14 +2665,14 @@ function CommandPalette({
2222
2665
  }) {
2223
2666
  const __twcStyles = useScopedStyles("twc-cmdk-styles", COMMAND_CSS);
2224
2667
  const renderPortal = usePortal();
2225
- const [query, setQuery] = React25__default.useState("");
2226
- const [active, setActive] = React25__default.useState(0);
2227
- const inputRef = React25__default.useRef(null);
2228
- const listRef = React25__default.useRef(null);
2229
- const paletteRef = React25__default.useRef(null);
2230
- const baseId = React25__default.useId();
2231
- const [mounted, setMounted] = React25__default.useState(open);
2232
- React25__default.useEffect(() => {
2668
+ const [query, setQuery] = React37__default.useState("");
2669
+ const [active, setActive] = React37__default.useState(0);
2670
+ const inputRef = React37__default.useRef(null);
2671
+ const listRef = React37__default.useRef(null);
2672
+ const paletteRef = React37__default.useRef(null);
2673
+ const baseId = React37__default.useId();
2674
+ const [mounted, setMounted] = React37__default.useState(open);
2675
+ React37__default.useEffect(() => {
2233
2676
  if (open) {
2234
2677
  setMounted(true);
2235
2678
  return;
@@ -2238,14 +2681,14 @@ function CommandPalette({
2238
2681
  return () => clearTimeout(t);
2239
2682
  }, [open]);
2240
2683
  useScrollLock(open);
2241
- React25__default.useEffect(() => {
2684
+ React37__default.useEffect(() => {
2242
2685
  if (open) {
2243
2686
  setQuery("");
2244
2687
  setActive(0);
2245
2688
  }
2246
2689
  }, [open]);
2247
2690
  useFocusTrap(paletteRef, open && mounted);
2248
- React25__default.useEffect(() => {
2691
+ React37__default.useEffect(() => {
2249
2692
  if (!open) return void 0;
2250
2693
  const onKey = (e) => {
2251
2694
  if (e.key === "Escape") {
@@ -2257,7 +2700,7 @@ function CommandPalette({
2257
2700
  return () => document.removeEventListener("keydown", onKey);
2258
2701
  }, [open, onClose]);
2259
2702
  const q = query.trim().toLowerCase();
2260
- const filtered = React25__default.useMemo(() => commands.filter(
2703
+ const filtered = React37__default.useMemo(() => commands.filter(
2261
2704
  (c) => !q || c.label.toLowerCase().includes(q) || (c.keywords || "").toLowerCase().includes(q) || (c.group || "").toLowerCase().includes(q)
2262
2705
  ), [commands, q]);
2263
2706
  const groups = [];
@@ -2272,7 +2715,7 @@ function CommandPalette({
2272
2715
  g.items.push(c);
2273
2716
  flat.push(c);
2274
2717
  });
2275
- React25__default.useEffect(() => {
2718
+ React37__default.useEffect(() => {
2276
2719
  setActive(0);
2277
2720
  }, [query]);
2278
2721
  const run = (cmd) => {
@@ -2292,7 +2735,7 @@ function CommandPalette({
2292
2735
  if (cmd) run(cmd);
2293
2736
  }
2294
2737
  }
2295
- React25__default.useEffect(() => {
2738
+ React37__default.useEffect(() => {
2296
2739
  const node = listRef.current?.querySelector('[data-active="true"]');
2297
2740
  if (node) node.scrollIntoView({ block: "nearest" });
2298
2741
  }, [active]);
@@ -2468,13 +2911,13 @@ function Currency({
2468
2911
  const prec = precision != null ? precision : meta.precision;
2469
2912
  const sym = symbol != null ? symbol : meta.symbol;
2470
2913
  const cur = code != null ? code : meta.code;
2471
- const autoId = React25__default.useId();
2914
+ const autoId = React37__default.useId();
2472
2915
  const fieldId = id || autoId;
2473
2916
  const invalid = Boolean(error);
2474
2917
  const controlled = value !== void 0;
2475
- const [internal, setInternal] = React25__default.useState(() => clampPrecision(String(defaultValue ?? ""), prec));
2918
+ const [internal, setInternal] = React37__default.useState(() => clampPrecision(String(defaultValue ?? ""), prec));
2476
2919
  const shown = controlled ? clampPrecision(String(value ?? ""), prec) : internal;
2477
- React25__default.useEffect(() => {
2920
+ React37__default.useEffect(() => {
2478
2921
  if (!controlled) return;
2479
2922
  const raw = String(value ?? "");
2480
2923
  if (shown !== raw) {
@@ -2661,6 +3104,8 @@ function Select({
2661
3104
  loading = false,
2662
3105
  emptyText = "No results found",
2663
3106
  name,
3107
+ virtualized = false,
3108
+ overscan = 8,
2664
3109
  id,
2665
3110
  className = "",
2666
3111
  onClick,
@@ -2668,32 +3113,54 @@ function Select({
2668
3113
  ...rest
2669
3114
  }) {
2670
3115
  const __twcStyles = useScopedStyles("twc-select-styles", SELECT_CSS);
2671
- const bufferRef = React25__default.useRef("");
2672
- const bufferTimerRef = React25__default.useRef(null);
2673
- const groups = React25__default.useMemo(() => normalizeGroups2(options), [options]);
2674
- const flat = React25__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
2675
- const autoId = React25__default.useId();
3116
+ const bufferRef = React37__default.useRef("");
3117
+ const bufferTimerRef = React37__default.useRef(null);
3118
+ const groups = React37__default.useMemo(() => normalizeGroups2(options), [options]);
3119
+ const flat = React37__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
3120
+ const autoId = React37__default.useId();
2676
3121
  const fieldId = id || autoId;
2677
- const [internal, setInternal] = React25__default.useState(defaultValue);
3122
+ const [internal, setInternal] = React37__default.useState(defaultValue);
2678
3123
  const current = value !== void 0 ? value : internal;
2679
- const [open, setOpen] = React25__default.useState(false);
2680
- const [render, setRender] = React25__default.useState(false);
2681
- const [active, setActive] = React25__default.useState(0);
2682
- const [coords, setCoords] = React25__default.useState(null);
2683
- const [query, setQuery] = React25__default.useState("");
2684
- const wrapRef = React25__default.useRef(null);
2685
- const triggerRef = React25__default.useRef(null);
2686
- const popRef = React25__default.useRef(null);
2687
- const listRef = React25__default.useRef(null);
2688
- const activeRef = React25__default.useRef(null);
2689
- const searchRef = React25__default.useRef(null);
3124
+ const [open, setOpen] = React37__default.useState(false);
3125
+ const [render, setRender] = React37__default.useState(false);
3126
+ const [active, setActive] = React37__default.useState(0);
3127
+ const [coords, setCoords] = React37__default.useState(null);
3128
+ const [query, setQuery] = React37__default.useState("");
3129
+ const [scrollTop, setScrollTop] = React37__default.useState(0);
3130
+ const [listH, setListH] = React37__default.useState(260);
3131
+ const wrapRef = React37__default.useRef(null);
3132
+ const triggerRef = React37__default.useRef(null);
3133
+ const popRef = React37__default.useRef(null);
3134
+ const listRef = React37__default.useRef(null);
3135
+ const activeRef = React37__default.useRef(null);
3136
+ const searchRef = React37__default.useRef(null);
2690
3137
  const showSearch = searchable === void 0 ? flat.length > 5 : searchable;
2691
- const fGroups = React25__default.useMemo(() => {
3138
+ const fGroups = React37__default.useMemo(() => {
2692
3139
  const q = query.trim().toLowerCase();
2693
3140
  if (!q) return groups;
2694
3141
  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);
2695
3142
  }, [groups, query]);
2696
- const visible = React25__default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
3143
+ const visible = React37__default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
3144
+ const rowH = React37__default.useMemo(() => visible.some((o) => o.description) ? 48 : 36, [visible]);
3145
+ const GROUP_H = 30;
3146
+ const { rows, totalH } = React37__default.useMemo(() => {
3147
+ if (!virtualized) return { rows: [], totalH: 0 };
3148
+ const rows2 = [];
3149
+ let off = 0;
3150
+ let optIdx = -1;
3151
+ fGroups.forEach((g, gi) => {
3152
+ if (g.group) {
3153
+ rows2.push({ kind: "group", gi, label: g.group, top: off, h: GROUP_H });
3154
+ off += GROUP_H;
3155
+ }
3156
+ g.options.forEach((o) => {
3157
+ optIdx += 1;
3158
+ rows2.push({ kind: "option", o, idx: optIdx, top: off, h: rowH });
3159
+ off += rowH;
3160
+ });
3161
+ });
3162
+ return { rows: rows2, totalH: off };
3163
+ }, [virtualized, fGroups, rowH]);
2697
3164
  const selected = flat.find((o) => o.value === current);
2698
3165
  const nextEnabled = (from, dir) => {
2699
3166
  let i = from + dir;
@@ -2703,7 +3170,7 @@ function Select({
2703
3170
  }
2704
3171
  return from;
2705
3172
  };
2706
- const place = React25__default.useCallback(() => {
3173
+ const place = React37__default.useCallback(() => {
2707
3174
  const el = triggerRef.current;
2708
3175
  if (!el) return;
2709
3176
  const r = el.getBoundingClientRect();
@@ -2719,7 +3186,7 @@ function Select({
2719
3186
  flip
2720
3187
  });
2721
3188
  }, [placement, minWidth, matchTriggerWidth]);
2722
- React25__default.useEffect(() => {
3189
+ React37__default.useEffect(() => {
2723
3190
  if (!open || !portal) return;
2724
3191
  place();
2725
3192
  const onMove = () => place();
@@ -2730,7 +3197,7 @@ function Select({
2730
3197
  window.removeEventListener("resize", onMove);
2731
3198
  };
2732
3199
  }, [open, portal, place]);
2733
- React25__default.useEffect(() => {
3200
+ React37__default.useEffect(() => {
2734
3201
  if (!open) return;
2735
3202
  const idx = flat.findIndex((o) => o.value === current);
2736
3203
  setActive(idx >= 0 ? idx : 0);
@@ -2746,13 +3213,32 @@ function Select({
2746
3213
  document.addEventListener("mousedown", onDown);
2747
3214
  return () => document.removeEventListener("mousedown", onDown);
2748
3215
  }, [open]);
2749
- React25__default.useEffect(() => {
3216
+ React37__default.useEffect(() => {
2750
3217
  setActive(0);
2751
3218
  }, [query]);
2752
- React25__default.useEffect(() => {
2753
- if (open) ensureVisible2(listRef.current, activeRef.current);
2754
- }, [active, open]);
2755
- React25__default.useEffect(() => {
3219
+ React37__default.useEffect(() => {
3220
+ if (!open || !virtualized) return;
3221
+ const el = listRef.current;
3222
+ if (el && el.clientHeight) setListH(el.clientHeight);
3223
+ }, [open, virtualized, render]);
3224
+ React37__default.useEffect(() => {
3225
+ if (!open) return;
3226
+ if (!virtualized) {
3227
+ ensureVisible2(listRef.current, activeRef.current);
3228
+ return;
3229
+ }
3230
+ const el = listRef.current;
3231
+ if (!el) return;
3232
+ const row = rows.find((r) => r.kind === "option" && r.idx === active);
3233
+ if (!row) return;
3234
+ const vh = el.clientHeight || listH;
3235
+ let next = el.scrollTop;
3236
+ if (row.top < el.scrollTop) next = row.top;
3237
+ else if (row.top + row.h > el.scrollTop + vh) next = row.top + row.h - vh;
3238
+ if (next !== el.scrollTop) el.scrollTop = next;
3239
+ setScrollTop(next);
3240
+ }, [active, open, virtualized, rows, listH]);
3241
+ React37__default.useEffect(() => {
2756
3242
  if (open) {
2757
3243
  setRender(true);
2758
3244
  return;
@@ -2760,8 +3246,8 @@ function Select({
2760
3246
  const t = setTimeout(() => setRender(false), 170);
2761
3247
  return () => clearTimeout(t);
2762
3248
  }, [open]);
2763
- const prevOpen = React25__default.useRef(false);
2764
- React25__default.useEffect(() => {
3249
+ const prevOpen = React37__default.useRef(false);
3250
+ React37__default.useEffect(() => {
2765
3251
  if (prevOpen.current && !open) {
2766
3252
  const ae = typeof document !== "undefined" ? document.activeElement : null;
2767
3253
  if (popRef.current && ae && popRef.current.contains(ae)) triggerRef.current?.focus();
@@ -2825,6 +3311,45 @@ function Select({
2825
3311
  const activeId = open && visible[active] ? optionId(active) : void 0;
2826
3312
  const descId = `${fieldId}-desc`;
2827
3313
  const describedBy = error || hint ? descId : void 0;
3314
+ const renderOption = (o, idx) => {
3315
+ const isSel = o.value === current;
3316
+ return /* @__PURE__ */ jsxs(
3317
+ "button",
3318
+ {
3319
+ id: optionId(idx),
3320
+ type: "button",
3321
+ className: "twc-opt",
3322
+ role: "option",
3323
+ "aria-selected": isSel,
3324
+ ref: idx === active ? activeRef : null,
3325
+ disabled: o.disabled || void 0,
3326
+ "aria-disabled": o.disabled || void 0,
3327
+ "data-disabled": o.disabled || void 0,
3328
+ "data-selected": isSel || void 0,
3329
+ "data-active": idx === active || void 0,
3330
+ onMouseEnter: () => {
3331
+ if (!o.disabled) setActive(idx);
3332
+ },
3333
+ onClick: () => commit(o.value),
3334
+ children: [
3335
+ /* @__PURE__ */ jsxs("span", { className: "twc-opt__main", children: [
3336
+ /* @__PURE__ */ jsx("span", { className: "twc-opt__label", children: o.label }),
3337
+ o.description ? /* @__PURE__ */ jsx("span", { className: "twc-opt__desc", children: o.description }) : null
3338
+ ] }),
3339
+ isSel ? /* @__PURE__ */ jsx("span", { className: "twc-opt__check", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.6", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) }) }) : null
3340
+ ]
3341
+ },
3342
+ o.value
3343
+ );
3344
+ };
3345
+ let vTop = 0, vBottom = 0, vShown = rows;
3346
+ if (virtualized && rows.length) {
3347
+ const winTop = scrollTop - overscan * rowH;
3348
+ const winBottom = scrollTop + listH + overscan * rowH;
3349
+ vShown = rows.filter((r) => r.top + r.h > winTop && r.top < winBottom);
3350
+ vTop = vShown.length ? vShown[0].top : 0;
3351
+ vBottom = vShown.length ? totalH - (vShown[vShown.length - 1].top + vShown[vShown.length - 1].h) : totalH;
3352
+ }
2828
3353
  let counter = -1;
2829
3354
  const popInner = /* @__PURE__ */ jsxs(Fragment, { children: [
2830
3355
  showSearch ? /* @__PURE__ */ jsxs("div", { className: "twc-pop__search", children: [
@@ -2852,43 +3377,19 @@ function Select({
2852
3377
  searchRef.current?.focus();
2853
3378
  }, children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
2854
3379
  ] }) : null,
2855
- /* @__PURE__ */ jsx("div", { className: "twc-pop__list", ref: listRef, children: loading ? /* @__PURE__ */ jsxs("div", { className: "twc-pop__loading", role: "status", children: [
3380
+ /* @__PURE__ */ jsx("div", { className: "twc-pop__list", ref: listRef, onScroll: virtualized ? (e) => setScrollTop(e.currentTarget.scrollTop) : void 0, children: loading ? /* @__PURE__ */ jsxs("div", { className: "twc-pop__loading", role: "status", children: [
2856
3381
  /* @__PURE__ */ jsx("span", { className: "twc-pop__spinner", "aria-hidden": "true" }),
2857
3382
  "Loading\u2026"
2858
- ] }) : visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: emptyText }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React25__default.Fragment, { children: [
3383
+ ] }) : visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: emptyText }) : virtualized ? /* @__PURE__ */ jsxs(Fragment, { children: [
3384
+ vTop > 0 ? /* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { height: vTop } }) : null,
3385
+ vShown.map((r) => r.kind === "group" ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: r.label }, `g${r.gi}`) : renderOption(r.o, r.idx)),
3386
+ vBottom > 0 ? /* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { height: vBottom } }) : null
3387
+ ] }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React37__default.Fragment, { children: [
2859
3388
  g.group ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: g.group }) : null,
2860
3389
  g.options.map((o) => {
2861
3390
  counter += 1;
2862
3391
  const idx = counter;
2863
- const isSel = o.value === current;
2864
- return /* @__PURE__ */ jsxs(
2865
- "button",
2866
- {
2867
- id: optionId(idx),
2868
- type: "button",
2869
- className: "twc-opt",
2870
- role: "option",
2871
- "aria-selected": isSel,
2872
- ref: idx === active ? activeRef : null,
2873
- disabled: o.disabled || void 0,
2874
- "aria-disabled": o.disabled || void 0,
2875
- "data-disabled": o.disabled || void 0,
2876
- "data-selected": isSel || void 0,
2877
- "data-active": idx === active || void 0,
2878
- onMouseEnter: () => {
2879
- if (!o.disabled) setActive(idx);
2880
- },
2881
- onClick: () => commit(o.value),
2882
- children: [
2883
- /* @__PURE__ */ jsxs("span", { className: "twc-opt__main", children: [
2884
- /* @__PURE__ */ jsx("span", { className: "twc-opt__label", children: o.label }),
2885
- o.description ? /* @__PURE__ */ jsx("span", { className: "twc-opt__desc", children: o.description }) : null
2886
- ] }),
2887
- isSel ? /* @__PURE__ */ jsx("span", { className: "twc-opt__check", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.6", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) }) }) : null
2888
- ]
2889
- },
2890
- o.value
2891
- );
3392
+ return renderOption(o, idx);
2892
3393
  })
2893
3394
  ] }, gi)) }),
2894
3395
  /* @__PURE__ */ jsx("div", { className: "twc-sel__sr", role: "status", "aria-live": "polite", children: loading ? "Loading\u2026" : visible.length === 0 ? emptyText : `${visible.length} result${visible.length === 1 ? "" : "s"}` })
@@ -3038,21 +3539,21 @@ function CurrencyField({
3038
3539
  ...rest
3039
3540
  }) {
3040
3541
  const __twcStyles = useScopedStyles("twc-curf-styles", CURF_CSS);
3041
- const autoId = React25__default.useId();
3542
+ const autoId = React37__default.useId();
3042
3543
  const fieldId = id || autoId;
3043
3544
  const invalid = Boolean(error);
3044
3545
  const curControlled = currency !== void 0;
3045
- const [curInternal, setCurInternal] = React25__default.useState(defaultCurrency);
3546
+ const [curInternal, setCurInternal] = React37__default.useState(defaultCurrency);
3046
3547
  const cur = curControlled ? currency : curInternal;
3047
3548
  const meta = CURRENCIES[cur] || CURRENCIES.USD;
3048
3549
  const prec = meta.precision;
3049
3550
  const valControlled = value !== void 0;
3050
- const [valInternal, setValInternal] = React25__default.useState(() => clampPrecision(String(defaultValue ?? ""), prec));
3551
+ const [valInternal, setValInternal] = React37__default.useState(() => clampPrecision(String(defaultValue ?? ""), prec));
3051
3552
  const shown = valControlled ? clampPrecision(String(value ?? ""), prec) : valInternal;
3052
3553
  const descId = `${fieldId}-desc`;
3053
3554
  const describedBy = [error || hint ? descId : null, rest["aria-describedby"]].filter(Boolean).join(" ") || void 0;
3054
3555
  const ariaInvalid = invalid ? true : rest["aria-invalid"] ?? void 0;
3055
- React25__default.useEffect(() => {
3556
+ React37__default.useEffect(() => {
3056
3557
  if (!valControlled) {
3057
3558
  const clamped = clampPrecision(valInternal, prec);
3058
3559
  if (clamped !== valInternal) {
@@ -3068,7 +3569,7 @@ function CurrencyField({
3068
3569
  }
3069
3570
  }
3070
3571
  }, [prec, cur, shown, value, valControlled, valInternal]);
3071
- const options = React25__default.useMemo(() => {
3572
+ const options = React37__default.useMemo(() => {
3072
3573
  if (!currencies) return CURRENCY_OPTIONS;
3073
3574
  return currencies.map((c) => typeof c === "string" ? { value: c, label: `${c} \u2014 ${(CURRENCIES[c] || {}).label || c}` } : c);
3074
3575
  }, [currencies]);
@@ -3222,13 +3723,13 @@ function Input({
3222
3723
  }) {
3223
3724
  const __twcStyles = useScopedStyles("twc-field-styles", FIELD_CSS2);
3224
3725
  const __twcExtra = useScopedStyles("twc-input-extra-styles", INPUT_EXTRA_CSS);
3225
- const autoId = React25__default.useId();
3726
+ const autoId = React37__default.useId();
3226
3727
  const fieldId = id || autoId;
3227
3728
  const descId = `${fieldId}-desc`;
3228
3729
  const countId = `${fieldId}-count`;
3229
3730
  const invalid = Boolean(error);
3230
3731
  const countControlled = rest.value !== void 0;
3231
- const [len2, setLen] = React25__default.useState(() => String(rest.defaultValue ?? "").length);
3732
+ const [len2, setLen] = React37__default.useState(() => String(rest.defaultValue ?? "").length);
3232
3733
  const count = countControlled ? String(rest.value ?? "").length : len2;
3233
3734
  const max = rest.maxLength;
3234
3735
  const showCounter = showCount && max != null;
@@ -3240,7 +3741,7 @@ function Input({
3240
3741
  const ariaInvalid = invalid ? true : rest["aria-invalid"] ?? void 0;
3241
3742
  const describedBy = [error || hint ? descId : null, showCounter ? countId : null, rest["aria-describedby"]].filter(Boolean).join(" ") || void 0;
3242
3743
  const isPassword = type === "password";
3243
- const [revealed, setRevealed] = React25__default.useState(false);
3744
+ const [revealed, setRevealed] = React37__default.useState(false);
3244
3745
  const effectiveType = isPassword && revealed ? "text" : type;
3245
3746
  const suffix = rightIcon ? /* @__PURE__ */ jsx("span", { className: "twc-input__affix", children: rightIcon }) : isPassword ? /* @__PURE__ */ jsx(
3246
3747
  "button",
@@ -3434,6 +3935,8 @@ function MultiSelect({
3434
3935
  name,
3435
3936
  max,
3436
3937
  maxTagCount,
3938
+ virtualized = false,
3939
+ overscan = 8,
3437
3940
  id,
3438
3941
  className = "",
3439
3942
  onFocus,
@@ -3441,27 +3944,49 @@ function MultiSelect({
3441
3944
  ...rest
3442
3945
  }) {
3443
3946
  const __twcStyles = useScopedStyles("twc-ms-styles", MULTI_CSS);
3444
- const groups = React25__default.useMemo(() => normalizeGroups3(options), [options]);
3445
- const flat = React25__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
3446
- const autoId = React25__default.useId();
3947
+ const groups = React37__default.useMemo(() => normalizeGroups3(options), [options]);
3948
+ const flat = React37__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
3949
+ const autoId = React37__default.useId();
3447
3950
  const fieldId = id || autoId;
3448
- const [internal, setInternal] = React25__default.useState(defaultValue);
3951
+ const [internal, setInternal] = React37__default.useState(defaultValue);
3449
3952
  const selected = value !== void 0 ? value : internal;
3450
- const [open, setOpen] = React25__default.useState(false);
3451
- const [query, setQuery] = React25__default.useState("");
3452
- const [active, setActive] = React25__default.useState(0);
3453
- const [coords, setCoords] = React25__default.useState(null);
3454
- const wrapRef = React25__default.useRef(null);
3455
- const controlRef = React25__default.useRef(null);
3456
- const inputRef = React25__default.useRef(null);
3457
- const popRef = React25__default.useRef(null);
3458
- const listRef = React25__default.useRef(null);
3459
- const activeRef = React25__default.useRef(null);
3460
- const fGroups = React25__default.useMemo(
3953
+ const [open, setOpen] = React37__default.useState(false);
3954
+ const [query, setQuery] = React37__default.useState("");
3955
+ const [active, setActive] = React37__default.useState(0);
3956
+ const [coords, setCoords] = React37__default.useState(null);
3957
+ const [scrollTop, setScrollTop] = React37__default.useState(0);
3958
+ const [listH, setListH] = React37__default.useState(260);
3959
+ const wrapRef = React37__default.useRef(null);
3960
+ const controlRef = React37__default.useRef(null);
3961
+ const inputRef = React37__default.useRef(null);
3962
+ const popRef = React37__default.useRef(null);
3963
+ const listRef = React37__default.useRef(null);
3964
+ const activeRef = React37__default.useRef(null);
3965
+ const fGroups = React37__default.useMemo(
3461
3966
  () => groups.map((g) => ({ group: g.group, options: g.options.filter((o) => matches2(o, query.trim())) })).filter((g) => g.options.length),
3462
3967
  [groups, query]
3463
3968
  );
3464
- const visible = React25__default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
3969
+ const visible = React37__default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
3970
+ const rowH = React37__default.useMemo(() => visible.some((o) => o.description) ? 48 : 36, [visible]);
3971
+ const GROUP_H = 30;
3972
+ const { rows, totalH } = React37__default.useMemo(() => {
3973
+ if (!virtualized) return { rows: [], totalH: 0 };
3974
+ const rows2 = [];
3975
+ let off = 0;
3976
+ let optIdx = -1;
3977
+ fGroups.forEach((g, gi) => {
3978
+ if (g.group) {
3979
+ rows2.push({ kind: "group", gi, label: g.group, top: off, h: GROUP_H });
3980
+ off += GROUP_H;
3981
+ }
3982
+ g.options.forEach((o) => {
3983
+ optIdx += 1;
3984
+ rows2.push({ kind: "option", o, idx: optIdx, top: off, h: rowH });
3985
+ off += rowH;
3986
+ });
3987
+ });
3988
+ return { rows: rows2, totalH: off };
3989
+ }, [virtualized, fGroups, rowH]);
3465
3990
  const capReached = max != null && (value !== void 0 ? value : internal).length >= max;
3466
3991
  const isOptDisabled = (o) => o.disabled || capReached && !(value !== void 0 ? value : internal).includes(o.value);
3467
3992
  const nextEnabled = (from, dir) => {
@@ -3472,7 +3997,7 @@ function MultiSelect({
3472
3997
  }
3473
3998
  return from;
3474
3999
  };
3475
- const place = React25__default.useCallback(() => {
4000
+ const place = React37__default.useCallback(() => {
3476
4001
  const el = controlRef.current;
3477
4002
  if (!el) return;
3478
4003
  const r = el.getBoundingClientRect();
@@ -3487,7 +4012,7 @@ function MultiSelect({
3487
4012
  flip
3488
4013
  });
3489
4014
  }, [placement, minWidth]);
3490
- React25__default.useEffect(() => {
4015
+ React37__default.useEffect(() => {
3491
4016
  if (!open || !portal) return;
3492
4017
  place();
3493
4018
  const onMove = () => place();
@@ -3498,7 +4023,7 @@ function MultiSelect({
3498
4023
  window.removeEventListener("resize", onMove);
3499
4024
  };
3500
4025
  }, [open, portal, place]);
3501
- React25__default.useEffect(() => {
4026
+ React37__default.useEffect(() => {
3502
4027
  if (!open) return;
3503
4028
  const onDown = (e) => {
3504
4029
  if (wrapRef.current && wrapRef.current.contains(e.target)) return;
@@ -3509,12 +4034,31 @@ function MultiSelect({
3509
4034
  document.addEventListener("mousedown", onDown);
3510
4035
  return () => document.removeEventListener("mousedown", onDown);
3511
4036
  }, [open]);
3512
- React25__default.useEffect(() => {
4037
+ React37__default.useEffect(() => {
3513
4038
  setActive(0);
3514
4039
  }, [query]);
3515
- React25__default.useEffect(() => {
3516
- if (open) ensureVisible3(listRef.current, activeRef.current);
3517
- }, [active, open]);
4040
+ React37__default.useEffect(() => {
4041
+ if (!open || !virtualized) return;
4042
+ const el = listRef.current;
4043
+ if (el && el.clientHeight) setListH(el.clientHeight);
4044
+ }, [open, virtualized]);
4045
+ React37__default.useEffect(() => {
4046
+ if (!open) return;
4047
+ if (!virtualized) {
4048
+ ensureVisible3(listRef.current, activeRef.current);
4049
+ return;
4050
+ }
4051
+ const el = listRef.current;
4052
+ if (!el) return;
4053
+ const row = rows.find((r) => r.kind === "option" && r.idx === active);
4054
+ if (!row) return;
4055
+ const vh = el.clientHeight || listH;
4056
+ let next = el.scrollTop;
4057
+ if (row.top < el.scrollTop) next = row.top;
4058
+ else if (row.top + row.h > el.scrollTop + vh) next = row.top + row.h - vh;
4059
+ if (next !== el.scrollTop) el.scrollTop = next;
4060
+ setScrollTop(next);
4061
+ }, [active, open, virtualized, rows, listH]);
3518
4062
  function commit(next) {
3519
4063
  if (value === void 0) setInternal(next);
3520
4064
  onChange?.(next);
@@ -3551,48 +4095,74 @@ function MultiSelect({
3551
4095
  const activeId = open && visible[active] ? optionId(active) : void 0;
3552
4096
  const descId = `${fieldId}-desc`;
3553
4097
  const describedBy = error || hint ? descId : void 0;
3554
- let counter = -1;
3555
- const popInner = /* @__PURE__ */ jsx("div", { className: "twc-pop__list", id: listboxId, ref: listRef, role: "listbox", "aria-multiselectable": "true", children: loading ? /* @__PURE__ */ jsxs("div", { className: "twc-pop__loading", role: "status", children: [
3556
- /* @__PURE__ */ jsx("span", { className: "twc-pop__spinner", "aria-hidden": "true" }),
3557
- "Loading\u2026"
3558
- ] }) : visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: emptyText }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React25__default.Fragment, { children: [
3559
- g.group ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: g.group }) : null,
3560
- g.options.map((o) => {
3561
- counter += 1;
3562
- const idx = counter;
3563
- const isSel = selected.includes(o.value);
3564
- const optDisabled = isOptDisabled(o);
3565
- return /* @__PURE__ */ jsxs(
3566
- "button",
3567
- {
3568
- id: optionId(idx),
3569
- type: "button",
3570
- className: "twc-opt",
3571
- role: "option",
3572
- "aria-selected": isSel,
3573
- ref: idx === active ? activeRef : null,
3574
- disabled: optDisabled || void 0,
3575
- "aria-disabled": optDisabled || void 0,
3576
- "data-disabled": optDisabled || void 0,
3577
- "data-selected": isSel || void 0,
3578
- "data-active": idx === active || void 0,
3579
- onMouseEnter: () => {
3580
- if (!optDisabled) setActive(idx);
3581
- },
3582
- onMouseDown: (e) => e.preventDefault(),
3583
- onClick: () => toggle(o.value),
3584
- children: [
3585
- /* @__PURE__ */ jsx("span", { className: "twc-opt__box", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) }) }),
3586
- /* @__PURE__ */ jsxs("span", { className: "twc-opt__main", children: [
3587
- /* @__PURE__ */ jsx("span", { className: "twc-opt__label", children: o.label }),
3588
- o.description ? /* @__PURE__ */ jsx("span", { className: "twc-opt__desc", children: o.description }) : null
3589
- ] })
3590
- ]
4098
+ const renderOption = (o, idx) => {
4099
+ const isSel = selected.includes(o.value);
4100
+ const optDisabled = isOptDisabled(o);
4101
+ return /* @__PURE__ */ jsxs(
4102
+ "button",
4103
+ {
4104
+ id: optionId(idx),
4105
+ type: "button",
4106
+ className: "twc-opt",
4107
+ role: "option",
4108
+ "aria-selected": isSel,
4109
+ ref: idx === active ? activeRef : null,
4110
+ disabled: optDisabled || void 0,
4111
+ "aria-disabled": optDisabled || void 0,
4112
+ "data-disabled": optDisabled || void 0,
4113
+ "data-selected": isSel || void 0,
4114
+ "data-active": idx === active || void 0,
4115
+ onMouseEnter: () => {
4116
+ if (!optDisabled) setActive(idx);
3591
4117
  },
3592
- o.value
3593
- );
3594
- })
3595
- ] }, gi)) });
4118
+ onMouseDown: (e) => e.preventDefault(),
4119
+ onClick: () => toggle(o.value),
4120
+ children: [
4121
+ /* @__PURE__ */ jsx("span", { className: "twc-opt__box", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) }) }),
4122
+ /* @__PURE__ */ jsxs("span", { className: "twc-opt__main", children: [
4123
+ /* @__PURE__ */ jsx("span", { className: "twc-opt__label", children: o.label }),
4124
+ o.description ? /* @__PURE__ */ jsx("span", { className: "twc-opt__desc", children: o.description }) : null
4125
+ ] })
4126
+ ]
4127
+ },
4128
+ o.value
4129
+ );
4130
+ };
4131
+ let vTop = 0, vBottom = 0, vShown = rows;
4132
+ if (virtualized && rows.length) {
4133
+ const winTop = scrollTop - overscan * rowH;
4134
+ const winBottom = scrollTop + listH + overscan * rowH;
4135
+ vShown = rows.filter((r) => r.top + r.h > winTop && r.top < winBottom);
4136
+ vTop = vShown.length ? vShown[0].top : 0;
4137
+ vBottom = vShown.length ? totalH - (vShown[vShown.length - 1].top + vShown[vShown.length - 1].h) : totalH;
4138
+ }
4139
+ let counter = -1;
4140
+ const popInner = /* @__PURE__ */ jsx(
4141
+ "div",
4142
+ {
4143
+ className: "twc-pop__list",
4144
+ id: listboxId,
4145
+ ref: listRef,
4146
+ role: "listbox",
4147
+ "aria-multiselectable": "true",
4148
+ onScroll: virtualized ? (e) => setScrollTop(e.currentTarget.scrollTop) : void 0,
4149
+ children: loading ? /* @__PURE__ */ jsxs("div", { className: "twc-pop__loading", role: "status", children: [
4150
+ /* @__PURE__ */ jsx("span", { className: "twc-pop__spinner", "aria-hidden": "true" }),
4151
+ "Loading\u2026"
4152
+ ] }) : visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: emptyText }) : virtualized ? /* @__PURE__ */ jsxs(Fragment, { children: [
4153
+ vTop > 0 ? /* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { height: vTop } }) : null,
4154
+ vShown.map((r) => r.kind === "group" ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: r.label }, `g${r.gi}`) : renderOption(r.o, r.idx)),
4155
+ vBottom > 0 ? /* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { height: vBottom } }) : null
4156
+ ] }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React37__default.Fragment, { children: [
4157
+ g.group ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: g.group }) : null,
4158
+ g.options.map((o) => {
4159
+ counter += 1;
4160
+ const idx = counter;
4161
+ return renderOption(o, idx);
4162
+ })
4163
+ ] }, gi))
4164
+ }
4165
+ );
3596
4166
  const RD = { createPortal: typeof createPortal === "function" ? createPortal : typeof window !== "undefined" && window.ReactDOM && window.ReactDOM.createPortal };
3597
4167
  const canPortal = portal && RD && RD.createPortal;
3598
4168
  let popEl = null;
@@ -3785,7 +4355,7 @@ function Pagination({
3785
4355
  }
3786
4356
  const jumperEnabled = showPageJumper ?? showJumper;
3787
4357
  const __twcStyles = useScopedStyles("twc-pagination-styles", PAGINATION_CSS);
3788
- const [internal, setInternal] = React25__default.useState(defaultPage);
4358
+ const [internal, setInternal] = React37__default.useState(defaultPage);
3789
4359
  const page = pageProp !== void 0 ? pageProp : internal;
3790
4360
  const pages = buildPages(page, total, siblings, boundaries);
3791
4361
  const go = (p) => {
@@ -3793,7 +4363,7 @@ function Pagination({
3793
4363
  if (pageProp === void 0) setInternal(p);
3794
4364
  onChange?.(p);
3795
4365
  };
3796
- const [jump, setJump] = React25__default.useState("");
4366
+ const [jump, setJump] = React37__default.useState("");
3797
4367
  const submitJump = () => {
3798
4368
  const n = parseInt(jump, 10);
3799
4369
  if (!Number.isNaN(n)) go(Math.min(Math.max(n, 1), total));
@@ -3876,13 +4446,13 @@ function Tooltip({
3876
4446
  ...rest
3877
4447
  }) {
3878
4448
  const __twcStyles = useScopedStyles("twc-tooltip-styles", TOOLTIP_CSS);
3879
- const id = React25__default.useId();
3880
- const [show, setShow] = React25__default.useState(false);
3881
- const [coords, setCoords] = React25__default.useState(null);
3882
- const timer = React25__default.useRef(null);
3883
- const closeTimer = React25__default.useRef(null);
3884
- const wrapRef = React25__default.useRef(null);
3885
- const tipRef = React25__default.useRef(null);
4449
+ const id = React37__default.useId();
4450
+ const [show, setShow] = React37__default.useState(false);
4451
+ const [coords, setCoords] = React37__default.useState(null);
4452
+ const timer = React37__default.useRef(null);
4453
+ const closeTimer = React37__default.useRef(null);
4454
+ const wrapRef = React37__default.useRef(null);
4455
+ const tipRef = React37__default.useRef(null);
3886
4456
  const open = () => {
3887
4457
  clearTimeout(closeTimer.current);
3888
4458
  clearTimeout(timer.current);
@@ -3896,11 +4466,11 @@ function Tooltip({
3896
4466
  const cancelClose = () => {
3897
4467
  clearTimeout(closeTimer.current);
3898
4468
  };
3899
- React25__default.useEffect(() => () => {
4469
+ React37__default.useEffect(() => () => {
3900
4470
  clearTimeout(timer.current);
3901
4471
  clearTimeout(closeTimer.current);
3902
4472
  }, []);
3903
- const place = React25__default.useCallback(() => {
4473
+ const place = React37__default.useCallback(() => {
3904
4474
  const el = wrapRef.current;
3905
4475
  if (!el) return;
3906
4476
  const r = el.getBoundingClientRect();
@@ -3923,10 +4493,10 @@ function Tooltip({
3923
4493
  else if (side === "right") setCoords({ ...base, top: clampY(cy), left: Math.round(r.right + gap) });
3924
4494
  else setCoords({ ...base, left: clampX(cx), bottom: Math.round(vh - r.top + gap) });
3925
4495
  }, [placement]);
3926
- React25__default.useEffect(() => {
4496
+ React37__default.useEffect(() => {
3927
4497
  place();
3928
4498
  }, [place]);
3929
- React25__default.useEffect(() => {
4499
+ React37__default.useEffect(() => {
3930
4500
  if (!show) return void 0;
3931
4501
  place();
3932
4502
  const onMove = () => place();
@@ -3937,7 +4507,7 @@ function Tooltip({
3937
4507
  window.removeEventListener("resize", onMove);
3938
4508
  };
3939
4509
  }, [show, place]);
3940
- React25__default.useEffect(() => {
4510
+ React37__default.useEffect(() => {
3941
4511
  if (!show) return;
3942
4512
  const onKeyDown = (e) => {
3943
4513
  if (e.key === "Escape") {
@@ -3949,7 +4519,7 @@ function Tooltip({
3949
4519
  return () => document.removeEventListener("keydown", onKeyDown);
3950
4520
  }, [show]);
3951
4521
  const describedBy = show ? id : void 0;
3952
- const trigger = React25__default.isValidElement(children) && children.type !== React25__default.Fragment ? React25__default.cloneElement(children, {
4522
+ const trigger = React37__default.isValidElement(children) && children.type !== React37__default.Fragment ? React37__default.cloneElement(children, {
3953
4523
  "aria-describedby": [children.props["aria-describedby"], describedBy].filter(Boolean).join(" ") || void 0
3954
4524
  }) : /* @__PURE__ */ jsx("span", { "aria-describedby": describedBy, children });
3955
4525
  return /* @__PURE__ */ jsxs(
@@ -4553,9 +5123,9 @@ function runDatatableQuery(rows, query, options = {}) {
4553
5123
  return { rows: page, total, filtered: out };
4554
5124
  }
4555
5125
  function useFloating() {
4556
- const [pos, setPos] = React25__default.useState(null);
4557
- const cfg = React25__default.useRef(null);
4558
- const place = React25__default.useCallback(() => {
5126
+ const [pos, setPos] = React37__default.useState(null);
5127
+ const cfg = React37__default.useRef(null);
5128
+ const place = React37__default.useCallback(() => {
4559
5129
  const c = cfg.current;
4560
5130
  if (!c || !c.el || !c.el.isConnected) return null;
4561
5131
  const r = c.el.getBoundingClientRect();
@@ -4566,17 +5136,17 @@ function useFloating() {
4566
5136
  const top = r.bottom + 6;
4567
5137
  return { top, left, width: c.width, anchorX: r.left + r.width / 2, maxHeight: Math.max(180, vh - top - M) };
4568
5138
  }, []);
4569
- const open = React25__default.useCallback((el, align = "left", width = 220) => {
5139
+ const open = React37__default.useCallback((el, align = "left", width = 220) => {
4570
5140
  cfg.current = { el, align, width };
4571
5141
  const p = place();
4572
5142
  if (p) setPos(p);
4573
5143
  }, [place]);
4574
- const close = React25__default.useCallback(() => {
5144
+ const close = React37__default.useCallback(() => {
4575
5145
  cfg.current = null;
4576
5146
  setPos(null);
4577
5147
  }, []);
4578
5148
  const isOpen = pos != null;
4579
- React25__default.useEffect(() => {
5149
+ React37__default.useEffect(() => {
4580
5150
  if (!isOpen) return void 0;
4581
5151
  const update = () => {
4582
5152
  const p = place();
@@ -4600,9 +5170,9 @@ function Caret({ pos }) {
4600
5170
  return /* @__PURE__ */ jsx("span", { className: "twc-dt__caret", style: { left } });
4601
5171
  }
4602
5172
  function EditCell({ col, value, options, onChange, onCommit, onCommitValue, onCancel, onKeyDown }) {
4603
- const ref = React25__default.useRef(null);
5173
+ const ref = React37__default.useRef(null);
4604
5174
  const isSelect = col.editType === "select" || options && col.editType !== "text";
4605
- React25__default.useEffect(() => {
5175
+ React37__default.useEffect(() => {
4606
5176
  if (isSelect) {
4607
5177
  const t = setTimeout(() => ref.current?.querySelector(".twc-sel__trigger")?.click(), 0);
4608
5178
  return () => clearTimeout(t);
@@ -4766,6 +5336,9 @@ function Datatable({
4766
5336
  density: densityProp = "comfortable",
4767
5337
  pageSize = 10,
4768
5338
  pageSizeOptions = [5, 10, 25, 50],
5339
+ page,
5340
+ onPageChange,
5341
+ onPageSizeChange,
4769
5342
  height = 440,
4770
5343
  serverMode = false,
4771
5344
  rowCount,
@@ -4807,7 +5380,7 @@ function Datatable({
4807
5380
  ...rest
4808
5381
  }) {
4809
5382
  const __twcStyles = useScopedStyles("twc-dt-styles", DT_CSS);
4810
- const cols = React25__default.useMemo(() => {
5383
+ const cols = React37__default.useMemo(() => {
4811
5384
  const out = columns.map((c) => {
4812
5385
  const isActions = c.type === "actions";
4813
5386
  return {
@@ -4842,7 +5415,7 @@ function Datatable({
4842
5415
  }
4843
5416
  return out;
4844
5417
  }, [columns, rowPinning]);
4845
- const _autoKey = React25__default.useRef();
5418
+ const _autoKey = React37__default.useRef();
4846
5419
  if (!_autoKey.current) _autoKey.current = { map: /* @__PURE__ */ new WeakMap(), n: 0 };
4847
5420
  const keyOf = rowKey || ((r, i) => {
4848
5421
  if (r != null && r.id != null) return r.id;
@@ -4857,17 +5430,17 @@ function Datatable({
4857
5430
  }
4858
5431
  return i;
4859
5432
  });
4860
- const [sort, setSort] = React25__default.useState(null);
4861
- const [filters, setFilters] = React25__default.useState([]);
4862
- const [hidden, setHidden] = React25__default.useState(() => /* @__PURE__ */ new Set());
4863
- const [showRowNum, setShowRowNum] = React25__default.useState(rowNumbers);
4864
- const [wrapped, setWrapped] = React25__default.useState(() => new Set((columns || []).filter((c) => c.wrapText).map((c) => c.field)));
5433
+ const [sort, setSort] = React37__default.useState(null);
5434
+ const [filters, setFilters] = React37__default.useState([]);
5435
+ const [hidden, setHidden] = React37__default.useState(() => /* @__PURE__ */ new Set());
5436
+ const [showRowNum, setShowRowNum] = React37__default.useState(rowNumbers);
5437
+ const [wrapped, setWrapped] = React37__default.useState(() => new Set((columns || []).filter((c) => c.wrapText).map((c) => c.field)));
4865
5438
  const toggleWrap = (field) => setWrapped((w) => {
4866
5439
  const n = new Set(w);
4867
5440
  n.has(field) ? n.delete(field) : n.add(field);
4868
5441
  return n;
4869
5442
  });
4870
- const [pins, setPins] = React25__default.useState(() => {
5443
+ const [pins, setPins] = React37__default.useState(() => {
4871
5444
  const left = [], right = [];
4872
5445
  columns.forEach((c) => {
4873
5446
  if (c.pinned === "left") left.push(c.field);
@@ -4875,34 +5448,47 @@ function Datatable({
4875
5448
  });
4876
5449
  return { left, right };
4877
5450
  });
4878
- const [density, setDensity] = React25__default.useState(densityProp);
4879
- const [quick, setQuick] = React25__default.useState("");
4880
- const [selected, setSelected] = React25__default.useState(() => /* @__PURE__ */ new Set());
4881
- const [activeRow, setActiveRow] = React25__default.useState(null);
4882
- const [activeCell, setActiveCell] = React25__default.useState(null);
4883
- const [page, setPage] = React25__default.useState(0);
4884
- const [rowsPerPage, setRowsPerPage] = React25__default.useState(pageSize > 0 ? pageSize : 10);
4885
- const [colQuery, setColQuery] = React25__default.useState("");
4886
- const [widths, setWidths] = React25__default.useState({});
4887
- const [order, setOrder] = React25__default.useState(() => columns.map((c) => c.field));
4888
- const [drag, setDrag] = React25__default.useState({ from: null, over: null, after: false });
4889
- const [aggOn, setAggOn] = React25__default.useState(showAggregation);
4890
- const [focus, setFocus] = React25__default.useState({ r: 0, c: 0 });
4891
- const gridRef = React25__default.useRef(null);
4892
- const [groupBy, setGroupBy] = React25__default.useState(rowGrouping || []);
4893
- const [collapsed, setCollapsed] = React25__default.useState(() => /* @__PURE__ */ new Set());
4894
- const [pinnedRows, setPinnedRows] = React25__default.useState({ top: [], bottom: [] });
4895
- const [headH, setHeadH] = React25__default.useState(41);
4896
- const theadRef = React25__default.useRef(null);
4897
- const [rowOrder, setRowOrder] = React25__default.useState(null);
4898
- const [rowHeights, setRowHeights] = React25__default.useState({});
4899
- const [rowDrag, setRowDrag] = React25__default.useState({ from: null, over: null, after: false });
4900
- const [rowGrab, setRowGrab] = React25__default.useState(null);
4901
- const [reorderMsg, setReorderMsg] = React25__default.useState("");
4902
- const rowFocusRef = React25__default.useRef(null);
4903
- const rootRef = React25__default.useRef(null);
4904
- const [compact, setCompact] = React25__default.useState(false);
4905
- React25__default.useEffect(() => {
5451
+ const [density, setDensity] = React37__default.useState(densityProp);
5452
+ const [quick, setQuick] = React37__default.useState("");
5453
+ const [selected, setSelected] = React37__default.useState(() => /* @__PURE__ */ new Set());
5454
+ const [activeRow, setActiveRow] = React37__default.useState(null);
5455
+ const [activeCell, setActiveCell] = React37__default.useState(null);
5456
+ const [internalPage, setInternalPage] = React37__default.useState(0);
5457
+ const [internalRpp, setInternalRpp] = React37__default.useState(pageSize > 0 ? pageSize : 10);
5458
+ const pageControlled = page !== void 0;
5459
+ const pageSizeControlled = onPageSizeChange !== void 0;
5460
+ const pageVal = pageControlled ? page : internalPage;
5461
+ const sizeVal = pageSizeControlled ? pageSize > 0 ? pageSize : 10 : internalRpp;
5462
+ const commitPage = (next) => {
5463
+ onPageChange?.(next);
5464
+ if (!pageControlled) setInternalPage(next);
5465
+ };
5466
+ const commitPageSize = (next) => {
5467
+ onPageSizeChange?.(next);
5468
+ if (!pageSizeControlled) setInternalRpp(next);
5469
+ commitPage(0);
5470
+ };
5471
+ const [colQuery, setColQuery] = React37__default.useState("");
5472
+ const [widths, setWidths] = React37__default.useState({});
5473
+ const [order, setOrder] = React37__default.useState(() => columns.map((c) => c.field));
5474
+ const [drag, setDrag] = React37__default.useState({ from: null, over: null, after: false });
5475
+ const [aggOn, setAggOn] = React37__default.useState(showAggregation);
5476
+ const [focus, setFocus] = React37__default.useState({ r: 0, c: 0 });
5477
+ const gridRef = React37__default.useRef(null);
5478
+ const [groupBy, setGroupBy] = React37__default.useState(rowGrouping || []);
5479
+ const [collapsed, setCollapsed] = React37__default.useState(() => /* @__PURE__ */ new Set());
5480
+ const [pinnedRows, setPinnedRows] = React37__default.useState({ top: [], bottom: [] });
5481
+ const [headH, setHeadH] = React37__default.useState(41);
5482
+ const theadRef = React37__default.useRef(null);
5483
+ const [rowOrder, setRowOrder] = React37__default.useState(null);
5484
+ const [rowHeights, setRowHeights] = React37__default.useState({});
5485
+ const [rowDrag, setRowDrag] = React37__default.useState({ from: null, over: null, after: false });
5486
+ const [rowGrab, setRowGrab] = React37__default.useState(null);
5487
+ const [reorderMsg, setReorderMsg] = React37__default.useState("");
5488
+ const rowFocusRef = React37__default.useRef(null);
5489
+ const rootRef = React37__default.useRef(null);
5490
+ const [compact, setCompact] = React37__default.useState(false);
5491
+ React37__default.useEffect(() => {
4906
5492
  const el = rootRef.current;
4907
5493
  if (!el) return void 0;
4908
5494
  const measure = () => setCompact((el.clientWidth || 0) < 720);
@@ -4915,11 +5501,11 @@ function Datatable({
4915
5501
  else if (typeof window !== "undefined") window.removeEventListener("resize", measure);
4916
5502
  };
4917
5503
  }, []);
4918
- const scrollRef = React25__default.useRef(null);
4919
- const [scrollTop, setScrollTop] = React25__default.useState(0);
4920
- const [viewportH, setViewportH] = React25__default.useState(0);
4921
- const [pivotOn, setPivotOn] = React25__default.useState(pivotMode);
4922
- const [aggConfig, setAggConfig] = React25__default.useState(() => {
5504
+ const scrollRef = React37__default.useRef(null);
5505
+ const [scrollTop, setScrollTop] = React37__default.useState(0);
5506
+ const [viewportH, setViewportH] = React37__default.useState(0);
5507
+ const [pivotOn, setPivotOn] = React37__default.useState(pivotMode);
5508
+ const [aggConfig, setAggConfig] = React37__default.useState(() => {
4923
5509
  const m = {};
4924
5510
  (columns || []).forEach((c) => {
4925
5511
  if (typeof c.aggregation === "string") m[c.field] = c.aggregation;
@@ -4927,13 +5513,13 @@ function Datatable({
4927
5513
  return m;
4928
5514
  });
4929
5515
  const aggOf = (c) => aggConfig[c.field] || (typeof c.aggregation === "function" ? c.aggregation : null);
4930
- const [pivotConfig, setPivotConfig] = React25__default.useState(() => ({
5516
+ const [pivotConfig, setPivotConfig] = React37__default.useState(() => ({
4931
5517
  rows: pivot && pivot.rows || [],
4932
5518
  columns: pivot && pivot.columns || [],
4933
5519
  values: pivot && pivot.values || []
4934
5520
  }));
4935
5521
  const pivotActive = pivotOn && pivotConfig.rows.length > 0 && pivotConfig.values.length > 0;
4936
- React25__default.useEffect(() => {
5522
+ React37__default.useEffect(() => {
4937
5523
  setOrder((prev) => {
4938
5524
  const fields = columns.map((c) => c.field);
4939
5525
  const kept = prev.filter((f) => fields.includes(f));
@@ -4941,32 +5527,37 @@ function Datatable({
4941
5527
  return [...kept, ...added];
4942
5528
  });
4943
5529
  }, [columns]);
4944
- React25__default.useEffect(() => {
5530
+ React37__default.useEffect(() => {
4945
5531
  setDensity(densityProp);
4946
5532
  }, [densityProp]);
4947
- React25__default.useEffect(() => {
5533
+ React37__default.useEffect(() => {
4948
5534
  setAggOn(showAggregation);
4949
5535
  }, [showAggregation]);
5536
+ React37__default.useEffect(() => {
5537
+ if (pageSizeControlled) return;
5538
+ setInternalRpp(pageSize > 0 ? pageSize : 10);
5539
+ setInternalPage(0);
5540
+ }, [pageSize]);
4950
5541
  const rowGroupingKey = (rowGrouping || []).join("\0");
4951
- const rowGroupingKeyRef = React25__default.useRef(rowGroupingKey);
4952
- React25__default.useEffect(() => {
5542
+ const rowGroupingKeyRef = React37__default.useRef(rowGroupingKey);
5543
+ React37__default.useEffect(() => {
4953
5544
  if (rowGroupingKeyRef.current === rowGroupingKey) return;
4954
5545
  rowGroupingKeyRef.current = rowGroupingKey;
4955
5546
  setGroupBy(rowGrouping || []);
4956
5547
  }, [rowGroupingKey]);
4957
5548
  const widthOf = (c) => widths[c.field] ?? c.width ?? 160;
4958
- const [colMenu, setColMenu] = React25__default.useState(null);
5549
+ const [colMenu, setColMenu] = React37__default.useState(null);
4959
5550
  const [menuPos, openMenu, closeMenu] = useFloating();
4960
- const [panel, setPanel] = React25__default.useState(null);
5551
+ const [panel, setPanel] = React37__default.useState(null);
4961
5552
  const [panelPos, openPanel, closePanel] = useFloating();
4962
- const [rowMenu, setRowMenu] = React25__default.useState(null);
5553
+ const [rowMenu, setRowMenu] = React37__default.useState(null);
4963
5554
  const [rowMenuPos, openRowMenu, closeRowMenu] = useFloating();
4964
- const [exportOpen, setExportOpen] = React25__default.useState(false);
5555
+ const [exportOpen, setExportOpen] = React37__default.useState(false);
4965
5556
  const [exportPos, openExport, closeExport] = useFloating();
4966
- const menuTriggerRef = React25__default.useRef(null);
4967
- const colMenuRef = React25__default.useRef(null);
4968
- const rowMenuRef = React25__default.useRef(null);
4969
- const exportMenuRef = React25__default.useRef(null);
5557
+ const menuTriggerRef = React37__default.useRef(null);
5558
+ const colMenuRef = React37__default.useRef(null);
5559
+ const rowMenuRef = React37__default.useRef(null);
5560
+ const exportMenuRef = React37__default.useRef(null);
4970
5561
  function focusFirstItem(container) {
4971
5562
  if (!container) return;
4972
5563
  const first = container.querySelector('[role="menuitem"]:not([disabled])');
@@ -5005,16 +5596,16 @@ function Datatable({
5005
5596
  restoreTriggerFocus();
5006
5597
  }
5007
5598
  }
5008
- React25__default.useEffect(() => {
5599
+ React37__default.useEffect(() => {
5009
5600
  if (colMenu) focusFirstItem(colMenuRef.current);
5010
5601
  }, [colMenu]);
5011
- React25__default.useEffect(() => {
5602
+ React37__default.useEffect(() => {
5012
5603
  if (rowMenu) focusFirstItem(rowMenuRef.current);
5013
5604
  }, [rowMenu]);
5014
- React25__default.useEffect(() => {
5605
+ React37__default.useEffect(() => {
5015
5606
  if (exportOpen) focusFirstItem(exportMenuRef.current);
5016
5607
  }, [exportOpen]);
5017
- React25__default.useEffect(() => {
5608
+ React37__default.useEffect(() => {
5018
5609
  if (!colMenu && !panel && !rowMenu) return;
5019
5610
  const closeAll = () => {
5020
5611
  setColMenu(null);
@@ -5037,7 +5628,7 @@ function Datatable({
5037
5628
  document.removeEventListener("keydown", onKey);
5038
5629
  };
5039
5630
  }, [colMenu, panel, rowMenu]);
5040
- React25__default.useEffect(() => {
5631
+ React37__default.useEffect(() => {
5041
5632
  if (!exportOpen) return;
5042
5633
  const close = () => {
5043
5634
  setExportOpen(false);
@@ -5056,9 +5647,9 @@ function Datatable({
5056
5647
  document.removeEventListener("keydown", onKey);
5057
5648
  };
5058
5649
  }, [exportOpen]);
5059
- const colByField = React25__default.useMemo(() => Object.fromEntries(cols.map((c) => [c.field, c])), [cols]);
5650
+ const colByField = React37__default.useMemo(() => Object.fromEntries(cols.map((c) => [c.field, c])), [cols]);
5060
5651
  const visibleCols = cols.filter((c) => !hidden.has(c.field));
5061
- const ordered = React25__default.useMemo(() => {
5652
+ const ordered = React37__default.useMemo(() => {
5062
5653
  const orderIdx = (f) => {
5063
5654
  const i = order.indexOf(f);
5064
5655
  return i === -1 ? 9999 : i;
@@ -5093,7 +5684,7 @@ function Datatable({
5093
5684
  }
5094
5685
  return {};
5095
5686
  };
5096
- const processed = React25__default.useMemo(() => {
5687
+ const processed = React37__default.useMemo(() => {
5097
5688
  if (serverMode) {
5098
5689
  if (rowOrder) {
5099
5690
  const idx = new Map(rowOrder.map((k, i) => [k, i]));
@@ -5130,12 +5721,12 @@ function Datatable({
5130
5721
  const paginated = pageSize > 0;
5131
5722
  const serverTotal = rowCount == null ? processed.length : rowCount;
5132
5723
  const totalRows = serverMode ? serverTotal : processed.length;
5133
- const totalPages = paginated ? Math.max(1, Math.ceil(totalRows / rowsPerPage)) : 1;
5134
- const paged = !paginated || serverMode ? processed : processed.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage);
5135
- React25__default.useEffect(() => {
5136
- if (page > totalPages - 1) setPage(0);
5724
+ const totalPages = paginated ? Math.max(1, Math.ceil(totalRows / sizeVal)) : 1;
5725
+ const paged = !paginated || serverMode ? processed : processed.slice(pageVal * sizeVal, pageVal * sizeVal + sizeVal);
5726
+ React37__default.useEffect(() => {
5727
+ if (pageVal > totalPages - 1) commitPage(0);
5137
5728
  }, [totalPages]);
5138
- const activeGroupBy = React25__default.useMemo(() => groupBy.filter((f) => colByField[f]), [groupBy, colByField]);
5729
+ const activeGroupBy = React37__default.useMemo(() => groupBy.filter((f) => colByField[f]), [groupBy, colByField]);
5139
5730
  function subtotalText(rowsIn) {
5140
5731
  const parts = [];
5141
5732
  for (const c of ordered) {
@@ -5162,7 +5753,7 @@ function Datatable({
5162
5753
  if (agg === "max") return Math.max(...nums);
5163
5754
  return null;
5164
5755
  }
5165
- const displayItems = React25__default.useMemo(() => {
5756
+ const displayItems = React37__default.useMemo(() => {
5166
5757
  if (!activeGroupBy.length) return null;
5167
5758
  const build = (rowsIn, depth, prefix) => {
5168
5759
  if (depth >= activeGroupBy.length) return rowsIn.map((row) => ({ kind: "leaf", row }));
@@ -5204,7 +5795,7 @@ function Datatable({
5204
5795
  return { top, bottom };
5205
5796
  });
5206
5797
  }
5207
- React25__default.useEffect(() => {
5798
+ React37__default.useEffect(() => {
5208
5799
  if (!rowPinning) return;
5209
5800
  const measure = () => {
5210
5801
  if (theadRef.current) setHeadH(theadRef.current.offsetHeight || 41);
@@ -5218,12 +5809,12 @@ function Datatable({
5218
5809
  const pinnedTopRows = canPinRows ? pinnedRows.top.map((k) => leafRows.find((r, i) => keyOf(r, i) === k)).filter(Boolean) : [];
5219
5810
  const pinnedBottomRows = canPinRows ? pinnedRows.bottom.map((k) => leafRows.find((r, i) => keyOf(r, i) === k)).filter(Boolean) : [];
5220
5811
  const middleRows = canPinRows ? leafRows.filter((r, i) => !pinSideOf(keyOf(r, i))) : leafRows;
5221
- const keyIndex = React25__default.useMemo(() => {
5812
+ const keyIndex = React37__default.useMemo(() => {
5222
5813
  const m = /* @__PURE__ */ new Map();
5223
5814
  leafRows.forEach((r, i) => m.set(keyOf(r, i), i));
5224
5815
  return m;
5225
5816
  }, [leafRows]);
5226
- const keyIndexMid = React25__default.useMemo(() => {
5817
+ const keyIndexMid = React37__default.useMemo(() => {
5227
5818
  const m = /* @__PURE__ */ new Map();
5228
5819
  middleRows.forEach((r, i) => m.set(keyOf(r, keyIndex.get(keyOf(r)) ?? i), i));
5229
5820
  return m;
@@ -5308,7 +5899,7 @@ function Datatable({
5308
5899
  setReorderMsg("Reorder cancelled.");
5309
5900
  }
5310
5901
  }
5311
- React25__default.useEffect(() => {
5902
+ React37__default.useEffect(() => {
5312
5903
  if (rowFocusRef.current == null) return;
5313
5904
  const key = rowFocusRef.current;
5314
5905
  rowFocusRef.current = null;
@@ -5320,7 +5911,7 @@ function Datatable({
5320
5911
  });
5321
5912
  const estRowH = rowHeight ?? (density === "compact" ? 36 : density === "comfortable" ? 56 : 44);
5322
5913
  const virtualizing = virtualized && !paginated && !activeGroupBy.length && !loading;
5323
- React25__default.useEffect(() => {
5914
+ React37__default.useEffect(() => {
5324
5915
  if (!virtualizing) return;
5325
5916
  const el = scrollRef.current;
5326
5917
  if (!el) return;
@@ -5330,13 +5921,13 @@ function Datatable({
5330
5921
  if (ro) ro.observe(el);
5331
5922
  return () => ro && ro.disconnect();
5332
5923
  }, [virtualizing, height]);
5333
- const onScrollVirtual = React25__default.useCallback((e) => {
5924
+ const onScrollVirtual = React37__default.useCallback((e) => {
5334
5925
  setScrollTop(e.currentTarget.scrollTop);
5335
5926
  }, []);
5336
5927
  const vh = viewportH || (typeof height === "number" ? height : 440);
5337
- const rowHRef = React25__default.useRef(/* @__PURE__ */ new Map());
5338
- const [measureTick, setMeasureTick] = React25__default.useState(0);
5339
- const offsets = React25__default.useMemo(() => {
5928
+ const rowHRef = React37__default.useRef(/* @__PURE__ */ new Map());
5929
+ const [measureTick, setMeasureTick] = React37__default.useState(0);
5930
+ const offsets = React37__default.useMemo(() => {
5340
5931
  if (!virtualizing) return null;
5341
5932
  const total = middleRows.length;
5342
5933
  const arr = new Float64Array(total + 1);
@@ -5346,7 +5937,7 @@ function Datatable({
5346
5937
  }
5347
5938
  return arr;
5348
5939
  }, [virtualizing, middleRows, estRowH, measureTick]);
5349
- const vWindow = React25__default.useMemo(() => {
5940
+ const vWindow = React37__default.useMemo(() => {
5350
5941
  if (!virtualizing || !offsets) return null;
5351
5942
  const total = middleRows.length;
5352
5943
  const totalH = offsets[total];
@@ -5375,7 +5966,7 @@ function Datatable({
5375
5966
  if (start > end) start = end;
5376
5967
  return { start, end, padTop: offsets[start], padBottom: Math.max(0, totalH - offsets[end]) };
5377
5968
  }, [virtualizing, offsets, middleRows.length, vh, scrollTop, overscan]);
5378
- React25__default.useLayoutEffect(() => {
5969
+ React37__default.useLayoutEffect(() => {
5379
5970
  if (!virtualizing) return;
5380
5971
  const el = scrollRef.current;
5381
5972
  if (!el) return;
@@ -5390,21 +5981,21 @@ function Datatable({
5390
5981
  }
5391
5982
  if (changed) setMeasureTick((t) => t + 1);
5392
5983
  });
5393
- const onServerChangeRef = React25__default.useRef(onServerChange);
5984
+ const onServerChangeRef = React37__default.useRef(onServerChange);
5394
5985
  onServerChangeRef.current = onServerChange;
5395
- React25__default.useEffect(() => {
5986
+ React37__default.useEffect(() => {
5396
5987
  if (!serverMode) return;
5397
5988
  const t = setTimeout(() => {
5398
5989
  onServerChangeRef.current?.({
5399
- page,
5400
- pageSize: rowsPerPage,
5990
+ page: pageVal,
5991
+ pageSize: sizeVal,
5401
5992
  sort,
5402
5993
  filters: filters.map(({ id, ...f }) => f),
5403
5994
  quickFilter: quick.trim()
5404
5995
  });
5405
5996
  }, 250);
5406
5997
  return () => clearTimeout(t);
5407
- }, [serverMode, page, rowsPerPage, sort, filters, quick]);
5998
+ }, [serverMode, pageVal, sizeVal, sort, filters, quick]);
5408
5999
  function cycleSort(field) {
5409
6000
  setSort((s) => !s || s.field !== field ? { field, dir: "asc" } : s.dir === "asc" ? { field, dir: "desc" } : null);
5410
6001
  }
@@ -5427,7 +6018,7 @@ function Datatable({
5427
6018
  return n;
5428
6019
  });
5429
6020
  }
5430
- const movableMidFields = React25__default.useMemo(
6021
+ const movableMidFields = React37__default.useMemo(
5431
6022
  () => ordered.filter((c) => !pins.left.includes(c.field) && !pins.right.includes(c.field) && c.reorderable !== false).map((c) => c.field),
5432
6023
  [ordered, pins]
5433
6024
  );
@@ -5458,7 +6049,7 @@ function Datatable({
5458
6049
  }
5459
6050
  return [...set].sort((a, b) => a.localeCompare(b)).map((v) => ({ value: v, label: v }));
5460
6051
  }
5461
- const [resizing, setResizing] = React25__default.useState(false);
6052
+ const [resizing, setResizing] = React37__default.useState(false);
5462
6053
  function startResize(e, field) {
5463
6054
  e.preventDefault();
5464
6055
  e.stopPropagation();
@@ -5565,7 +6156,7 @@ function Datatable({
5565
6156
  if (!agg) return null;
5566
6157
  if (aggregationValues && col.field in aggregationValues) {
5567
6158
  const pre = aggregationValues[col.field];
5568
- if (pre && typeof pre === "object" && !React25__default.isValidElement(pre)) {
6159
+ if (pre && typeof pre === "object" && !React37__default.isValidElement(pre)) {
5569
6160
  if (typeof agg === "string" && agg in pre) return pre[agg];
5570
6161
  } else {
5571
6162
  return pre;
@@ -5683,14 +6274,14 @@ function Datatable({
5683
6274
  focusCell(r, c);
5684
6275
  }
5685
6276
  }
5686
- React25__default.useEffect(() => {
6277
+ React37__default.useEffect(() => {
5687
6278
  setFocus((f) => ({ r: Math.min(f.r, Math.max(0, leafRows.length - 1)), c: Math.min(f.c, Math.max(0, ordered.length - 1)) }));
5688
- }, [leafRows.length, ordered.length, page]);
5689
- const selectedRows = React25__default.useMemo(() => rows.filter((r, i) => selected.has(keyOf(r, i))), [rows, selected]);
6279
+ }, [leafRows.length, ordered.length, pageVal]);
6280
+ const selectedRows = React37__default.useMemo(() => rows.filter((r, i) => selected.has(keyOf(r, i))), [rows, selected]);
5690
6281
  function clearSelection() {
5691
6282
  setSelected(/* @__PURE__ */ new Set());
5692
6283
  }
5693
- const [editing, setEditing] = React25__default.useState(null);
6284
+ const [editing, setEditing] = React37__default.useState(null);
5694
6285
  const isColEditable = (c) => c.type !== "actions" && (c.editable ?? (editMode && c.editable !== false));
5695
6286
  function beginEdit(rowK, col, row) {
5696
6287
  if (!isColEditable(col)) return;
@@ -5725,17 +6316,17 @@ function Datatable({
5725
6316
  cancelEdit();
5726
6317
  }
5727
6318
  }
5728
- const batchEditableCols = React25__default.useMemo(
6319
+ const batchEditableCols = React37__default.useMemo(
5729
6320
  () => cols.filter((c) => c.type !== "actions" && (c.editable ?? (editMode && c.editable !== false))),
5730
6321
  [cols, editMode]
5731
6322
  );
5732
- const [batchEdit, setBatchEdit] = React25__default.useState(null);
6323
+ const [batchEdit, setBatchEdit] = React37__default.useState(null);
5733
6324
  const [batchEditPos, openBatchEdit, closeBatchEdit] = useFloating();
5734
6325
  function openBatchEditor(el) {
5735
6326
  setBatchEdit({ fields: {}, values: {} });
5736
6327
  openBatchEdit(el, "left", 320);
5737
6328
  }
5738
- React25__default.useEffect(() => {
6329
+ React37__default.useEffect(() => {
5739
6330
  if (!batchEdit) return;
5740
6331
  const close = () => {
5741
6332
  setBatchEdit(null);
@@ -5754,7 +6345,7 @@ function Datatable({
5754
6345
  document.removeEventListener("keydown", onKey);
5755
6346
  };
5756
6347
  }, [batchEdit]);
5757
- React25__default.useEffect(() => {
6348
+ React37__default.useEffect(() => {
5758
6349
  if (batchEdit && selected.size === 0) {
5759
6350
  setBatchEdit(null);
5760
6351
  closeBatchEdit();
@@ -5791,7 +6382,7 @@ function Datatable({
5791
6382
  setBatchEdit(null);
5792
6383
  closeBatchEdit();
5793
6384
  }
5794
- React25__default.useEffect(() => {
6385
+ React37__default.useEffect(() => {
5795
6386
  if (!editing) return;
5796
6387
  const onDown = (e) => {
5797
6388
  if (e.target.closest(".twc-dt__editor-wrap") || e.target.closest(".twc-pop")) return;
@@ -5930,7 +6521,7 @@ function Datatable({
5930
6521
  {
5931
6522
  className: "twc-dt__row",
5932
6523
  role: "row",
5933
- "aria-rowindex": (paginated && !serverMode ? page * rowsPerPage : 0) + ri + 2,
6524
+ "aria-rowindex": (paginated && !serverMode ? pageVal * sizeVal : 0) + ri + 2,
5934
6525
  "aria-selected": (checkboxSelection ? sel : rowActive) || void 0,
5935
6526
  "data-selected": sel || void 0,
5936
6527
  "data-active": rowActive || void 0,
@@ -5988,7 +6579,7 @@ function Datatable({
5988
6579
  ] }),
5989
6580
  rowResize && !pinSide ? /* @__PURE__ */ jsx("span", { className: "twc-dt__row-resizer", title: "Drag to resize row", onPointerDown: (e) => startRowResize(e, k, e.currentTarget.closest("tr")), onClick: (e) => e.stopPropagation() }) : null
5990
6581
  ] }) : null,
5991
- showRowNum ? /* @__PURE__ */ jsx("td", { className: "twc-dt__td twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", "data-pin-edge": pins.left.length ? void 0 : "left", style: { insetInlineStart: numLeft, width: NUM_W }, children: typeof ri === "number" ? (paginated || serverMode ? page * rowsPerPage : 0) + ri + 1 : "" }) : null,
6582
+ showRowNum ? /* @__PURE__ */ jsx("td", { className: "twc-dt__td twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", "data-pin-edge": pins.left.length ? void 0 : "left", style: { insetInlineStart: numLeft, width: NUM_W }, children: typeof ri === "number" ? (paginated || serverMode ? pageVal * sizeVal : 0) + ri + 1 : "" }) : null,
5992
6583
  ordered.map((c, ci) => {
5993
6584
  const st = stickyOf(c.field);
5994
6585
  const val = row[c.field];
@@ -6316,7 +6907,7 @@ function Datatable({
6316
6907
  /* @__PURE__ */ jsx(Svg, { d: I.search }),
6317
6908
  /* @__PURE__ */ jsx("input", { placeholder: "Search\u2026", "aria-label": "Search rows", value: quick, onChange: (e) => {
6318
6909
  setQuick(e.target.value);
6319
- setPage(0);
6910
+ commitPage(0);
6320
6911
  } })
6321
6912
  ] })
6322
6913
  ] }),
@@ -6518,7 +7109,7 @@ function Datatable({
6518
7109
  );
6519
7110
  })
6520
7111
  ] }) }),
6521
- /* @__PURE__ */ jsx("tbody", { children: loading ? Array.from({ length: paginated ? Math.min(rowsPerPage, 8) : 8 }).map((_, ri) => /* @__PURE__ */ jsxs("tr", { className: "twc-dt__row", role: "row", children: [
7112
+ /* @__PURE__ */ jsx("tbody", { children: loading ? Array.from({ length: paginated ? Math.min(sizeVal, 8) : 8 }).map((_, ri) => /* @__PURE__ */ jsxs("tr", { className: "twc-dt__row", role: "row", children: [
6522
7113
  checkboxSelection ? /* @__PURE__ */ jsx("td", { className: "twc-dt__td", role: "gridcell", "data-pin": "left", style: { insetInlineStart: 0, width: 44 }, children: /* @__PURE__ */ jsx("span", { className: "twc-dt__sk", "aria-hidden": "true", style: { "--_w": "18px", height: 18, borderRadius: 4 } }) }) : null,
6523
7114
  showRowNum ? /* @__PURE__ */ jsx("td", { className: "twc-dt__td twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", style: { insetInlineStart: numLeft, width: NUM_W }, children: /* @__PURE__ */ jsx("span", { className: "twc-dt__sk", "aria-hidden": "true", style: { "--_w": "16px", height: 14, borderRadius: 4 } }) }) : null,
6524
7115
  ordered.map((c, ci) => {
@@ -6562,7 +7153,7 @@ function Datatable({
6562
7153
  const nf = (n) => n.toLocaleString();
6563
7154
  if (totalRows === 0) return "No rows";
6564
7155
  const shown = paged.length;
6565
- const start = paginated ? page * rowsPerPage + 1 : 1;
7156
+ const start = paginated ? pageVal * sizeVal + 1 : 1;
6566
7157
  const end = paginated ? start + shown - 1 : shown;
6567
7158
  return /* @__PURE__ */ jsxs(Fragment, { children: [
6568
7159
  paginated ? /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -6590,13 +7181,10 @@ function Datatable({
6590
7181
  })() }),
6591
7182
  paginated ? /* @__PURE__ */ jsxs("div", { className: "twc-dt__rpp", children: [
6592
7183
  /* @__PURE__ */ jsx("span", { className: "twc-dt__rpp-label", children: "Rows per page" }),
6593
- /* @__PURE__ */ jsx("div", { style: { width: 78 }, children: /* @__PURE__ */ jsx(Select, { size: "sm", portal: true, searchable: false, value: String(rowsPerPage), options: rppOptions, placement: "top", onChange: (v) => {
6594
- setRowsPerPage(Number(v));
6595
- setPage(0);
6596
- } }) })
7184
+ /* @__PURE__ */ jsx("div", { style: { width: 78 }, children: /* @__PURE__ */ jsx(Select, { size: "sm", portal: true, searchable: false, value: String(sizeVal), options: rppOptions, placement: "top", onChange: (v) => commitPageSize(Number(v)) }) })
6597
7185
  ] }) : null
6598
7186
  ] }),
6599
- paginated ? /* @__PURE__ */ jsx("div", { className: "twc-dt__footer-row", "data-pager": "true", children: /* @__PURE__ */ jsx(Pagination, { size: "sm", page: page + 1, total: totalPages, boundaries: 3, showPageJumper: showPageJumper && totalPages > 5, onChange: (p) => setPage(p - 1) }) }) : null
7187
+ paginated ? /* @__PURE__ */ jsx("div", { className: "twc-dt__footer-row", "data-pager": "true", children: /* @__PURE__ */ jsx(Pagination, { size: "sm", page: pageVal + 1, total: totalPages, boundaries: 3, showPageJumper: showPageJumper && totalPages > 5, onChange: (p) => commitPage(p - 1) }) }) : null
6600
7188
  ] }) : null,
6601
7189
  exportOpen && exportPos ? /* @__PURE__ */ jsxs(
6602
7190
  "div",
@@ -7245,6 +7833,18 @@ var DATEPICKER_CSS = `
7245
7833
  .twc-dp__clear { position: absolute; inset-inline-end: 10px; top: 50%; transform: translateY(-50%); display: inline-grid; place-items: center; width: 20px; height: 20px; border: none; background: transparent; color: var(--color-text-subtle); cursor: pointer; border-radius: var(--radius-full); }
7246
7834
  .twc-dp__clear:hover { background: var(--color-surface-sunken); color: var(--color-text); }
7247
7835
  .twc-dp__clear svg { width: 14px; height: 14px; }
7836
+ /* #105: editable (typed entry) variant \u2014 the control wraps a real text input + a trailing toggle. */
7837
+ .twc-dp__control--editable { cursor: text; gap: 0; padding-inline-end: var(--space-1); }
7838
+ .twc-dp__input { flex: 1; min-width: 0; height: 100%; border: none; background: transparent; outline: none; padding: 0;
7839
+ font-family: inherit; font-size: var(--text-sm); color: var(--color-text); }
7840
+ .twc-dp__input::placeholder { color: var(--color-text-subtle); }
7841
+ .twc-dp__input:disabled { cursor: not-allowed; }
7842
+ .twc-dp__clear--inline { position: static; transform: none; flex: none; }
7843
+ .twc-dp__toggle { flex: none; display: inline-grid; place-items: center; width: 26px; height: 26px; border: none; background: transparent;
7844
+ color: var(--color-text-subtle); cursor: pointer; border-radius: var(--radius-md); transition: background-color var(--duration-fast), color var(--duration-fast); }
7845
+ .twc-dp__toggle:hover:not(:disabled) { background: var(--color-surface-sunken); color: var(--color-text); }
7846
+ .twc-dp__toggle:disabled { cursor: not-allowed; }
7847
+ .twc-dp__toggle svg { width: 17px; height: 17px; }
7248
7848
 
7249
7849
  .twc-dp__pop {
7250
7850
  position: fixed; z-index: var(--z-popover); width: 280px;
@@ -7304,6 +7904,8 @@ function DatePicker({
7304
7904
  disabled = false,
7305
7905
  tone = "primary",
7306
7906
  clearable = true,
7907
+ editable = false,
7908
+ parse,
7307
7909
  format,
7308
7910
  locale,
7309
7911
  weekStartsOn = 0,
@@ -7314,23 +7916,25 @@ function DatePicker({
7314
7916
  }) {
7315
7917
  const __twcStyles0 = useScopedStyles("twc-field-styles", FIELD_CSS3);
7316
7918
  const __twcStyles1 = useScopedStyles("twc-datepicker-styles", DATEPICKER_CSS);
7317
- const autoId = React25__default.useId();
7919
+ const autoId = React37__default.useId();
7318
7920
  const fieldId = id || autoId;
7319
7921
  const descId = `${fieldId}-desc`;
7320
7922
  const invalid = Boolean(error);
7321
- const [internal, setInternal] = React25__default.useState(defaultValue);
7923
+ const [internal, setInternal] = React37__default.useState(defaultValue);
7322
7924
  const selected = value !== void 0 ? value : internal;
7323
- const [open, setOpen] = React25__default.useState(false);
7324
- const [view, setView] = React25__default.useState(selected || /* @__PURE__ */ new Date());
7325
- const [mode, setMode] = React25__default.useState("days");
7326
- const [focusDate, setFocusDate] = React25__default.useState(null);
7327
- const [coords, setCoords] = React25__default.useState(null);
7328
- const wrapRef = React25__default.useRef(null);
7329
- const triggerRef = React25__default.useRef(null);
7330
- const popRef = React25__default.useRef(null);
7331
- const gridRef = React25__default.useRef(null);
7925
+ const [open, setOpen] = React37__default.useState(false);
7926
+ const [view, setView] = React37__default.useState(selected || /* @__PURE__ */ new Date());
7927
+ const [mode, setMode] = React37__default.useState("days");
7928
+ const [focusDate, setFocusDate] = React37__default.useState(null);
7929
+ const [focusMonth, setFocusMonth] = React37__default.useState(null);
7930
+ const [editText, setEditText] = React37__default.useState(null);
7931
+ const [coords, setCoords] = React37__default.useState(null);
7932
+ const wrapRef = React37__default.useRef(null);
7933
+ const triggerRef = React37__default.useRef(null);
7934
+ const popRef = React37__default.useRef(null);
7935
+ const gridRef = React37__default.useRef(null);
7332
7936
  const POP_W = 280;
7333
- const place = React25__default.useCallback(() => {
7937
+ const place = React37__default.useCallback(() => {
7334
7938
  const el = triggerRef.current;
7335
7939
  if (!el) return;
7336
7940
  const r = el.getBoundingClientRect();
@@ -7341,7 +7945,7 @@ function DatePicker({
7341
7945
  left = Math.max(8, left);
7342
7946
  setCoords({ left, top: flip ? void 0 : Math.round(r.bottom + 6), bottom: flip ? Math.round(vh - r.top + 6) : void 0 });
7343
7947
  }, []);
7344
- React25__default.useEffect(() => {
7948
+ React37__default.useEffect(() => {
7345
7949
  if (!open) return void 0;
7346
7950
  place();
7347
7951
  const onMove = () => place();
@@ -7352,7 +7956,7 @@ function DatePicker({
7352
7956
  window.removeEventListener("resize", onMove);
7353
7957
  };
7354
7958
  }, [open, place]);
7355
- React25__default.useEffect(() => {
7959
+ React37__default.useEffect(() => {
7356
7960
  if (!open) return;
7357
7961
  setView(selected || /* @__PURE__ */ new Date());
7358
7962
  setMode("days");
@@ -7372,21 +7976,10 @@ function DatePicker({
7372
7976
  document.removeEventListener("keydown", onKey);
7373
7977
  };
7374
7978
  }, [open]);
7375
- const prevOpen = React25__default.useRef(false);
7376
- React25__default.useEffect(() => {
7377
- let id2;
7378
- if (!prevOpen.current && open) {
7379
- id2 = setTimeout(() => gridRef.current?.querySelector('[tabindex="0"]')?.focus({ preventScroll: true }), 30);
7380
- } else if (prevOpen.current && !open) {
7381
- const ae = typeof document !== "undefined" ? document.activeElement : null;
7382
- if (!ae || ae === document.body) triggerRef.current?.focus();
7383
- }
7384
- prevOpen.current = open;
7385
- return () => clearTimeout(id2);
7386
- }, [open]);
7387
- const months = React25__default.useMemo(() => locale === void 0 ? MONTHS : monthNames(locale), [locale]);
7388
- const monthsShort = React25__default.useMemo(() => locale === void 0 ? MONTHS.map((n) => n.slice(0, 3)) : monthShortNames(locale), [locale]);
7389
- const dows = React25__default.useMemo(
7979
+ useFocusTrap(popRef, open && !!coords, { initialFocus: () => gridRef.current?.querySelector('[tabindex="0"]') });
7980
+ const months = React37__default.useMemo(() => locale === void 0 ? MONTHS : monthNames(locale), [locale]);
7981
+ const monthsShort = React37__default.useMemo(() => locale === void 0 ? MONTHS.map((n) => n.slice(0, 3)) : monthShortNames(locale), [locale]);
7982
+ const dows = React37__default.useMemo(
7390
7983
  () => locale === void 0 ? Array.from({ length: 7 }, (_, i) => DOW[(i + weekStartsOn) % 7]) : weekdayNames(locale, weekStartsOn),
7391
7984
  [locale, weekStartsOn]
7392
7985
  );
@@ -7398,8 +7991,33 @@ function DatePicker({
7398
7991
  const pick = (d) => {
7399
7992
  if (value === void 0) setInternal(d);
7400
7993
  onChange?.(d);
7994
+ setEditText(null);
7401
7995
  setOpen(false);
7402
7996
  };
7997
+ const parseTyped = (s) => {
7998
+ const str = s.trim();
7999
+ if (str === "") return null;
8000
+ if (parse) {
8001
+ const d = parse(str);
8002
+ return d instanceof Date && !Number.isNaN(d.getTime()) ? d : void 0;
8003
+ }
8004
+ const t = Date.parse(str);
8005
+ return Number.isNaN(t) ? void 0 : new Date(t);
8006
+ };
8007
+ const commitText = () => {
8008
+ if (editText == null) return;
8009
+ const parsed = parseTyped(editText);
8010
+ if (parsed === null) {
8011
+ setEditText(null);
8012
+ if (selected) pick(null);
8013
+ return;
8014
+ }
8015
+ if (parsed === void 0 || outOfRange(parsed)) {
8016
+ setEditText(null);
8017
+ return;
8018
+ }
8019
+ pick(parsed);
8020
+ };
7403
8021
  const y = view.getFullYear(), m = view.getMonth();
7404
8022
  const first = new Date(y, m, 1);
7405
8023
  const startOffset = (first.getDay() - weekStartsOn + 7) % 7;
@@ -7414,10 +8032,34 @@ function DatePicker({
7414
8032
  };
7415
8033
  const cells = Array.from({ length: 42 }, (_, i) => new Date(gridStart.getFullYear(), gridStart.getMonth(), gridStart.getDate() + i));
7416
8034
  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);
7417
- React25__default.useEffect(() => {
8035
+ React37__default.useEffect(() => {
7418
8036
  if (!open || mode !== "days" || !focusDate) return;
7419
8037
  gridRef.current?.querySelector(`[data-key="${keyOf(focusDate)}"]`)?.focus();
7420
8038
  }, [focusDate, open, mode]);
8039
+ React37__default.useEffect(() => {
8040
+ if (!open || mode !== "months" || focusMonth == null) return;
8041
+ gridRef.current?.querySelector(`[data-mo="${focusMonth}"]`)?.focus();
8042
+ }, [focusMonth, open, mode]);
8043
+ const onMonthsKeyDown = (e) => {
8044
+ const cur = focusMonth == null ? m : focusMonth;
8045
+ let next;
8046
+ if (e.key === "ArrowRight") next = cur + 1;
8047
+ else if (e.key === "ArrowLeft") next = cur - 1;
8048
+ else if (e.key === "ArrowDown") next = cur + 3;
8049
+ else if (e.key === "ArrowUp") next = cur - 3;
8050
+ else if (e.key === "Home") next = 0;
8051
+ else if (e.key === "End") next = 11;
8052
+ else return;
8053
+ e.preventDefault();
8054
+ if (next < 0) {
8055
+ setView(new Date(y - 1, 0, 1));
8056
+ next += 12;
8057
+ } else if (next > 11) {
8058
+ setView(new Date(y + 1, 0, 1));
8059
+ next -= 12;
8060
+ }
8061
+ setFocusMonth(next);
8062
+ };
7421
8063
  const onGridKeyDown = (e) => {
7422
8064
  const btn = e.target.closest?.("[data-key]");
7423
8065
  if (!btn) return;
@@ -7451,7 +8093,82 @@ function DatePicker({
7451
8093
  label,
7452
8094
  required ? /* @__PURE__ */ jsx("span", { className: "twc-field__req", children: "*" }) : null
7453
8095
  ] }) : null,
7454
- /* @__PURE__ */ jsxs("div", { className: "twc-dp__field", children: [
8096
+ /* @__PURE__ */ jsx("div", { className: "twc-dp__field", children: editable ? (
8097
+ // #105: typed entry — the trigger is a real text input with a trailing
8098
+ // calendar toggle button; typing commits via `parse` on Enter/blur.
8099
+ /* @__PURE__ */ jsxs(
8100
+ "div",
8101
+ {
8102
+ className: "twc-dp__control twc-dp__control--editable",
8103
+ "data-open": open || void 0,
8104
+ "data-disabled": disabled || void 0,
8105
+ "data-tone": tone,
8106
+ "data-invalid": invalid || void 0,
8107
+ children: [
8108
+ /* @__PURE__ */ jsx(
8109
+ "input",
8110
+ {
8111
+ ref: triggerRef,
8112
+ className: "twc-dp__input",
8113
+ id: fieldId,
8114
+ type: "text",
8115
+ inputMode: "numeric",
8116
+ autoComplete: "off",
8117
+ disabled,
8118
+ placeholder,
8119
+ value: editText != null ? editText : selected ? fmt(selected) : "",
8120
+ "aria-haspopup": "dialog",
8121
+ "aria-expanded": open,
8122
+ "aria-labelledby": label ? `${fieldId}-label` : void 0,
8123
+ "aria-invalid": invalid || void 0,
8124
+ "aria-describedby": error || hint ? descId : void 0,
8125
+ onChange: (e) => setEditText(e.target.value),
8126
+ onKeyDown: (e) => {
8127
+ if (e.key === "Enter") {
8128
+ e.preventDefault();
8129
+ commitText();
8130
+ } else if (e.key === "ArrowDown" && (e.altKey || !open)) {
8131
+ e.preventDefault();
8132
+ setOpen(true);
8133
+ } else if (e.key === "Escape" && open) setOpen(false);
8134
+ },
8135
+ onBlur: (e) => {
8136
+ if (popRef.current && popRef.current.contains(e.relatedTarget)) return;
8137
+ commitText();
8138
+ }
8139
+ }
8140
+ ),
8141
+ clearable && selected && !disabled ? /* @__PURE__ */ jsx(
8142
+ "button",
8143
+ {
8144
+ type: "button",
8145
+ className: "twc-dp__clear twc-dp__clear--inline",
8146
+ "aria-label": "Clear",
8147
+ tabIndex: -1,
8148
+ onMouseDown: (e) => e.preventDefault(),
8149
+ onClick: () => pick(null),
8150
+ children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
8151
+ }
8152
+ ) : null,
8153
+ /* @__PURE__ */ jsx(
8154
+ "button",
8155
+ {
8156
+ type: "button",
8157
+ className: "twc-dp__toggle",
8158
+ "aria-label": "Open calendar",
8159
+ tabIndex: -1,
8160
+ disabled,
8161
+ onClick: () => !disabled && setOpen((o) => !o),
8162
+ children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
8163
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
8164
+ /* @__PURE__ */ jsx("path", { d: "M16 2v4M8 2v4M3 10h18" })
8165
+ ] })
8166
+ }
8167
+ )
8168
+ ]
8169
+ }
8170
+ )
8171
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
7455
8172
  /* @__PURE__ */ jsxs(
7456
8173
  "div",
7457
8174
  {
@@ -7490,7 +8207,7 @@ function DatePicker({
7490
8207
  e.stopPropagation();
7491
8208
  pick(null);
7492
8209
  }, children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
7493
- ] }),
8210
+ ] }) }),
7494
8211
  open && coords ? createPortal(
7495
8212
  /* @__PURE__ */ jsxs(
7496
8213
  "div",
@@ -7498,12 +8215,16 @@ function DatePicker({
7498
8215
  className: "twc-dp__pop",
7499
8216
  ref: popRef,
7500
8217
  role: "dialog",
8218
+ "aria-modal": "true",
7501
8219
  "aria-label": "Choose date",
7502
8220
  style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-tooltip)" },
7503
8221
  children: [
7504
8222
  /* @__PURE__ */ jsxs("div", { className: "twc-dp__head", children: [
7505
8223
  /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dp__nav", "aria-label": "Previous", onClick: () => setView(mode === "months" ? new Date(y - 1, m, 1) : new Date(y, m - 1, 1)), children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m15 18-6-6 6-6" }) }) }),
7506
- /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dp__title", onClick: () => setMode(mode === "days" ? "months" : "days"), children: mode === "days" ? `${months[m]} ${y}` : y }),
8224
+ /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dp__title", onClick: () => {
8225
+ if (mode === "days") setFocusMonth(m);
8226
+ setMode(mode === "days" ? "months" : "days");
8227
+ }, children: mode === "days" ? `${months[m]} ${y}` : y }),
7507
8228
  /* @__PURE__ */ jsx("span", { className: "twc-dp__sr", "aria-live": "polite", children: mode === "days" ? `${months[m]} ${y}` : y }),
7508
8229
  /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dp__nav", "aria-label": "Next", onClick: () => setView(mode === "months" ? new Date(y + 1, m, 1) : new Date(y, m + 1, 1)), children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" }) }) })
7509
8230
  ] }),
@@ -7531,11 +8252,14 @@ function DatePicker({
7531
8252
  i
7532
8253
  );
7533
8254
  })
7534
- ] }) : /* @__PURE__ */ jsx("div", { className: "twc-dp__months", children: monthsShort.map((name, i) => /* @__PURE__ */ jsx(
8255
+ ] }) : /* @__PURE__ */ jsx("div", { className: "twc-dp__months", ref: gridRef, onKeyDown: onMonthsKeyDown, role: "grid", children: monthsShort.map((name, i) => /* @__PURE__ */ jsx(
7535
8256
  "button",
7536
8257
  {
7537
8258
  type: "button",
7538
8259
  className: "twc-dp__mo",
8260
+ role: "gridcell",
8261
+ "data-mo": i,
8262
+ tabIndex: i === (focusMonth ?? m) ? 0 : -1,
7539
8263
  "data-selected": selected && selected.getFullYear() === y && selected.getMonth() === i || void 0,
7540
8264
  onClick: () => {
7541
8265
  setView(new Date(y, i, 1));
@@ -7582,6 +8306,17 @@ var RANGE_CSS = `
7582
8306
  .twc-drp__ic svg { width: 17px; height: 17px; }
7583
8307
  .twc-drp__text { flex: 1; font-size: var(--text-sm); color: var(--color-text); white-space: nowrap; }
7584
8308
  .twc-drp__text[data-placeholder="true"] { color: var(--color-text-subtle); }
8309
+ /* #105: editable (typed entry) variant. */
8310
+ .twc-drp__control--editable { cursor: text; gap: 0; padding-inline-end: var(--space-1); }
8311
+ .twc-drp__input { flex: 1; min-width: 0; height: 100%; border: none; background: transparent; outline: none; padding: 0;
8312
+ font-family: inherit; font-size: var(--text-sm); color: var(--color-text); }
8313
+ .twc-drp__input::placeholder { color: var(--color-text-subtle); }
8314
+ .twc-drp__input:disabled { cursor: not-allowed; }
8315
+ .twc-drp__toggle { flex: none; display: inline-grid; place-items: center; width: 26px; height: 26px; border: none; background: transparent;
8316
+ color: var(--color-text-subtle); cursor: pointer; border-radius: var(--radius-md); transition: background-color var(--duration-fast), color var(--duration-fast); }
8317
+ .twc-drp__toggle:hover:not(:disabled) { background: var(--color-surface-sunken); color: var(--color-text); }
8318
+ .twc-drp__toggle:disabled { cursor: not-allowed; }
8319
+ .twc-drp__toggle svg { width: 17px; height: 17px; }
7585
8320
  .twc-drp__pop { position: fixed; z-index: var(--z-popover); display: flex;
7586
8321
  background: var(--color-surface-raised); border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-lg);
7587
8322
  box-shadow: var(--shadow-lg); animation: twico-scale-in var(--duration-fast) var(--ease-spring); transform-origin: top; }
@@ -7636,29 +8371,34 @@ function DateRangePicker({
7636
8371
  disabledDate,
7637
8372
  disabled = false,
7638
8373
  tone = "primary",
8374
+ editable = false,
8375
+ parse,
7639
8376
  onChange,
7640
8377
  className = "",
7641
8378
  ...rest
7642
8379
  }) {
7643
8380
  const __twcStyles0 = useScopedStyles("twc-field-styles", FIELD_CSS4);
7644
8381
  const __twcStyles1 = useScopedStyles("twc-drp-styles", RANGE_CSS);
7645
- const [internal, setInternal] = React25__default.useState(defaultValue);
8382
+ const [internal, setInternal] = React37__default.useState(defaultValue);
7646
8383
  const range = value !== void 0 ? value : internal;
7647
- const [open, setOpen] = React25__default.useState(false);
7648
- const [view, setView] = React25__default.useState(range.start || /* @__PURE__ */ new Date());
7649
- const [hover, setHover] = React25__default.useState(null);
7650
- const [coords, setCoords] = React25__default.useState(null);
7651
- const wrapRef = React25__default.useRef(null);
7652
- const triggerRef = React25__default.useRef(null);
7653
- const popRef = React25__default.useRef(null);
7654
- const labelId = React25__default.useId();
8384
+ const [open, setOpen] = React37__default.useState(false);
8385
+ const [view, setView] = React37__default.useState(range.start || /* @__PURE__ */ new Date());
8386
+ const [hover, setHover] = React37__default.useState(null);
8387
+ const [focusDate, setFocusDate] = React37__default.useState(null);
8388
+ const [editText, setEditText] = React37__default.useState(null);
8389
+ const [coords, setCoords] = React37__default.useState(null);
8390
+ const wrapRef = React37__default.useRef(null);
8391
+ const triggerRef = React37__default.useRef(null);
8392
+ const popRef = React37__default.useRef(null);
8393
+ const gridRef = React37__default.useRef(null);
8394
+ const labelId = React37__default.useId();
7655
8395
  const descId = `${labelId}-desc`;
7656
8396
  const invalid = Boolean(error);
7657
- React25__default.useEffect(() => {
8397
+ React37__default.useEffect(() => {
7658
8398
  if (disabled) setOpen(false);
7659
8399
  }, [disabled]);
7660
8400
  const POP_W = 420;
7661
- const place = React25__default.useCallback(() => {
8401
+ const place = React37__default.useCallback(() => {
7662
8402
  const el = triggerRef.current;
7663
8403
  if (!el) return;
7664
8404
  const r = el.getBoundingClientRect();
@@ -7669,7 +8409,7 @@ function DateRangePicker({
7669
8409
  left = Math.max(8, left);
7670
8410
  setCoords({ left, top: flip ? void 0 : Math.round(r.bottom + 6), bottom: flip ? Math.round(vh - r.top + 6) : void 0 });
7671
8411
  }, []);
7672
- React25__default.useEffect(() => {
8412
+ React37__default.useEffect(() => {
7673
8413
  if (!open) return void 0;
7674
8414
  place();
7675
8415
  const onMove = () => place();
@@ -7680,7 +8420,7 @@ function DateRangePicker({
7680
8420
  window.removeEventListener("resize", onMove);
7681
8421
  };
7682
8422
  }, [open, place]);
7683
- React25__default.useEffect(() => {
8423
+ React37__default.useEffect(() => {
7684
8424
  if (!open) return;
7685
8425
  const onDown = (e) => {
7686
8426
  if (wrapRef.current && wrapRef.current.contains(e.target)) return;
@@ -7701,7 +8441,86 @@ function DateRangePicker({
7701
8441
  if (value === void 0) setInternal(r);
7702
8442
  onChange?.(r);
7703
8443
  };
8444
+ const parseOne = (s) => {
8445
+ const str = s.trim();
8446
+ if (str === "") return null;
8447
+ if (parse) {
8448
+ const d = parse(str);
8449
+ return d instanceof Date && !Number.isNaN(d.getTime()) ? d : void 0;
8450
+ }
8451
+ const t = Date.parse(str);
8452
+ return Number.isNaN(t) ? void 0 : new Date(t);
8453
+ };
8454
+ const commitText = () => {
8455
+ if (editText == null) return;
8456
+ const raw = editText.trim();
8457
+ if (raw === "") {
8458
+ setEditText(null);
8459
+ if (range.start || range.end) set({ start: null, end: null });
8460
+ return;
8461
+ }
8462
+ const parts = raw.split(/\s*(?:–|—|\bto\b|\.\.+)\s*/i).map((p) => p.trim());
8463
+ let a = parseOne(parts[0] || "");
8464
+ let b = parts.length > 1 ? parseOne(parts[1] || "") : null;
8465
+ if (a === void 0 || b === void 0 || a && outOfRange(a) || b && outOfRange(b)) {
8466
+ setEditText(null);
8467
+ return;
8468
+ }
8469
+ if (a && b && ymd(b) < ymd(a)) {
8470
+ const t = a;
8471
+ a = b;
8472
+ b = t;
8473
+ }
8474
+ set({ start: a || null, end: b || null });
8475
+ setEditText(null);
8476
+ setOpen(false);
8477
+ };
8478
+ useFocusTrap(popRef, open && !!coords, { initialFocus: () => gridRef.current?.querySelector('[tabindex="0"]') });
7704
8479
  const outOfRange = (d) => min && ymd(d) < ymd(min) || max && ymd(d) > ymd(max) || Boolean(disabledDate && disabledDate(d));
8480
+ const sameDay2 = (a, b) => a && b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
8481
+ const keyOf = (d) => `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
8482
+ const addDays = (d, n) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);
8483
+ const addMonths = (d, n) => {
8484
+ const last = new Date(d.getFullYear(), d.getMonth() + n + 1, 0);
8485
+ return new Date(last.getFullYear(), last.getMonth(), Math.min(d.getDate(), last.getDate()));
8486
+ };
8487
+ React37__default.useEffect(() => {
8488
+ if (!open) {
8489
+ setFocusDate(null);
8490
+ setHover(null);
8491
+ }
8492
+ }, [open]);
8493
+ React37__default.useEffect(() => {
8494
+ if (!open || !focusDate) return;
8495
+ gridRef.current?.querySelector(`[data-key="${keyOf(focusDate)}"]`)?.focus();
8496
+ }, [focusDate, open]);
8497
+ const onGridKeyDown = (e) => {
8498
+ const btn = e.target.closest && e.target.closest("[data-key]");
8499
+ if (!btn) return;
8500
+ const [fy, fm, fd] = btn.getAttribute("data-key").split("-").map(Number);
8501
+ const cur = new Date(fy, fm, fd);
8502
+ let step;
8503
+ if (e.key === "ArrowLeft") step = (d) => addDays(d, -1);
8504
+ else if (e.key === "ArrowRight") step = (d) => addDays(d, 1);
8505
+ else if (e.key === "ArrowUp") step = (d) => addDays(d, -7);
8506
+ else if (e.key === "ArrowDown") step = (d) => addDays(d, 7);
8507
+ else if (e.key === "Home") step = (d) => addDays(d, -((d.getDay() - weekStartsOn + 7) % 7));
8508
+ else if (e.key === "End") step = (d) => addDays(d, 6 - (d.getDay() - weekStartsOn + 7) % 7);
8509
+ else if (e.key === "PageUp") step = (d) => addMonths(d, -1);
8510
+ else if (e.key === "PageDown") step = (d) => addMonths(d, 1);
8511
+ else return;
8512
+ e.preventDefault();
8513
+ let next = step(cur), guard = 0;
8514
+ while (outOfRange(next) && guard < 366) {
8515
+ next = step(next);
8516
+ guard += 1;
8517
+ }
8518
+ if (outOfRange(next)) return;
8519
+ setFocusDate(next);
8520
+ setHover(next);
8521
+ if (next.getFullYear() !== view.getFullYear() || next.getMonth() !== view.getMonth()) setView(new Date(next.getFullYear(), next.getMonth(), 1));
8522
+ };
8523
+ const tabbableDate = focusDate || range.start || /* @__PURE__ */ new Date();
7705
8524
  const clickDay = (d) => {
7706
8525
  if (outOfRange(d)) return;
7707
8526
  if (!range.start || range.start && range.end) {
@@ -7720,8 +8539,8 @@ function DateRangePicker({
7720
8539
  setView(start);
7721
8540
  setOpen(false);
7722
8541
  };
7723
- const months = React25__default.useMemo(() => locale === void 0 ? MONTHS2 : monthNames2(locale), [locale]);
7724
- const dows = React25__default.useMemo(
8542
+ const months = React37__default.useMemo(() => locale === void 0 ? MONTHS2 : monthNames2(locale), [locale]);
8543
+ const dows = React37__default.useMemo(
7725
8544
  () => locale === void 0 ? Array.from({ length: 7 }, (_, i) => DOW2[(i + weekStartsOn) % 7]) : weekdayNames2(locale, weekStartsOn),
7726
8545
  [locale, weekStartsOn]
7727
8546
  );
@@ -7751,7 +8570,57 @@ function DateRangePicker({
7751
8570
  label,
7752
8571
  required ? /* @__PURE__ */ jsx("span", { className: "twc-field__req", children: "*" }) : null
7753
8572
  ] }) : null,
7754
- /* @__PURE__ */ jsxs(
8573
+ editable ? (
8574
+ // #105: typed entry — a text input accepting "start – end"; commits via `parse` on Enter/blur.
8575
+ /* @__PURE__ */ jsxs("div", { className: "twc-drp__control twc-drp__control--editable", "data-open": open || void 0, "data-disabled": disabled || void 0, "data-invalid": invalid || void 0, "data-tone": tone, children: [
8576
+ /* @__PURE__ */ jsx(
8577
+ "input",
8578
+ {
8579
+ ref: triggerRef,
8580
+ className: "twc-drp__input",
8581
+ type: "text",
8582
+ autoComplete: "off",
8583
+ disabled,
8584
+ placeholder,
8585
+ value: editText != null ? editText : text,
8586
+ "aria-haspopup": "dialog",
8587
+ "aria-expanded": open,
8588
+ "aria-labelledby": label ? labelId : void 0,
8589
+ "aria-invalid": invalid || void 0,
8590
+ "aria-describedby": error || hint ? descId : void 0,
8591
+ onChange: (e) => setEditText(e.target.value),
8592
+ onKeyDown: (e) => {
8593
+ if (e.key === "Enter") {
8594
+ e.preventDefault();
8595
+ commitText();
8596
+ } else if (e.key === "ArrowDown" && (e.altKey || !open)) {
8597
+ e.preventDefault();
8598
+ setOpen(true);
8599
+ } else if (e.key === "Escape" && open) setOpen(false);
8600
+ },
8601
+ onBlur: (e) => {
8602
+ if (popRef.current && popRef.current.contains(e.relatedTarget)) return;
8603
+ commitText();
8604
+ }
8605
+ }
8606
+ ),
8607
+ /* @__PURE__ */ jsx(
8608
+ "button",
8609
+ {
8610
+ type: "button",
8611
+ className: "twc-drp__toggle",
8612
+ "aria-label": "Open calendar",
8613
+ tabIndex: -1,
8614
+ disabled,
8615
+ onClick: () => !disabled && setOpen((o) => !o),
8616
+ children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
8617
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
8618
+ /* @__PURE__ */ jsx("path", { d: "M16 2v4M8 2v4M3 10h18" })
8619
+ ] })
8620
+ }
8621
+ )
8622
+ ] })
8623
+ ) : /* @__PURE__ */ jsxs(
7755
8624
  "div",
7756
8625
  {
7757
8626
  ref: triggerRef,
@@ -7791,6 +8660,7 @@ function DateRangePicker({
7791
8660
  className: "twc-drp__pop",
7792
8661
  ref: popRef,
7793
8662
  role: "dialog",
8663
+ "aria-modal": "true",
7794
8664
  "aria-label": "Choose date range",
7795
8665
  style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-tooltip)" },
7796
8666
  children: [
@@ -7810,7 +8680,7 @@ function DateRangePicker({
7810
8680
  ] }),
7811
8681
  /* @__PURE__ */ jsx("button", { type: "button", className: "twc-drp__nav", "aria-label": "Next month", onClick: () => setView(new Date(y, m + 1, 1)), children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" }) }) })
7812
8682
  ] }),
7813
- /* @__PURE__ */ jsxs("div", { className: "twc-drp__grid", children: [
8683
+ /* @__PURE__ */ jsxs("div", { className: "twc-drp__grid", ref: gridRef, onKeyDown: onGridKeyDown, role: "grid", children: [
7814
8684
  dows.map((d, i) => /* @__PURE__ */ jsx("div", { className: "twc-drp__dow", children: d }, i)),
7815
8685
  Array.from({ length: 42 }).map((_, i) => {
7816
8686
  const d = new Date(gridStart.getFullYear(), gridStart.getMonth(), gridStart.getDate() + i);
@@ -7822,6 +8692,8 @@ function DateRangePicker({
7822
8692
  className: "twc-drp__day",
7823
8693
  "data-outside": outside || void 0,
7824
8694
  disabled: outOfRange(d) || void 0,
8695
+ "data-key": keyOf(d),
8696
+ tabIndex: sameDay2(d, tabbableDate) ? 0 : -1,
7825
8697
  "data-in": inRange(t) || void 0,
7826
8698
  "data-edge": edgeOf(t) || void 0,
7827
8699
  "aria-pressed": !!edgeOf(t),
@@ -7908,14 +8780,14 @@ function Dialog({
7908
8780
  className = "",
7909
8781
  ...rest
7910
8782
  }) {
7911
- const autoId = React25__default.useId();
8783
+ const autoId = React37__default.useId();
7912
8784
  const titleId = `${autoId}-title`;
7913
8785
  const descId = `${autoId}-desc`;
7914
- const dialogRef = React25__default.useRef(null);
8786
+ const dialogRef = React37__default.useRef(null);
7915
8787
  const __twcStyles = useScopedStyles("twc-dialog-styles", DIALOG_CSS);
7916
8788
  const renderPortal = usePortal();
7917
- const [mounted, setMounted] = React25__default.useState(open);
7918
- React25__default.useEffect(() => {
8789
+ const [mounted, setMounted] = React37__default.useState(open);
8790
+ React37__default.useEffect(() => {
7919
8791
  if (open) {
7920
8792
  setMounted(true);
7921
8793
  return;
@@ -7926,7 +8798,7 @@ function Dialog({
7926
8798
  useScrollLock(open);
7927
8799
  useInertBackground(dialogRef, open && mounted);
7928
8800
  useFocusTrap(dialogRef, open && mounted);
7929
- React25__default.useEffect(() => {
8801
+ React37__default.useEffect(() => {
7930
8802
  if (!open) return void 0;
7931
8803
  const onKey = (e) => {
7932
8804
  if (e.key === "Escape") {
@@ -8073,14 +8945,14 @@ function Drawer({
8073
8945
  style,
8074
8946
  ...rest
8075
8947
  }) {
8076
- const autoId = React25__default.useId();
8948
+ const autoId = React37__default.useId();
8077
8949
  const titleId = `${autoId}-title`;
8078
8950
  const descId = `${autoId}-desc`;
8079
- const panelRef = React25__default.useRef(null);
8951
+ const panelRef = React37__default.useRef(null);
8080
8952
  const __twcStyles = useScopedStyles("twc-drawer-styles", DRAWER_CSS);
8081
8953
  const renderPortal = usePortal();
8082
- const [mounted, setMounted] = React25__default.useState(open);
8083
- React25__default.useEffect(() => {
8954
+ const [mounted, setMounted] = React37__default.useState(open);
8955
+ React37__default.useEffect(() => {
8084
8956
  if (open) {
8085
8957
  setMounted(true);
8086
8958
  return;
@@ -8091,7 +8963,7 @@ function Drawer({
8091
8963
  useScrollLock(open);
8092
8964
  useInertBackground(panelRef, open && mounted);
8093
8965
  useFocusTrap(panelRef, open && mounted);
8094
- React25__default.useEffect(() => {
8966
+ React37__default.useEffect(() => {
8095
8967
  if (!open) return void 0;
8096
8968
  const onKey = (e) => {
8097
8969
  if (e.key === "Escape") {
@@ -8180,11 +9052,11 @@ function Field({
8180
9052
  ...rest
8181
9053
  }) {
8182
9054
  const __twcStyles = useScopedStyles("twc-field-styles", FIELD_CSS5);
8183
- const autoId = React25__default.useId();
9055
+ const autoId = React37__default.useId();
8184
9056
  const fieldId = id || autoId;
8185
9057
  const descId = `${fieldId}-desc`;
8186
9058
  const hasMsg = Boolean(error || hint);
8187
- const control = React25__default.isValidElement(children) ? React25__default.cloneElement(children, {
9059
+ const control = React37__default.isValidElement(children) ? React37__default.cloneElement(children, {
8188
9060
  "aria-describedby": [children.props["aria-describedby"], hasMsg ? descId : null].filter(Boolean).join(" ") || void 0,
8189
9061
  "aria-invalid": children.props["aria-invalid"] !== void 0 ? children.props["aria-invalid"] : error ? true : void 0
8190
9062
  }) : children;
@@ -8276,11 +9148,11 @@ function FileUpload({
8276
9148
  ...rest
8277
9149
  }) {
8278
9150
  const __twcStyles = useScopedStyles("twc-upload-styles", UPLOAD_CSS);
8279
- const [internal, setInternal] = React25__default.useState(defaultValue);
9151
+ const [internal, setInternal] = React37__default.useState(defaultValue);
8280
9152
  const files = value !== void 0 ? value : internal;
8281
- const [drag, setDrag] = React25__default.useState(false);
8282
- const inputRef = React25__default.useRef(null);
8283
- const autoId = React25__default.useId();
9153
+ const [drag, setDrag] = React37__default.useState(false);
9154
+ const inputRef = React37__default.useRef(null);
9155
+ const autoId = React37__default.useId();
8284
9156
  const fieldId = id || autoId;
8285
9157
  const descId = `${fieldId}-desc`;
8286
9158
  const invalid = Boolean(error);
@@ -8503,15 +9375,15 @@ function Kanban({
8503
9375
  ...rest
8504
9376
  }) {
8505
9377
  const __twcStyles = useScopedStyles("twc-kanban-styles", KANBAN_CSS);
8506
- const [internal, setInternal] = React25__default.useState(cards ?? defaultCards ?? []);
9378
+ const [internal, setInternal] = React37__default.useState(cards ?? defaultCards ?? []);
8507
9379
  const items = cards !== void 0 ? cards : internal;
8508
- const [drag, setDrag] = React25__default.useState(null);
8509
- const [overCol, setOverCol] = React25__default.useState(null);
8510
- const [grab, setGrab] = React25__default.useState(null);
8511
- const [announce, setAnnounce] = React25__default.useState("");
8512
- const rootRef = React25__default.useRef(null);
8513
- const focusIdRef = React25__default.useRef(null);
8514
- React25__default.useEffect(() => {
9380
+ const [drag, setDrag] = React37__default.useState(null);
9381
+ const [overCol, setOverCol] = React37__default.useState(null);
9382
+ const [grab, setGrab] = React37__default.useState(null);
9383
+ const [announce, setAnnounce] = React37__default.useState("");
9384
+ const rootRef = React37__default.useRef(null);
9385
+ const focusIdRef = React37__default.useRef(null);
9386
+ React37__default.useEffect(() => {
8515
9387
  if (focusIdRef.current == null) return void 0;
8516
9388
  const raf = requestAnimationFrame(() => {
8517
9389
  const id = focusIdRef.current;
@@ -8660,7 +9532,7 @@ var LIST_CSS = `
8660
9532
  `;
8661
9533
  function List({ items, plain = false, emptyMessage, className = "", ...rest }) {
8662
9534
  const __twcStyles = useScopedStyles("twc-list-styles", LIST_CSS);
8663
- const safeHref12 = (url) => {
9535
+ const safeHref13 = (url) => {
8664
9536
  if (url == null) return void 0;
8665
9537
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
8666
9538
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -8672,7 +9544,7 @@ function List({ items, plain = false, emptyMessage, className = "", ...rest }) {
8672
9544
  /* @__PURE__ */ jsxs("ul", { className: `twc-list ${className}`, role: "list", "data-plain": plain || void 0, ...rest, children: [
8673
9545
  __twcStyles,
8674
9546
  items.length === 0 ? /* @__PURE__ */ jsx("li", { role: "presentation", style: { display: "contents" }, children: /* @__PURE__ */ jsx("div", { className: "twc-list__empty", children: emptyMessage ?? "Nothing here yet" }) }) : items.map((it, i) => {
8675
- const href = safeHref12(it.href);
9547
+ const href = safeHref13(it.href);
8676
9548
  const interactive = Boolean(it.onClick || href);
8677
9549
  const Tag2 = href ? "a" : interactive ? "button" : "div";
8678
9550
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -8728,7 +9600,7 @@ button.twc-navbar__brand, a.twc-navbar__brand { cursor: pointer; }
8728
9600
  .twc-navbar__menu-btn { display: inline-grid; }
8729
9601
  }
8730
9602
  `;
8731
- function safeHref4(url) {
9603
+ function safeHref5(url) {
8732
9604
  if (url == null) return void 0;
8733
9605
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
8734
9606
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -8751,9 +9623,9 @@ function Navbar({
8751
9623
  return /* @__PURE__ */ jsxs("header", { className: `twc-navbar ${className}`, "data-sticky": sticky || void 0, ...rest, children: [
8752
9624
  __twcStyles,
8753
9625
  onMenuClick ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-navbar__menu-btn", "aria-expanded": menuOpen, "aria-controls": menuControls, "aria-label": menuOpen ? "Close menu" : "Open menu", onClick: onMenuClick, children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M4 6h16M4 12h16M4 18h16" }) }) }) : null,
8754
- brand ? brandHref ? /* @__PURE__ */ jsx("a", { className: "twc-navbar__brand", href: safeHref4(brandHref), children: brand }) : onBrandClick ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-navbar__brand", onClick: onBrandClick, children: brand }) : /* @__PURE__ */ jsx("span", { className: "twc-navbar__brand", children: brand }) : null,
9626
+ brand ? brandHref ? /* @__PURE__ */ jsx("a", { className: "twc-navbar__brand", href: safeHref5(brandHref), children: brand }) : onBrandClick ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-navbar__brand", onClick: onBrandClick, children: brand }) : /* @__PURE__ */ jsx("span", { className: "twc-navbar__brand", children: brand }) : null,
8755
9627
  /* @__PURE__ */ jsx("nav", { className: "twc-navbar__links", "aria-label": navLabel, children: links.map((l, i) => {
8756
- const href = safeHref4(l.href);
9628
+ const href = safeHref5(l.href);
8757
9629
  const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
8758
9630
  l.icon,
8759
9631
  l.label
@@ -8821,21 +9693,21 @@ function Popover({
8821
9693
  ...rest
8822
9694
  }) {
8823
9695
  const __twcStyles = useScopedStyles("twc-popover-styles", POPOVER_CSS);
8824
- const [openState, setOpenState] = React25__default.useState(defaultOpen);
8825
- const [render, setRender] = React25__default.useState(false);
8826
- const [pos, setPos] = React25__default.useState(null);
8827
- const wrapRef = React25__default.useRef(null);
8828
- const popRef = React25__default.useRef(null);
8829
- const popId = React25__default.useId();
9696
+ const [openState, setOpenState] = React37__default.useState(defaultOpen);
9697
+ const [render, setRender] = React37__default.useState(false);
9698
+ const [pos, setPos] = React37__default.useState(null);
9699
+ const wrapRef = React37__default.useRef(null);
9700
+ const popRef = React37__default.useRef(null);
9701
+ const popId = React37__default.useId();
8830
9702
  const controlled = openProp !== void 0;
8831
9703
  const open = controlled ? !!openProp : openState;
8832
- const openRef = React25__default.useRef(open);
9704
+ const openRef = React37__default.useRef(open);
8833
9705
  openRef.current = open;
8834
- const controlledRef = React25__default.useRef(controlled);
9706
+ const controlledRef = React37__default.useRef(controlled);
8835
9707
  controlledRef.current = controlled;
8836
- const onOpenChangeRef = React25__default.useRef(onOpenChange);
9708
+ const onOpenChangeRef = React37__default.useRef(onOpenChange);
8837
9709
  onOpenChangeRef.current = onOpenChange;
8838
- const setOpen = React25__default.useCallback((next) => {
9710
+ const setOpen = React37__default.useCallback((next) => {
8839
9711
  const value = typeof next === "function" ? next(openRef.current) : next;
8840
9712
  if (value === openRef.current) return;
8841
9713
  if (!controlledRef.current) setOpenState(value);
@@ -8843,7 +9715,7 @@ function Popover({
8843
9715
  }, []);
8844
9716
  const toggle = () => setOpen((o) => !o);
8845
9717
  const RD = { createPortal: typeof createPortal === "function" ? createPortal : typeof window !== "undefined" && window.ReactDOM && window.ReactDOM.createPortal };
8846
- const place = React25__default.useCallback(() => {
9718
+ const place = React37__default.useCallback(() => {
8847
9719
  const t = wrapRef.current;
8848
9720
  if (!t) return;
8849
9721
  const r = t.getBoundingClientRect();
@@ -8880,7 +9752,7 @@ function Popover({
8880
9752
  arrow = { top: Math.min(Math.max(cy - top - 5.5, 8), ph - 18), [onRight ? "left" : "right"]: -6 };
8881
9753
  setPos({ top, left, width: w, flip: false, arrow });
8882
9754
  }, [placement, align, width]);
8883
- React25__default.useEffect(() => {
9755
+ React37__default.useEffect(() => {
8884
9756
  if (!open) return;
8885
9757
  place();
8886
9758
  const onMove = () => place();
@@ -8903,7 +9775,7 @@ function Popover({
8903
9775
  document.removeEventListener("keydown", onKey);
8904
9776
  };
8905
9777
  }, [open, place]);
8906
- React25__default.useEffect(() => {
9778
+ React37__default.useEffect(() => {
8907
9779
  if (open) {
8908
9780
  setRender(true);
8909
9781
  return;
@@ -8911,12 +9783,12 @@ function Popover({
8911
9783
  const t = setTimeout(() => setRender(false), 170);
8912
9784
  return () => clearTimeout(t);
8913
9785
  }, [open]);
8914
- React25__default.useEffect(() => {
9786
+ React37__default.useEffect(() => {
8915
9787
  if (render && open) place();
8916
9788
  }, [render, place]);
8917
- const restoreRef = React25__default.useRef(null);
8918
- const needFocusRef = React25__default.useRef(false);
8919
- React25__default.useEffect(() => {
9789
+ const restoreRef = React37__default.useRef(null);
9790
+ const needFocusRef = React37__default.useRef(false);
9791
+ React37__default.useEffect(() => {
8920
9792
  if (open) {
8921
9793
  restoreRef.current = document.activeElement;
8922
9794
  needFocusRef.current = true;
@@ -8951,7 +9823,7 @@ function Popover({
8951
9823
  ]
8952
9824
  }
8953
9825
  ) : null;
8954
- const triggerEl = React25__default.isValidElement(trigger) ? React25__default.cloneElement(trigger, {
9826
+ const triggerEl = React37__default.isValidElement(trigger) ? React37__default.cloneElement(trigger, {
8955
9827
  onClick: (e) => {
8956
9828
  trigger.props.onClick?.(e);
8957
9829
  toggle();
@@ -8994,7 +9866,7 @@ function Progress({
8994
9866
  className = "",
8995
9867
  ...rest
8996
9868
  }) {
8997
- const labelId = React25__default.useId();
9869
+ const labelId = React37__default.useId();
8998
9870
  const { "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...restProps } = rest;
8999
9871
  const __twcStyles = useScopedStyles("twc-progress-styles", `
9000
9872
  .twc-progress-wrap { display: flex; flex-direction: column; gap: 6px; font-family: var(--font-sans); }
@@ -9117,7 +9989,7 @@ function Radio({
9117
9989
  .twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
9118
9990
  .twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
9119
9991
  `);
9120
- const autoId = React25__default.useId();
9992
+ const autoId = React37__default.useId();
9121
9993
  const fieldId = id || autoId;
9122
9994
  const errId = `${fieldId}-error`;
9123
9995
  const invalid = Boolean(error);
@@ -9187,13 +10059,13 @@ function RadioGroup({
9187
10059
  ...rest
9188
10060
  }) {
9189
10061
  const __twcStyles = useScopedStyles("twc-radio-group-styles", RADIO_GROUP_CSS);
9190
- const autoId = React25__default.useId();
10062
+ const autoId = React37__default.useId();
9191
10063
  const fieldId = id || autoId;
9192
10064
  const labelId = `${fieldId}-label`;
9193
10065
  const descId = `${fieldId}-desc`;
9194
10066
  const groupName = name || `${fieldId}-name`;
9195
10067
  const invalid = Boolean(error);
9196
- const [internal, setInternal] = React25__default.useState(defaultValue);
10068
+ const [internal, setInternal] = React37__default.useState(defaultValue);
9197
10069
  const current = value !== void 0 ? value : internal;
9198
10070
  const select = (v) => {
9199
10071
  if (value === void 0) setInternal(v);
@@ -9214,10 +10086,10 @@ function RadioGroup({
9214
10086
  tone
9215
10087
  },
9216
10088
  o.value
9217
- )) : React25__default.Children.map(children, (child) => {
9218
- if (!React25__default.isValidElement(child)) return child;
10089
+ )) : React37__default.Children.map(children, (child) => {
10090
+ if (!React37__default.isValidElement(child)) return child;
9219
10091
  const v = child.props.value;
9220
- return React25__default.cloneElement(child, {
10092
+ return React37__default.cloneElement(child, {
9221
10093
  name: child.props.name ?? groupName,
9222
10094
  checked: child.props.checked ?? current === v,
9223
10095
  onChange: child.props.onChange ?? (() => select(v)),
@@ -9297,12 +10169,12 @@ function Rating({
9297
10169
  ...rest
9298
10170
  }) {
9299
10171
  const __twcStyles = useScopedStyles("twc-rating-styles", RATING_CSS);
9300
- const [internal, setInternal] = React25__default.useState(defaultValue);
9301
- const [hover, setHover] = React25__default.useState(0);
10172
+ const [internal, setInternal] = React37__default.useState(defaultValue);
10173
+ const [hover, setHover] = React37__default.useState(0);
9302
10174
  const val = value !== void 0 ? value : internal;
9303
10175
  const shown = hover || val;
9304
10176
  const interactive = !readOnly && !disabled;
9305
- const btnRefs = React25__default.useRef([]);
10177
+ const btnRefs = React37__default.useRef([]);
9306
10178
  const tabStar = Math.min(count, Math.max(1, Math.round(val) || 1));
9307
10179
  const fmt = (v) => format ? format(v) : Number.isInteger(v) ? String(v) : v.toFixed(1);
9308
10180
  if (process.env.NODE_ENV !== "production" && interactive && !Number.isInteger(val)) {
@@ -9489,24 +10361,24 @@ function Sidebar({
9489
10361
  ...rest
9490
10362
  }) {
9491
10363
  const __twcStyles = useScopedStyles("twc-sidebar-styles", SIDEBAR_CSS);
9492
- const navId = React25__default.useId();
9493
- const panelRef = React25__default.useRef(null);
10364
+ const navId = React37__default.useId();
10365
+ const panelRef = React37__default.useRef(null);
9494
10366
  const renderPortal = usePortal();
9495
- const [internal, setInternal] = React25__default.useState(defaultCollapsed);
10367
+ const [internal, setInternal] = React37__default.useState(defaultCollapsed);
9496
10368
  const collapsed = collapsedProp !== void 0 ? collapsedProp : internal;
9497
10369
  const toggle = () => {
9498
10370
  const next = !collapsed;
9499
10371
  if (collapsedProp === void 0) setInternal(next);
9500
10372
  onCollapsedChange?.(next);
9501
10373
  };
9502
- const [openInternal, setOpenInternal] = React25__default.useState(defaultOpen);
10374
+ const [openInternal, setOpenInternal] = React37__default.useState(defaultOpen);
9503
10375
  const open = openProp !== void 0 ? openProp : openInternal;
9504
10376
  const setOpen = (next) => {
9505
10377
  if (openProp === void 0) setOpenInternal(next);
9506
10378
  onOpenChange?.(next);
9507
10379
  };
9508
- const [mounted, setMounted] = React25__default.useState(open);
9509
- React25__default.useEffect(() => {
10380
+ const [mounted, setMounted] = React37__default.useState(open);
10381
+ React37__default.useEffect(() => {
9510
10382
  if (!overlay) return void 0;
9511
10383
  if (open) {
9512
10384
  setMounted(true);
@@ -9515,7 +10387,7 @@ function Sidebar({
9515
10387
  const t = setTimeout(() => setMounted(false), 170);
9516
10388
  return () => clearTimeout(t);
9517
10389
  }, [overlay, open]);
9518
- React25__default.useEffect(() => {
10390
+ React37__default.useEffect(() => {
9519
10391
  if (!overlay || !open) return void 0;
9520
10392
  const prev = document.body.style.overflow;
9521
10393
  document.body.style.overflow = "hidden";
@@ -9524,7 +10396,7 @@ function Sidebar({
9524
10396
  };
9525
10397
  }, [overlay, open]);
9526
10398
  useFocusTrap(panelRef, overlay && open && mounted);
9527
- React25__default.useEffect(() => {
10399
+ React37__default.useEffect(() => {
9528
10400
  if (!overlay || !open) return void 0;
9529
10401
  const onKey = (e) => {
9530
10402
  if (e.key === "Escape") {
@@ -9536,13 +10408,13 @@ function Sidebar({
9536
10408
  document.addEventListener("keydown", onKey);
9537
10409
  return () => document.removeEventListener("keydown", onKey);
9538
10410
  }, [overlay, open, openProp, onOpenChange]);
9539
- const safeHref12 = (url) => {
10411
+ const safeHref13 = (url) => {
9540
10412
  if (url == null) return void 0;
9541
10413
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
9542
10414
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
9543
10415
  };
9544
10416
  const renderItem = (it, i) => {
9545
- const href = safeHref12(it.href);
10417
+ const href = safeHref13(it.href);
9546
10418
  const labelStr = typeof it.label === "string" ? it.label : void 0;
9547
10419
  const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
9548
10420
  it.icon ? /* @__PURE__ */ jsx("span", { className: "twc-sidebar__ic", "aria-hidden": "true", children: it.icon }) : labelStr != null ? /* @__PURE__ */ jsx("span", { className: "twc-sidebar__ic twc-sidebar__ic--initial", "aria-hidden": "true", children: labelStr.charAt(0) }) : null,
@@ -9576,7 +10448,7 @@ function Sidebar({
9576
10448
  const body = /* @__PURE__ */ jsxs(Fragment, { children: [
9577
10449
  __twcStyles,
9578
10450
  brand ? /* @__PURE__ */ jsx("div", { className: "twc-sidebar__head", children: /* @__PURE__ */ jsx("span", { className: "twc-sidebar__brand", children: brand }) }) : null,
9579
- /* @__PURE__ */ jsx("nav", { id: navId, className: "twc-sidebar__nav", "aria-label": navLabel, children: groups.map((g, gi) => /* @__PURE__ */ jsxs(React25__default.Fragment, { children: [
10451
+ /* @__PURE__ */ jsx("nav", { id: navId, className: "twc-sidebar__nav", "aria-label": navLabel, children: groups.map((g, gi) => /* @__PURE__ */ jsxs(React37__default.Fragment, { children: [
9580
10452
  g.section != null ? /* @__PURE__ */ jsx("div", { className: "twc-sidebar__section", id: g.sid, children: g.section }) : null,
9581
10453
  /* @__PURE__ */ jsx("ul", { className: "twc-sidebar__list", ...g.section != null ? { "aria-labelledby": g.sid } : {}, children: g.entries.map(({ it, i }) => /* @__PURE__ */ jsx("li", { children: renderItem(it) }, i)) })
9582
10454
  ] }, gi)) }),
@@ -9745,10 +10617,10 @@ function Slider({
9745
10617
  return Math.min(max, Math.max(min, Math.round(stepped * 1e6) / 1e6));
9746
10618
  };
9747
10619
  const __twcStyles = useScopedStyles("twc-slider-styles", SLIDER_CSS);
9748
- const autoId = React25__default.useId();
10620
+ const autoId = React37__default.useId();
9749
10621
  const fieldId = id || autoId;
9750
10622
  const isRange = range || Array.isArray(value) || Array.isArray(defaultValue);
9751
- const [internal, setInternal] = React25__default.useState(() => {
10623
+ const [internal, setInternal] = React37__default.useState(() => {
9752
10624
  if (isRange) {
9753
10625
  const dv = Array.isArray(defaultValue) ? defaultValue : [min, max];
9754
10626
  return [clampSnap(dv[0]), clampSnap(dv[1])];
@@ -9758,8 +10630,8 @@ function Slider({
9758
10630
  const rawVal = value !== void 0 ? value : internal;
9759
10631
  const clampedVals = (isRange ? [Number(rawVal[0]), Number(rawVal[1])] : [Number(rawVal)]).map((v) => Math.min(max, Math.max(min, Number.isFinite(v) ? v : min)));
9760
10632
  const indices = isRange ? [0, 1] : [0];
9761
- const trackRef = React25__default.useRef(null);
9762
- const [dragging, setDragging] = React25__default.useState(false);
10633
+ const trackRef = React37__default.useRef(null);
10634
+ const [dragging, setDragging] = React37__default.useState(false);
9763
10635
  const fmt = (v) => formatValue ? formatValue(v) : v.toFixed(decimals);
9764
10636
  const valueTextFor = (v) => {
9765
10637
  if (getAriaValueText) return getAriaValueText(v);
@@ -9790,8 +10662,8 @@ function Slider({
9790
10662
  const ratio = Math.min(1, Math.max(0, (clientX - r.left) / r.width));
9791
10663
  return clampSnap(min + ratio * (max - min));
9792
10664
  };
9793
- const dragCleanupRef = React25__default.useRef(null);
9794
- React25__default.useEffect(() => () => dragCleanupRef.current?.(), []);
10665
+ const dragCleanupRef = React37__default.useRef(null);
10666
+ React37__default.useEffect(() => () => dragCleanupRef.current?.(), []);
9795
10667
  function onPointerDown(e) {
9796
10668
  if (disabled) return;
9797
10669
  e.preventDefault();
@@ -10022,7 +10894,7 @@ function Stepper({
10022
10894
  ...rest
10023
10895
  }) {
10024
10896
  const __twcStyles = useScopedStyles("twc-stepper-styles", STEPPER_CSS);
10025
- const [activeInternal, setActiveInternal] = React25__default.useState(defaultActive);
10897
+ const [activeInternal, setActiveInternal] = React37__default.useState(defaultActive);
10026
10898
  const active = activeProp !== void 0 ? activeProp : activeInternal;
10027
10899
  const handleStep = (i) => {
10028
10900
  if (activeProp === void 0) setActiveInternal(i);
@@ -10154,7 +11026,7 @@ function Switch({
10154
11026
  .twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
10155
11027
  .twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
10156
11028
  `);
10157
- const autoId = React25__default.useId();
11029
+ const autoId = React37__default.useId();
10158
11030
  const fieldId = id || autoId;
10159
11031
  const errId = `${fieldId}-error`;
10160
11032
  const invalid = Boolean(error);
@@ -10257,14 +11129,14 @@ function Table({
10257
11129
  ...rest
10258
11130
  }) {
10259
11131
  const __twcStyles = useScopedStyles("twc-table-styles", TABLE_CSS);
10260
- const cols = React25__default.useMemo(
11132
+ const cols = React37__default.useMemo(
10261
11133
  () => (columns || []).map((c) => ({ ...c, header: c.headerName, render: c.renderCell })),
10262
11134
  [columns]
10263
11135
  );
10264
11136
  const dataRows = rowsProp || [];
10265
- const [internalSort, setInternalSort] = React25__default.useState(defaultSort || { field: null, dir: "asc" });
11137
+ const [internalSort, setInternalSort] = React37__default.useState(defaultSort || { field: null, dir: "asc" });
10266
11138
  const sort = (sortProp !== void 0 ? sortProp : internalSort) || { field: null, dir: "asc" };
10267
- const rows = React25__default.useMemo(() => {
11139
+ const rows = React37__default.useMemo(() => {
10268
11140
  if (!sortable || !sort.field) return dataRows;
10269
11141
  const col = cols.find((c) => c.field === sort.field);
10270
11142
  if (!col) return dataRows;
@@ -10411,15 +11283,15 @@ function Tabs({
10411
11283
  }) {
10412
11284
  const vertical = orientation === "vertical";
10413
11285
  const __twcStyles = useScopedStyles("twc-tabs-styles", TABS_CSS);
10414
- const [internal, setInternal] = React25__default.useState(defaultValue ?? items[0]?.value);
11286
+ const [internal, setInternal] = React37__default.useState(defaultValue ?? items[0]?.value);
10415
11287
  const active = value ?? internal;
10416
- const listRef = React25__default.useRef(null);
10417
- const [ind, setInd] = React25__default.useState({ left: 0, width: 0, top: 0, height: 0 });
10418
- const baseId = React25__default.useId();
11288
+ const listRef = React37__default.useRef(null);
11289
+ const [ind, setInd] = React37__default.useState({ left: 0, width: 0, top: 0, height: 0 });
11290
+ const baseId = React37__default.useId();
10419
11291
  const tabIdAt = (i) => `${baseId}-tab-${i}`;
10420
11292
  const panelId = `${baseId}-panel`;
10421
11293
  const activeIndex = items.findIndex((it) => it.value === active);
10422
- const updateIndicator = React25__default.useCallback(() => {
11294
+ const updateIndicator = React37__default.useCallback(() => {
10423
11295
  const list = listRef.current;
10424
11296
  if (!list) return;
10425
11297
  const el = list.querySelector('[data-active="true"]');
@@ -10428,10 +11300,10 @@ function Tabs({
10428
11300
  if (!vertical) el.scrollIntoView?.({ inline: "nearest", block: "nearest" });
10429
11301
  }
10430
11302
  }, [vertical]);
10431
- React25__default.useEffect(() => {
11303
+ React37__default.useEffect(() => {
10432
11304
  updateIndicator();
10433
11305
  }, [active, updateIndicator, items, orientation]);
10434
- React25__default.useEffect(() => {
11306
+ React37__default.useEffect(() => {
10435
11307
  const r = () => updateIndicator();
10436
11308
  window.addEventListener("resize", r);
10437
11309
  if (typeof document !== "undefined" && document.fonts && document.fonts.ready) {
@@ -10576,7 +11448,7 @@ function Tag({
10576
11448
  }, "aria-label": _removeLabel, type: "button", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
10577
11449
  ] });
10578
11450
  }
10579
- var useIso = typeof document !== "undefined" ? React25__default.useLayoutEffect : React25__default.useEffect;
11451
+ var useIso = typeof document !== "undefined" ? React37__default.useLayoutEffect : React37__default.useEffect;
10580
11452
  var TEXTAREA_CSS = `
10581
11453
  .twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
10582
11454
  .twc-field__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); display: flex; gap: 4px; align-items: center; }
@@ -10612,7 +11484,7 @@ var TEXTAREA_CSS = `
10612
11484
  .twc-field__count { margin-inline-start: auto; font-size: var(--text-xs); color: var(--color-text-muted); font-variant-numeric: tabular-nums; flex: none; }
10613
11485
  .twc-field__count[data-danger="true"] { color: var(--color-danger-subtle-fg); }
10614
11486
  `;
10615
- var Textarea = React25__default.forwardRef(function Textarea2({
11487
+ var Textarea = React37__default.forwardRef(function Textarea2({
10616
11488
  label,
10617
11489
  hint,
10618
11490
  error,
@@ -10630,19 +11502,19 @@ var Textarea = React25__default.forwardRef(function Textarea2({
10630
11502
  ...rest
10631
11503
  }, ref) {
10632
11504
  const __twcStyles = useScopedStyles("twc-textarea-styles", TEXTAREA_CSS);
10633
- const autoId = React25__default.useId();
11505
+ const autoId = React37__default.useId();
10634
11506
  const fieldId = id || autoId;
10635
11507
  const descId = `${fieldId}-desc`;
10636
11508
  const countId = `${fieldId}-count`;
10637
11509
  const invalid = Boolean(error);
10638
- const innerRef = React25__default.useRef(null);
11510
+ const innerRef = React37__default.useRef(null);
10639
11511
  const setRef = (el) => {
10640
11512
  innerRef.current = el;
10641
11513
  if (typeof ref === "function") ref(el);
10642
11514
  else if (ref) ref.current = el;
10643
11515
  };
10644
11516
  const countControlled = rest.value !== void 0;
10645
- const [len2, setLen] = React25__default.useState(() => String(rest.defaultValue ?? "").length);
11517
+ const [len2, setLen] = React37__default.useState(() => String(rest.defaultValue ?? "").length);
10646
11518
  const count = countControlled ? String(rest.value ?? "").length : len2;
10647
11519
  const max = rest.maxLength;
10648
11520
  const showCounter = showCount && max != null;
@@ -10820,19 +11692,19 @@ function Toast({
10820
11692
  }) {
10821
11693
  const resolvedTone = tone === "neutral" ? "default" : tone;
10822
11694
  const __twcStyles = useScopedStyles("twc-toast-styles", TOAST_CSS);
10823
- const onCloseRef = React25__default.useRef(onClose);
10824
- React25__default.useEffect(() => {
11695
+ const onCloseRef = React37__default.useRef(onClose);
11696
+ React37__default.useEffect(() => {
10825
11697
  onCloseRef.current = onClose;
10826
11698
  }, [onClose]);
10827
- const timer = React25__default.useRef();
10828
- const stop = React25__default.useCallback(() => clearTimeout(timer.current), []);
10829
- const start = React25__default.useCallback(() => {
11699
+ const timer = React37__default.useRef();
11700
+ const stop = React37__default.useCallback(() => clearTimeout(timer.current), []);
11701
+ const start = React37__default.useCallback(() => {
10830
11702
  stop();
10831
11703
  if (duration && duration !== Infinity && onCloseRef.current) {
10832
11704
  timer.current = setTimeout(() => onCloseRef.current && onCloseRef.current(), duration);
10833
11705
  }
10834
11706
  }, [duration, stop]);
10835
- React25__default.useEffect(() => {
11707
+ React37__default.useEffect(() => {
10836
11708
  start();
10837
11709
  return stop;
10838
11710
  }, [start, stop]);
@@ -10877,30 +11749,30 @@ function Toast({
10877
11749
  }
10878
11750
  function ToastViewport({ children, limit, className = "", ...rest }) {
10879
11751
  const __twcStyles = useScopedStyles("twc-toast-styles", TOAST_CSS);
10880
- const shown = limit && limit > 0 ? React25__default.Children.toArray(children).slice(-limit) : children;
11752
+ const shown = limit && limit > 0 ? React37__default.Children.toArray(children).slice(-limit) : children;
10881
11753
  return /* @__PURE__ */ jsxs("div", { className: `twc-toast-viewport ${className}`, role: "region", "aria-label": "Notifications", ...rest, children: [
10882
11754
  __twcStyles,
10883
11755
  shown
10884
11756
  ] });
10885
11757
  }
10886
- var ToastContext = React25__default.createContext(null);
11758
+ var ToastContext = React37__default.createContext(null);
10887
11759
  function useToast() {
10888
- const ctx = React25__default.useContext(ToastContext);
11760
+ const ctx = React37__default.useContext(ToastContext);
10889
11761
  if (!ctx) throw new Error("useToast must be used within a <ToastProvider>.");
10890
11762
  return ctx;
10891
11763
  }
10892
11764
  function ToastProvider({ children, limit = 4, duration = 4500, ...viewportProps }) {
10893
- const [toasts, setToasts] = React25__default.useState([]);
10894
- const idRef = React25__default.useRef(0);
10895
- const limitRef = React25__default.useRef(limit);
10896
- React25__default.useEffect(() => {
11765
+ const [toasts, setToasts] = React37__default.useState([]);
11766
+ const idRef = React37__default.useRef(0);
11767
+ const limitRef = React37__default.useRef(limit);
11768
+ React37__default.useEffect(() => {
10897
11769
  limitRef.current = limit;
10898
11770
  }, [limit]);
10899
- const dismiss = React25__default.useCallback((id) => {
11771
+ const dismiss = React37__default.useCallback((id) => {
10900
11772
  setToasts((s) => s.filter((t) => t.id !== id));
10901
11773
  }, []);
10902
- const clear = React25__default.useCallback(() => setToasts([]), []);
10903
- const api = React25__default.useMemo(() => {
11774
+ const clear = React37__default.useCallback(() => setToasts([]), []);
11775
+ const api = React37__default.useMemo(() => {
10904
11776
  const push = (opts) => {
10905
11777
  const id = idRef.current += 1;
10906
11778
  const next = typeof opts === "string" ? { title: opts } : opts && typeof opts === "object" ? opts : {};
@@ -10921,7 +11793,7 @@ function ToastProvider({ children, limit = 4, duration = 4500, ...viewportProps
10921
11793
  toast.show = withTone("default");
10922
11794
  return { toast, dismiss, clear };
10923
11795
  }, [dismiss, clear]);
10924
- const value = React25__default.useMemo(() => ({ ...api, toasts }), [api, toasts]);
11796
+ const value = React37__default.useMemo(() => ({ ...api, toasts }), [api, toasts]);
10925
11797
  return /* @__PURE__ */ jsxs(ToastContext.Provider, { value, children: [
10926
11798
  children,
10927
11799
  /* @__PURE__ */ jsx(ToastViewport, { limit, ...viewportProps, children: toasts.map((t) => /* @__PURE__ */ jsx(
@@ -11029,13 +11901,13 @@ function TreeView({
11029
11901
  }) {
11030
11902
  const nodes = items;
11031
11903
  const __twcStyles = useScopedStyles("twc-tree-styles", TREE_CSS);
11032
- const [expInternal, setExpInternal] = React25__default.useState(() => new Set(defaultExpanded));
11904
+ const [expInternal, setExpInternal] = React37__default.useState(() => new Set(defaultExpanded));
11033
11905
  const expanded = expandedProp !== void 0 ? new Set(expandedProp) : expInternal;
11034
- const [selInternal, setSelInternal] = React25__default.useState(defaultSelectedId);
11906
+ const [selInternal, setSelInternal] = React37__default.useState(defaultSelectedId);
11035
11907
  const selectedId = selectedProp !== void 0 ? selectedProp : selInternal;
11036
- const [focusId, setFocusId] = React25__default.useState(null);
11037
- const rowRefs = React25__default.useRef(/* @__PURE__ */ new Map());
11038
- const taRef = React25__default.useRef({ str: "", t: 0 });
11908
+ const [focusId, setFocusId] = React37__default.useState(null);
11909
+ const rowRefs = React37__default.useRef(/* @__PURE__ */ new Map());
11910
+ const taRef = React37__default.useRef({ str: "", t: 0 });
11039
11911
  const toggle = (id) => {
11040
11912
  const n = new Set(expanded);
11041
11913
  n.has(id) ? n.delete(id) : n.add(id);
@@ -11167,7 +12039,7 @@ function AppShell({
11167
12039
  ...rest
11168
12040
  }) {
11169
12041
  const __twcStyles = useScopedStyles("twc-shell-styles", SHELL_CSS);
11170
- const wiredSidebar = React25__default.isValidElement(sidebar) && (sidebarOpen !== void 0 || onSidebarOpenChange !== void 0) ? React25__default.cloneElement(sidebar, {
12042
+ const wiredSidebar = React37__default.isValidElement(sidebar) && (sidebarOpen !== void 0 || onSidebarOpenChange !== void 0) ? React37__default.cloneElement(sidebar, {
11171
12043
  overlay: sidebar.props.overlay !== void 0 ? sidebar.props.overlay : true,
11172
12044
  open: sidebar.props.open !== void 0 ? sidebar.props.open : sidebarOpen,
11173
12045
  onOpenChange: sidebar.props.onOpenChange !== void 0 ? sidebar.props.onOpenChange : onSidebarOpenChange
@@ -11197,12 +12069,12 @@ function bgValue(bg) {
11197
12069
  if (BG[bg]) return `var(${BG[bg]})`;
11198
12070
  return String(bg).startsWith("--") ? `var(${bg})` : bg;
11199
12071
  }
11200
- function safeHref5(url) {
12072
+ function safeHref6(url) {
11201
12073
  if (url == null) return void 0;
11202
12074
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
11203
12075
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
11204
12076
  }
11205
- function Box({
12077
+ var Box = React37__default.forwardRef(function Box2({
11206
12078
  as: Tag2 = "div",
11207
12079
  p,
11208
12080
  px,
@@ -11222,11 +12094,13 @@ function Box({
11222
12094
  border = false,
11223
12095
  radius,
11224
12096
  shadow,
12097
+ sx,
11225
12098
  className = "",
11226
12099
  style,
11227
12100
  children,
11228
12101
  ...rest
11229
- }) {
12102
+ }, ref) {
12103
+ const { flatStyle, styleNode, sxAttr } = useSx(sx);
11230
12104
  const s = {
11231
12105
  paddingTop: sp(pt ?? py ?? p),
11232
12106
  paddingRight: sp(pr ?? px ?? p),
@@ -11240,44 +12114,58 @@ function Box({
11240
12114
  border: border ? "var(--border-thin, 1px) solid var(--color-border)" : void 0,
11241
12115
  borderRadius: radius ? `var(--radius-${radius})` : void 0,
11242
12116
  boxShadow: shadow ? `var(--shadow-${shadow})` : void 0,
11243
- ...style
12117
+ ...style,
12118
+ ...flatStyle
11244
12119
  };
11245
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref5(rest.href);
11246
- return /* @__PURE__ */ jsx(Tag2, { className: `twc-box ${className}`.trim(), style: s, ...rest, children });
11247
- }
12120
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref6(rest.href);
12121
+ return /* @__PURE__ */ jsxs(Tag2, { ref, className: `twc-box ${className}`.trim(), style: s, "data-twc-sx": sxAttr, ...rest, children: [
12122
+ styleNode,
12123
+ children
12124
+ ] });
12125
+ });
12126
+ Box.displayName = "Box";
11248
12127
  var SIZES = { sm: 640, md: 768, lg: 1024, xl: 1280, full: "100%" };
11249
- function safeHref6(url) {
12128
+ function safeHref7(url) {
11250
12129
  if (url == null) return void 0;
11251
12130
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
11252
12131
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
11253
12132
  }
11254
- function Container({
12133
+ var Container = React37__default.forwardRef(function Container2({
11255
12134
  as: Tag2 = "div",
11256
12135
  size = "lg",
11257
12136
  padded = true,
12137
+ sx,
11258
12138
  className = "",
11259
12139
  style,
11260
12140
  children,
11261
12141
  ...rest
11262
- }) {
12142
+ }, ref) {
12143
+ const { flatStyle, styleNode, sxAttr } = useSx(sx);
11263
12144
  const max = SIZES[size] ?? size;
11264
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref6(rest.href);
11265
- return /* @__PURE__ */ jsx(
12145
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref7(rest.href);
12146
+ return /* @__PURE__ */ jsxs(
11266
12147
  Tag2,
11267
12148
  {
12149
+ ref,
11268
12150
  className: `twc-container ${className}`.trim(),
12151
+ "data-twc-sx": sxAttr,
11269
12152
  style: {
11270
12153
  width: "100%",
11271
12154
  maxWidth: typeof max === "number" ? `${max}px` : max,
11272
12155
  marginInline: "auto",
11273
12156
  paddingInline: padded ? "var(--space-5)" : void 0,
11274
- ...style
12157
+ ...style,
12158
+ ...flatStyle
11275
12159
  },
11276
12160
  ...rest,
11277
- children
12161
+ children: [
12162
+ styleNode,
12163
+ children
12164
+ ]
11278
12165
  }
11279
12166
  );
11280
- }
12167
+ });
12168
+ Container.displayName = "Container";
11281
12169
  function space(v) {
11282
12170
  if (v == null) return void 0;
11283
12171
  if (typeof v === "number") return `var(--space-${String(v).replace(".", "-")})`;
@@ -11287,12 +12175,12 @@ function len(v) {
11287
12175
  return typeof v === "number" ? `${v}px` : v;
11288
12176
  }
11289
12177
  var BP = { sm: 640, md: 768, lg: 1024, xl: 1280 };
11290
- function safeHref7(url) {
12178
+ function safeHref8(url) {
11291
12179
  if (url == null) return void 0;
11292
12180
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
11293
12181
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
11294
12182
  }
11295
- function Grid({
12183
+ var Grid = React37__default.forwardRef(function Grid2({
11296
12184
  as: Tag2 = "div",
11297
12185
  columns,
11298
12186
  minChildWidth,
@@ -11303,13 +12191,15 @@ function Grid({
11303
12191
  justify,
11304
12192
  alignContent,
11305
12193
  justifyContent,
12194
+ sx,
11306
12195
  className = "",
11307
12196
  style,
11308
12197
  children,
11309
12198
  ...rest
11310
- }) {
12199
+ }, ref) {
12200
+ const { flatStyle, styleNode, sxAttr } = useSx(sx);
11311
12201
  const responsive = columns != null && typeof columns === "object";
11312
- const uid = React25__default.useId();
12202
+ const uid = React37__default.useId();
11313
12203
  const gridId = responsive ? `g${uid.replace(/[^a-zA-Z0-9]/g, "")}` : null;
11314
12204
  let css = "";
11315
12205
  if (responsive) {
@@ -11323,12 +12213,14 @@ function Grid({
11323
12213
  }
11324
12214
  const __twcStyles = useScopedStyles(gridId ? `twc-grid-${gridId}` : "twc-grid", css);
11325
12215
  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))`;
11326
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref7(rest.href);
12216
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref8(rest.href);
11327
12217
  return /* @__PURE__ */ jsxs(
11328
12218
  Tag2,
11329
12219
  {
12220
+ ref,
11330
12221
  className: `twc-grid ${className}`.trim(),
11331
12222
  "data-twc-grid-id": gridId || void 0,
12223
+ "data-twc-sx": sxAttr,
11332
12224
  style: {
11333
12225
  display: "grid",
11334
12226
  gridTemplateColumns: templateColumns,
@@ -11338,27 +12230,30 @@ function Grid({
11338
12230
  justifyItems: justify,
11339
12231
  alignContent,
11340
12232
  justifyContent,
11341
- ...style
12233
+ ...style,
12234
+ ...flatStyle
11342
12235
  },
11343
12236
  ...rest,
11344
12237
  children: [
11345
12238
  responsive ? __twcStyles : null,
12239
+ styleNode,
11346
12240
  children
11347
12241
  ]
11348
12242
  }
11349
12243
  );
11350
- }
12244
+ });
12245
+ Grid.displayName = "Grid";
11351
12246
  function space2(v) {
11352
12247
  if (v == null) return void 0;
11353
12248
  if (typeof v === "number") return `var(--space-${String(v).replace(".", "-")})`;
11354
12249
  return v;
11355
12250
  }
11356
- function safeHref8(url) {
12251
+ function safeHref9(url) {
11357
12252
  if (url == null) return void 0;
11358
12253
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
11359
12254
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
11360
12255
  }
11361
- function Stack({
12256
+ var Stack = React37__default.forwardRef(function Stack2({
11362
12257
  as: Tag2 = "div",
11363
12258
  direction = "column",
11364
12259
  gap = 4,
@@ -11374,17 +12269,21 @@ function Stack({
11374
12269
  pb,
11375
12270
  pl,
11376
12271
  divider,
12272
+ sx,
11377
12273
  className = "",
11378
12274
  style,
11379
12275
  children,
11380
12276
  ...rest
11381
- }) {
11382
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref8(rest.href);
11383
- const kids = divider != null ? React25__default.Children.toArray(children).flatMap((child, i, arr) => i < arr.length - 1 ? [child, /* @__PURE__ */ jsx(React25__default.Fragment, { children: divider }, `twc-stack-div-${i}`)] : [child]) : children;
11384
- return /* @__PURE__ */ jsx(
12277
+ }, ref) {
12278
+ const { flatStyle, styleNode, sxAttr } = useSx(sx);
12279
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref9(rest.href);
12280
+ const kids = divider != null ? React37__default.Children.toArray(children).flatMap((child, i, arr) => i < arr.length - 1 ? [child, /* @__PURE__ */ jsx(React37__default.Fragment, { children: divider }, `twc-stack-div-${i}`)] : [child]) : children;
12281
+ return /* @__PURE__ */ jsxs(
11385
12282
  Tag2,
11386
12283
  {
12284
+ ref,
11387
12285
  className: `twc-stack ${className}`.trim(),
12286
+ "data-twc-sx": sxAttr,
11388
12287
  style: {
11389
12288
  display: inline ? "inline-flex" : "flex",
11390
12289
  flexDirection: direction,
@@ -11397,13 +12296,18 @@ function Stack({
11397
12296
  paddingBottom: space2(pb ?? py ?? p),
11398
12297
  paddingLeft: space2(pl ?? px ?? p),
11399
12298
  minWidth: 0,
11400
- ...style
12299
+ ...style,
12300
+ ...flatStyle
11401
12301
  },
11402
12302
  ...rest,
11403
- children: kids
12303
+ children: [
12304
+ styleNode,
12305
+ kids
12306
+ ]
11404
12307
  }
11405
12308
  );
11406
- }
12309
+ });
12310
+ Stack.displayName = "Stack";
11407
12311
  var CODE_CSS = `
11408
12312
  .twc-code {
11409
12313
  font-family: var(--font-mono); font-size: 0.875em;
@@ -11427,7 +12331,7 @@ var CODE_CSS = `
11427
12331
  .twc-code__copy:focus-visible { outline: none; box-shadow: var(--ring); }
11428
12332
  .twc-code__copy svg { width: 15px; height: 15px; display: block; }
11429
12333
  `;
11430
- function safeHref9(url) {
12334
+ function safeHref10(url) {
11431
12335
  if (url == null) return void 0;
11432
12336
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
11433
12337
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
@@ -11444,11 +12348,11 @@ function Code({
11444
12348
  }) {
11445
12349
  const __twcStyles = useScopedStyles("twc-code-styles", CODE_CSS);
11446
12350
  const Tag2 = as ?? (block ? "pre" : "code");
11447
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref9(rest.href);
11448
- const rootRef = React25__default.useRef(null);
11449
- const [copied, setCopied] = React25__default.useState(false);
11450
- const timerRef = React25__default.useRef(null);
11451
- React25__default.useEffect(() => () => clearTimeout(timerRef.current), []);
12351
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref10(rest.href);
12352
+ const rootRef = React37__default.useRef(null);
12353
+ const [copied, setCopied] = React37__default.useState(false);
12354
+ const timerRef = React37__default.useRef(null);
12355
+ React37__default.useEffect(() => () => clearTimeout(timerRef.current), []);
11452
12356
  const doCopy = () => {
11453
12357
  if (typeof navigator === "undefined" || !navigator.clipboard) return;
11454
12358
  const text = typeof children === "string" ? children : rootRef.current?.textContent ?? "";
@@ -11469,12 +12373,12 @@ function Code({
11469
12373
  ] });
11470
12374
  }
11471
12375
  var LEVEL_SIZE = { 1: "4xl", 2: "2xl", 3: "xl", 4: "lg", 5: "base", 6: "sm" };
11472
- function safeHref10(url) {
12376
+ function safeHref11(url) {
11473
12377
  if (url == null) return void 0;
11474
12378
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
11475
12379
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
11476
12380
  }
11477
- function Heading({
12381
+ var Heading = React37__default.forwardRef(function Heading2({
11478
12382
  as,
11479
12383
  level = 2,
11480
12384
  size,
@@ -11482,18 +12386,22 @@ function Heading({
11482
12386
  align,
11483
12387
  truncate,
11484
12388
  lineClamp,
12389
+ sx,
11485
12390
  className = "",
11486
12391
  style,
11487
12392
  children,
11488
12393
  ...rest
11489
- }) {
12394
+ }, ref) {
12395
+ const { flatStyle, styleNode, sxAttr } = useSx(sx);
11490
12396
  const Tag2 = as || `h${level}`;
11491
12397
  const sz = size || (display ? "display" : LEVEL_SIZE[level]) || "2xl";
11492
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref10(rest.href);
11493
- return /* @__PURE__ */ jsx(
12398
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref11(rest.href);
12399
+ return /* @__PURE__ */ jsxs(
11494
12400
  Tag2,
11495
12401
  {
12402
+ ref,
11496
12403
  className: `twc-heading ${className}`.trim(),
12404
+ "data-twc-sx": sxAttr,
11497
12405
  style: {
11498
12406
  margin: 0,
11499
12407
  fontFamily: "var(--font-sans)",
@@ -11504,13 +12412,18 @@ function Heading({
11504
12412
  fontSize: `var(--text-${sz})`,
11505
12413
  textAlign: align,
11506
12414
  ...lineClamp != null ? { display: "-webkit-box", WebkitBoxOrient: "vertical", WebkitLineClamp: lineClamp, overflow: "hidden" } : truncate ? { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", minWidth: 0 } : null,
11507
- ...style
12415
+ ...style,
12416
+ ...flatStyle
11508
12417
  },
11509
12418
  ...rest,
11510
- children
12419
+ children: [
12420
+ styleNode,
12421
+ children
12422
+ ]
11511
12423
  }
11512
12424
  );
11513
- }
12425
+ });
12426
+ Heading.displayName = "Heading";
11514
12427
  var TONE = {
11515
12428
  default: "--color-text",
11516
12429
  muted: "--color-text-muted",
@@ -11526,12 +12439,12 @@ var TONE = {
11526
12439
  // Adopt the surrounding color (e.g. inside a solid Button/Badge/Alert or a link).
11527
12440
  inherit: "inherit"
11528
12441
  };
11529
- function safeHref11(url) {
12442
+ function safeHref12(url) {
11530
12443
  if (url == null) return void 0;
11531
12444
  const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
11532
12445
  return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
11533
12446
  }
11534
- function Text({
12447
+ var Text = React37__default.forwardRef(function Text2({
11535
12448
  as: Tag2 = "p",
11536
12449
  size = "base",
11537
12450
  tone = "default",
@@ -11539,17 +12452,21 @@ function Text({
11539
12452
  align,
11540
12453
  truncate,
11541
12454
  lineClamp,
12455
+ sx,
11542
12456
  className = "",
11543
12457
  style,
11544
12458
  children,
11545
12459
  ...rest
11546
- }) {
11547
- if (Tag2 === "a" && rest.href != null) rest.href = safeHref11(rest.href);
12460
+ }, ref) {
12461
+ const { flatStyle, styleNode, sxAttr } = useSx(sx);
12462
+ if (Tag2 === "a" && rest.href != null) rest.href = safeHref12(rest.href);
11548
12463
  const toneToken = TONE[tone] || TONE.default;
11549
- return /* @__PURE__ */ jsx(
12464
+ return /* @__PURE__ */ jsxs(
11550
12465
  Tag2,
11551
12466
  {
12467
+ ref,
11552
12468
  className: `twc-text ${className}`.trim(),
12469
+ "data-twc-sx": sxAttr,
11553
12470
  style: {
11554
12471
  margin: 0,
11555
12472
  fontFamily: "var(--font-sans)",
@@ -11559,53 +12476,58 @@ function Text({
11559
12476
  fontWeight: weight ? `var(--font-${weight})` : void 0,
11560
12477
  textAlign: align,
11561
12478
  ...lineClamp != null ? { display: "-webkit-box", WebkitBoxOrient: "vertical", WebkitLineClamp: lineClamp, overflow: "hidden" } : truncate ? { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", minWidth: 0 } : null,
11562
- ...style
12479
+ ...style,
12480
+ ...flatStyle
11563
12481
  },
11564
12482
  ...rest,
11565
- children
12483
+ children: [
12484
+ styleNode,
12485
+ children
12486
+ ]
11566
12487
  }
11567
12488
  );
11568
- }
12489
+ });
12490
+ Text.displayName = "Text";
11569
12491
  var canUseDOM2 = typeof window !== "undefined" && typeof document !== "undefined";
11570
- var useIsomorphicLayoutEffect = canUseDOM2 ? React25__default.useLayoutEffect : React25__default.useEffect;
12492
+ var useIsomorphicLayoutEffect = canUseDOM2 ? React37__default.useLayoutEffect : React37__default.useEffect;
11571
12493
  function useMounted() {
11572
- const [mounted, setMounted] = React25__default.useState(false);
11573
- React25__default.useEffect(() => {
12494
+ const [mounted, setMounted] = React37__default.useState(false);
12495
+ React37__default.useEffect(() => {
11574
12496
  setMounted(true);
11575
12497
  }, []);
11576
12498
  return mounted;
11577
12499
  }
11578
12500
  function usePrevious(value) {
11579
- const ref = React25__default.useRef(void 0);
11580
- React25__default.useEffect(() => {
12501
+ const ref = React37__default.useRef(void 0);
12502
+ React37__default.useEffect(() => {
11581
12503
  ref.current = value;
11582
12504
  }, [value]);
11583
12505
  return ref.current;
11584
12506
  }
11585
12507
  function useToggle(initial = false) {
11586
- const [on, setOn] = React25__default.useState(initial);
11587
- const toggle = React25__default.useCallback((next) => {
12508
+ const [on, setOn] = React37__default.useState(initial);
12509
+ const toggle = React37__default.useCallback((next) => {
11588
12510
  setOn((prev) => typeof next === "boolean" ? next : !prev);
11589
12511
  }, []);
11590
12512
  return [on, toggle, setOn];
11591
12513
  }
11592
12514
  function useDisclosure(initial = false) {
11593
- const [open, setOpen] = React25__default.useState(initial);
11594
- const onOpen = React25__default.useCallback(() => setOpen(true), []);
11595
- const onClose = React25__default.useCallback(() => setOpen(false), []);
11596
- const onToggle = React25__default.useCallback(() => setOpen((p) => !p), []);
12515
+ const [open, setOpen] = React37__default.useState(initial);
12516
+ const onOpen = React37__default.useCallback(() => setOpen(true), []);
12517
+ const onClose = React37__default.useCallback(() => setOpen(false), []);
12518
+ const onToggle = React37__default.useCallback(() => setOpen((p) => !p), []);
11597
12519
  return { open, onOpen, onClose, onToggle, setOpen };
11598
12520
  }
11599
12521
  function useControllableState({ value, defaultValue, onChange } = {}) {
11600
12522
  const isControlled = value !== void 0;
11601
- const [uncontrolled, setUncontrolled] = React25__default.useState(defaultValue);
12523
+ const [uncontrolled, setUncontrolled] = React37__default.useState(defaultValue);
11602
12524
  const current = isControlled ? value : uncontrolled;
11603
- const ref = React25__default.useRef({ current, isControlled, onChange });
12525
+ const ref = React37__default.useRef({ current, isControlled, onChange });
11604
12526
  useIsomorphicLayoutEffect(() => {
11605
12527
  ref.current = { current, isControlled, onChange };
11606
12528
  });
11607
- const wasControlled = React25__default.useRef(isControlled);
11608
- React25__default.useEffect(() => {
12529
+ const wasControlled = React37__default.useRef(isControlled);
12530
+ React37__default.useEffect(() => {
11609
12531
  if (wasControlled.current !== isControlled) {
11610
12532
  warnOnce(
11611
12533
  "useControllableState:switch",
@@ -11614,7 +12536,7 @@ function useControllableState({ value, defaultValue, onChange } = {}) {
11614
12536
  wasControlled.current = isControlled;
11615
12537
  }
11616
12538
  });
11617
- const setValue = React25__default.useCallback((next) => {
12539
+ const setValue = React37__default.useCallback((next) => {
11618
12540
  const { current: cur, isControlled: ctrl, onChange: cb } = ref.current;
11619
12541
  const resolved = typeof next === "function" ? next(cur) : next;
11620
12542
  if (resolved === cur) return;
@@ -11625,7 +12547,7 @@ function useControllableState({ value, defaultValue, onChange } = {}) {
11625
12547
  }
11626
12548
  function useMediaQuery(query, { defaultValue = false, initializeWithValue = false } = {}) {
11627
12549
  const get = () => canUseDOM2 ? window.matchMedia(query).matches : defaultValue;
11628
- const [matches3, setMatches] = React25__default.useState(initializeWithValue ? get : defaultValue);
12550
+ const [matches3, setMatches] = React37__default.useState(initializeWithValue ? get : defaultValue);
11629
12551
  useIsomorphicLayoutEffect(() => {
11630
12552
  if (!canUseDOM2) return void 0;
11631
12553
  const mql = window.matchMedia(query);
@@ -11641,7 +12563,7 @@ function usePrefersReducedMotion() {
11641
12563
  }
11642
12564
  function useColorScheme({ storageKey = "twico-theme", attribute = "class", element, disableTransitionsOnChange = true } = {}) {
11643
12565
  const getTarget = () => element || (canUseDOM2 ? document.documentElement : null);
11644
- const firstApply = React25__default.useRef(true);
12566
+ const firstApply = React37__default.useRef(true);
11645
12567
  const read = () => {
11646
12568
  if (!canUseDOM2) return "light";
11647
12569
  try {
@@ -11651,8 +12573,8 @@ function useColorScheme({ storageKey = "twico-theme", attribute = "class", eleme
11651
12573
  }
11652
12574
  return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
11653
12575
  };
11654
- const [theme, setThemeState] = React25__default.useState(read);
11655
- const apply = React25__default.useCallback(
12576
+ const [theme, setThemeState] = React37__default.useState(read);
12577
+ const apply = React37__default.useCallback(
11656
12578
  (t) => {
11657
12579
  const target = getTarget();
11658
12580
  if (!target) return;
@@ -11678,11 +12600,11 @@ function useColorScheme({ storageKey = "twico-theme", attribute = "class", eleme
11678
12600
  useIsomorphicLayoutEffect(() => {
11679
12601
  apply(theme);
11680
12602
  }, [theme, apply]);
11681
- const themeRef = React25__default.useRef(theme);
12603
+ const themeRef = React37__default.useRef(theme);
11682
12604
  useIsomorphicLayoutEffect(() => {
11683
12605
  themeRef.current = theme;
11684
12606
  }, [theme]);
11685
- const setTheme = React25__default.useCallback(
12607
+ const setTheme = React37__default.useCallback(
11686
12608
  (t) => {
11687
12609
  setThemeState(t);
11688
12610
  try {
@@ -11693,10 +12615,10 @@ function useColorScheme({ storageKey = "twico-theme", attribute = "class", eleme
11693
12615
  },
11694
12616
  [storageKey]
11695
12617
  );
11696
- const toggle = React25__default.useCallback(() => {
12618
+ const toggle = React37__default.useCallback(() => {
11697
12619
  setTheme(themeRef.current === "dark" ? "light" : "dark");
11698
12620
  }, [setTheme]);
11699
- React25__default.useEffect(() => {
12621
+ React37__default.useEffect(() => {
11700
12622
  if (!canUseDOM2) return void 0;
11701
12623
  const sync = () => setThemeState(read());
11702
12624
  const onStorage = (e) => {
@@ -11712,14 +12634,14 @@ function useColorScheme({ storageKey = "twico-theme", attribute = "class", eleme
11712
12634
  return { theme, setTheme, toggle, isDark: theme === "dark" };
11713
12635
  }
11714
12636
  function useEventListener(eventName, handler, element, options) {
11715
- const saved = React25__default.useRef(handler);
12637
+ const saved = React37__default.useRef(handler);
11716
12638
  useIsomorphicLayoutEffect(() => {
11717
12639
  saved.current = handler;
11718
12640
  }, [handler]);
11719
12641
  const capture = typeof options === "boolean" ? options : options && options.capture;
11720
12642
  const passive = typeof options === "object" && options ? options.passive : void 0;
11721
12643
  const once = typeof options === "object" && options ? options.once : void 0;
11722
- React25__default.useEffect(() => {
12644
+ React37__default.useEffect(() => {
11723
12645
  const target = element && element.current || element || (canUseDOM2 ? window : null);
11724
12646
  if (!target || !target.addEventListener) return void 0;
11725
12647
  const opts = typeof options === "boolean" ? options : { capture, passive, once };
@@ -11729,11 +12651,11 @@ function useEventListener(eventName, handler, element, options) {
11729
12651
  }, [eventName, element, capture, passive, once]);
11730
12652
  }
11731
12653
  function useClickOutside(ref, handler, events = ["mousedown", "touchstart"]) {
11732
- const saved = React25__default.useRef(handler);
12654
+ const saved = React37__default.useRef(handler);
11733
12655
  useIsomorphicLayoutEffect(() => {
11734
12656
  saved.current = handler;
11735
12657
  }, [handler]);
11736
- React25__default.useEffect(() => {
12658
+ React37__default.useEffect(() => {
11737
12659
  if (!canUseDOM2) return void 0;
11738
12660
  const listener = (e) => {
11739
12661
  const el = ref && ref.current;
@@ -11768,8 +12690,8 @@ function useLocalStorage(key, initialValue) {
11768
12690
  return initialValue;
11769
12691
  }
11770
12692
  };
11771
- const [stored, setStored] = React25__default.useState(read);
11772
- const setValue = React25__default.useCallback(
12693
+ const [stored, setStored] = React37__default.useState(read);
12694
+ const setValue = React37__default.useCallback(
11773
12695
  (value) => {
11774
12696
  setStored((prev) => {
11775
12697
  const next = typeof value === "function" ? value(prev) : value;
@@ -11785,8 +12707,8 @@ function useLocalStorage(key, initialValue) {
11785
12707
  return [stored, setValue];
11786
12708
  }
11787
12709
  function useCopyToClipboard(timeout = 1500) {
11788
- const [copied, setCopied] = React25__default.useState(false);
11789
- const copy = React25__default.useCallback(async (text) => {
12710
+ const [copied, setCopied] = React37__default.useState(false);
12711
+ const copy = React37__default.useCallback(async (text) => {
11790
12712
  if (!canUseDOM2 || !navigator.clipboard) {
11791
12713
  setCopied(false);
11792
12714
  return false;
@@ -11800,7 +12722,7 @@ function useCopyToClipboard(timeout = 1500) {
11800
12722
  return false;
11801
12723
  }
11802
12724
  }, []);
11803
- React25__default.useEffect(() => {
12725
+ React37__default.useEffect(() => {
11804
12726
  if (!copied) return void 0;
11805
12727
  const t = setTimeout(() => setCopied(false), timeout);
11806
12728
  return () => clearTimeout(t);
@@ -11808,23 +12730,23 @@ function useCopyToClipboard(timeout = 1500) {
11808
12730
  return { copied, copy };
11809
12731
  }
11810
12732
  function useDebouncedValue(value, delay = 200) {
11811
- const [debounced, setDebounced] = React25__default.useState(value);
11812
- React25__default.useEffect(() => {
12733
+ const [debounced, setDebounced] = React37__default.useState(value);
12734
+ React37__default.useEffect(() => {
11813
12735
  const t = setTimeout(() => setDebounced(value), delay);
11814
12736
  return () => clearTimeout(t);
11815
12737
  }, [value, delay]);
11816
12738
  return debounced;
11817
12739
  }
11818
12740
  function useDebouncedCallback(callback, delay = 200) {
11819
- const saved = React25__default.useRef(callback);
11820
- const timer = React25__default.useRef(null);
12741
+ const saved = React37__default.useRef(callback);
12742
+ const timer = React37__default.useRef(null);
11821
12743
  useIsomorphicLayoutEffect(() => {
11822
12744
  saved.current = callback;
11823
12745
  }, [callback]);
11824
- React25__default.useEffect(() => () => {
12746
+ React37__default.useEffect(() => () => {
11825
12747
  if (timer.current) clearTimeout(timer.current);
11826
12748
  }, []);
11827
- return React25__default.useCallback(
12749
+ return React37__default.useCallback(
11828
12750
  (...args) => {
11829
12751
  if (timer.current) clearTimeout(timer.current);
11830
12752
  timer.current = setTimeout(() => saved.current(...args), delay);
@@ -11833,33 +12755,33 @@ function useDebouncedCallback(callback, delay = 200) {
11833
12755
  );
11834
12756
  }
11835
12757
  function useInterval(callback, delay) {
11836
- const saved = React25__default.useRef(callback);
12758
+ const saved = React37__default.useRef(callback);
11837
12759
  useIsomorphicLayoutEffect(() => {
11838
12760
  saved.current = callback;
11839
12761
  }, [callback]);
11840
- React25__default.useEffect(() => {
12762
+ React37__default.useEffect(() => {
11841
12763
  if (delay == null) return void 0;
11842
12764
  const id = setInterval(() => saved.current(), delay);
11843
12765
  return () => clearInterval(id);
11844
12766
  }, [delay]);
11845
12767
  }
11846
12768
  function useTimeout(callback, delay) {
11847
- const saved = React25__default.useRef(callback);
12769
+ const saved = React37__default.useRef(callback);
11848
12770
  useIsomorphicLayoutEffect(() => {
11849
12771
  saved.current = callback;
11850
12772
  }, [callback]);
11851
- React25__default.useEffect(() => {
12773
+ React37__default.useEffect(() => {
11852
12774
  if (delay == null) return void 0;
11853
12775
  const id = setTimeout(() => saved.current(), delay);
11854
12776
  return () => clearTimeout(id);
11855
12777
  }, [delay]);
11856
12778
  }
11857
12779
  function useWindowSize() {
11858
- const [size, setSize] = React25__default.useState(() => ({
12780
+ const [size, setSize] = React37__default.useState(() => ({
11859
12781
  width: canUseDOM2 ? window.innerWidth : 0,
11860
12782
  height: canUseDOM2 ? window.innerHeight : 0
11861
12783
  }));
11862
- React25__default.useEffect(() => {
12784
+ React37__default.useEffect(() => {
11863
12785
  if (!canUseDOM2) return void 0;
11864
12786
  const onResize = () => setSize({ width: window.innerWidth, height: window.innerHeight });
11865
12787
  onResize();
@@ -11869,8 +12791,8 @@ function useWindowSize() {
11869
12791
  return size;
11870
12792
  }
11871
12793
  function useHover(ref) {
11872
- const [hovered, setHovered] = React25__default.useState(false);
11873
- React25__default.useEffect(() => {
12794
+ const [hovered, setHovered] = React37__default.useState(false);
12795
+ React37__default.useEffect(() => {
11874
12796
  const el = ref && ref.current;
11875
12797
  if (!el) return void 0;
11876
12798
  const on = () => setHovered(true);
@@ -11886,8 +12808,8 @@ function useHover(ref) {
11886
12808
  }
11887
12809
  function useIntersectionObserver(ref, options = {}) {
11888
12810
  const { root = null, rootMargin = "0px", threshold = 0 } = options;
11889
- const [entry, setEntry] = React25__default.useState(null);
11890
- React25__default.useEffect(() => {
12811
+ const [entry, setEntry] = React37__default.useState(null);
12812
+ React37__default.useEffect(() => {
11891
12813
  const el = ref && ref.current;
11892
12814
  if (!canUseDOM2 || !el || typeof IntersectionObserver === "undefined") return void 0;
11893
12815
  const obs = new IntersectionObserver(([e]) => setEntry(e), { root, rootMargin, threshold });
@@ -11897,13 +12819,13 @@ function useIntersectionObserver(ref, options = {}) {
11897
12819
  return entry;
11898
12820
  }
11899
12821
  function useId(prefix = "twc") {
11900
- const raw = React25__default.useId();
12822
+ const raw = React37__default.useId();
11901
12823
  return prefix ? `${prefix}-${raw.replace(/:/g, "")}` : raw;
11902
12824
  }
11903
12825
  var useFocusTrap2 = useFocusTrap;
11904
12826
  var usePortal2 = usePortal;
11905
12827
  var useScrollLock2 = useScrollLock;
11906
12828
 
11907
- export { Accordion, Alert, AppShell, Avatar, AvatarMenu, Badge, Box, Breadcrumb, Button, Card, Carousel, Chart, Checkbox, Code, ColorPicker, Combobox, CommandPalette, Container, Currency, CurrencyField, Datatable, DatePicker, DateRangePicker, Dialog, Divider, Drawer, EmptyState, Field, FileUpload, Grid, Heading, IconButton, Input, Kanban, List, Menu, MultiSelect, Navbar, Pagination, Popover, Progress, Radio, RadioGroup, Rating, Select, Sidebar, Skeleton, Slider, Spinner, Stack, Stat, Stepper, Switch, Table, Tabs, Tag, Text, Textarea, Timeline, Toast, ToastProvider, ToastViewport, Tooltip, TreeView, runDatatableQuery, useClickOutside, useColorScheme, useControllableState, useCopyToClipboard, useDebouncedCallback, useDebouncedValue, useDisclosure, useEventListener, useFocusTrap2 as useFocusTrap, useHover, useId, useIntersectionObserver, useInterval, useIsomorphicLayoutEffect, useKeyPress, useLocalStorage, useMediaQuery, useMounted, usePortal2 as usePortal, usePrefersReducedMotion, usePrevious, useScrollLock2 as useScrollLock, useTimeout, useToast, useToggle, useWindowSize };
12829
+ export { Accordion, Alert, Anchor, AppShell, Avatar, AvatarMenu, Badge, Box, Breadcrumb, Button, Card, Carousel, Chart, Checkbox, Code, ColorPicker, ColorSchemeScript, Combobox, CommandPalette, Container, Currency, CurrencyField, Datatable, DatePicker, DateRangePicker, Dialog, Divider, Drawer, EmptyState, Field, FileUpload, Form, Grid, Heading, IconButton, Image, Input, Kanban, Kbd, Label, List, Menu, MultiSelect, Navbar, Pagination, Popover, Portal, Pre, Progress, Radio, RadioGroup, Rating, Select, Sidebar, Skeleton, Slider, Spinner, Stack, Stat, Stepper, Switch, Table, Tabs, Tag, Text, Textarea, ThemeProvider, Timeline, Toast, ToastProvider, ToastViewport, Tooltip, TreeView, TwicoProvider, VisuallyHidden, createTheme, getColorSchemeScript, runDatatableQuery, useClickOutside, useColorScheme, useControllableState, useCopyToClipboard, useDebouncedCallback, useDebouncedValue, useDisclosure, useEventListener, useFocusTrap2 as useFocusTrap, useHover, useId, useIntersectionObserver, useInterval, useIsomorphicLayoutEffect, useKeyPress, useLocalStorage, useMediaQuery, useMounted, usePortal2 as usePortal, usePrefersReducedMotion, usePrevious, useScrollLock2 as useScrollLock, useTimeout, useToast, useToggle, useWindowSize };
11908
12830
  //# sourceMappingURL=index.mjs.map
11909
12831
  //# sourceMappingURL=index.mjs.map