trc-ui 0.0.0-stage → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,2710 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var src_exports = {};
23
+ __export(src_exports, {
24
+ AccentText: () => AccentText,
25
+ Accordion: () => Accordion,
26
+ Alert: () => Alert,
27
+ ArrowLeft: () => ArrowLeft,
28
+ ArrowRight: () => ArrowRight,
29
+ ArrowUp: () => ArrowUp,
30
+ Avatar: () => Avatar,
31
+ AvatarGroup: () => AvatarGroup,
32
+ BackToTop: () => BackToTop,
33
+ Breadcrumbs: () => Breadcrumbs,
34
+ Calendar: () => Calendar,
35
+ Card: () => Card,
36
+ Check: () => Check,
37
+ Checkbox: () => Checkbox,
38
+ ChevronDown: () => ChevronDown,
39
+ ChevronLeft: () => ChevronLeft,
40
+ ChevronRight: () => ChevronRight,
41
+ Close: () => Close,
42
+ CodeBlock: () => CodeBlock,
43
+ Combobox: () => Combobox,
44
+ Container: () => Container,
45
+ DatePicker: () => DatePicker,
46
+ Dialog: () => Dialog,
47
+ Divider: () => Divider,
48
+ Drawer: () => Drawer,
49
+ DropdownMenu: () => DropdownMenu,
50
+ Dropzone: () => Dropzone,
51
+ Field: () => Field,
52
+ FileInput: () => FileInput,
53
+ Heading: () => Heading,
54
+ HeroVideo: () => HeroVideo,
55
+ Input: () => Input,
56
+ Kbd: () => Kbd,
57
+ LanguageSwitcher: () => LanguageSwitcher,
58
+ Menu: () => Menu,
59
+ PageHero: () => PageHero,
60
+ Pagination: () => Pagination,
61
+ PasswordInput: () => PasswordInput,
62
+ PillButton: () => PillButton,
63
+ PillLink: () => PillLink,
64
+ PinInput: () => PinInput,
65
+ Popover: () => Popover,
66
+ Progress: () => Progress,
67
+ RadioGroup: () => RadioGroup,
68
+ Section: () => Section,
69
+ SegmentedControl: () => SegmentedControl,
70
+ Select: () => Select,
71
+ SiteFooter: () => SiteFooter,
72
+ SiteHeader: () => SiteHeader,
73
+ Skeleton: () => Skeleton,
74
+ Slider: () => Slider,
75
+ Spinner: () => Spinner2,
76
+ Stat: () => Stat,
77
+ StepNumber: () => StepNumber,
78
+ Steps: () => Steps,
79
+ Switch: () => Switch,
80
+ Table: () => Table,
81
+ Tabs: () => Tabs,
82
+ Tag: () => Tag,
83
+ Text: () => Text,
84
+ Textarea: () => Textarea,
85
+ Toaster: () => Toaster,
86
+ Tooltip: () => Tooltip,
87
+ acceptsFile: () => acceptsFile,
88
+ cx: () => cx,
89
+ formatBytes: () => formatBytes,
90
+ initials: () => initials,
91
+ paginationRange: () => paginationRange,
92
+ plainText: () => plainText,
93
+ toast: () => toast,
94
+ validateFiles: () => validateFiles
95
+ });
96
+ module.exports = __toCommonJS(src_exports);
97
+
98
+ // src/utils/cx.ts
99
+ function cx(...classes) {
100
+ return classes.filter(Boolean).join(" ");
101
+ }
102
+
103
+ // src/components/typography.tsx
104
+ var import_jsx_runtime = require("react/jsx-runtime");
105
+ function AccentText({ text, accentLast = 0 }) {
106
+ if (text.includes("*")) {
107
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: text.split("*").map(
108
+ (part, i) => i % 2 === 1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "trc-accent", children: part }, i) : part
109
+ ) });
110
+ }
111
+ const words = text.split(" ");
112
+ if (!accentLast || words.length < 2) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: text });
113
+ const n = Math.min(accentLast, words.length - 1);
114
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
115
+ words.slice(0, -n).join(" "),
116
+ " ",
117
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "trc-accent", children: words.slice(-n).join(" ") })
118
+ ] });
119
+ }
120
+ var plainText = (text) => text.replaceAll("*", "");
121
+ function Heading({ as: Tag2 = "h2", size: size2 = "xl", accentLast, className, children, ...props }) {
122
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tag2, { className: cx("trc-display", `trc-heading--${size2}`, className), ...props, children: typeof children === "string" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AccentText, { text: children, accentLast }) : children });
123
+ }
124
+ function Text({
125
+ as,
126
+ size: size2 = "md",
127
+ tone = "muted",
128
+ className,
129
+ ...props
130
+ }) {
131
+ const Tag2 = as ?? "p";
132
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tag2, { className: cx("trc-text", `trc-text--${size2}`, `trc-text--${tone}`, className), ...props });
133
+ }
134
+ function StepNumber({ n, size: size2 = "md", className }) {
135
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": true, className: cx("trc-step-number", size2 === "sm" && "trc-step-number--sm", className), children: String(n).padStart(2, "0") });
136
+ }
137
+
138
+ // src/components/pill.tsx
139
+ var import_react = require("react");
140
+
141
+ // src/utils/icons.tsx
142
+ var import_jsx_runtime2 = require("react/jsx-runtime");
143
+ var base = {
144
+ xmlns: "http://www.w3.org/2000/svg",
145
+ viewBox: "0 0 24 24",
146
+ fill: "none",
147
+ stroke: "currentColor",
148
+ strokeWidth: 2,
149
+ strokeLinecap: "round",
150
+ strokeLinejoin: "round",
151
+ "aria-hidden": true
152
+ };
153
+ var ArrowRight = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...base, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M5 12h14M13 6l6 6-6 6" }) });
154
+ var ArrowLeft = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...base, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M19 12H5M11 18l-6-6 6-6" }) });
155
+ var Spinner = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...base, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M21 12a9 9 0 1 1-6.22-8.56" }) });
156
+ var ChevronDown = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...base, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m6 9 6 6 6-6" }) });
157
+ var Check = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...base, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M20 6 9 17l-5-5" }) });
158
+ var Menu = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...base, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M4 7h16M4 12h16M4 17h16" }) });
159
+ var Close = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...base, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M18 6 6 18M6 6l12 12" }) });
160
+ var ArrowUp = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...base, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 19V5M6 11l6-6 6 6" }) });
161
+ var Calendar = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { ...base, ...props, children: [
162
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "3", y: "5", width: "18", height: "16", rx: "3" }),
163
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M3 10h18M8 3v4M16 3v4" })
164
+ ] });
165
+ var ChevronLeft = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...base, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m15 6-6 6 6 6" }) });
166
+ var ChevronRight = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...base, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m9 6 6 6-6 6" }) });
167
+
168
+ // src/components/pill.tsx
169
+ var import_jsx_runtime3 = require("react/jsx-runtime");
170
+ var pillClass = ({ solid, size: size2 }, className) => cx("trc-pill", size2 === "sm" && "trc-pill--sm", solid && "trc-pill--solid", className);
171
+ function PillInner({ icon, children }) {
172
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
173
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { "aria-hidden": true, className: "trc-pill__fill" }),
174
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { "aria-hidden": true, className: "trc-pill__icon", children: icon ?? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ArrowRight, {}) }),
175
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "trc-pill__label", children })
176
+ ] });
177
+ }
178
+ var PillButton = (0, import_react.forwardRef)(function PillButton2({ solid, size: size2 = "md", icon, loading = false, disabled, type = "button", className, children, ...props }, ref) {
179
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
180
+ "button",
181
+ {
182
+ ref,
183
+ type,
184
+ disabled: disabled || loading,
185
+ "aria-busy": loading || void 0,
186
+ className: pillClass({ solid, size: size2 }, className),
187
+ ...props,
188
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PillInner, { icon: loading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Spinner, { className: "trc-spin" }) : icon, children })
189
+ }
190
+ );
191
+ });
192
+ var PillLink = (0, import_react.forwardRef)(function PillLink2({ as, solid, size: size2 = "md", icon, className, children, ...props }, ref) {
193
+ const Tag2 = as ?? "a";
194
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Tag2, { ref, className: pillClass({ solid, size: size2 }, className), ...props, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PillInner, { icon, children }) });
195
+ });
196
+
197
+ // src/components/surfaces.tsx
198
+ var import_jsx_runtime4 = require("react/jsx-runtime");
199
+ function Container({
200
+ as,
201
+ size: size2 = "default",
202
+ className,
203
+ ...props
204
+ }) {
205
+ const Tag2 = as ?? "div";
206
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Tag2, { className: cx("trc-container", size2 !== "default" && `trc-container--${size2}`, className), ...props });
207
+ }
208
+ function Section({
209
+ as,
210
+ spacing = "md",
211
+ inset = false,
212
+ className,
213
+ children,
214
+ ...props
215
+ }) {
216
+ const Tag2 = as ?? "section";
217
+ if (inset) {
218
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Tag2, { className: cx("trc-section-inset", className), ...props, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: cx("trc-section-inset__card", spacing !== "none" && `trc-section--${spacing}`), children }) });
219
+ }
220
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Tag2, { className: cx(spacing !== "none" && `trc-section--${spacing}`, className), ...props, children });
221
+ }
222
+ function Card({
223
+ as,
224
+ tone = "default",
225
+ padding = "md",
226
+ interactive = false,
227
+ watermark,
228
+ className,
229
+ children,
230
+ ...props
231
+ }) {
232
+ const Tag2 = as ?? "div";
233
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
234
+ Tag2,
235
+ {
236
+ className: cx(
237
+ "trc-card",
238
+ tone === "alt" && "trc-card--alt",
239
+ padding !== "none" && `trc-card--pad-${padding}`,
240
+ interactive && "trc-card--interactive",
241
+ !!watermark && "trc-card--watermark",
242
+ className
243
+ ),
244
+ ...props,
245
+ children: [
246
+ !!watermark && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "aria-hidden": true, className: "trc-card__watermark", children: watermark }),
247
+ children
248
+ ]
249
+ }
250
+ );
251
+ }
252
+
253
+ // src/components/field.tsx
254
+ var import_react2 = require("react");
255
+ var import_jsx_runtime5 = require("react/jsx-runtime");
256
+ var FieldContext = (0, import_react2.createContext)(null);
257
+ function Field({ label, hint, error, required = false, id, className, children }) {
258
+ const generated = (0, import_react2.useId)();
259
+ const fieldId = id ?? generated;
260
+ const messageId = `${fieldId}-message`;
261
+ const message = error ?? hint;
262
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
263
+ FieldContext.Provider,
264
+ {
265
+ value: { id: fieldId, describedBy: message ? messageId : void 0, invalid: error != null, required },
266
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: cx("trc-field", className), children: [
267
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { htmlFor: fieldId, className: "trc-field__label", children: [
268
+ label,
269
+ required && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { "aria-hidden": true, className: "trc-field__required", children: [
270
+ " ",
271
+ "*"
272
+ ] })
273
+ ] }),
274
+ children,
275
+ message != null && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { id: messageId, className: cx("trc-field__message", error != null && "trc-field__message--error"), children: message })
276
+ ] })
277
+ }
278
+ );
279
+ }
280
+ function useFieldProps(props) {
281
+ const field = (0, import_react2.useContext)(FieldContext);
282
+ const invalid = props.invalid ?? field?.invalid ?? false;
283
+ return {
284
+ id: props.id ?? field?.id,
285
+ required: props.required ?? field?.required,
286
+ "aria-describedby": cx(field?.describedBy, props["aria-describedby"]) || void 0,
287
+ "aria-invalid": invalid || void 0
288
+ };
289
+ }
290
+ var Input = (0, import_react2.forwardRef)(function Input2({ invalid, className, ...props }, ref) {
291
+ const a11y = useFieldProps({ ...props, invalid });
292
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { ref, className: cx("trc-control", className), ...props, ...a11y });
293
+ });
294
+ var Textarea = (0, import_react2.forwardRef)(function Textarea2({ invalid, rows = 4, className, ...props }, ref) {
295
+ const a11y = useFieldProps({ ...props, invalid });
296
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
297
+ "textarea",
298
+ {
299
+ ref,
300
+ rows,
301
+ className: cx("trc-control", "trc-control--textarea", className),
302
+ ...props,
303
+ ...a11y
304
+ }
305
+ );
306
+ });
307
+ var Select = (0, import_react2.forwardRef)(function Select2({ invalid, placeholder, defaultValue, className, children, ...props }, ref) {
308
+ const a11y = useFieldProps({ ...props, invalid });
309
+ const initial = defaultValue ?? (props.value === void 0 && placeholder != null ? "" : void 0);
310
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: cx("trc-select", className), children: [
311
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { ref, className: "trc-control trc-control--select", defaultValue: initial, ...props, ...a11y, children: [
312
+ placeholder != null && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "", disabled: true, children: placeholder }),
313
+ children
314
+ ] }),
315
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronDown, { className: "trc-select__chevron" })
316
+ ] });
317
+ });
318
+
319
+ // src/components/toggle.tsx
320
+ var import_react3 = require("react");
321
+ var import_jsx_runtime6 = require("react/jsx-runtime");
322
+ function ToggleLabel({
323
+ kind,
324
+ label,
325
+ description,
326
+ className,
327
+ children
328
+ }) {
329
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: cx("trc-toggle", `trc-toggle--${kind}`, className), children: [
330
+ children,
331
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "trc-toggle__text", children: [
332
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "trc-toggle__label", children: label }),
333
+ description != null && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "trc-toggle__description", children: description })
334
+ ] })
335
+ ] });
336
+ }
337
+ var Checkbox = (0, import_react3.forwardRef)(function Checkbox2({ label, description, className, ...props }, ref) {
338
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleLabel, { kind: "checkbox", label, description, className, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "trc-checkbox", children: [
339
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { ref, type: "checkbox", className: "trc-checkbox__input", ...props }),
340
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Check, { className: "trc-checkbox__check" })
341
+ ] }) });
342
+ });
343
+ var Switch = (0, import_react3.forwardRef)(function Switch2({ label, description, className, ...props }, ref) {
344
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleLabel, { kind: "switch", label, description, className, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "trc-switch", children: [
345
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { ref, type: "checkbox", role: "switch", className: "trc-switch__input", ...props }),
346
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { "aria-hidden": true, className: "trc-switch__thumb" })
347
+ ] }) });
348
+ });
349
+
350
+ // src/components/site-header.tsx
351
+ var import_react7 = require("react");
352
+
353
+ // src/components/layer.tsx
354
+ var import_react6 = require("react");
355
+
356
+ // src/hooks/use-modal.ts
357
+ var import_react4 = require("react");
358
+ var FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
359
+ function useModal(open, panelRef, onClose) {
360
+ const close = (0, import_react4.useRef)(onClose);
361
+ close.current = onClose;
362
+ (0, import_react4.useEffect)(() => {
363
+ const panel = panelRef.current;
364
+ if (!open || !panel) return;
365
+ const previous = document.activeElement;
366
+ const overflow = document.body.style.overflow;
367
+ document.body.style.overflow = "hidden";
368
+ (panel.querySelector("[data-autofocus]") ?? panel.querySelector(FOCUSABLE) ?? panel).focus();
369
+ const onKeyDown = (e) => {
370
+ if (e.key === "Escape") {
371
+ e.stopPropagation();
372
+ close.current();
373
+ return;
374
+ }
375
+ if (e.key !== "Tab") return;
376
+ const items2 = [...panel.querySelectorAll(FOCUSABLE)].filter((el) => el.offsetParent !== null);
377
+ const first = items2[0];
378
+ const last = items2[items2.length - 1];
379
+ if (!first || !last) {
380
+ e.preventDefault();
381
+ return;
382
+ }
383
+ if (e.shiftKey && document.activeElement === first) {
384
+ e.preventDefault();
385
+ last.focus();
386
+ } else if (!e.shiftKey && document.activeElement === last) {
387
+ e.preventDefault();
388
+ first.focus();
389
+ }
390
+ };
391
+ document.addEventListener("keydown", onKeyDown);
392
+ return () => {
393
+ document.removeEventListener("keydown", onKeyDown);
394
+ document.body.style.overflow = overflow;
395
+ previous?.focus();
396
+ };
397
+ }, [open, panelRef]);
398
+ }
399
+
400
+ // src/utils/portal.tsx
401
+ var import_react5 = require("react");
402
+ var import_react_dom = require("react-dom");
403
+ var noop = () => () => {
404
+ };
405
+ var useIsClient = () => (0, import_react5.useSyncExternalStore)(
406
+ noop,
407
+ () => true,
408
+ () => false
409
+ );
410
+ function Portal({ children }) {
411
+ return useIsClient() ? (0, import_react_dom.createPortal)(children, document.body) : null;
412
+ }
413
+
414
+ // src/components/layer.tsx
415
+ var import_jsx_runtime7 = require("react/jsx-runtime");
416
+ function ModalLayer({
417
+ open,
418
+ onClose,
419
+ title,
420
+ description,
421
+ children,
422
+ footer,
423
+ closeLabel,
424
+ closeOnOverlay,
425
+ rootClassName,
426
+ panelClassName
427
+ }) {
428
+ const titleId = (0, import_react6.useId)();
429
+ const descriptionId = (0, import_react6.useId)();
430
+ const panel = (0, import_react6.useRef)(null);
431
+ useModal(open, panel, onClose);
432
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: cx("trc-layer", rootClassName, open && "trc-layer--open"), "aria-hidden": !open, children: [
433
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "trc-layer__overlay", onClick: closeOnOverlay ? onClose : void 0 }),
434
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
435
+ "div",
436
+ {
437
+ ref: panel,
438
+ role: "dialog",
439
+ "aria-modal": "true",
440
+ "aria-labelledby": titleId,
441
+ "aria-describedby": description != null ? descriptionId : void 0,
442
+ tabIndex: -1,
443
+ className: panelClassName,
444
+ children: [
445
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "trc-layer__head", children: [
446
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { id: titleId, className: "trc-layer__title", children: title }),
447
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "trc-layer__close", "aria-label": closeLabel, onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Close, {}) })
448
+ ] }),
449
+ description != null && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { id: descriptionId, className: "trc-layer__description", children: description }),
450
+ children != null && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "trc-layer__body", children }),
451
+ footer != null && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "trc-layer__footer", children: footer })
452
+ ]
453
+ }
454
+ )
455
+ ] }) });
456
+ }
457
+
458
+ // src/components/drawer.tsx
459
+ var import_jsx_runtime8 = require("react/jsx-runtime");
460
+ function Drawer({
461
+ side = "right",
462
+ size: size2 = "sm",
463
+ closeLabel = "Close",
464
+ closeOnOverlay = true,
465
+ className,
466
+ ...props
467
+ }) {
468
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
469
+ ModalLayer,
470
+ {
471
+ ...props,
472
+ closeLabel,
473
+ closeOnOverlay,
474
+ rootClassName: `trc-layer--drawer trc-layer--${side}`,
475
+ panelClassName: cx("trc-drawer", `trc-drawer--${size2}`, className)
476
+ }
477
+ );
478
+ }
479
+
480
+ // src/components/site-header.tsx
481
+ var import_jsx_runtime9 = require("react/jsx-runtime");
482
+ var isMenu = (item) => "items" in item;
483
+ function SiteHeader({
484
+ logo,
485
+ logoLabel,
486
+ homeHref = "/",
487
+ nav = [],
488
+ cta,
489
+ actions,
490
+ mobileFooter,
491
+ linkAs: LinkTag = "a",
492
+ scrollThreshold = 24,
493
+ menuLabel = "Menu",
494
+ closeLabel = "Close",
495
+ className
496
+ }) {
497
+ const [scrolled, setScrolled] = (0, import_react7.useState)(false);
498
+ const [open, setOpen] = (0, import_react7.useState)(false);
499
+ (0, import_react7.useEffect)(() => {
500
+ const update = () => setScrolled(window.scrollY > scrollThreshold);
501
+ update();
502
+ window.addEventListener("scroll", update, { passive: true });
503
+ return () => window.removeEventListener("scroll", update);
504
+ }, [scrollThreshold]);
505
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("header", { className: cx("trc-header", className), children: [
506
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: cx("trc-header__bar", scrolled && "trc-header__bar--scrolled"), children: [
507
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LinkTag, { href: homeHref, "aria-label": logoLabel, className: "trc-header__logo", children: logo }),
508
+ nav.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("nav", { className: "trc-header__nav", children: nav.map(
509
+ (item, i) => isMenu(item) ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(NavDropdown, { menu: item, linkAs: LinkTag }, i) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
510
+ LinkTag,
511
+ {
512
+ href: item.href,
513
+ "aria-current": item.active ? "page" : void 0,
514
+ className: cx("trc-header__link", item.active && "trc-header__link--active"),
515
+ children: item.label
516
+ },
517
+ i
518
+ )
519
+ ) }),
520
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "trc-header__end", children: [
521
+ actions && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "trc-header__actions", children: actions }),
522
+ cta && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PillLink, { as: LinkTag, href: cta.href, size: "sm", className: "trc-header__cta", children: cta.label }),
523
+ (nav.length > 0 || cta || mobileFooter) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
524
+ "button",
525
+ {
526
+ type: "button",
527
+ className: "trc-header__burger",
528
+ "aria-label": menuLabel,
529
+ "aria-expanded": open,
530
+ onClick: () => setOpen(true),
531
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Menu, {})
532
+ }
533
+ )
534
+ ] })
535
+ ] }),
536
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
537
+ MobileMenu,
538
+ {
539
+ open,
540
+ onClose: () => setOpen(false),
541
+ nav,
542
+ cta,
543
+ footer: mobileFooter,
544
+ linkAs: LinkTag,
545
+ title: menuLabel,
546
+ closeLabel
547
+ }
548
+ )
549
+ ] });
550
+ }
551
+ function NavDropdown({ menu, linkAs: LinkTag }) {
552
+ const id = (0, import_react7.useId)();
553
+ const [open, setOpen] = (0, import_react7.useState)(false);
554
+ const closeTimer = (0, import_react7.useRef)(void 0);
555
+ const button = (0, import_react7.useRef)(null);
556
+ const openedByHover = (0, import_react7.useRef)(false);
557
+ const show = () => {
558
+ window.clearTimeout(closeTimer.current);
559
+ if (!open) openedByHover.current = true;
560
+ setOpen(true);
561
+ };
562
+ const hide = () => {
563
+ closeTimer.current = window.setTimeout(() => setOpen(false), 120);
564
+ };
565
+ (0, import_react7.useEffect)(() => () => window.clearTimeout(closeTimer.current), []);
566
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
567
+ "div",
568
+ {
569
+ className: "trc-dropdown",
570
+ onMouseEnter: show,
571
+ onMouseLeave: hide,
572
+ onKeyDown: (e) => {
573
+ if (e.key === "Escape" && open) {
574
+ setOpen(false);
575
+ button.current?.focus();
576
+ }
577
+ },
578
+ onBlur: (e) => !e.currentTarget.contains(e.relatedTarget) && setOpen(false),
579
+ children: [
580
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
581
+ "button",
582
+ {
583
+ ref: button,
584
+ type: "button",
585
+ "aria-expanded": open,
586
+ "aria-controls": id,
587
+ onClick: () => {
588
+ if (open && openedByHover.current) openedByHover.current = false;
589
+ else setOpen((o) => !o);
590
+ },
591
+ className: cx("trc-header__link", "trc-dropdown__trigger", open && "trc-dropdown__trigger--open"),
592
+ children: [
593
+ menu.label,
594
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ChevronDown, { className: "trc-dropdown__chevron" })
595
+ ]
596
+ }
597
+ ),
598
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { id, className: cx("trc-dropdown__panel", open && "trc-dropdown__panel--open"), children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { className: "trc-dropdown__list", children: menu.items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
599
+ LinkTag,
600
+ {
601
+ href: item.href,
602
+ "aria-current": item.active ? "page" : void 0,
603
+ onClick: () => setOpen(false),
604
+ className: "trc-dropdown__item",
605
+ children: [
606
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "trc-dropdown__label", children: item.label }),
607
+ item.description != null && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "trc-dropdown__description", children: item.description })
608
+ ]
609
+ }
610
+ ) }, i)) }) })
611
+ ]
612
+ }
613
+ );
614
+ }
615
+ function MobileMenu({
616
+ open,
617
+ onClose,
618
+ nav,
619
+ cta,
620
+ footer,
621
+ linkAs: LinkTag,
622
+ title,
623
+ closeLabel
624
+ }) {
625
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Drawer, { open, onClose, title, closeLabel, className: "trc-mobile-menu", children: [
626
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("nav", { className: "trc-mobile-nav", children: nav.map(
627
+ (item, i) => isMenu(item) ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "trc-mobile-nav__group", children: [
628
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "trc-mobile-nav__heading", children: item.label }),
629
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { className: "trc-mobile-nav__sub", children: item.items.map((sub, j) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
630
+ LinkTag,
631
+ {
632
+ href: sub.href,
633
+ "aria-current": sub.active ? "page" : void 0,
634
+ onClick: onClose,
635
+ className: "trc-mobile-nav__sublink",
636
+ children: sub.label
637
+ }
638
+ ) }, j)) })
639
+ ] }, i) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
640
+ LinkTag,
641
+ {
642
+ href: item.href,
643
+ "aria-current": item.active ? "page" : void 0,
644
+ onClick: onClose,
645
+ className: cx("trc-mobile-nav__link", item.active && "trc-mobile-nav__link--active"),
646
+ children: item.label
647
+ },
648
+ i
649
+ )
650
+ ) }),
651
+ cta && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PillLink, { as: LinkTag, href: cta.href, onClick: onClose, className: "trc-mobile-menu__cta", children: cta.label }),
652
+ footer != null && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "trc-mobile-menu__footer", children: footer })
653
+ ] });
654
+ }
655
+
656
+ // src/components/site-footer.tsx
657
+ var import_jsx_runtime10 = require("react/jsx-runtime");
658
+ function SiteFooter({
659
+ logo,
660
+ logoLabel,
661
+ homeHref = "/",
662
+ tagline,
663
+ children,
664
+ columns = [],
665
+ columnsLabel = "Site map",
666
+ copyright,
667
+ legal = [],
668
+ legalLabel = "Legal",
669
+ linkAs: LinkTag = "a",
670
+ className
671
+ }) {
672
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("footer", { className: cx("trc-footer", className), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "trc-footer__card", children: [
673
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "trc-footer__main", children: [
674
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "trc-footer__brand", children: [
675
+ logo != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LinkTag, { href: homeHref, "aria-label": logoLabel, className: "trc-footer__logo", children: logo }),
676
+ tagline != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "trc-footer__tagline", children: tagline }),
677
+ children != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "trc-footer__extra", children })
678
+ ] }),
679
+ columns.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("nav", { className: "trc-footer__columns", "aria-label": columnsLabel, children: columns.map((col, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
680
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "trc-footer__heading", children: col.title }),
681
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ul", { className: "trc-footer__list", children: col.links.map((link, j) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LinkTag, { href: link.href, className: "trc-footer__link", children: link.label }) }, j)) })
682
+ ] }, i)) })
683
+ ] }),
684
+ (copyright != null || legal.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "trc-footer__bottom", children: [
685
+ copyright != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "trc-footer__copyright", children: copyright }),
686
+ legal.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("nav", { "aria-label": legalLabel, className: "trc-footer__legal", children: legal.map((link, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LinkTag, { href: link.href, className: "trc-footer__legal-link", children: link.label }, i)) })
687
+ ] })
688
+ ] }) });
689
+ }
690
+
691
+ // src/components/hero.tsx
692
+ var import_react8 = require("react");
693
+ var import_jsx_runtime11 = require("react/jsx-runtime");
694
+ var delay = (ms) => ({ "--trc-delay": `${ms}ms` });
695
+ function PageHero({
696
+ title,
697
+ accentLast,
698
+ description,
699
+ meta,
700
+ image,
701
+ imagePosition = "50% 50%",
702
+ children,
703
+ className
704
+ }) {
705
+ const words = title.split(" ").length;
706
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("section", { className: cx("trc-hero-inset", className), children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "trc-page-hero", children: [
707
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { "aria-hidden": true, className: "trc-hero__media", children: typeof image === "string" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("img", { src: image, alt: "", className: "trc-hero__image", style: { objectPosition: imagePosition } }) : image != null ? image : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "trc-page-hero__glow" }) }),
708
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { "aria-hidden": true, className: "trc-page-hero__veil" }),
709
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "trc-page-hero__content", children: [
710
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { className: "trc-display trc-page-hero__title trc-enter", style: delay(150), children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AccentText, { text: title, accentLast: accentLast ?? (words > 3 ? 2 : 1) }) }),
711
+ description != null && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "trc-page-hero__description trc-enter", style: delay(250), children: description }),
712
+ meta != null && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "trc-page-hero__meta trc-enter", style: delay(350), children: meta }),
713
+ children != null && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "trc-page-hero__actions trc-enter", style: delay(450), children })
714
+ ] })
715
+ ] }) });
716
+ }
717
+ var prefersReducedMotion = () => window.matchMedia("(prefers-reduced-motion: reduce)").matches;
718
+ function HeroVideo({ clips, children, aside, fade = 1.2, parallax = true, className }) {
719
+ const videos = (0, import_react8.useRef)([]);
720
+ const section = (0, import_react8.useRef)(null);
721
+ const media = (0, import_react8.useRef)(null);
722
+ const [active, setActive] = (0, import_react8.useState)(-1);
723
+ (0, import_react8.useEffect)(() => {
724
+ if (clips.length === 0) return;
725
+ const start = Math.floor(Math.random() * clips.length);
726
+ const video = videos.current[start];
727
+ if (!prefersReducedMotion()) void video?.play().catch(() => {
728
+ });
729
+ const frame = requestAnimationFrame(() => setActive(start));
730
+ return () => {
731
+ cancelAnimationFrame(frame);
732
+ video?.pause();
733
+ };
734
+ }, [clips.length]);
735
+ (0, import_react8.useEffect)(() => {
736
+ const el = section.current;
737
+ const layer = media.current;
738
+ if (!parallax || !el || !layer || prefersReducedMotion()) return;
739
+ let frame = 0;
740
+ const update = () => {
741
+ frame = 0;
742
+ const rect = el.getBoundingClientRect();
743
+ const progress = Math.min(Math.max(-rect.top / rect.height, 0), 1);
744
+ layer.style.transform = `translate3d(0, ${progress * 120}px, 0)`;
745
+ };
746
+ const onScroll = () => {
747
+ if (!frame) frame = requestAnimationFrame(update);
748
+ };
749
+ update();
750
+ window.addEventListener("scroll", onScroll, { passive: true });
751
+ return () => {
752
+ window.removeEventListener("scroll", onScroll);
753
+ cancelAnimationFrame(frame);
754
+ };
755
+ }, [parallax]);
756
+ const playNext = (i) => {
757
+ const next = videos.current[(i + 1) % clips.length];
758
+ if (!next) return;
759
+ next.currentTime = 0;
760
+ void next.play().catch(() => {
761
+ });
762
+ setActive((i + 1) % clips.length);
763
+ };
764
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("section", { ref: section, className: cx("trc-hero-inset", className), children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "trc-hero-video", children: [
765
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { ref: media, "aria-hidden": true, className: "trc-hero__media trc-hero-video__media", children: clips.map((clip, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
766
+ "video",
767
+ {
768
+ ref: (el) => {
769
+ videos.current[i] = el;
770
+ },
771
+ className: cx("trc-hero__image", "trc-hero-video__clip", i === active && "trc-hero-video__clip--active"),
772
+ style: { transitionDuration: `${fade}s` },
773
+ muted: true,
774
+ playsInline: true,
775
+ preload: "metadata",
776
+ poster: clip.poster,
777
+ onTimeUpdate: (e) => {
778
+ const v = e.currentTarget;
779
+ if (i === active && v.duration && v.duration - v.currentTime <= fade) playNext(i);
780
+ },
781
+ onEnded: () => i === active && playNext(i),
782
+ children: [
783
+ clip.webm && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("source", { src: clip.webm, type: "video/webm" }),
784
+ clip.mp4 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("source", { src: clip.mp4, type: "video/mp4" })
785
+ ]
786
+ },
787
+ i
788
+ )) }),
789
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { "aria-hidden": true, className: "trc-hero-video__veil" }),
790
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "trc-hero-video__content", children: [
791
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "trc-hero-video__main", children }),
792
+ aside != null && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "trc-hero-video__aside", children: aside })
793
+ ] })
794
+ ] }) });
795
+ }
796
+
797
+ // src/components/back-to-top.tsx
798
+ var import_react9 = require("react");
799
+ var import_jsx_runtime12 = require("react/jsx-runtime");
800
+ function BackToTop({ label = "Back to top", threshold = 0.8, className }) {
801
+ const [visible, setVisible] = (0, import_react9.useState)(false);
802
+ (0, import_react9.useEffect)(() => {
803
+ const update = () => setVisible(window.scrollY > window.innerHeight * threshold);
804
+ update();
805
+ window.addEventListener("scroll", update, { passive: true });
806
+ return () => window.removeEventListener("scroll", update);
807
+ }, [threshold]);
808
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
809
+ "button",
810
+ {
811
+ type: "button",
812
+ onClick: () => window.scrollTo({
813
+ top: 0,
814
+ behavior: window.matchMedia("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth"
815
+ }),
816
+ "aria-label": label,
817
+ "aria-hidden": !visible,
818
+ tabIndex: visible ? 0 : -1,
819
+ className: cx("trc-back-to-top", visible && "trc-back-to-top--visible", className),
820
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ArrowUp, {})
821
+ }
822
+ );
823
+ }
824
+
825
+ // src/components/dialog.tsx
826
+ var import_jsx_runtime13 = require("react/jsx-runtime");
827
+ function Dialog({ size: size2 = "md", closeLabel = "Close", closeOnOverlay = true, className, ...props }) {
828
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
829
+ ModalLayer,
830
+ {
831
+ ...props,
832
+ closeLabel,
833
+ closeOnOverlay,
834
+ rootClassName: "trc-layer--dialog",
835
+ panelClassName: cx("trc-dialog", `trc-dialog--${size2}`, className)
836
+ }
837
+ );
838
+ }
839
+
840
+ // src/components/dropdown-menu.tsx
841
+ var import_react12 = require("react");
842
+
843
+ // src/hooks/use-floating.ts
844
+ var import_react10 = require("react");
845
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? import_react10.useEffect : import_react10.useLayoutEffect;
846
+ var MARGIN = 8;
847
+ function useAnchoredPosition(open, anchorRef, floatingRef, { side = "bottom", align = "start", offset = 8 } = {}) {
848
+ useIsomorphicLayoutEffect(() => {
849
+ if (!open) return;
850
+ const update = () => {
851
+ const anchor = anchorRef.current;
852
+ const floating = floatingRef.current;
853
+ if (!anchor || !floating) return;
854
+ const a = anchor.getBoundingClientRect();
855
+ const f = floating.getBoundingClientRect();
856
+ const vw = window.innerWidth;
857
+ const vh = window.innerHeight;
858
+ const below = a.bottom + offset;
859
+ const above = a.top - offset - f.height;
860
+ const fitsBelow = below + f.height <= vh - MARGIN;
861
+ const fitsAbove = above >= MARGIN;
862
+ const resolved = side === "bottom" ? fitsBelow || !fitsAbove ? "bottom" : "top" : fitsAbove || !fitsBelow ? "top" : "bottom";
863
+ const top = resolved === "bottom" ? below : above;
864
+ let left = align === "start" ? a.left : align === "end" ? a.right - f.width : a.left + a.width / 2 - f.width / 2;
865
+ left = Math.min(Math.max(left, MARGIN), Math.max(MARGIN, vw - f.width - MARGIN));
866
+ floating.style.top = `${Math.round(top)}px`;
867
+ floating.style.left = `${Math.round(left)}px`;
868
+ floating.dataset.side = resolved;
869
+ };
870
+ update();
871
+ window.addEventListener("resize", update);
872
+ window.addEventListener("scroll", update, true);
873
+ return () => {
874
+ window.removeEventListener("resize", update);
875
+ window.removeEventListener("scroll", update, true);
876
+ };
877
+ }, [open, side, align, offset]);
878
+ }
879
+ function useDismiss(open, refs, onDismiss) {
880
+ const dismiss2 = (0, import_react10.useRef)(onDismiss);
881
+ dismiss2.current = onDismiss;
882
+ (0, import_react10.useEffect)(() => {
883
+ if (!open) return;
884
+ const onPointerDown = (e) => {
885
+ const target = e.target;
886
+ if (!refs.some((ref) => ref.current?.contains(target))) dismiss2.current("outside");
887
+ };
888
+ const onKeyDown = (e) => {
889
+ if (e.key === "Escape") dismiss2.current("escape");
890
+ };
891
+ document.addEventListener("pointerdown", onPointerDown);
892
+ document.addEventListener("keydown", onKeyDown);
893
+ return () => {
894
+ document.removeEventListener("pointerdown", onPointerDown);
895
+ document.removeEventListener("keydown", onKeyDown);
896
+ };
897
+ }, [open]);
898
+ }
899
+
900
+ // src/utils/compose.ts
901
+ var import_react11 = require("react");
902
+ function callAll(...fns) {
903
+ return (...args) => fns.forEach((fn) => fn?.(...args));
904
+ }
905
+ function mergeRefs(...refs) {
906
+ return (value) => {
907
+ for (const ref of refs) {
908
+ if (typeof ref === "function") ref(value);
909
+ else if (ref) ref.current = value;
910
+ }
911
+ };
912
+ }
913
+ function getElementRef(element) {
914
+ const fromProps = element.props.ref;
915
+ if (Number.parseInt(import_react11.version, 10) >= 19) return fromProps;
916
+ return element.ref;
917
+ }
918
+
919
+ // src/components/dropdown-menu.tsx
920
+ var import_jsx_runtime14 = require("react/jsx-runtime");
921
+ var isAction = (item) => item !== "separator";
922
+ var textOf = (item) => (item.textValue ?? (typeof item.label === "string" ? item.label : "")).toLowerCase();
923
+ function DropdownMenu({ trigger, items: items2, align = "start", linkAs: LinkTag = "a", className }) {
924
+ const [open, setOpen] = (0, import_react12.useState)(false);
925
+ const triggerRef = (0, import_react12.useRef)(null);
926
+ const menuRef = (0, import_react12.useRef)(null);
927
+ const itemRefs = (0, import_react12.useRef)([]);
928
+ const generatedId = (0, import_react12.useId)();
929
+ const triggerId = trigger.props.id ?? `${generatedId}-trigger`;
930
+ const menuId = `${generatedId}-menu`;
931
+ const enabled = items2.map((item, i) => isAction(item) && !item.disabled ? i : -1).filter((i) => i >= 0);
932
+ const focusItem = (index) => index !== void 0 && itemRefs.current[index]?.focus();
933
+ const openMenu = (focus) => {
934
+ setOpen(true);
935
+ requestAnimationFrame(() => focusItem(focus === "first" ? enabled[0] : enabled[enabled.length - 1]));
936
+ };
937
+ const close = (returnFocus = true) => {
938
+ setOpen(false);
939
+ if (returnFocus) triggerRef.current?.focus();
940
+ };
941
+ useAnchoredPosition(open, triggerRef, menuRef, { side: "bottom", align });
942
+ useDismiss(open, [triggerRef, menuRef], (reason) => close(reason === "escape"));
943
+ const select = (item) => {
944
+ item.onSelect?.();
945
+ close();
946
+ };
947
+ const onMenuKeyDown = (e) => {
948
+ const current = itemRefs.current.findIndex((el) => el === document.activeElement);
949
+ const position = enabled.indexOf(current);
950
+ const move = (to) => {
951
+ e.preventDefault();
952
+ focusItem(enabled[(to + enabled.length) % enabled.length]);
953
+ };
954
+ if (e.key === "ArrowDown") move(position + 1);
955
+ else if (e.key === "ArrowUp") move(position - 1);
956
+ else if (e.key === "Home") move(0);
957
+ else if (e.key === "End") move(enabled.length - 1);
958
+ else if (e.key === "Tab") close(false);
959
+ else if (e.key.length === 1 && /\S/.test(e.key)) {
960
+ const letter = e.key.toLowerCase();
961
+ const order = [...enabled.slice(position + 1), ...enabled.slice(0, position + 1)];
962
+ const match = order.find((i) => textOf(items2[i]).startsWith(letter));
963
+ if (match !== void 0) focusItem(match);
964
+ }
965
+ };
966
+ const triggerElement = (0, import_react12.cloneElement)(trigger, {
967
+ ref: mergeRefs(triggerRef, getElementRef(trigger)),
968
+ id: triggerId,
969
+ "aria-haspopup": "menu",
970
+ "aria-expanded": open,
971
+ "aria-controls": open ? menuId : void 0,
972
+ onClick: callAll(trigger.props.onClick, () => open ? close() : openMenu("first")),
973
+ onKeyDown: callAll(trigger.props.onKeyDown, (e) => {
974
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
975
+ e.preventDefault();
976
+ openMenu(e.key === "ArrowDown" ? "first" : "last");
977
+ }
978
+ })
979
+ });
980
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
981
+ triggerElement,
982
+ open && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
983
+ "div",
984
+ {
985
+ ref: menuRef,
986
+ id: menuId,
987
+ role: "menu",
988
+ "aria-labelledby": triggerId,
989
+ className: cx("trc-floating", "trc-menu", className),
990
+ onKeyDown: onMenuKeyDown,
991
+ children: items2.map((item, i) => {
992
+ if (!isAction(item)) return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { role: "separator", className: "trc-menu__separator" }, i);
993
+ const shared = {
994
+ ref: (el) => {
995
+ itemRefs.current[i] = el;
996
+ },
997
+ role: "menuitem",
998
+ tabIndex: -1,
999
+ "aria-disabled": item.disabled || void 0,
1000
+ className: cx("trc-menu__item", item.danger && "trc-menu__item--danger"),
1001
+ onMouseMove: (e) => !item.disabled && e.currentTarget.focus(),
1002
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
1003
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "trc-menu__label", children: item.label }),
1004
+ item.hint != null && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "trc-menu__hint", children: item.hint })
1005
+ ] })
1006
+ };
1007
+ return item.href && !item.disabled ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(LinkTag, { href: item.href, ...shared, onClick: () => select(item) }, i) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1008
+ "div",
1009
+ {
1010
+ ...shared,
1011
+ onClick: () => !item.disabled && select(item),
1012
+ onKeyDown: (e) => {
1013
+ if ((e.key === "Enter" || e.key === " ") && !item.disabled) {
1014
+ e.preventDefault();
1015
+ select(item);
1016
+ }
1017
+ }
1018
+ },
1019
+ i
1020
+ );
1021
+ })
1022
+ }
1023
+ ) })
1024
+ ] });
1025
+ }
1026
+
1027
+ // src/components/popover.tsx
1028
+ var import_react13 = require("react");
1029
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1030
+ function Popover({
1031
+ trigger,
1032
+ title,
1033
+ label,
1034
+ children,
1035
+ side = "bottom",
1036
+ align = "start",
1037
+ open: controlled,
1038
+ onOpenChange,
1039
+ className
1040
+ }) {
1041
+ const [uncontrolled, setUncontrolled] = (0, import_react13.useState)(false);
1042
+ const open = controlled ?? uncontrolled;
1043
+ const setOpen = (value) => {
1044
+ if (controlled === void 0) setUncontrolled(value);
1045
+ onOpenChange?.(value);
1046
+ };
1047
+ const triggerRef = (0, import_react13.useRef)(null);
1048
+ const panelRef = (0, import_react13.useRef)(null);
1049
+ const id = (0, import_react13.useId)();
1050
+ useAnchoredPosition(open, triggerRef, panelRef, { side, align });
1051
+ useDismiss(open, [triggerRef, panelRef], (reason) => {
1052
+ setOpen(false);
1053
+ if (reason === "escape") triggerRef.current?.focus();
1054
+ });
1055
+ (0, import_react13.useEffect)(() => {
1056
+ if (!open) return;
1057
+ const panel = panelRef.current;
1058
+ const first = panel?.querySelector(
1059
+ "[data-autofocus], input, select, textarea, button, a[href], [tabindex]:not([tabindex='-1'])"
1060
+ );
1061
+ (first ?? panel)?.focus();
1062
+ }, [open]);
1063
+ const triggerElement = (0, import_react13.cloneElement)(trigger, {
1064
+ ref: mergeRefs(triggerRef, getElementRef(trigger)),
1065
+ "aria-haspopup": "dialog",
1066
+ "aria-expanded": open,
1067
+ "aria-controls": open ? `${id}-panel` : void 0,
1068
+ onClick: callAll(trigger.props.onClick, () => setOpen(!open))
1069
+ });
1070
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
1071
+ triggerElement,
1072
+ open && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1073
+ "div",
1074
+ {
1075
+ ref: panelRef,
1076
+ id: `${id}-panel`,
1077
+ role: "dialog",
1078
+ "aria-labelledby": title != null ? `${id}-title` : void 0,
1079
+ "aria-label": title == null ? label : void 0,
1080
+ tabIndex: -1,
1081
+ className: cx("trc-floating", "trc-popover", className),
1082
+ children: [
1083
+ title != null && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { id: `${id}-title`, className: "trc-popover__title", children: title }),
1084
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "trc-popover__body", children })
1085
+ ]
1086
+ }
1087
+ ) })
1088
+ ] });
1089
+ }
1090
+
1091
+ // src/components/tooltip.tsx
1092
+ var import_react14 = require("react");
1093
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1094
+ function Tooltip({ label, children, side = "top", delay: delay2 = 300, className }) {
1095
+ const [open, setOpen] = (0, import_react14.useState)(false);
1096
+ const anchorRef = (0, import_react14.useRef)(null);
1097
+ const tipRef = (0, import_react14.useRef)(null);
1098
+ const timer = (0, import_react14.useRef)(void 0);
1099
+ const id = (0, import_react14.useId)();
1100
+ const show = (wait) => {
1101
+ window.clearTimeout(timer.current);
1102
+ timer.current = window.setTimeout(() => setOpen(true), wait);
1103
+ };
1104
+ const hide = () => {
1105
+ window.clearTimeout(timer.current);
1106
+ timer.current = window.setTimeout(() => setOpen(false), 100);
1107
+ };
1108
+ (0, import_react14.useEffect)(() => () => window.clearTimeout(timer.current), []);
1109
+ (0, import_react14.useEffect)(() => {
1110
+ if (!open) return;
1111
+ const onKeyDown = (e) => e.key === "Escape" && setOpen(false);
1112
+ document.addEventListener("keydown", onKeyDown);
1113
+ return () => document.removeEventListener("keydown", onKeyDown);
1114
+ }, [open]);
1115
+ useAnchoredPosition(open, anchorRef, tipRef, { side, align: "center", offset: 8 });
1116
+ const child = (0, import_react14.cloneElement)(children, {
1117
+ ref: mergeRefs(anchorRef, getElementRef(children)),
1118
+ "aria-describedby": [children.props["aria-describedby"], id].filter(Boolean).join(" "),
1119
+ onMouseEnter: callAll(children.props.onMouseEnter, () => show(delay2)),
1120
+ onMouseLeave: callAll(children.props.onMouseLeave, hide),
1121
+ onFocus: callAll(children.props.onFocus, () => show(0)),
1122
+ onBlur: callAll(children.props.onBlur, () => {
1123
+ window.clearTimeout(timer.current);
1124
+ setOpen(false);
1125
+ })
1126
+ });
1127
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
1128
+ child,
1129
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1130
+ "div",
1131
+ {
1132
+ ref: tipRef,
1133
+ id,
1134
+ role: "tooltip",
1135
+ className: cx("trc-floating", "trc-tooltip", open && "trc-tooltip--open", className),
1136
+ onMouseEnter: () => window.clearTimeout(timer.current),
1137
+ onMouseLeave: hide,
1138
+ children: label
1139
+ }
1140
+ ) })
1141
+ ] });
1142
+ }
1143
+
1144
+ // src/components/toast.tsx
1145
+ var import_react15 = require("react");
1146
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1147
+ var items = [];
1148
+ var nextId = 1;
1149
+ var listeners = /* @__PURE__ */ new Set();
1150
+ var emit = () => listeners.forEach((listener) => listener());
1151
+ var subscribe = (listener) => {
1152
+ listeners.add(listener);
1153
+ return () => listeners.delete(listener);
1154
+ };
1155
+ var EMPTY = [];
1156
+ var LEAVE_MS = 200;
1157
+ function dismiss(id) {
1158
+ items = items.map((t) => id === void 0 || t.id === id ? { ...t, leaving: true } : t);
1159
+ emit();
1160
+ window.setTimeout(() => {
1161
+ items = items.filter((t) => !(t.leaving && (id === void 0 || t.id === id)));
1162
+ emit();
1163
+ }, LEAVE_MS);
1164
+ }
1165
+ function toast(title, options = {}) {
1166
+ const id = nextId++;
1167
+ items = [...items, { ...options, id, title, leaving: false }];
1168
+ emit();
1169
+ return id;
1170
+ }
1171
+ toast.success = (title, options = {}) => toast(title, { ...options, tone: "success" });
1172
+ toast.error = (title, options = {}) => toast(title, { ...options, tone: "error" });
1173
+ toast.dismiss = dismiss;
1174
+ function Toaster({
1175
+ position = "bottom-right",
1176
+ duration = 5e3,
1177
+ label = "Notifications",
1178
+ closeLabel = "Close"
1179
+ }) {
1180
+ const toasts = (0, import_react15.useSyncExternalStore)(
1181
+ subscribe,
1182
+ () => items,
1183
+ () => EMPTY
1184
+ );
1185
+ const [paused, setPaused] = (0, import_react15.useState)(false);
1186
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1187
+ "section",
1188
+ {
1189
+ "aria-label": label,
1190
+ className: cx("trc-toaster", `trc-toaster--${position}`),
1191
+ onMouseEnter: () => setPaused(true),
1192
+ onMouseLeave: () => setPaused(false),
1193
+ onFocus: () => setPaused(true),
1194
+ onBlur: (e) => !e.currentTarget.contains(e.relatedTarget) && setPaused(false),
1195
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("ol", { "aria-live": "polite", "aria-relevant": "additions", className: "trc-toaster__list", children: toasts.map((t) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ToastCard, { toast: t, duration: t.duration ?? duration, paused, closeLabel }, t.id)) })
1196
+ }
1197
+ ) });
1198
+ }
1199
+ function ToastCard({
1200
+ toast: t,
1201
+ duration,
1202
+ paused,
1203
+ closeLabel
1204
+ }) {
1205
+ const remaining = (0, import_react15.useRef)(duration);
1206
+ (0, import_react15.useEffect)(() => {
1207
+ if (paused || t.leaving || !Number.isFinite(remaining.current)) return;
1208
+ const started = Date.now();
1209
+ const timer = window.setTimeout(() => dismiss(t.id), remaining.current);
1210
+ return () => {
1211
+ window.clearTimeout(timer);
1212
+ remaining.current -= Date.now() - started;
1213
+ };
1214
+ }, [paused, t.leaving, t.id]);
1215
+ const tone = t.tone ?? "default";
1216
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("li", { className: cx("trc-toast", `trc-toast--${tone}`, t.leaving && "trc-toast--leaving"), children: [
1217
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "trc-toast__text", role: tone === "error" ? "alert" : void 0, children: [
1218
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "trc-toast__title", children: t.title }),
1219
+ t.description != null && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "trc-toast__description", children: t.description })
1220
+ ] }),
1221
+ t.action && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1222
+ "button",
1223
+ {
1224
+ type: "button",
1225
+ className: "trc-toast__action",
1226
+ onClick: () => {
1227
+ t.action?.onClick();
1228
+ dismiss(t.id);
1229
+ },
1230
+ children: t.action.label
1231
+ }
1232
+ ),
1233
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: "trc-toast__close", "aria-label": closeLabel, onClick: () => dismiss(t.id), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Close, {}) })
1234
+ ] });
1235
+ }
1236
+
1237
+ // src/components/alert.tsx
1238
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1239
+ function Alert({ title, tone = "info", actions, className, children, ...props }) {
1240
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: cx("trc-alert", `trc-alert--${tone}`, className), ...props, children: [
1241
+ title != null && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "trc-alert__title", children: title }),
1242
+ children != null && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "trc-alert__body", children }),
1243
+ actions != null && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "trc-alert__actions", children: actions })
1244
+ ] });
1245
+ }
1246
+
1247
+ // src/components/tabs.tsx
1248
+ var import_react17 = require("react");
1249
+
1250
+ // src/hooks/use-controllable.ts
1251
+ var import_react16 = require("react");
1252
+ function useControllable(value, defaultValue, onChange) {
1253
+ const [internal, setInternal] = (0, import_react16.useState)(defaultValue);
1254
+ const controlled = (0, import_react16.useRef)(value !== void 0).current;
1255
+ const current = controlled ? value : internal;
1256
+ const set = (next) => {
1257
+ if (!controlled) setInternal(next);
1258
+ onChange?.(next);
1259
+ };
1260
+ return [current, set];
1261
+ }
1262
+
1263
+ // src/components/tabs.tsx
1264
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1265
+ function Tabs({
1266
+ items: items2,
1267
+ value,
1268
+ defaultValue,
1269
+ onValueChange,
1270
+ label,
1271
+ activation = "automatic",
1272
+ className
1273
+ }) {
1274
+ const firstEnabled = items2.find((item) => !item.disabled)?.value ?? "";
1275
+ const [selected, setSelected] = useControllable(value, defaultValue ?? firstEnabled, onValueChange);
1276
+ const id = (0, import_react17.useId)();
1277
+ const tabRefs = (0, import_react17.useRef)([]);
1278
+ const enabled = items2.map((item, i) => item.disabled ? -1 : i).filter((i) => i >= 0);
1279
+ const onKeyDown = (e, index) => {
1280
+ const position = enabled.indexOf(index);
1281
+ let target;
1282
+ if (e.key === "ArrowRight") target = enabled[(position + 1) % enabled.length];
1283
+ else if (e.key === "ArrowLeft") target = enabled[(position - 1 + enabled.length) % enabled.length];
1284
+ else if (e.key === "Home") target = enabled[0];
1285
+ else if (e.key === "End") target = enabled[enabled.length - 1];
1286
+ if (target === void 0) return;
1287
+ e.preventDefault();
1288
+ tabRefs.current[target]?.focus();
1289
+ if (activation === "automatic") setSelected(items2[target].value);
1290
+ };
1291
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: cx("trc-tabs", className), children: [
1292
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "tablist", "aria-label": label, className: "trc-tabs__list", children: items2.map((item, i) => {
1293
+ const isSelected = item.value === selected;
1294
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1295
+ "button",
1296
+ {
1297
+ ref: (el) => {
1298
+ tabRefs.current[i] = el;
1299
+ },
1300
+ type: "button",
1301
+ role: "tab",
1302
+ id: `${id}-tab-${i}`,
1303
+ "aria-selected": isSelected,
1304
+ "aria-controls": `${id}-panel-${i}`,
1305
+ disabled: item.disabled,
1306
+ tabIndex: isSelected ? 0 : -1,
1307
+ className: "trc-tabs__tab",
1308
+ onClick: () => setSelected(item.value),
1309
+ onKeyDown: (e) => onKeyDown(e, i),
1310
+ children: item.label
1311
+ },
1312
+ item.value
1313
+ );
1314
+ }) }),
1315
+ items2.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1316
+ "div",
1317
+ {
1318
+ role: "tabpanel",
1319
+ id: `${id}-panel-${i}`,
1320
+ "aria-labelledby": `${id}-tab-${i}`,
1321
+ hidden: item.value !== selected,
1322
+ tabIndex: 0,
1323
+ className: "trc-tabs__panel",
1324
+ children: item.content
1325
+ },
1326
+ item.value
1327
+ ))
1328
+ ] });
1329
+ }
1330
+
1331
+ // src/components/segmented-control.tsx
1332
+ var import_react18 = require("react");
1333
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1334
+ function SegmentedControl({
1335
+ options,
1336
+ value,
1337
+ defaultValue,
1338
+ onValueChange,
1339
+ label,
1340
+ name,
1341
+ size: size2 = "md",
1342
+ className
1343
+ }) {
1344
+ const [selected, setSelected] = useControllable(value, defaultValue ?? options[0]?.value ?? "", onValueChange);
1345
+ const generated = (0, import_react18.useId)();
1346
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1347
+ "div",
1348
+ {
1349
+ role: "radiogroup",
1350
+ "aria-label": label,
1351
+ className: cx("trc-segmented", size2 === "sm" && "trc-segmented--sm", className),
1352
+ children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { className: "trc-segmented__option", children: [
1353
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1354
+ "input",
1355
+ {
1356
+ type: "radio",
1357
+ name: name ?? generated,
1358
+ value: option.value,
1359
+ checked: option.value === selected,
1360
+ disabled: option.disabled,
1361
+ onChange: () => setSelected(option.value),
1362
+ className: "trc-segmented__input"
1363
+ }
1364
+ ),
1365
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "trc-segmented__label", children: option.label })
1366
+ ] }, option.value))
1367
+ }
1368
+ );
1369
+ }
1370
+
1371
+ // src/components/accordion.tsx
1372
+ var import_react19 = require("react");
1373
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1374
+ function Accordion({
1375
+ items: items2,
1376
+ type = "single",
1377
+ value,
1378
+ defaultValue = [],
1379
+ onValueChange,
1380
+ headingLevel = 3,
1381
+ className
1382
+ }) {
1383
+ const [open, setOpen] = useControllable(value, defaultValue, onValueChange);
1384
+ const id = (0, import_react19.useId)();
1385
+ const buttons = (0, import_react19.useRef)([]);
1386
+ const Heading2 = `h${headingLevel}`;
1387
+ const enabled = items2.map((item, i) => item.disabled ? -1 : i).filter((i) => i >= 0);
1388
+ const toggle = (itemValue) => {
1389
+ const isOpen = open.includes(itemValue);
1390
+ if (type === "single") setOpen(isOpen ? [] : [itemValue]);
1391
+ else setOpen(isOpen ? open.filter((v) => v !== itemValue) : [...open, itemValue]);
1392
+ };
1393
+ const onKeyDown = (e, index) => {
1394
+ const position = enabled.indexOf(index);
1395
+ let target;
1396
+ if (e.key === "ArrowDown") target = enabled[(position + 1) % enabled.length];
1397
+ else if (e.key === "ArrowUp") target = enabled[(position - 1 + enabled.length) % enabled.length];
1398
+ else if (e.key === "Home") target = enabled[0];
1399
+ else if (e.key === "End") target = enabled[enabled.length - 1];
1400
+ if (target === void 0) return;
1401
+ e.preventDefault();
1402
+ buttons.current[target]?.focus();
1403
+ };
1404
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: cx("trc-accordion", className), children: items2.map((item, i) => {
1405
+ const isOpen = open.includes(item.value);
1406
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: cx("trc-accordion__item", isOpen && "trc-accordion__item--open"), children: [
1407
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Heading2, { className: "trc-accordion__heading", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
1408
+ "button",
1409
+ {
1410
+ ref: (el) => {
1411
+ buttons.current[i] = el;
1412
+ },
1413
+ type: "button",
1414
+ id: `${id}-trigger-${i}`,
1415
+ "aria-expanded": isOpen,
1416
+ "aria-controls": `${id}-panel-${i}`,
1417
+ disabled: item.disabled,
1418
+ className: "trc-accordion__trigger",
1419
+ onClick: () => toggle(item.value),
1420
+ onKeyDown: (e) => onKeyDown(e, i),
1421
+ children: [
1422
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: item.title }),
1423
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ChevronDown, { className: "trc-accordion__chevron" })
1424
+ ]
1425
+ }
1426
+ ) }),
1427
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1428
+ "div",
1429
+ {
1430
+ id: `${id}-panel-${i}`,
1431
+ role: "region",
1432
+ "aria-labelledby": `${id}-trigger-${i}`,
1433
+ className: "trc-accordion__panel",
1434
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "trc-accordion__inner", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "trc-accordion__content", children: item.content }) })
1435
+ }
1436
+ )
1437
+ ] }, item.value);
1438
+ }) });
1439
+ }
1440
+
1441
+ // src/components/steps.tsx
1442
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1443
+ function Steps({ items: items2, current, className }) {
1444
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ol", { className: cx("trc-steps", className), children: items2.map((item, i) => {
1445
+ const state = current === void 0 ? "default" : i < current ? "complete" : i === current ? "current" : "upcoming";
1446
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
1447
+ "li",
1448
+ {
1449
+ className: cx("trc-steps__item", `trc-steps__item--${state}`),
1450
+ "aria-current": state === "current" ? "step" : void 0,
1451
+ children: [
1452
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "aria-hidden": true, className: "trc-steps__number", children: String(i + 1).padStart(2, "0") }),
1453
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "trc-steps__text", children: [
1454
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "trc-steps__title", children: item.title }),
1455
+ item.description != null && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "trc-steps__description", children: item.description })
1456
+ ] })
1457
+ ]
1458
+ },
1459
+ i
1460
+ );
1461
+ }) });
1462
+ }
1463
+
1464
+ // src/components/breadcrumbs.tsx
1465
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1466
+ function Breadcrumbs({ items: items2, label = "Breadcrumb", linkAs: LinkTag = "a", className }) {
1467
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("nav", { "aria-label": label, className: cx("trc-breadcrumbs", className), children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("ol", { className: "trc-breadcrumbs__list", children: items2.map((item, i) => {
1468
+ const last = i === items2.length - 1;
1469
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("li", { className: "trc-breadcrumbs__item", children: [
1470
+ last || !item.href ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-current": last ? "page" : void 0, className: "trc-breadcrumbs__current", children: item.label }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LinkTag, { href: item.href, className: "trc-breadcrumbs__link", children: item.label }),
1471
+ !last && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": true, className: "trc-breadcrumbs__separator", children: "/" })
1472
+ ] }, i);
1473
+ }) }) });
1474
+ }
1475
+
1476
+ // src/utils/label.ts
1477
+ function fill(template, values) {
1478
+ return template.replace(/\{(\w+)\}/g, (match, key) => key in values ? String(values[key]) : match);
1479
+ }
1480
+
1481
+ // src/components/pagination.tsx
1482
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1483
+ function paginationRange(page, total, siblings = 1) {
1484
+ const slots = siblings * 2 + 5;
1485
+ if (total <= slots) return Array.from({ length: total }, (_, i) => i + 1);
1486
+ const range = (from, to) => Array.from({ length: to - from + 1 }, (_, i) => from + i);
1487
+ if (page <= siblings + 3) return [...range(1, slots - 2), "ellipsis", total];
1488
+ if (page >= total - siblings - 2) return [1, "ellipsis", ...range(total - slots + 3, total)];
1489
+ return [1, "ellipsis", ...range(page - siblings, page + siblings), "ellipsis", total];
1490
+ }
1491
+ function Pagination({
1492
+ page,
1493
+ total,
1494
+ onPageChange,
1495
+ href,
1496
+ siblings = 1,
1497
+ linkAs: LinkTag = "a",
1498
+ label = "Pagination",
1499
+ previousLabel = "Previous",
1500
+ nextLabel = "Next",
1501
+ pageLabel = "Page {page}",
1502
+ className
1503
+ }) {
1504
+ if (total <= 1) return null;
1505
+ const getHref = href === void 0 ? void 0 : typeof href === "string" ? (p) => href.replace("{page}", String(p)) : href;
1506
+ const control = (target, content, extra) => {
1507
+ const disabled = target < 1 || target > total;
1508
+ const common = {
1509
+ className: cx("trc-pagination__control", extra.className),
1510
+ "aria-label": extra.ariaLabel,
1511
+ "aria-current": extra.current ? "page" : void 0
1512
+ };
1513
+ if (getHref) {
1514
+ return disabled ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { ...common, "aria-disabled": "true", children: content }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(LinkTag, { href: getHref(target), ...common, children: content });
1515
+ }
1516
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", ...common, disabled, onClick: () => !extra.current && onPageChange?.(target), children: content });
1517
+ };
1518
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("nav", { "aria-label": label, className: cx("trc-pagination", className), children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("ul", { className: "trc-pagination__list", children: [
1519
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { children: control(page - 1, /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ArrowLeft, {}), { className: "trc-pagination__step", ariaLabel: previousLabel }) }),
1520
+ paginationRange(page, total, siblings).map(
1521
+ (entry, i) => entry === "ellipsis" ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { "aria-hidden": true, className: "trc-pagination__ellipsis", children: "\u2026" }, `e${i}`) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { children: control(entry, entry, {
1522
+ className: "trc-pagination__page",
1523
+ ariaLabel: typeof pageLabel === "string" ? fill(pageLabel, { page: entry }) : pageLabel(entry),
1524
+ current: entry === page
1525
+ }) }, entry)
1526
+ ),
1527
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { children: control(page + 1, /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ArrowRight, {}), { className: "trc-pagination__step", ariaLabel: nextLabel }) })
1528
+ ] }) });
1529
+ }
1530
+
1531
+ // src/components/language-switcher.tsx
1532
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1533
+ function LanguageSwitcher({
1534
+ languages,
1535
+ value,
1536
+ onChange,
1537
+ label = "Language",
1538
+ linkAs: LinkTag = "a",
1539
+ className
1540
+ }) {
1541
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("nav", { "aria-label": label, className: cx("trc-languages", className), children: languages.map((language) => {
1542
+ const common = {
1543
+ lang: language.code,
1544
+ "aria-label": language.name,
1545
+ "aria-current": language.code === value ? "true" : void 0,
1546
+ className: "trc-languages__item",
1547
+ children: language.code.toUpperCase()
1548
+ };
1549
+ return language.href ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LinkTag, { href: language.href, hrefLang: language.code, ...common }, language.code) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { type: "button", onClick: () => onChange?.(language.code), ...common }, language.code);
1550
+ }) });
1551
+ }
1552
+
1553
+ // src/components/radio-group.tsx
1554
+ var import_react20 = require("react");
1555
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1556
+ function RadioGroup({
1557
+ label,
1558
+ options,
1559
+ value,
1560
+ defaultValue,
1561
+ onValueChange,
1562
+ name,
1563
+ hint,
1564
+ error,
1565
+ required = false,
1566
+ orientation = "vertical",
1567
+ className
1568
+ }) {
1569
+ const [selected, setSelected] = useControllable(
1570
+ value,
1571
+ defaultValue,
1572
+ (v) => v && onValueChange?.(v)
1573
+ );
1574
+ const id = (0, import_react20.useId)();
1575
+ const message = error ?? hint;
1576
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1577
+ "fieldset",
1578
+ {
1579
+ className: cx("trc-radio-group", className),
1580
+ "aria-describedby": message != null ? `${id}-message` : void 0,
1581
+ "aria-invalid": error != null || void 0,
1582
+ "aria-required": required || void 0,
1583
+ children: [
1584
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("legend", { className: "trc-field__label", children: [
1585
+ label,
1586
+ required && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { "aria-hidden": true, className: "trc-field__required", children: [
1587
+ " ",
1588
+ "*"
1589
+ ] })
1590
+ ] }),
1591
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: cx("trc-radio-group__options", orientation === "horizontal" && "trc-radio-group__options--row"), children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("label", { className: "trc-toggle trc-toggle--radio", children: [
1592
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "trc-radio", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1593
+ "input",
1594
+ {
1595
+ type: "radio",
1596
+ name: name ?? id,
1597
+ value: option.value,
1598
+ checked: selected === option.value,
1599
+ disabled: option.disabled,
1600
+ required,
1601
+ onChange: () => setSelected(option.value),
1602
+ className: "trc-radio__input"
1603
+ }
1604
+ ) }),
1605
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "trc-toggle__text", children: [
1606
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "trc-toggle__label", children: option.label }),
1607
+ option.description != null && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "trc-toggle__description", children: option.description })
1608
+ ] })
1609
+ ] }, option.value)) }),
1610
+ message != null && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { id: `${id}-message`, className: cx("trc-field__message", error != null && "trc-field__message--error"), children: message })
1611
+ ]
1612
+ }
1613
+ );
1614
+ }
1615
+
1616
+ // src/components/password-input.tsx
1617
+ var import_react21 = require("react");
1618
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1619
+ var PasswordInput = (0, import_react21.forwardRef)(function PasswordInput2({ showLabel = "Show", hideLabel = "Hide", noun = "password", className, autoComplete = "current-password", ...props }, ref) {
1620
+ const [visible, setVisible] = (0, import_react21.useState)(false);
1621
+ const { id } = useFieldProps(props);
1622
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: cx("trc-password", className), children: [
1623
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Input, { ref, ...props, id, type: visible ? "text" : "password", autoComplete }),
1624
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("button", { type: "button", className: "trc-password__toggle", "aria-controls": id, onClick: () => setVisible((v) => !v), children: [
1625
+ visible ? hideLabel : showLabel,
1626
+ " ",
1627
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "trc-visually-hidden", children: noun })
1628
+ ] })
1629
+ ] });
1630
+ });
1631
+
1632
+ // src/components/pin-input.tsx
1633
+ var import_react22 = require("react");
1634
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1635
+ function PinInput({
1636
+ length = 6,
1637
+ value,
1638
+ defaultValue = "",
1639
+ onChange,
1640
+ onComplete,
1641
+ type = "numeric",
1642
+ mask = false,
1643
+ label = "Verification code",
1644
+ charLabel = "Character {index} of {length}",
1645
+ invalid,
1646
+ disabled,
1647
+ id,
1648
+ name,
1649
+ className
1650
+ }) {
1651
+ const [code, setCode] = useControllable(value, defaultValue, onChange);
1652
+ const inputs = (0, import_react22.useRef)([]);
1653
+ const field = useFieldProps({ id, invalid });
1654
+ const accepted = type === "numeric" ? /[0-9]/ : /[0-9a-z]/i;
1655
+ const clean = (text) => [...text].filter((c) => accepted.test(c)).join("");
1656
+ const update = (next) => {
1657
+ const trimmed = next.slice(0, length);
1658
+ setCode(trimmed);
1659
+ if (trimmed.length === length && !trimmed.includes(" ")) onComplete?.(trimmed);
1660
+ };
1661
+ const focus = (index) => {
1662
+ const target = inputs.current[Math.max(0, Math.min(index, length - 1))];
1663
+ target?.focus();
1664
+ target?.select();
1665
+ };
1666
+ const charAt = (i) => code[i] && code[i] !== " " ? code[i] : "";
1667
+ const setCharAt = (i, char) => {
1668
+ const chars = Array.from({ length }, (_, k) => code[k] ?? " ");
1669
+ chars[i] = char || " ";
1670
+ return chars.join("").replace(/\s+$/, "");
1671
+ };
1672
+ const onInput = (i, raw) => {
1673
+ const typed = clean(raw);
1674
+ if (!typed) return;
1675
+ if (typed.length > 1) {
1676
+ const merged = (code.slice(0, i).padEnd(i, " ") + typed).slice(0, length);
1677
+ update(merged);
1678
+ focus(Math.min(i + typed.length, length - 1));
1679
+ return;
1680
+ }
1681
+ update(setCharAt(i, typed.slice(-1)));
1682
+ focus(i + 1);
1683
+ };
1684
+ const onKeyDown = (i, e) => {
1685
+ if (e.key === "Backspace") {
1686
+ e.preventDefault();
1687
+ if (charAt(i)) update(setCharAt(i, ""));
1688
+ else if (i > 0) {
1689
+ update(setCharAt(i - 1, ""));
1690
+ focus(i - 1);
1691
+ }
1692
+ } else if (e.key === "ArrowLeft") {
1693
+ e.preventDefault();
1694
+ focus(i - 1);
1695
+ } else if (e.key === "ArrowRight") {
1696
+ e.preventDefault();
1697
+ focus(i + 1);
1698
+ } else if (e.key === "Home") {
1699
+ e.preventDefault();
1700
+ focus(0);
1701
+ } else if (e.key === "End") {
1702
+ e.preventDefault();
1703
+ focus(length - 1);
1704
+ }
1705
+ };
1706
+ const onPaste = (i, e) => {
1707
+ e.preventDefault();
1708
+ onInput(i, e.clipboardData.getData("text"));
1709
+ };
1710
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
1711
+ "div",
1712
+ {
1713
+ role: "group",
1714
+ "aria-label": label,
1715
+ "aria-describedby": field["aria-describedby"],
1716
+ className: cx("trc-pin", className),
1717
+ children: [
1718
+ Array.from({ length }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1719
+ "input",
1720
+ {
1721
+ ref: (el) => {
1722
+ inputs.current[i] = el;
1723
+ },
1724
+ id: i === 0 ? field.id : void 0,
1725
+ type: mask ? "password" : "text",
1726
+ inputMode: type === "numeric" ? "numeric" : "text",
1727
+ autoComplete: i === 0 ? "one-time-code" : "off",
1728
+ maxLength: length,
1729
+ "aria-label": typeof charLabel === "string" ? fill(charLabel, { index: i + 1, length }) : charLabel(i, length),
1730
+ "aria-invalid": field["aria-invalid"],
1731
+ disabled,
1732
+ value: charAt(i),
1733
+ onChange: (e) => onInput(i, e.target.value.replace(charAt(i), "") || e.target.value),
1734
+ onKeyDown: (e) => onKeyDown(i, e),
1735
+ onPaste: (e) => onPaste(i, e),
1736
+ onFocus: (e) => e.target.select(),
1737
+ className: "trc-control trc-pin__box"
1738
+ },
1739
+ i
1740
+ )),
1741
+ name && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("input", { type: "hidden", name, value: code.replace(/\s/g, "") })
1742
+ ]
1743
+ }
1744
+ );
1745
+ }
1746
+
1747
+ // src/components/combobox.tsx
1748
+ var import_react23 = require("react");
1749
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1750
+ var normalize = (text) => text.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase();
1751
+ function Combobox({
1752
+ options,
1753
+ value,
1754
+ defaultValue = null,
1755
+ onValueChange,
1756
+ placeholder,
1757
+ emptyText = "No results",
1758
+ invalid,
1759
+ disabled,
1760
+ required,
1761
+ id,
1762
+ name,
1763
+ className
1764
+ }) {
1765
+ const [selected, setSelected] = useControllable(value, defaultValue, onValueChange);
1766
+ const selectedOption = options.find((o) => o.value === selected) ?? null;
1767
+ const [query, setQuery] = (0, import_react23.useState)(selectedOption?.label ?? "");
1768
+ const [open, setOpen] = (0, import_react23.useState)(false);
1769
+ const [active, setActive] = (0, import_react23.useState)(-1);
1770
+ const wrapperRef = (0, import_react23.useRef)(null);
1771
+ const inputRef = (0, import_react23.useRef)(null);
1772
+ const listRef = (0, import_react23.useRef)(null);
1773
+ const listId = (0, import_react23.useId)();
1774
+ const a11y = useFieldProps({ id, invalid, required });
1775
+ const searching = query !== (selectedOption?.label ?? "");
1776
+ const visible = searching ? options.filter((o) => normalize(o.label).includes(normalize(query))) : options;
1777
+ const enabled = visible.map((o, i) => o.disabled ? -1 : i).filter((i) => i >= 0);
1778
+ (0, import_react23.useEffect)(() => {
1779
+ if (!open) setQuery(selectedOption?.label ?? "");
1780
+ }, [selectedOption?.label, open]);
1781
+ useAnchoredPosition(open, wrapperRef, listRef, { side: "bottom", align: "start", offset: 6 });
1782
+ useIsomorphicLayoutEffect(() => {
1783
+ if (open && listRef.current && wrapperRef.current)
1784
+ listRef.current.style.width = `${wrapperRef.current.offsetWidth}px`;
1785
+ }, [open]);
1786
+ useDismiss(open, [wrapperRef, listRef], () => close());
1787
+ (0, import_react23.useEffect)(() => {
1788
+ if (open && active >= 0)
1789
+ listRef.current?.querySelector(`[data-index="${active}"]`)?.scrollIntoView({ block: "nearest" });
1790
+ }, [open, active]);
1791
+ const openList = (index) => {
1792
+ setOpen(true);
1793
+ const current = visible.findIndex((o) => o.value === selected);
1794
+ setActive(index ?? (current >= 0 ? current : enabled[0] ?? -1));
1795
+ };
1796
+ const close = () => {
1797
+ setOpen(false);
1798
+ setActive(-1);
1799
+ setQuery(selectedOption?.label ?? "");
1800
+ };
1801
+ const choose = (option) => {
1802
+ if (option.disabled) return;
1803
+ setSelected(option.value);
1804
+ setQuery(option.label);
1805
+ setOpen(false);
1806
+ setActive(-1);
1807
+ };
1808
+ const onKeyDown = (e) => {
1809
+ const position = enabled.indexOf(active);
1810
+ if (e.key === "ArrowDown") {
1811
+ e.preventDefault();
1812
+ if (!open) openList();
1813
+ else setActive(enabled[(position + 1) % enabled.length] ?? -1);
1814
+ } else if (e.key === "ArrowUp") {
1815
+ e.preventDefault();
1816
+ if (!open) openList(enabled[enabled.length - 1]);
1817
+ else setActive(enabled[(position - 1 + enabled.length) % enabled.length] ?? -1);
1818
+ } else if (e.key === "Enter" && open) {
1819
+ e.preventDefault();
1820
+ const option = visible[active];
1821
+ if (option) choose(option);
1822
+ } else if (e.key === "Escape") {
1823
+ if (open) {
1824
+ e.preventDefault();
1825
+ close();
1826
+ } else if (query) {
1827
+ setQuery(selectedOption?.label ?? "");
1828
+ }
1829
+ } else if (e.key === "Tab" && open) {
1830
+ close();
1831
+ }
1832
+ };
1833
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { ref: wrapperRef, className: cx("trc-combobox", className), children: [
1834
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1835
+ "input",
1836
+ {
1837
+ ref: inputRef,
1838
+ type: "text",
1839
+ role: "combobox",
1840
+ "aria-expanded": open,
1841
+ "aria-controls": listId,
1842
+ "aria-autocomplete": "list",
1843
+ "aria-activedescendant": open && active >= 0 ? `${listId}-${active}` : void 0,
1844
+ autoComplete: "off",
1845
+ placeholder,
1846
+ disabled,
1847
+ value: query,
1848
+ onChange: (e) => {
1849
+ setQuery(e.target.value);
1850
+ setOpen(true);
1851
+ setActive(0);
1852
+ },
1853
+ onClick: () => open ? close() : openList(),
1854
+ onKeyDown,
1855
+ className: "trc-control trc-combobox__input",
1856
+ ...a11y
1857
+ }
1858
+ ),
1859
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ChevronDown, { "aria-hidden": true, className: "trc-combobox__chevron" }),
1860
+ name && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("input", { type: "hidden", name, value: selected ?? "" }),
1861
+ open && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("ul", { ref: listRef, id: listId, role: "listbox", className: "trc-floating trc-listbox", children: [
1862
+ visible.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("li", { role: "presentation", className: "trc-listbox__empty", children: emptyText }),
1863
+ visible.map((option, i) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1864
+ "li",
1865
+ {
1866
+ id: `${listId}-${i}`,
1867
+ "data-index": i,
1868
+ role: "option",
1869
+ "aria-selected": option.value === selected,
1870
+ "aria-disabled": option.disabled || void 0,
1871
+ className: cx("trc-listbox__option", i === active && "trc-listbox__option--active"),
1872
+ onMouseDown: (e) => e.preventDefault(),
1873
+ onMouseMove: () => !option.disabled && setActive(i),
1874
+ onClick: () => choose(option),
1875
+ children: [
1876
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "trc-listbox__label", children: option.label }),
1877
+ option.description != null && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "trc-listbox__description", children: option.description })
1878
+ ]
1879
+ },
1880
+ option.value
1881
+ ))
1882
+ ] }) })
1883
+ ] });
1884
+ }
1885
+
1886
+ // src/components/file-input.tsx
1887
+ var import_react24 = require("react");
1888
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1889
+ function formatBytes(bytes) {
1890
+ if (bytes < 1024) return `${bytes} B`;
1891
+ const units = ["KB", "MB", "GB"];
1892
+ let value = bytes / 1024;
1893
+ let unit = 0;
1894
+ while (value >= 1024 && unit < units.length - 1) {
1895
+ value /= 1024;
1896
+ unit++;
1897
+ }
1898
+ return `${value < 10 ? value.toFixed(1) : Math.round(value)} ${units[unit]}`;
1899
+ }
1900
+ function acceptsFile(file, accept) {
1901
+ if (!accept) return true;
1902
+ const name = file.name.toLowerCase();
1903
+ const type = file.type.toLowerCase();
1904
+ return accept.split(",").map((rule) => rule.trim().toLowerCase()).filter(Boolean).some(
1905
+ (rule) => rule.startsWith(".") ? name.endsWith(rule) : rule.endsWith("/*") ? type.startsWith(rule.slice(0, -1)) : type === rule
1906
+ );
1907
+ }
1908
+ function validateFiles(files, { accept, maxSize, maxFiles }, alreadyAccepted = 0) {
1909
+ const accepted = [];
1910
+ const rejected = [];
1911
+ for (const file of files) {
1912
+ if (!acceptsFile(file, accept)) rejected.push({ file, reason: "type" });
1913
+ else if (maxSize !== void 0 && file.size > maxSize) rejected.push({ file, reason: "size" });
1914
+ else if (maxFiles !== void 0 && alreadyAccepted + accepted.length >= maxFiles)
1915
+ rejected.push({ file, reason: "count" });
1916
+ else accepted.push(file);
1917
+ }
1918
+ return { accepted, rejected };
1919
+ }
1920
+ var FileInput = (0, import_react24.forwardRef)(function FileInput2({
1921
+ onFilesChange,
1922
+ buttonLabel = "Choose a file",
1923
+ placeholder = "No file chosen",
1924
+ countLabel = "{count} files",
1925
+ disabled,
1926
+ invalid,
1927
+ className,
1928
+ ...props
1929
+ }, ref) {
1930
+ const [files, setFiles] = (0, import_react24.useState)([]);
1931
+ const a11y = useFieldProps({ ...props, invalid });
1932
+ const summary = files.length === 0 ? placeholder : files.length === 1 ? files[0].name : typeof countLabel === "string" ? fill(countLabel, { count: files.length }) : countLabel(files.length);
1933
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("label", { className: cx("trc-file-input", disabled && "trc-file-input--disabled", className), children: [
1934
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1935
+ "input",
1936
+ {
1937
+ ref,
1938
+ ...props,
1939
+ ...a11y,
1940
+ type: "file",
1941
+ disabled,
1942
+ className: "trc-visually-hidden",
1943
+ onChange: (e) => {
1944
+ const chosen = [...e.target.files ?? []];
1945
+ setFiles(chosen);
1946
+ onFilesChange?.(chosen);
1947
+ }
1948
+ }
1949
+ ),
1950
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { "aria-hidden": true, className: "trc-file-input__button", children: buttonLabel }),
1951
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: cx("trc-file-input__name", files.length === 0 && "trc-file-input__name--empty"), children: summary })
1952
+ ] });
1953
+ });
1954
+ var DEFAULT_REJECTIONS = {
1955
+ type: "{name}: this type of file is not accepted",
1956
+ size: "{name}: the file is too large",
1957
+ count: "{name}: too many files"
1958
+ };
1959
+ function Dropzone({
1960
+ accept,
1961
+ maxSize,
1962
+ maxFiles,
1963
+ multiple = true,
1964
+ onFilesChange,
1965
+ title = "Drop files here or",
1966
+ browseLabel = "browse",
1967
+ hint,
1968
+ removeLabel = "Remove {name}",
1969
+ rejectionLabel = DEFAULT_REJECTIONS,
1970
+ name,
1971
+ disabled,
1972
+ id,
1973
+ className
1974
+ }) {
1975
+ const [files, setFiles] = (0, import_react24.useState)([]);
1976
+ const [rejections, setRejections] = (0, import_react24.useState)([]);
1977
+ const rejectionText = (rejection) => typeof rejectionLabel === "function" ? rejectionLabel(rejection) : fill(rejectionLabel[rejection.reason] ?? DEFAULT_REJECTIONS[rejection.reason], { name: rejection.file.name });
1978
+ const [dragging, setDragging] = (0, import_react24.useState)(false);
1979
+ const hintId = (0, import_react24.useId)();
1980
+ const a11y = useFieldProps({ id });
1981
+ const add = (incoming) => {
1982
+ const base2 = multiple ? files : [];
1983
+ const { accepted, rejected } = validateFiles(
1984
+ multiple ? incoming : incoming.slice(0, 1),
1985
+ { accept, maxSize, maxFiles },
1986
+ base2.length
1987
+ );
1988
+ const next = [...base2, ...accepted];
1989
+ setFiles(next);
1990
+ setRejections(rejected);
1991
+ onFilesChange?.(next);
1992
+ };
1993
+ const remove = (index) => {
1994
+ const next = files.filter((_, i) => i !== index);
1995
+ setFiles(next);
1996
+ setRejections([]);
1997
+ onFilesChange?.(next);
1998
+ };
1999
+ const onDrop = (e) => {
2000
+ e.preventDefault();
2001
+ setDragging(false);
2002
+ if (!disabled) add([...e.dataTransfer.files]);
2003
+ };
2004
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: cx("trc-dropzone", className), children: [
2005
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
2006
+ "label",
2007
+ {
2008
+ className: cx(
2009
+ "trc-dropzone__area",
2010
+ dragging && "trc-dropzone__area--dragging",
2011
+ disabled && "trc-dropzone__area--disabled"
2012
+ ),
2013
+ onDragEnter: (e) => {
2014
+ e.preventDefault();
2015
+ if (!disabled) setDragging(true);
2016
+ },
2017
+ onDragOver: (e) => e.preventDefault(),
2018
+ onDragLeave: (e) => {
2019
+ if (!e.currentTarget.contains(e.relatedTarget)) setDragging(false);
2020
+ },
2021
+ onDrop,
2022
+ children: [
2023
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
2024
+ "input",
2025
+ {
2026
+ type: "file",
2027
+ accept,
2028
+ multiple,
2029
+ name,
2030
+ disabled,
2031
+ className: "trc-visually-hidden",
2032
+ onChange: (e) => {
2033
+ add([...e.target.files ?? []]);
2034
+ e.target.value = "";
2035
+ },
2036
+ ...a11y,
2037
+ "aria-describedby": cx(a11y["aria-describedby"], hint != null && hintId) || void 0
2038
+ }
2039
+ ),
2040
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "trc-dropzone__title", children: [
2041
+ title,
2042
+ " ",
2043
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "trc-dropzone__browse", children: browseLabel })
2044
+ ] }),
2045
+ hint != null && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { id: hintId, "aria-hidden": true, className: "trc-dropzone__hint", children: hint })
2046
+ ]
2047
+ }
2048
+ ),
2049
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { "aria-live": "polite", children: rejections.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("ul", { className: "trc-dropzone__rejections", children: rejections.map((rejection, i) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("li", { children: rejectionText(rejection) }, i)) }) }),
2050
+ files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("ul", { className: "trc-dropzone__files", children: files.map((file, i) => /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("li", { className: "trc-dropzone__file", children: [
2051
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "trc-dropzone__file-name", children: file.name }),
2052
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "trc-dropzone__file-size", children: formatBytes(file.size) }),
2053
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
2054
+ "button",
2055
+ {
2056
+ type: "button",
2057
+ className: "trc-dropzone__remove",
2058
+ "aria-label": typeof removeLabel === "string" ? fill(removeLabel, { name: file.name }) : removeLabel(file),
2059
+ onClick: () => remove(i),
2060
+ children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Close, {})
2061
+ }
2062
+ )
2063
+ ] }, `${file.name}-${i}`)) })
2064
+ ] });
2065
+ }
2066
+
2067
+ // src/components/slider.tsx
2068
+ var import_react25 = require("react");
2069
+ var import_jsx_runtime31 = require("react/jsx-runtime");
2070
+ var Slider = (0, import_react25.forwardRef)(function Slider2({
2071
+ value,
2072
+ defaultValue,
2073
+ onValueChange,
2074
+ min = 0,
2075
+ max = 100,
2076
+ step = 1,
2077
+ showValue = false,
2078
+ formatValue = (v) => v,
2079
+ invalid,
2080
+ className,
2081
+ style,
2082
+ ...props
2083
+ }, ref) {
2084
+ const [current, setCurrent] = useControllable(value, defaultValue ?? min, onValueChange);
2085
+ const a11y = useFieldProps({ ...props, invalid });
2086
+ const progress = max > min ? (current - min) / (max - min) * 100 : 0;
2087
+ const formatted = formatValue(current);
2088
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: cx("trc-slider", className), children: [
2089
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2090
+ "input",
2091
+ {
2092
+ ref,
2093
+ ...props,
2094
+ ...a11y,
2095
+ type: "range",
2096
+ min,
2097
+ max,
2098
+ step,
2099
+ value: current,
2100
+ "aria-valuetext": typeof formatted === "string" ? formatted : void 0,
2101
+ onChange: (e) => setCurrent(Number(e.target.value)),
2102
+ className: "trc-slider__input",
2103
+ style: { ...style, "--trc-slider-progress": `${progress}%` }
2104
+ }
2105
+ ),
2106
+ showValue && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("output", { htmlFor: a11y.id, className: "trc-slider__value", "aria-hidden": true, children: formatted })
2107
+ ] });
2108
+ });
2109
+
2110
+ // src/components/date-picker.tsx
2111
+ var import_react26 = require("react");
2112
+
2113
+ // src/utils/dates.ts
2114
+ var startOfDay = (date) => new Date(date.getFullYear(), date.getMonth(), date.getDate());
2115
+ var addDays = (date, days) => new Date(date.getFullYear(), date.getMonth(), date.getDate() + days);
2116
+ function addMonths(date, months) {
2117
+ const target = new Date(date.getFullYear(), date.getMonth() + months, 1);
2118
+ const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();
2119
+ return new Date(target.getFullYear(), target.getMonth(), Math.min(date.getDate(), lastDay));
2120
+ }
2121
+ var sameDay = (a, b) => !!a && !!b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
2122
+ var toISODate = (date) => `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
2123
+ function gridStart(month, weekStartsOn) {
2124
+ const first = new Date(month.getFullYear(), month.getMonth(), 1);
2125
+ const offset = (first.getDay() - weekStartsOn + 7) % 7;
2126
+ return addDays(first, -offset);
2127
+ }
2128
+ var isBefore = (a, b) => startOfDay(a).getTime() < startOfDay(b).getTime();
2129
+
2130
+ // src/components/date-picker.tsx
2131
+ var import_jsx_runtime32 = require("react/jsx-runtime");
2132
+ function DatePicker({
2133
+ value,
2134
+ defaultValue = null,
2135
+ onValueChange,
2136
+ min,
2137
+ max,
2138
+ locale,
2139
+ weekStartsOn = 1,
2140
+ placeholder = "Choose a date",
2141
+ formatDate,
2142
+ name,
2143
+ label = "Choose a date",
2144
+ previousMonthLabel = "Previous month",
2145
+ nextMonthLabel = "Next month",
2146
+ invalid,
2147
+ disabled,
2148
+ required,
2149
+ id,
2150
+ className
2151
+ }) {
2152
+ const [selected, setSelected] = useControllable(value, defaultValue, onValueChange);
2153
+ const [open, setOpen] = (0, import_react26.useState)(false);
2154
+ const [focused, setFocused] = (0, import_react26.useState)(() => startOfDay(selected ?? /* @__PURE__ */ new Date()));
2155
+ const triggerRef = (0, import_react26.useRef)(null);
2156
+ const panelRef = (0, import_react26.useRef)(null);
2157
+ const uid = (0, import_react26.useId)();
2158
+ const a11y = useFieldProps({ id, invalid, required });
2159
+ const display = new Intl.DateTimeFormat(locale, { dateStyle: "medium" });
2160
+ const full = new Intl.DateTimeFormat(locale, { dateStyle: "full" });
2161
+ const monthTitle = new Intl.DateTimeFormat(locale, { month: "long", year: "numeric" });
2162
+ const weekdayShort = new Intl.DateTimeFormat(locale, { weekday: "short" });
2163
+ const weekdayLong = new Intl.DateTimeFormat(locale, { weekday: "long" });
2164
+ const format = formatDate ?? ((d) => display.format(d));
2165
+ const outOfRange = (date) => !!min && isBefore(date, min) || !!max && isBefore(max, date);
2166
+ const clamp = (date) => min && isBefore(date, min) ? startOfDay(min) : max && isBefore(max, date) ? startOfDay(max) : date;
2167
+ const openCalendar = () => {
2168
+ setFocused(clamp(startOfDay(selected ?? /* @__PURE__ */ new Date())));
2169
+ setOpen(true);
2170
+ };
2171
+ const close = (returnFocus = true) => {
2172
+ setOpen(false);
2173
+ if (returnFocus) triggerRef.current?.focus();
2174
+ };
2175
+ const choose = (date) => {
2176
+ if (outOfRange(date)) return;
2177
+ setSelected(date);
2178
+ close();
2179
+ };
2180
+ useAnchoredPosition(open, triggerRef, panelRef, { side: "bottom", align: "start" });
2181
+ useDismiss(open, [triggerRef, panelRef], (reason) => close(reason === "escape"));
2182
+ (0, import_react26.useEffect)(() => {
2183
+ if (open) panelRef.current?.querySelector(`[data-date="${toISODate(focused)}"]`)?.focus();
2184
+ }, [open, focused]);
2185
+ const onGridKeyDown = (e) => {
2186
+ const moves = {
2187
+ ArrowLeft: () => addDays(focused, -1),
2188
+ ArrowRight: () => addDays(focused, 1),
2189
+ ArrowUp: () => addDays(focused, -7),
2190
+ ArrowDown: () => addDays(focused, 7),
2191
+ Home: () => addDays(focused, -((focused.getDay() - weekStartsOn + 7) % 7)),
2192
+ End: () => addDays(focused, 6 - (focused.getDay() - weekStartsOn + 7) % 7),
2193
+ PageUp: () => addMonths(focused, e.shiftKey ? -12 : -1),
2194
+ PageDown: () => addMonths(focused, e.shiftKey ? 12 : 1)
2195
+ };
2196
+ const move = moves[e.key];
2197
+ if (move) {
2198
+ e.preventDefault();
2199
+ setFocused(clamp(move()));
2200
+ }
2201
+ };
2202
+ const onPanelKeyDown = (e) => {
2203
+ if (e.key !== "Tab") return;
2204
+ const items2 = [
2205
+ ...panelRef.current?.querySelectorAll("button:not([disabled]):not([tabindex='-1'])") ?? []
2206
+ ];
2207
+ const first = items2[0];
2208
+ const last = items2[items2.length - 1];
2209
+ if (e.shiftKey && document.activeElement === first) {
2210
+ e.preventDefault();
2211
+ last?.focus();
2212
+ } else if (!e.shiftKey && document.activeElement === last) {
2213
+ e.preventDefault();
2214
+ first?.focus();
2215
+ }
2216
+ };
2217
+ const start = gridStart(focused, weekStartsOn);
2218
+ const days = Array.from({ length: 42 }, (_, i) => addDays(start, i));
2219
+ const weeks = Array.from({ length: 6 }, (_, w) => days.slice(w * 7, w * 7 + 7));
2220
+ const today = startOfDay(/* @__PURE__ */ new Date());
2221
+ const valueId = `${uid}-value`;
2222
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: cx("trc-date-picker", className), children: [
2223
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
2224
+ "button",
2225
+ {
2226
+ ref: triggerRef,
2227
+ type: "button",
2228
+ id: a11y.id,
2229
+ "aria-haspopup": "dialog",
2230
+ "aria-expanded": open,
2231
+ "aria-invalid": a11y["aria-invalid"],
2232
+ "aria-describedby": cx(valueId, a11y["aria-describedby"]) || void 0,
2233
+ disabled,
2234
+ onClick: () => open ? close() : openCalendar(),
2235
+ className: cx("trc-control", "trc-date-picker__trigger", !selected && "trc-date-picker__trigger--empty"),
2236
+ children: [
2237
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { id: valueId, children: selected ? format(selected) : placeholder }),
2238
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Calendar, { className: "trc-date-picker__icon" })
2239
+ ]
2240
+ }
2241
+ ),
2242
+ name && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("input", { type: "hidden", name, value: selected ? toISODate(selected) : "", required }),
2243
+ open && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
2244
+ "div",
2245
+ {
2246
+ ref: panelRef,
2247
+ role: "dialog",
2248
+ "aria-modal": "true",
2249
+ "aria-label": label,
2250
+ className: "trc-floating trc-calendar",
2251
+ onKeyDown: onPanelKeyDown,
2252
+ children: [
2253
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "trc-calendar__head", children: [
2254
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2255
+ "button",
2256
+ {
2257
+ type: "button",
2258
+ className: "trc-calendar__nav",
2259
+ "aria-label": previousMonthLabel,
2260
+ onClick: () => setFocused(clamp(addMonths(focused, -1))),
2261
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ChevronLeft, {})
2262
+ }
2263
+ ),
2264
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { id: `${uid}-title`, className: "trc-calendar__title", "aria-live": "polite", children: monthTitle.format(focused) }),
2265
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2266
+ "button",
2267
+ {
2268
+ type: "button",
2269
+ className: "trc-calendar__nav",
2270
+ "aria-label": nextMonthLabel,
2271
+ onClick: () => setFocused(clamp(addMonths(focused, 1))),
2272
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ChevronRight, {})
2273
+ }
2274
+ )
2275
+ ] }),
2276
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
2277
+ "table",
2278
+ {
2279
+ role: "grid",
2280
+ "aria-labelledby": `${uid}-title`,
2281
+ className: "trc-calendar__grid",
2282
+ onKeyDown: onGridKeyDown,
2283
+ children: [
2284
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("tr", { children: weeks[0].map((day) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("th", { scope: "col", abbr: weekdayLong.format(day), className: "trc-calendar__weekday", children: weekdayShort.format(day).replace(".", "").slice(0, 3) }, day.getDay())) }) }),
2285
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("tbody", { children: weeks.map((week, w) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("tr", { children: week.map((day) => {
2286
+ const isSelected = sameDay(day, selected);
2287
+ const disabledDay = outOfRange(day);
2288
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { role: "gridcell", "aria-selected": isSelected || void 0, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2289
+ "button",
2290
+ {
2291
+ type: "button",
2292
+ "data-date": toISODate(day),
2293
+ tabIndex: sameDay(day, focused) ? 0 : -1,
2294
+ "aria-label": full.format(day),
2295
+ "aria-current": sameDay(day, today) ? "date" : void 0,
2296
+ disabled: disabledDay,
2297
+ onClick: () => choose(day),
2298
+ onKeyDown: (e) => {
2299
+ if (e.key === "Enter" || e.key === " ") {
2300
+ e.preventDefault();
2301
+ choose(day);
2302
+ }
2303
+ },
2304
+ className: cx(
2305
+ "trc-calendar__day",
2306
+ day.getMonth() !== focused.getMonth() && "trc-calendar__day--outside",
2307
+ isSelected && "trc-calendar__day--selected"
2308
+ ),
2309
+ children: day.getDate()
2310
+ }
2311
+ ) }, toISODate(day));
2312
+ }) }, w)) })
2313
+ ]
2314
+ }
2315
+ )
2316
+ ]
2317
+ }
2318
+ ) })
2319
+ ] });
2320
+ }
2321
+
2322
+ // src/components/avatar.tsx
2323
+ var import_react27 = require("react");
2324
+ var import_jsx_runtime33 = require("react/jsx-runtime");
2325
+ function initials(name) {
2326
+ const words = name.trim().split(/\s+/).filter(Boolean);
2327
+ const letters = words.length > 1 ? [words[0][0], words[words.length - 1][0]] : [words[0]?.[0]];
2328
+ return letters.filter(Boolean).join("").toUpperCase();
2329
+ }
2330
+ function Avatar({ name, src, size: size2 = "md", className }) {
2331
+ const [failed, setFailed] = (0, import_react27.useState)(false);
2332
+ const showImage = src && !failed;
2333
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: cx("trc-avatar", `trc-avatar--${size2}`, className), children: showImage ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("img", { src, alt: name, className: "trc-avatar__image", onError: () => setFailed(true) }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { role: "img", "aria-label": name, className: "trc-avatar__initials", children: initials(name) }) });
2334
+ }
2335
+ function AvatarGroup({
2336
+ children,
2337
+ max = 4,
2338
+ moreLabel = "{count} more",
2339
+ size: size2 = "md",
2340
+ className
2341
+ }) {
2342
+ const items2 = import_react27.Children.toArray(children);
2343
+ const hidden = items2.length - max;
2344
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: cx("trc-avatar-group", className), children: [
2345
+ items2.slice(0, max),
2346
+ hidden > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: cx("trc-avatar", `trc-avatar--${size2}`, "trc-avatar--more"), children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
2347
+ "span",
2348
+ {
2349
+ role: "img",
2350
+ "aria-label": typeof moreLabel === "string" ? fill(moreLabel, { count: hidden }) : moreLabel(hidden),
2351
+ className: "trc-avatar__initials",
2352
+ children: [
2353
+ "+",
2354
+ hidden
2355
+ ]
2356
+ }
2357
+ ) })
2358
+ ] });
2359
+ }
2360
+
2361
+ // src/components/tag.tsx
2362
+ var import_jsx_runtime34 = require("react/jsx-runtime");
2363
+ function Tag({ tone = "default", onRemove, removeLabel = "Remove", className, children, ...props }) {
2364
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: cx("trc-tag", tone === "accent" && "trc-tag--accent", className), ...props, children: [
2365
+ children,
2366
+ onRemove && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
2367
+ "button",
2368
+ {
2369
+ type: "button",
2370
+ className: "trc-tag__remove",
2371
+ "aria-label": `${removeLabel} ${typeof children === "string" ? children : ""}`.trim(),
2372
+ onClick: onRemove,
2373
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Close, {})
2374
+ }
2375
+ )
2376
+ ] });
2377
+ }
2378
+
2379
+ // src/components/stat.tsx
2380
+ var import_jsx_runtime35 = require("react/jsx-runtime");
2381
+ function Stat({ label, value, change, changeTone = "neutral", description, className }) {
2382
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("dl", { className: cx("trc-stat", className), children: [
2383
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("dt", { className: "trc-stat__label", children: label }),
2384
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("dd", { className: "trc-stat__value", children: value }),
2385
+ (change != null || description != null) && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("dd", { className: "trc-stat__meta", children: [
2386
+ change != null && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: cx("trc-stat__change", `trc-stat__change--${changeTone}`), children: change }),
2387
+ description != null && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "trc-stat__description", children: description })
2388
+ ] })
2389
+ ] });
2390
+ }
2391
+
2392
+ // src/components/table.tsx
2393
+ var import_react28 = require("react");
2394
+ var import_jsx_runtime36 = require("react/jsx-runtime");
2395
+ var compare = (a, b) => {
2396
+ if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();
2397
+ if (typeof a === "number" && typeof b === "number") return a - b;
2398
+ return String(a ?? "").localeCompare(String(b ?? ""), void 0, { numeric: true, sensitivity: "base" });
2399
+ };
2400
+ function Table({
2401
+ columns,
2402
+ rows,
2403
+ rowKey,
2404
+ caption,
2405
+ hideCaption = false,
2406
+ defaultSort,
2407
+ dense = false,
2408
+ emptyText = "No data",
2409
+ className
2410
+ }) {
2411
+ const [sort, setSort] = (0, import_react28.useState)(defaultSort);
2412
+ const field = (row, key) => row[key];
2413
+ const sorted = (() => {
2414
+ const column = columns.find((c) => c.key === sort?.key);
2415
+ if (!sort || !column) return rows;
2416
+ const value = (row) => column.sortValue ? column.sortValue(row) : field(row, column.key);
2417
+ const ordered = [...rows].sort((a, b) => compare(value(a), value(b)));
2418
+ return sort.direction === "ascending" ? ordered : ordered.reverse();
2419
+ })();
2420
+ const toggle = (key) => setSort(
2421
+ (current) => current?.key === key && current.direction === "ascending" ? { key, direction: "descending" } : { key, direction: "ascending" }
2422
+ );
2423
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2424
+ "div",
2425
+ {
2426
+ className: cx("trc-table", dense && "trc-table--dense", className),
2427
+ role: "region",
2428
+ "aria-label": typeof caption === "string" ? caption : void 0,
2429
+ tabIndex: 0,
2430
+ children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("table", { className: "trc-table__table", children: [
2431
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("caption", { className: cx("trc-table__caption", hideCaption && "trc-visually-hidden"), children: caption }),
2432
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("tr", { children: columns.map((column) => {
2433
+ const direction = sort?.key === column.key ? sort.direction : void 0;
2434
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2435
+ "th",
2436
+ {
2437
+ scope: "col",
2438
+ "aria-sort": column.sortable ? direction ?? "none" : void 0,
2439
+ className: cx("trc-table__head", column.align && `trc-table__cell--${column.align}`),
2440
+ children: column.sortable ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("button", { type: "button", className: "trc-table__sort", onClick: () => toggle(column.key), children: [
2441
+ column.header,
2442
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2443
+ ChevronDown,
2444
+ {
2445
+ className: cx(
2446
+ "trc-table__sort-icon",
2447
+ direction && "trc-table__sort-icon--active",
2448
+ direction === "ascending" && "trc-table__sort-icon--up"
2449
+ )
2450
+ }
2451
+ )
2452
+ ] }) : column.header
2453
+ },
2454
+ column.key
2455
+ );
2456
+ }) }) }),
2457
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("tbody", { children: sorted.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("td", { colSpan: columns.length, className: "trc-table__empty", children: emptyText }) }) : sorted.map((row) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("tr", { children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2458
+ "td",
2459
+ {
2460
+ className: cx("trc-table__cell", column.align && `trc-table__cell--${column.align}`),
2461
+ children: column.render ? column.render(row) : field(row, column.key)
2462
+ },
2463
+ column.key
2464
+ )) }, rowKey(row))) })
2465
+ ] })
2466
+ }
2467
+ );
2468
+ }
2469
+
2470
+ // src/components/loading.tsx
2471
+ var import_react29 = require("react");
2472
+ var import_jsx_runtime37 = require("react/jsx-runtime");
2473
+ var size = (value) => typeof value === "number" ? `${value}px` : value;
2474
+ function Skeleton({ width, height, circle = false, lines, className }) {
2475
+ if (lines && lines > 1) {
2476
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { "aria-hidden": true, className: cx("trc-skeleton-lines", className), style: { width: size(width) }, children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2477
+ "span",
2478
+ {
2479
+ className: "trc-skeleton trc-skeleton--text",
2480
+ style: { width: i === lines - 1 ? "60%" : "100%" }
2481
+ },
2482
+ i
2483
+ )) });
2484
+ }
2485
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2486
+ "span",
2487
+ {
2488
+ "aria-hidden": true,
2489
+ className: cx(
2490
+ "trc-skeleton",
2491
+ circle && "trc-skeleton--circle",
2492
+ !height && !circle && "trc-skeleton--text",
2493
+ className
2494
+ ),
2495
+ style: { width: size(width), height: size(height) ?? (circle ? size(width) : void 0) }
2496
+ }
2497
+ );
2498
+ }
2499
+ function Spinner2({ size: s = "md", label = "Loading", className }) {
2500
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { role: "status", className: cx("trc-spinner", `trc-spinner--${s}`, className), children: [
2501
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("svg", { viewBox: "0 0 24 24", "aria-hidden": true, className: "trc-spinner__svg", children: [
2502
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("circle", { cx: "12", cy: "12", r: "10", className: "trc-spinner__track" }),
2503
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("path", { d: "M12 2a10 10 0 0 1 10 10", className: "trc-spinner__arc" })
2504
+ ] }),
2505
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "trc-visually-hidden", children: label })
2506
+ ] });
2507
+ }
2508
+ function Progress({
2509
+ value,
2510
+ max = 100,
2511
+ label,
2512
+ "aria-label": ariaLabel,
2513
+ showValue = false,
2514
+ formatValue = (v, m) => `${Math.round(v / m * 100)} %`,
2515
+ className
2516
+ }) {
2517
+ const id = (0, import_react29.useId)();
2518
+ const determinate = value !== void 0 && value !== null;
2519
+ const clamped = determinate ? Math.min(Math.max(value, 0), max) : 0;
2520
+ const text = determinate ? formatValue(clamped, max) : void 0;
2521
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: cx("trc-progress", !determinate && "trc-progress--indeterminate", className), children: [
2522
+ (label != null || showValue && text) && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "trc-progress__head", children: [
2523
+ label != null && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { id: `${id}-label`, className: "trc-progress__label", children: label }),
2524
+ showValue && text && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { "aria-hidden": true, className: "trc-progress__value", children: text })
2525
+ ] }),
2526
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2527
+ "div",
2528
+ {
2529
+ role: "progressbar",
2530
+ "aria-labelledby": label != null ? `${id}-label` : void 0,
2531
+ "aria-label": label == null ? ariaLabel : void 0,
2532
+ "aria-valuemin": 0,
2533
+ "aria-valuemax": max,
2534
+ "aria-valuenow": determinate ? clamped : void 0,
2535
+ "aria-valuetext": text,
2536
+ className: "trc-progress__track",
2537
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2538
+ "div",
2539
+ {
2540
+ className: "trc-progress__fill",
2541
+ style: { "--trc-progress": `${clamped / max * 100}%` }
2542
+ }
2543
+ )
2544
+ }
2545
+ )
2546
+ ] });
2547
+ }
2548
+
2549
+ // src/components/kbd.tsx
2550
+ var import_jsx_runtime38 = require("react/jsx-runtime");
2551
+ function Kbd({ className, ...props }) {
2552
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("kbd", { className: cx("trc-kbd", className), ...props });
2553
+ }
2554
+ function Divider({ label, orientation = "horizontal", className }) {
2555
+ if (orientation === "vertical") {
2556
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { role: "separator", "aria-orientation": "vertical", className: cx("trc-divider--vertical", className) });
2557
+ }
2558
+ if (label == null) return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("hr", { className: cx("trc-divider", className) });
2559
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { role: "separator", className: cx("trc-divider-label", className), children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "trc-divider-label__text", children: label }) });
2560
+ }
2561
+
2562
+ // src/components/code-block.tsx
2563
+ var import_react30 = require("react");
2564
+ var import_jsx_runtime39 = require("react/jsx-runtime");
2565
+ var BADGES = {
2566
+ tsx: "TS",
2567
+ ts: "TS",
2568
+ jsx: "JS",
2569
+ js: "JS",
2570
+ css: "CSS",
2571
+ bash: "SH",
2572
+ sh: "SH",
2573
+ html: "HTML",
2574
+ json: "JSON"
2575
+ };
2576
+ var CopyIcon = () => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
2577
+ "svg",
2578
+ {
2579
+ viewBox: "0 0 24 24",
2580
+ fill: "none",
2581
+ stroke: "currentColor",
2582
+ strokeWidth: 1.75,
2583
+ strokeLinecap: "round",
2584
+ strokeLinejoin: "round",
2585
+ "aria-hidden": true,
2586
+ children: [
2587
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("rect", { x: "9", y: "9", width: "12", height: "12", rx: "2.5" }),
2588
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("path", { d: "M5 15H4.5A1.5 1.5 0 0 1 3 13.5v-9A1.5 1.5 0 0 1 4.5 3h9A1.5 1.5 0 0 1 15 4.5V5" })
2589
+ ]
2590
+ }
2591
+ );
2592
+ function CodeBlock({
2593
+ code,
2594
+ title,
2595
+ language,
2596
+ children,
2597
+ copyLabel = "Copy code",
2598
+ copiedLabel = "Copied",
2599
+ className
2600
+ }) {
2601
+ const [copied, setCopied] = (0, import_react30.useState)(false);
2602
+ const timer = (0, import_react30.useRef)(void 0);
2603
+ (0, import_react30.useEffect)(() => () => window.clearTimeout(timer.current), []);
2604
+ const copy = async () => {
2605
+ await navigator.clipboard.writeText(code);
2606
+ setCopied(true);
2607
+ window.clearTimeout(timer.current);
2608
+ timer.current = window.setTimeout(() => setCopied(false), 1600);
2609
+ };
2610
+ const button = /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
2611
+ "button",
2612
+ {
2613
+ type: "button",
2614
+ onClick: copy,
2615
+ className: "trc-code__copy",
2616
+ "aria-label": copyLabel,
2617
+ title: copyLabel,
2618
+ "data-copied": copied,
2619
+ children: [
2620
+ copied ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Check, {}) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CopyIcon, {}),
2621
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "trc-visually-hidden", "aria-live": "polite", children: copied ? copiedLabel : "" })
2622
+ ]
2623
+ }
2624
+ );
2625
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: cx("trc-code", title == null && "trc-code--bare", className), children: [
2626
+ title != null ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "trc-code__bar", children: [
2627
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "trc-code__file", children: [
2628
+ language && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "trc-code__lang", children: BADGES[language] ?? language.toUpperCase() }),
2629
+ title
2630
+ ] }),
2631
+ button
2632
+ ] }) : button,
2633
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("pre", { className: "trc-code__pre", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("code", { children: children ?? code }) })
2634
+ ] });
2635
+ }
2636
+ // Annotate the CommonJS export names for ESM import in node:
2637
+ 0 && (module.exports = {
2638
+ AccentText,
2639
+ Accordion,
2640
+ Alert,
2641
+ ArrowLeft,
2642
+ ArrowRight,
2643
+ ArrowUp,
2644
+ Avatar,
2645
+ AvatarGroup,
2646
+ BackToTop,
2647
+ Breadcrumbs,
2648
+ Calendar,
2649
+ Card,
2650
+ Check,
2651
+ Checkbox,
2652
+ ChevronDown,
2653
+ ChevronLeft,
2654
+ ChevronRight,
2655
+ Close,
2656
+ CodeBlock,
2657
+ Combobox,
2658
+ Container,
2659
+ DatePicker,
2660
+ Dialog,
2661
+ Divider,
2662
+ Drawer,
2663
+ DropdownMenu,
2664
+ Dropzone,
2665
+ Field,
2666
+ FileInput,
2667
+ Heading,
2668
+ HeroVideo,
2669
+ Input,
2670
+ Kbd,
2671
+ LanguageSwitcher,
2672
+ Menu,
2673
+ PageHero,
2674
+ Pagination,
2675
+ PasswordInput,
2676
+ PillButton,
2677
+ PillLink,
2678
+ PinInput,
2679
+ Popover,
2680
+ Progress,
2681
+ RadioGroup,
2682
+ Section,
2683
+ SegmentedControl,
2684
+ Select,
2685
+ SiteFooter,
2686
+ SiteHeader,
2687
+ Skeleton,
2688
+ Slider,
2689
+ Spinner,
2690
+ Stat,
2691
+ StepNumber,
2692
+ Steps,
2693
+ Switch,
2694
+ Table,
2695
+ Tabs,
2696
+ Tag,
2697
+ Text,
2698
+ Textarea,
2699
+ Toaster,
2700
+ Tooltip,
2701
+ acceptsFile,
2702
+ cx,
2703
+ formatBytes,
2704
+ initials,
2705
+ paginationRange,
2706
+ plainText,
2707
+ toast,
2708
+ validateFiles
2709
+ });
2710
+ //# sourceMappingURL=index.cjs.map