@terminal-blueprint/react 0.1.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,2178 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ Badge: () => Badge,
24
+ Battery: () => Battery,
25
+ BatteryInline: () => BatteryInline,
26
+ Breadcrumbs: () => Breadcrumbs,
27
+ Button: () => Button,
28
+ Card: () => Card,
29
+ Checkbox: () => Checkbox,
30
+ CodeBlock: () => CodeBlock,
31
+ CornerBrackets: () => CornerBrackets,
32
+ Input: () => Input,
33
+ Modal: () => Modal,
34
+ NavDropdown: () => NavDropdown,
35
+ Pagination: () => Pagination,
36
+ Progress: () => Progress,
37
+ RadioGroup: () => RadioGroup,
38
+ RadioItem: () => RadioItem,
39
+ SafePortal: () => SafePortal,
40
+ Select: () => Select,
41
+ SelectContent: () => SelectContent,
42
+ SelectItem: () => SelectItem,
43
+ SelectTrigger: () => SelectTrigger,
44
+ Sidenav: () => Sidenav,
45
+ Skeleton: () => Skeleton,
46
+ Spinner: () => Spinner,
47
+ Table: () => Table,
48
+ Tabs: () => Tabs,
49
+ TabsContent: () => TabsContent,
50
+ TabsList: () => TabsList,
51
+ TabsTrigger: () => TabsTrigger,
52
+ Tag: () => Tag,
53
+ Textarea: () => Textarea,
54
+ ThemeProvider: () => ThemeProvider,
55
+ TitleLine: () => TitleLine,
56
+ Toaster: () => Toaster,
57
+ Toggle: () => Toggle,
58
+ Toolbar: () => Toolbar,
59
+ Tooltip: () => Tooltip,
60
+ cn: () => cn,
61
+ toast: () => createToast,
62
+ useDisclosure: () => useDisclosure,
63
+ useFocusTrap: () => useFocusTrap,
64
+ useKeyboardNav: () => useKeyboardNav,
65
+ useMergedRef: () => useMergedRef,
66
+ useReducedMotion: () => useReducedMotion,
67
+ useTheme: () => useTheme
68
+ });
69
+ module.exports = __toCommonJS(index_exports);
70
+ var import_css = require("@terminal-blueprint/core/css");
71
+
72
+ // src/utils/cn.ts
73
+ var import_clsx = require("clsx");
74
+ function cn(...inputs) {
75
+ return (0, import_clsx.clsx)(inputs);
76
+ }
77
+
78
+ // src/components/Button.tsx
79
+ var import_jsx_runtime = require("react/jsx-runtime");
80
+ function Button({
81
+ as,
82
+ variant = "default",
83
+ size = "md",
84
+ isLoading = false,
85
+ loadingText,
86
+ icon,
87
+ iconPosition = "left",
88
+ className,
89
+ disabled,
90
+ children,
91
+ ref,
92
+ ...props
93
+ }) {
94
+ const Component = as || "button";
95
+ const isDisabled = disabled || isLoading;
96
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
97
+ Component,
98
+ {
99
+ ref,
100
+ className: cn(
101
+ "tb-btn",
102
+ variant !== "default" && `tb-btn--${variant}`,
103
+ size !== "md" && `tb-btn--${size}`,
104
+ isLoading && "tb-btn--loading",
105
+ isLoading && loadingText && "tb-btn--loading-text",
106
+ isDisabled && "tb-btn--disabled",
107
+ className
108
+ ),
109
+ disabled: Component === "button" ? isDisabled : void 0,
110
+ "aria-disabled": Component !== "button" && isDisabled ? true : void 0,
111
+ ...props,
112
+ children: [
113
+ isLoading && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "tb-btn__spinner", "aria-hidden": "true", children: [
114
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tb-btn__spinner-square" }),
115
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tb-btn__spinner-square" }),
116
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tb-btn__spinner-square" })
117
+ ] }),
118
+ icon && iconPosition === "left" && !isLoading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tb-btn__icon", children: icon }),
119
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: isLoading && !loadingText ? { visibility: "hidden" } : void 0, children: isLoading && loadingText ? loadingText : children }),
120
+ icon && iconPosition === "right" && !isLoading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tb-btn__icon", children: icon })
121
+ ]
122
+ }
123
+ );
124
+ }
125
+
126
+ // src/components/Input.tsx
127
+ var import_react = require("react");
128
+ var import_jsx_runtime2 = require("react/jsx-runtime");
129
+ function Input({
130
+ label,
131
+ error,
132
+ hint,
133
+ size = "md",
134
+ icon,
135
+ iconPosition = "left",
136
+ className,
137
+ id: idProp,
138
+ ref,
139
+ ...props
140
+ }) {
141
+ const autoId = (0, import_react.useId)();
142
+ const id = idProp ?? autoId;
143
+ const errorId = error ? `${id}-error` : void 0;
144
+ const hintId = hint && !error ? `${id}-hint` : void 0;
145
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "tb-form-group", children: [
146
+ label && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: id, className: "tb-label", children: label }),
147
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
148
+ "div",
149
+ {
150
+ className: cn(
151
+ "tb-input-wrapper",
152
+ icon && `tb-input-wrapper--icon-${iconPosition}`
153
+ ),
154
+ children: [
155
+ icon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "tb-input__icon", "aria-hidden": "true", children: icon }),
156
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
157
+ "input",
158
+ {
159
+ ref,
160
+ id,
161
+ className: cn(
162
+ "tb-input",
163
+ size !== "md" && `tb-input--${size}`,
164
+ error && "tb-input--error",
165
+ className
166
+ ),
167
+ "aria-invalid": error ? true : void 0,
168
+ "aria-describedby": errorId ?? hintId,
169
+ ...props
170
+ }
171
+ )
172
+ ]
173
+ }
174
+ ),
175
+ error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { id: errorId, className: "tb-input__error", role: "alert", children: error }),
176
+ hint && !error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { id: hintId, className: "tb-input__hint", children: hint })
177
+ ] });
178
+ }
179
+
180
+ // src/components/Textarea.tsx
181
+ var import_react2 = require("react");
182
+ var import_jsx_runtime3 = require("react/jsx-runtime");
183
+ function Textarea({
184
+ label,
185
+ error,
186
+ hint,
187
+ className,
188
+ id: idProp,
189
+ ref,
190
+ ...props
191
+ }) {
192
+ const autoId = (0, import_react2.useId)();
193
+ const id = idProp ?? autoId;
194
+ const errorId = error ? `${id}-error` : void 0;
195
+ const hintId = hint && !error ? `${id}-hint` : void 0;
196
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tb-form-group", children: [
197
+ label && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { htmlFor: id, className: "tb-label", children: label }),
198
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
199
+ "textarea",
200
+ {
201
+ ref,
202
+ id,
203
+ className: cn(
204
+ "tb-textarea",
205
+ error && "tb-textarea--error",
206
+ className
207
+ ),
208
+ "aria-invalid": error ? true : void 0,
209
+ "aria-describedby": errorId ?? hintId,
210
+ ...props
211
+ }
212
+ ),
213
+ error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { id: errorId, className: "tb-textarea__error", role: "alert", children: error }),
214
+ hint && !error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { id: hintId, className: "tb-textarea__hint", children: hint })
215
+ ] });
216
+ }
217
+
218
+ // src/components/Card/Card.tsx
219
+ var import_jsx_runtime4 = require("react/jsx-runtime");
220
+ function CardRoot({
221
+ as,
222
+ brackets = false,
223
+ pulse = false,
224
+ hoverable = false,
225
+ className,
226
+ children,
227
+ ref,
228
+ ...props
229
+ }) {
230
+ const Component = as || "div";
231
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
232
+ Component,
233
+ {
234
+ ref,
235
+ className: cn(
236
+ "tb-card",
237
+ brackets && "tb-card--bracketed",
238
+ pulse && "tb-card--pulse",
239
+ hoverable && "tb-card--hoverable",
240
+ className
241
+ ),
242
+ ...props,
243
+ children: [
244
+ brackets && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
245
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tb-card__bracket tb-card__bracket--tl" }),
246
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tb-card__bracket tb-card__bracket--tr" }),
247
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tb-card__bracket tb-card__bracket--bl" }),
248
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "tb-card__bracket tb-card__bracket--br" })
249
+ ] }),
250
+ children
251
+ ]
252
+ }
253
+ );
254
+ }
255
+ function Header({ className, ref, ...props }) {
256
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
257
+ "div",
258
+ {
259
+ ref,
260
+ className: cn("tb-card__header", className),
261
+ ...props
262
+ }
263
+ );
264
+ }
265
+ function Title({ className, ref, ...props }) {
266
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
267
+ "div",
268
+ {
269
+ ref,
270
+ className: cn("tb-card__title", className),
271
+ ...props
272
+ }
273
+ );
274
+ }
275
+ function Body({ className, ref, ...props }) {
276
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
277
+ "div",
278
+ {
279
+ ref,
280
+ className: cn("tb-card__body", className),
281
+ ...props
282
+ }
283
+ );
284
+ }
285
+ function Tags({ className, ref, ...props }) {
286
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
287
+ "div",
288
+ {
289
+ ref,
290
+ className: cn("tb-card__tags", className),
291
+ ...props
292
+ }
293
+ );
294
+ }
295
+ function Footer({ className, ref, ...props }) {
296
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
297
+ "div",
298
+ {
299
+ ref,
300
+ className: cn("tb-card__footer", className),
301
+ ...props
302
+ }
303
+ );
304
+ }
305
+ var Card = Object.assign(CardRoot, {
306
+ Header,
307
+ Title,
308
+ Body,
309
+ Tags,
310
+ Footer
311
+ });
312
+
313
+ // src/components/Badge.tsx
314
+ var import_jsx_runtime5 = require("react/jsx-runtime");
315
+ function Badge({
316
+ variant = "default",
317
+ dot = false,
318
+ pulse = false,
319
+ className,
320
+ children,
321
+ ref,
322
+ ...props
323
+ }) {
324
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
325
+ "span",
326
+ {
327
+ ref,
328
+ className: cn(
329
+ "tb-badge",
330
+ variant !== "default" && `tb-badge--${variant}`,
331
+ pulse && "tb-badge--pulse",
332
+ className
333
+ ),
334
+ ...props,
335
+ children: [
336
+ dot && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
337
+ "span",
338
+ {
339
+ className: cn(
340
+ "tb-badge__dot"
341
+ ),
342
+ "aria-hidden": "true"
343
+ }
344
+ ),
345
+ children
346
+ ]
347
+ }
348
+ );
349
+ }
350
+
351
+ // src/components/Tag.tsx
352
+ var import_jsx_runtime6 = require("react/jsx-runtime");
353
+ function Tag({ className, children, ref, ...props }) {
354
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { ref, className: cn("tb-tag", className), ...props, children });
355
+ }
356
+
357
+ // src/components/TitleLine.tsx
358
+ var import_jsx_runtime7 = require("react/jsx-runtime");
359
+ function TitleLine({ label, className }) {
360
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: cn("tb-title-line", className), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "tb-title-line__label", children: label }) });
361
+ }
362
+
363
+ // src/components/CornerBrackets.tsx
364
+ var import_jsx_runtime8 = require("react/jsx-runtime");
365
+ function CornerBrackets({ pulse, children, className, ref, ...props }) {
366
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
367
+ "div",
368
+ {
369
+ ref,
370
+ className: cn("tb-brackets", pulse && "tb-brackets--pulse", className),
371
+ ...props,
372
+ children: [
373
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "tb-brackets__corner tb-brackets__corner--tl" }),
374
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "tb-brackets__corner tb-brackets__corner--tr" }),
375
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "tb-brackets__corner tb-brackets__corner--bl" }),
376
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "tb-brackets__corner tb-brackets__corner--br" }),
377
+ children
378
+ ]
379
+ }
380
+ );
381
+ }
382
+
383
+ // src/components/Select/Select.tsx
384
+ var import_react3 = require("react");
385
+ var import_jsx_runtime9 = require("react/jsx-runtime");
386
+ var SelectContext = (0, import_react3.createContext)(null);
387
+ function useSelectContext() {
388
+ const ctx = (0, import_react3.useContext)(SelectContext);
389
+ if (!ctx) throw new Error("Select compound components must be used within <Select>");
390
+ return ctx;
391
+ }
392
+ function Select({
393
+ value: controlledValue,
394
+ defaultValue = "",
395
+ onValueChange,
396
+ placeholder = "Select...",
397
+ disabled = false,
398
+ error,
399
+ label,
400
+ children,
401
+ className,
402
+ ref
403
+ }) {
404
+ const [internalValue, setInternalValue] = (0, import_react3.useState)(defaultValue);
405
+ const [open, setOpen] = (0, import_react3.useState)(false);
406
+ const [focusedIndex, setFocusedIndex] = (0, import_react3.useState)(-1);
407
+ const [itemValues, setItemValues] = (0, import_react3.useState)([]);
408
+ const isControlled = controlledValue !== void 0;
409
+ const value = isControlled ? controlledValue : internalValue;
410
+ const triggerRef = (0, import_react3.useRef)(null);
411
+ const listRef = (0, import_react3.useRef)(null);
412
+ const rootRef = (0, import_react3.useRef)(null);
413
+ const onSelect = (0, import_react3.useCallback)(
414
+ (val) => {
415
+ if (!isControlled) setInternalValue(val);
416
+ onValueChange?.(val);
417
+ setOpen(false);
418
+ triggerRef.current?.focus();
419
+ },
420
+ [isControlled, onValueChange]
421
+ );
422
+ const registerItem = (0, import_react3.useCallback)((val) => {
423
+ setItemValues((prev) => prev.includes(val) ? prev : [...prev, val]);
424
+ }, []);
425
+ const unregisterItem = (0, import_react3.useCallback)((val) => {
426
+ setItemValues((prev) => prev.filter((v) => v !== val));
427
+ }, []);
428
+ (0, import_react3.useEffect)(() => {
429
+ if (!open) return;
430
+ function handleClick(e) {
431
+ if (rootRef.current && !rootRef.current.contains(e.target)) {
432
+ setOpen(false);
433
+ }
434
+ }
435
+ document.addEventListener("pointerdown", handleClick);
436
+ return () => document.removeEventListener("pointerdown", handleClick);
437
+ }, [open]);
438
+ (0, import_react3.useEffect)(() => {
439
+ if (!open) return;
440
+ function handleKey(e) {
441
+ if (e.key === "Escape") {
442
+ setOpen(false);
443
+ triggerRef.current?.focus();
444
+ }
445
+ }
446
+ document.addEventListener("keydown", handleKey);
447
+ return () => document.removeEventListener("keydown", handleKey);
448
+ }, [open]);
449
+ (0, import_react3.useEffect)(() => {
450
+ if (open) {
451
+ const idx = itemValues.indexOf(value);
452
+ setFocusedIndex(idx >= 0 ? idx : 0);
453
+ }
454
+ }, [open, itemValues, value]);
455
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
456
+ SelectContext.Provider,
457
+ {
458
+ value: {
459
+ open,
460
+ setOpen,
461
+ value,
462
+ onSelect,
463
+ placeholder,
464
+ disabled,
465
+ focusedIndex,
466
+ setFocusedIndex,
467
+ itemValues,
468
+ registerItem,
469
+ unregisterItem,
470
+ triggerRef,
471
+ listRef
472
+ },
473
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
474
+ "div",
475
+ {
476
+ ref: (node) => {
477
+ rootRef.current = node;
478
+ if (typeof ref === "function") ref(node);
479
+ else if (ref) ref.current = node;
480
+ },
481
+ className: cn(
482
+ "tb-select",
483
+ error && "tb-select--error",
484
+ disabled && "tb-select--disabled",
485
+ className
486
+ ),
487
+ children: [
488
+ label && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "tb-select__label", children: label }),
489
+ children,
490
+ error && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "tb-select__error", children: error })
491
+ ]
492
+ }
493
+ )
494
+ }
495
+ );
496
+ }
497
+
498
+ // src/components/Select/SelectTrigger.tsx
499
+ var import_jsx_runtime10 = require("react/jsx-runtime");
500
+ function SelectTrigger({ className, ref }) {
501
+ const { open, setOpen, value, placeholder, disabled, triggerRef, itemValues, focusedIndex, setFocusedIndex, onSelect } = useSelectContext();
502
+ function handleKeyDown(e) {
503
+ if (disabled) return;
504
+ switch (e.key) {
505
+ case "ArrowDown": {
506
+ e.preventDefault();
507
+ if (!open) {
508
+ setOpen(true);
509
+ } else {
510
+ setFocusedIndex(Math.min(focusedIndex + 1, itemValues.length - 1));
511
+ }
512
+ break;
513
+ }
514
+ case "ArrowUp": {
515
+ e.preventDefault();
516
+ if (open) {
517
+ setFocusedIndex(Math.max(focusedIndex - 1, 0));
518
+ }
519
+ break;
520
+ }
521
+ case "Enter":
522
+ case " ": {
523
+ e.preventDefault();
524
+ if (open && focusedIndex >= 0 && itemValues[focusedIndex]) {
525
+ onSelect(itemValues[focusedIndex]);
526
+ } else {
527
+ setOpen(!open);
528
+ }
529
+ break;
530
+ }
531
+ }
532
+ }
533
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
534
+ "button",
535
+ {
536
+ ref: (node) => {
537
+ triggerRef.current = node;
538
+ if (typeof ref === "function") ref(node);
539
+ else if (ref) ref.current = node;
540
+ },
541
+ type: "button",
542
+ role: "combobox",
543
+ "aria-expanded": open,
544
+ "aria-haspopup": "listbox",
545
+ disabled,
546
+ className: cn("tb-select__trigger", open && "tb-select__trigger--open", className),
547
+ onPointerDown: (e) => {
548
+ e.preventDefault();
549
+ if (!disabled) setOpen(!open);
550
+ },
551
+ onKeyDown: handleKeyDown,
552
+ children: [
553
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: cn("tb-select__value", !value && "tb-select__placeholder"), children: value || placeholder }),
554
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "tb-select__chevron", "aria-hidden": "true" })
555
+ ]
556
+ }
557
+ );
558
+ }
559
+
560
+ // src/components/Select/SelectContent.tsx
561
+ var import_jsx_runtime11 = require("react/jsx-runtime");
562
+ function SelectContent({ children, className, ref }) {
563
+ const { open, listRef } = useSelectContext();
564
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
565
+ "div",
566
+ {
567
+ ref: (node) => {
568
+ listRef.current = node;
569
+ if (typeof ref === "function") ref(node);
570
+ else if (ref) ref.current = node;
571
+ },
572
+ role: "listbox",
573
+ className: cn("tb-select__dropdown", open && "tb-select__dropdown--open", className),
574
+ children
575
+ }
576
+ );
577
+ }
578
+
579
+ // src/components/Select/SelectItem.tsx
580
+ var import_react4 = require("react");
581
+ var import_jsx_runtime12 = require("react/jsx-runtime");
582
+ function SelectItem({
583
+ value: itemValue,
584
+ disabled = false,
585
+ children,
586
+ className,
587
+ ref
588
+ }) {
589
+ const { value, onSelect, focusedIndex, setFocusedIndex, itemValues, registerItem, unregisterItem } = useSelectContext();
590
+ const index = itemValues.indexOf(itemValue);
591
+ const isSelected = value === itemValue;
592
+ const isFocused = focusedIndex === index;
593
+ (0, import_react4.useEffect)(() => {
594
+ registerItem(itemValue);
595
+ return () => unregisterItem(itemValue);
596
+ }, [itemValue, registerItem, unregisterItem]);
597
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
598
+ "div",
599
+ {
600
+ ref,
601
+ role: "option",
602
+ "aria-selected": isSelected,
603
+ "aria-disabled": disabled,
604
+ "data-focused": isFocused || void 0,
605
+ className: cn(
606
+ "tb-select__option",
607
+ isSelected && "tb-select__option--selected",
608
+ isFocused && "tb-select__option--focused",
609
+ disabled && "tb-select__option--disabled",
610
+ className
611
+ ),
612
+ onClick: () => {
613
+ if (!disabled) onSelect(itemValue);
614
+ },
615
+ onMouseEnter: () => {
616
+ if (!disabled) setFocusedIndex(index);
617
+ },
618
+ children
619
+ }
620
+ );
621
+ }
622
+
623
+ // src/components/Modal/Modal.tsx
624
+ var import_react6 = require("react");
625
+
626
+ // src/utils/SafePortal.tsx
627
+ var import_react5 = require("react");
628
+ var import_react_dom = require("react-dom");
629
+ function SafePortal({ children, target }) {
630
+ const [mounted, setMounted] = (0, import_react5.useState)(false);
631
+ (0, import_react5.useEffect)(() => {
632
+ setMounted(true);
633
+ }, []);
634
+ if (!mounted) return null;
635
+ return (0, import_react_dom.createPortal)(children, target ?? document.body);
636
+ }
637
+
638
+ // src/components/Modal/Modal.tsx
639
+ var import_jsx_runtime13 = require("react/jsx-runtime");
640
+ var ModalContext = (0, import_react6.createContext)(null);
641
+ function useModalContext() {
642
+ const ctx = (0, import_react6.useContext)(ModalContext);
643
+ if (!ctx) throw new Error("Modal sub-components must be used within <Modal>");
644
+ return ctx;
645
+ }
646
+ function ModalRoot({
647
+ open,
648
+ onOpenChange,
649
+ closeOnEscape = true,
650
+ closeOnBackdrop = true,
651
+ hideCloseButton = false,
652
+ portalTarget,
653
+ children,
654
+ className,
655
+ ref
656
+ }) {
657
+ const modalRef = (0, import_react6.useRef)(null);
658
+ const previousFocusRef = (0, import_react6.useRef)(null);
659
+ const uid = (0, import_react6.useId)();
660
+ const titleId = `tb-modal-title-${uid}`;
661
+ const descId = `tb-modal-desc-${uid}`;
662
+ const onClose = (0, import_react6.useCallback)(() => onOpenChange(false), [onOpenChange]);
663
+ (0, import_react6.useEffect)(() => {
664
+ if (!open) return;
665
+ const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
666
+ const originalOverflow = document.body.style.overflow;
667
+ const originalPaddingRight = document.body.style.paddingRight;
668
+ document.body.style.overflow = "hidden";
669
+ document.body.style.paddingRight = `${scrollbarWidth}px`;
670
+ return () => {
671
+ document.body.style.overflow = originalOverflow;
672
+ document.body.style.paddingRight = originalPaddingRight;
673
+ };
674
+ }, [open]);
675
+ (0, import_react6.useEffect)(() => {
676
+ if (open) {
677
+ previousFocusRef.current = document.activeElement;
678
+ requestAnimationFrame(() => {
679
+ const focusable = modalRef.current?.querySelector(
680
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
681
+ );
682
+ (focusable ?? modalRef.current)?.focus();
683
+ });
684
+ } else {
685
+ previousFocusRef.current?.focus();
686
+ }
687
+ }, [open]);
688
+ (0, import_react6.useEffect)(() => {
689
+ if (!open || !closeOnEscape) return;
690
+ function handleKey(e) {
691
+ if (e.key === "Escape") onOpenChange(false);
692
+ }
693
+ document.addEventListener("keydown", handleKey);
694
+ return () => document.removeEventListener("keydown", handleKey);
695
+ }, [open, closeOnEscape, onOpenChange]);
696
+ const handleKeyDown = (0, import_react6.useCallback)(
697
+ (e) => {
698
+ if (e.key !== "Tab" || !modalRef.current) return;
699
+ const focusable = modalRef.current.querySelectorAll(
700
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
701
+ );
702
+ if (focusable.length === 0) return;
703
+ const first = focusable[0];
704
+ const last = focusable[focusable.length - 1];
705
+ if (e.shiftKey) {
706
+ if (document.activeElement === first) {
707
+ e.preventDefault();
708
+ last.focus();
709
+ }
710
+ } else {
711
+ if (document.activeElement === last) {
712
+ e.preventDefault();
713
+ first.focus();
714
+ }
715
+ }
716
+ },
717
+ []
718
+ );
719
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SafePortal, { target: portalTarget, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
720
+ "div",
721
+ {
722
+ className: cn("tb-modal-overlay", open && "tb-modal-overlay--open"),
723
+ onClick: (e) => {
724
+ if (closeOnBackdrop && e.target === e.currentTarget) onClose();
725
+ },
726
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
727
+ "div",
728
+ {
729
+ ref: (node) => {
730
+ modalRef.current = node;
731
+ if (typeof ref === "function") ref(node);
732
+ else if (ref) ref.current = node;
733
+ },
734
+ role: "dialog",
735
+ "aria-modal": "true",
736
+ "aria-labelledby": titleId,
737
+ "aria-describedby": descId,
738
+ className: cn("tb-modal", className),
739
+ tabIndex: -1,
740
+ onKeyDown: handleKeyDown,
741
+ children: [
742
+ !hideCloseButton && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
743
+ "button",
744
+ {
745
+ type: "button",
746
+ className: "tb-modal__close",
747
+ "aria-label": "Close",
748
+ onClick: onClose,
749
+ children: "\xD7"
750
+ }
751
+ ),
752
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ModalContext.Provider, { value: { onClose, titleId, descId }, children })
753
+ ]
754
+ }
755
+ )
756
+ }
757
+ ) });
758
+ }
759
+ function Title2({ className, ref, ...props }) {
760
+ const { titleId } = useModalContext();
761
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
762
+ "h2",
763
+ {
764
+ ref,
765
+ id: titleId,
766
+ className: cn("tb-modal__title", className),
767
+ ...props
768
+ }
769
+ );
770
+ }
771
+ function Body2({ className, ref, ...props }) {
772
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
773
+ "div",
774
+ {
775
+ ref,
776
+ className: cn("tb-modal__body", className),
777
+ ...props
778
+ }
779
+ );
780
+ }
781
+ function Footer2({ className, ref, ...props }) {
782
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
783
+ "div",
784
+ {
785
+ ref,
786
+ className: cn("tb-modal__footer", className),
787
+ ...props
788
+ }
789
+ );
790
+ }
791
+ function Close({
792
+ className,
793
+ children,
794
+ ref,
795
+ ...props
796
+ }) {
797
+ const { onClose } = useModalContext();
798
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
799
+ "button",
800
+ {
801
+ ref,
802
+ type: "button",
803
+ className: cn("tb-modal__close", className),
804
+ "aria-label": "Close",
805
+ onClick: onClose,
806
+ ...props,
807
+ children: children ?? "\xD7"
808
+ }
809
+ );
810
+ }
811
+ var Modal = Object.assign(ModalRoot, {
812
+ Title: Title2,
813
+ Body: Body2,
814
+ Footer: Footer2,
815
+ Close
816
+ });
817
+
818
+ // src/components/Tabs/Tabs.tsx
819
+ var import_react7 = require("react");
820
+ var import_jsx_runtime14 = require("react/jsx-runtime");
821
+ var TabsContext = (0, import_react7.createContext)(null);
822
+ function useTabsContext() {
823
+ const ctx = (0, import_react7.useContext)(TabsContext);
824
+ if (!ctx) throw new Error("Tabs compound components must be used within <Tabs>");
825
+ return ctx;
826
+ }
827
+ function Tabs({
828
+ value: controlledValue,
829
+ defaultValue = "",
830
+ onValueChange: onValueChangeProp,
831
+ children,
832
+ className,
833
+ ref
834
+ }) {
835
+ const [internalValue, setInternalValue] = (0, import_react7.useState)(defaultValue);
836
+ const isControlled = controlledValue !== void 0;
837
+ const value = isControlled ? controlledValue : internalValue;
838
+ const onValueChange = (0, import_react7.useCallback)(
839
+ (val) => {
840
+ if (!isControlled) setInternalValue(val);
841
+ onValueChangeProp?.(val);
842
+ },
843
+ [isControlled, onValueChangeProp]
844
+ );
845
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TabsContext.Provider, { value: { value, onValueChange }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { ref, className: cn("tb-tabs", className), children }) });
846
+ }
847
+ function TabsList({ children, className, ref }) {
848
+ const listRef = (0, import_react7.useRef)(null);
849
+ function handleKeyDown(e) {
850
+ if (e.key !== "ArrowLeft" && e.key !== "ArrowRight") return;
851
+ const triggers = Array.from(
852
+ (listRef.current ?? e.currentTarget).querySelectorAll(
853
+ ".tb-tabs__trigger:not(:disabled)"
854
+ )
855
+ );
856
+ if (triggers.length === 0) return;
857
+ const current = document.activeElement;
858
+ const idx = triggers.indexOf(current);
859
+ if (idx < 0) return;
860
+ e.preventDefault();
861
+ let next;
862
+ if (e.key === "ArrowRight") {
863
+ next = (idx + 1) % triggers.length;
864
+ } else {
865
+ next = (idx - 1 + triggers.length) % triggers.length;
866
+ }
867
+ triggers[next].focus();
868
+ }
869
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
870
+ "div",
871
+ {
872
+ ref: (node) => {
873
+ listRef.current = node;
874
+ if (typeof ref === "function") ref(node);
875
+ else if (ref) ref.current = node;
876
+ },
877
+ role: "tablist",
878
+ className: cn("tb-tabs__list", className),
879
+ onKeyDown: handleKeyDown,
880
+ children
881
+ }
882
+ );
883
+ }
884
+ function TabsTrigger({
885
+ value: triggerValue,
886
+ icon,
887
+ disabled = false,
888
+ children,
889
+ className,
890
+ ref
891
+ }) {
892
+ const { value, onValueChange } = useTabsContext();
893
+ const isActive = value === triggerValue;
894
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
895
+ "button",
896
+ {
897
+ ref,
898
+ type: "button",
899
+ role: "tab",
900
+ "aria-selected": isActive,
901
+ tabIndex: isActive ? 0 : -1,
902
+ disabled,
903
+ className: cn(
904
+ "tb-tabs__trigger",
905
+ isActive && "tb-tabs__trigger--active",
906
+ disabled && "tb-tabs__trigger--disabled",
907
+ className
908
+ ),
909
+ onClick: () => {
910
+ if (!disabled) onValueChange(triggerValue);
911
+ },
912
+ children: [
913
+ icon && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "tb-tabs__trigger-icon", children: icon }),
914
+ children
915
+ ]
916
+ }
917
+ );
918
+ }
919
+ function TabsContent({ value: contentValue, children, className, ref }) {
920
+ const { value } = useTabsContext();
921
+ const isActive = value === contentValue;
922
+ if (!isActive) return null;
923
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
924
+ "div",
925
+ {
926
+ ref,
927
+ role: "tabpanel",
928
+ className: cn("tb-tabs__content", isActive && "tb-tabs__content--active", className),
929
+ children
930
+ }
931
+ );
932
+ }
933
+
934
+ // src/components/Toast/ToastProvider.tsx
935
+ var import_react8 = require("react");
936
+ var import_jsx_runtime15 = require("react/jsx-runtime");
937
+ var toasts = [];
938
+ var nextId = 0;
939
+ var listeners = /* @__PURE__ */ new Set();
940
+ var timers = /* @__PURE__ */ new Map();
941
+ function emit() {
942
+ for (const fn of listeners) fn();
943
+ }
944
+ function getSnapshot() {
945
+ return toasts;
946
+ }
947
+ function subscribe(fn) {
948
+ listeners.add(fn);
949
+ return () => listeners.delete(fn);
950
+ }
951
+ function addToast(options, maxCount = 3) {
952
+ const id = `toast-${++nextId}`;
953
+ const entry = {
954
+ ...options,
955
+ id,
956
+ type: options.type ?? "info"
957
+ };
958
+ toasts = [...toasts, entry];
959
+ while (toasts.length > maxCount) {
960
+ const removed = toasts[0];
961
+ toasts = toasts.slice(1);
962
+ const timer = timers.get(removed.id);
963
+ if (timer) {
964
+ clearTimeout(timer);
965
+ timers.delete(removed.id);
966
+ }
967
+ }
968
+ const duration = options.duration === void 0 ? 3500 : options.duration;
969
+ if (duration !== null) {
970
+ const timer = setTimeout(() => {
971
+ timers.delete(id);
972
+ toasts = toasts.filter((t) => t.id !== id);
973
+ emit();
974
+ }, duration);
975
+ timers.set(id, timer);
976
+ }
977
+ emit();
978
+ return id;
979
+ }
980
+ function dismissToast(id) {
981
+ const timer = timers.get(id);
982
+ if (timer) {
983
+ clearTimeout(timer);
984
+ timers.delete(id);
985
+ }
986
+ toasts = toasts.filter((t) => t.id !== id);
987
+ emit();
988
+ }
989
+ function dismissAll() {
990
+ timers.forEach((timer) => clearTimeout(timer));
991
+ timers.clear();
992
+ toasts = [];
993
+ emit();
994
+ }
995
+ function createToast(options) {
996
+ return addToast(options);
997
+ }
998
+ createToast.success = (title, options) => addToast({ ...options, title, type: "success" });
999
+ createToast.error = (title, options) => addToast({ ...options, title, type: "error" });
1000
+ createToast.warning = (title, options) => addToast({ ...options, title, type: "warning" });
1001
+ createToast.info = (title, options) => addToast({ ...options, title, type: "info" });
1002
+ createToast.dismiss = dismissToast;
1003
+ createToast.dismissAll = dismissAll;
1004
+ var ICONS = {
1005
+ success: "\u2713",
1006
+ error: "\u2717",
1007
+ warning: "\u26A0",
1008
+ info: "\u2139"
1009
+ };
1010
+ function Toaster({ position = "top-right" }) {
1011
+ const currentToasts = (0, import_react8.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
1012
+ if (currentToasts.length === 0) return null;
1013
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SafePortal, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1014
+ "div",
1015
+ {
1016
+ className: cn("tb-toast-container", `tb-toast-container--${position}`),
1017
+ "aria-live": "polite",
1018
+ children: currentToasts.map((t) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1019
+ "div",
1020
+ {
1021
+ className: cn("tb-toast", `tb-toast--${t.type}`, "tb-toast--show"),
1022
+ role: "alert",
1023
+ children: [
1024
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "tb-toast__icon", "aria-hidden": "true", children: ICONS[t.type] }),
1025
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "tb-toast__content", children: [
1026
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "tb-toast__title", children: t.title }),
1027
+ t.description && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "tb-toast__description", children: t.description })
1028
+ ] }),
1029
+ t.action && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1030
+ "button",
1031
+ {
1032
+ type: "button",
1033
+ className: "tb-toast__action",
1034
+ onClick: () => {
1035
+ t.action.onClick();
1036
+ dismissToast(t.id);
1037
+ },
1038
+ children: t.action.label
1039
+ }
1040
+ ),
1041
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1042
+ "button",
1043
+ {
1044
+ type: "button",
1045
+ className: "tb-toast__dismiss",
1046
+ "aria-label": "Dismiss",
1047
+ onClick: () => dismissToast(t.id),
1048
+ children: "\xD7"
1049
+ }
1050
+ )
1051
+ ]
1052
+ },
1053
+ t.id
1054
+ ))
1055
+ }
1056
+ ) });
1057
+ }
1058
+
1059
+ // src/components/Tooltip.tsx
1060
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1061
+ function Tooltip({
1062
+ content,
1063
+ side = "top",
1064
+ align = "center",
1065
+ children,
1066
+ className,
1067
+ ref
1068
+ }) {
1069
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1070
+ "div",
1071
+ {
1072
+ ref,
1073
+ className: cn("tb-tooltip-wrap", className),
1074
+ children: [
1075
+ children,
1076
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1077
+ "span",
1078
+ {
1079
+ role: "tooltip",
1080
+ className: cn(
1081
+ "tb-tooltip",
1082
+ `tb-tooltip--${side}`,
1083
+ align !== "center" && `tb-tooltip--align-${align}`
1084
+ ),
1085
+ children: content
1086
+ }
1087
+ )
1088
+ ]
1089
+ }
1090
+ );
1091
+ }
1092
+
1093
+ // src/components/NavDropdown.tsx
1094
+ var import_react9 = require("react");
1095
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1096
+ function NavDropdown({ trigger, items, align = "left", className, ref }) {
1097
+ const [open, setOpen] = (0, import_react9.useState)(false);
1098
+ const rootRef = (0, import_react9.useRef)(null);
1099
+ (0, import_react9.useEffect)(() => {
1100
+ if (!open) return;
1101
+ function handlePointer(e) {
1102
+ if (rootRef.current && !rootRef.current.contains(e.target)) {
1103
+ setOpen(false);
1104
+ }
1105
+ }
1106
+ document.addEventListener("pointerdown", handlePointer);
1107
+ return () => document.removeEventListener("pointerdown", handlePointer);
1108
+ }, [open]);
1109
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1110
+ "div",
1111
+ {
1112
+ ref: (node) => {
1113
+ rootRef.current = node;
1114
+ if (typeof ref === "function") ref(node);
1115
+ else if (ref) ref.current = node;
1116
+ },
1117
+ className: cn("tb-nav-item", open && "tb-nav-item--open", align !== "left" && `tb-nav-item--align-${align}`, className),
1118
+ children: [
1119
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1120
+ "button",
1121
+ {
1122
+ type: "button",
1123
+ className: "tb-nav-item__trigger",
1124
+ onClick: () => setOpen(!open),
1125
+ children: [
1126
+ typeof trigger === "string" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: trigger }) : trigger,
1127
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "tb-nav-item__chevron", "aria-hidden": "true" })
1128
+ ]
1129
+ }
1130
+ ),
1131
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: cn("tb-nav-dropdown", open && "tb-nav-dropdown--open"), children: items.map((item, i) => {
1132
+ const content = /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1133
+ item.icon && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "tb-nav-dropdown__icon", children: item.icon }),
1134
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: item.label })
1135
+ ] });
1136
+ if (item.href) {
1137
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1138
+ "a",
1139
+ {
1140
+ href: item.href,
1141
+ className: "tb-nav-dropdown__item",
1142
+ onClick: () => {
1143
+ setOpen(false);
1144
+ item.onClick?.();
1145
+ },
1146
+ children: content
1147
+ },
1148
+ i
1149
+ );
1150
+ }
1151
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1152
+ "button",
1153
+ {
1154
+ type: "button",
1155
+ className: "tb-nav-dropdown__item",
1156
+ onClick: () => {
1157
+ setOpen(false);
1158
+ item.onClick?.();
1159
+ },
1160
+ children: content
1161
+ },
1162
+ i
1163
+ );
1164
+ }) })
1165
+ ]
1166
+ }
1167
+ );
1168
+ }
1169
+
1170
+ // src/components/Checkbox.tsx
1171
+ var import_react10 = require("react");
1172
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1173
+ function Checkbox({
1174
+ checked: controlledChecked,
1175
+ defaultChecked = false,
1176
+ onCheckedChange,
1177
+ disabled = false,
1178
+ label,
1179
+ error,
1180
+ ref,
1181
+ className
1182
+ }) {
1183
+ const [internalChecked, setInternalChecked] = (0, import_react10.useState)(defaultChecked);
1184
+ const isControlled = controlledChecked !== void 0;
1185
+ const isChecked = isControlled ? controlledChecked : internalChecked;
1186
+ function handleChange() {
1187
+ if (disabled) return;
1188
+ const next = !isChecked;
1189
+ if (!isControlled) setInternalChecked(next);
1190
+ onCheckedChange?.(next);
1191
+ }
1192
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
1193
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1194
+ "label",
1195
+ {
1196
+ className: cn(
1197
+ "tb-checkbox",
1198
+ error && "tb-checkbox--error",
1199
+ className
1200
+ ),
1201
+ children: [
1202
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1203
+ "input",
1204
+ {
1205
+ ref,
1206
+ type: "checkbox",
1207
+ checked: isChecked,
1208
+ disabled,
1209
+ onChange: handleChange
1210
+ }
1211
+ ),
1212
+ label && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: label })
1213
+ ]
1214
+ }
1215
+ ),
1216
+ error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { color: "var(--tb-error)", fontSize: "0.5rem", letterSpacing: "0.2em", marginTop: 4, display: "block" }, children: error })
1217
+ ] });
1218
+ }
1219
+
1220
+ // src/components/Toggle.tsx
1221
+ var import_react11 = require("react");
1222
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1223
+ function Toggle({
1224
+ checked: controlledChecked,
1225
+ defaultChecked = false,
1226
+ onCheckedChange,
1227
+ disabled = false,
1228
+ label,
1229
+ ref,
1230
+ className
1231
+ }) {
1232
+ const [internalChecked, setInternalChecked] = (0, import_react11.useState)(defaultChecked);
1233
+ const isControlled = controlledChecked !== void 0;
1234
+ const isChecked = isControlled ? controlledChecked : internalChecked;
1235
+ function handleChange() {
1236
+ if (disabled) return;
1237
+ const next = !isChecked;
1238
+ if (!isControlled) setInternalChecked(next);
1239
+ onCheckedChange?.(next);
1240
+ }
1241
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1242
+ "label",
1243
+ {
1244
+ className: cn(
1245
+ "tb-toggle",
1246
+ isChecked && "tb-toggle--checked",
1247
+ disabled && "tb-toggle--disabled",
1248
+ className
1249
+ ),
1250
+ children: [
1251
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1252
+ "input",
1253
+ {
1254
+ ref,
1255
+ type: "checkbox",
1256
+ className: "tb-toggle__input",
1257
+ checked: isChecked,
1258
+ disabled,
1259
+ onChange: handleChange
1260
+ }
1261
+ ),
1262
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "tb-toggle__track", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "tb-toggle__thumb" }) }),
1263
+ label && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "tb-toggle__label", children: label })
1264
+ ]
1265
+ }
1266
+ );
1267
+ }
1268
+
1269
+ // src/components/Radio.tsx
1270
+ var import_react12 = require("react");
1271
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1272
+ var RadioContext = (0, import_react12.createContext)(null);
1273
+ var radioGroupId = 0;
1274
+ function RadioGroup({
1275
+ value: controlledValue,
1276
+ defaultValue = "",
1277
+ onValueChange,
1278
+ disabled = false,
1279
+ label,
1280
+ orientation = "vertical",
1281
+ children,
1282
+ className
1283
+ }) {
1284
+ const [internalValue, setInternalValue] = (0, import_react12.useState)(defaultValue);
1285
+ const isControlled = controlledValue !== void 0;
1286
+ const currentValue = isControlled ? controlledValue : internalValue;
1287
+ const [name] = (0, import_react12.useState)(() => `tb-radio-group-${++radioGroupId}`);
1288
+ function handleChange(val) {
1289
+ if (!isControlled) setInternalValue(val);
1290
+ onValueChange?.(val);
1291
+ }
1292
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(RadioContext.Provider, { value: { value: currentValue, onChange: handleChange, disabled, name }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1293
+ "fieldset",
1294
+ {
1295
+ className: cn(
1296
+ "tb-radio-group",
1297
+ orientation === "horizontal" && "tb-radio-group--horizontal",
1298
+ disabled && "tb-radio-group--disabled",
1299
+ className
1300
+ ),
1301
+ disabled,
1302
+ children: [
1303
+ label && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("legend", { className: "tb-radio-group__label", children: label }),
1304
+ children
1305
+ ]
1306
+ }
1307
+ ) });
1308
+ }
1309
+ function RadioItem({
1310
+ value,
1311
+ label,
1312
+ disabled: itemDisabled = false,
1313
+ className
1314
+ }) {
1315
+ const ctx = (0, import_react12.useContext)(RadioContext);
1316
+ if (!ctx) throw new Error("RadioItem must be used within a RadioGroup");
1317
+ const isDisabled = ctx.disabled || itemDisabled;
1318
+ const isChecked = ctx.value === value;
1319
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1320
+ "label",
1321
+ {
1322
+ className: cn(
1323
+ "tb-radio",
1324
+ isChecked && "tb-radio--checked",
1325
+ isDisabled && "tb-radio--disabled",
1326
+ className
1327
+ ),
1328
+ children: [
1329
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1330
+ "input",
1331
+ {
1332
+ type: "radio",
1333
+ name: ctx.name,
1334
+ value,
1335
+ checked: isChecked,
1336
+ disabled: isDisabled,
1337
+ onChange: () => ctx.onChange(value)
1338
+ }
1339
+ ),
1340
+ label
1341
+ ]
1342
+ }
1343
+ );
1344
+ }
1345
+
1346
+ // src/components/Progress.tsx
1347
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1348
+ function Progress({
1349
+ value,
1350
+ variant = "default",
1351
+ animated = false,
1352
+ indeterminate = false,
1353
+ label,
1354
+ showValue = false,
1355
+ className
1356
+ }) {
1357
+ const clampedValue = Math.max(0, Math.min(100, value));
1358
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
1359
+ "div",
1360
+ {
1361
+ className: cn(
1362
+ "tb-progress",
1363
+ variant !== "default" && `tb-progress--${variant}`,
1364
+ animated && "tb-progress--animated",
1365
+ indeterminate && "tb-progress--indeterminate",
1366
+ className
1367
+ ),
1368
+ role: "progressbar",
1369
+ "aria-valuenow": indeterminate ? void 0 : clampedValue,
1370
+ "aria-valuemin": 0,
1371
+ "aria-valuemax": 100,
1372
+ "aria-label": label,
1373
+ children: [
1374
+ label && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "tb-progress__label", children: label }),
1375
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "tb-progress__track", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1376
+ "div",
1377
+ {
1378
+ className: "tb-progress__fill",
1379
+ style: indeterminate ? void 0 : { width: `${clampedValue}%` }
1380
+ }
1381
+ ) }),
1382
+ showValue && !indeterminate && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "tb-progress__value", children: [
1383
+ clampedValue,
1384
+ "%"
1385
+ ] })
1386
+ ]
1387
+ }
1388
+ );
1389
+ }
1390
+
1391
+ // src/components/Battery.tsx
1392
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1393
+ function Battery({
1394
+ value,
1395
+ total = 10,
1396
+ variant = "default",
1397
+ animated = false,
1398
+ label,
1399
+ className
1400
+ }) {
1401
+ const clampedValue = Math.max(0, Math.min(total, value));
1402
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
1403
+ "div",
1404
+ {
1405
+ className: cn(
1406
+ "tb-battery",
1407
+ variant !== "default" && `tb-battery--${variant}`,
1408
+ animated && "tb-battery--animated",
1409
+ className
1410
+ ),
1411
+ role: "meter",
1412
+ "aria-valuenow": clampedValue,
1413
+ "aria-valuemin": 0,
1414
+ "aria-valuemax": total,
1415
+ "aria-label": label,
1416
+ children: [
1417
+ label && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "tb-battery__label", children: label }),
1418
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "tb-battery__body", children: [
1419
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "tb-battery__cap" }),
1420
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "tb-battery__segments", children: Array.from({ length: total }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1421
+ "div",
1422
+ {
1423
+ className: cn(
1424
+ "tb-battery__segment",
1425
+ i < clampedValue && "tb-battery__segment--filled"
1426
+ )
1427
+ },
1428
+ i
1429
+ )) })
1430
+ ] })
1431
+ ]
1432
+ }
1433
+ );
1434
+ }
1435
+
1436
+ // src/components/BatteryInline.tsx
1437
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1438
+ function BatteryInline({
1439
+ value,
1440
+ total = 10,
1441
+ variant = "default",
1442
+ animated = false,
1443
+ label,
1444
+ showValue = false,
1445
+ className
1446
+ }) {
1447
+ const clampedValue = Math.max(0, Math.min(total, value));
1448
+ const percent = Math.round(clampedValue / total * 100);
1449
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1450
+ "div",
1451
+ {
1452
+ className: cn(
1453
+ "tb-battery tb-battery--inline",
1454
+ animated && "tb-battery--animated",
1455
+ className
1456
+ ),
1457
+ role: "meter",
1458
+ "aria-valuenow": clampedValue,
1459
+ "aria-valuemin": 0,
1460
+ "aria-valuemax": total,
1461
+ "aria-label": label,
1462
+ children: [
1463
+ label && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "tb-battery__label", children: label }),
1464
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "tb-battery__track", children: Array.from({ length: total }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1465
+ "div",
1466
+ {
1467
+ className: cn(
1468
+ "tb-battery__segment",
1469
+ i < clampedValue && "tb-battery__segment--filled",
1470
+ i < clampedValue && variant !== "default" && `tb-battery__segment--${variant}`
1471
+ )
1472
+ },
1473
+ i
1474
+ )) }),
1475
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "tb-battery__cap" }),
1476
+ showValue && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "tb-battery__value", children: [
1477
+ percent,
1478
+ "%"
1479
+ ] })
1480
+ ]
1481
+ }
1482
+ );
1483
+ }
1484
+
1485
+ // src/components/Table.tsx
1486
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1487
+ function getCellValue(row, accessor) {
1488
+ if (typeof accessor === "function") return accessor(row);
1489
+ return row[accessor];
1490
+ }
1491
+ function Table({
1492
+ columns,
1493
+ data,
1494
+ onRowClick,
1495
+ className
1496
+ }) {
1497
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cn("tb-table__wrapper", className), children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("table", { className: "tb-table", children: [
1498
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("thead", { className: "tb-table__head", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("tr", { className: "tb-table__row", children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("th", { className: "tb-table__th", children: col.header }, col.id)) }) }),
1499
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("tbody", { className: "tb-table__body", children: data.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1500
+ "tr",
1501
+ {
1502
+ className: cn(
1503
+ "tb-table__row",
1504
+ onRowClick && "tb-table__row--clickable"
1505
+ ),
1506
+ onClick: onRowClick ? () => onRowClick(row) : void 0,
1507
+ children: columns.map((col) => {
1508
+ const value = getCellValue(row, col.accessor);
1509
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("td", { className: "tb-table__td", children: col.cell ? col.cell(value, row) : value }, col.id);
1510
+ })
1511
+ },
1512
+ rowIndex
1513
+ )) })
1514
+ ] }) });
1515
+ }
1516
+
1517
+ // src/components/Skeleton.tsx
1518
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1519
+ function Skeleton({
1520
+ variant = "text",
1521
+ width,
1522
+ height,
1523
+ lines = 1,
1524
+ className
1525
+ }) {
1526
+ const style = {
1527
+ width: typeof width === "number" ? `${width}px` : width,
1528
+ height: typeof height === "number" ? `${height}px` : height
1529
+ };
1530
+ if (variant === "text" && lines > 1) {
1531
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: cn("tb-skeleton__group", className), children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1532
+ "div",
1533
+ {
1534
+ className: cn(
1535
+ "tb-skeleton",
1536
+ "tb-skeleton--text"
1537
+ ),
1538
+ style: i === lines - 1 ? { ...style, width: style.width ?? "75%" } : style
1539
+ },
1540
+ i
1541
+ )) });
1542
+ }
1543
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1544
+ "div",
1545
+ {
1546
+ className: cn(
1547
+ "tb-skeleton",
1548
+ `tb-skeleton--${variant}`,
1549
+ className
1550
+ ),
1551
+ style
1552
+ }
1553
+ );
1554
+ }
1555
+
1556
+ // src/components/Spinner.tsx
1557
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1558
+ function Spinner({
1559
+ variant = "multi-square",
1560
+ size = "md",
1561
+ className
1562
+ }) {
1563
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1564
+ "span",
1565
+ {
1566
+ className: cn(
1567
+ "tb-spinner",
1568
+ `tb-spinner--${variant}`,
1569
+ size !== "md" && `tb-spinner--${size}`,
1570
+ className
1571
+ ),
1572
+ role: "status",
1573
+ "aria-label": "Loading",
1574
+ children: variant === "multi-square" && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
1575
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "tb-spinner__square" }),
1576
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "tb-spinner__square" }),
1577
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "tb-spinner__square" }),
1578
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "tb-spinner__square" }),
1579
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "tb-spinner__square" })
1580
+ ] })
1581
+ }
1582
+ );
1583
+ }
1584
+
1585
+ // src/components/Pagination.tsx
1586
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1587
+ function getPageRange(page, totalPages, siblingCount) {
1588
+ const totalSlots = siblingCount * 2 + 5;
1589
+ if (totalPages <= totalSlots) {
1590
+ return Array.from({ length: totalPages }, (_, i) => i + 1);
1591
+ }
1592
+ const leftSibling = Math.max(page - siblingCount, 2);
1593
+ const rightSibling = Math.min(page + siblingCount, totalPages - 1);
1594
+ const showLeftEllipsis = leftSibling > 2;
1595
+ const showRightEllipsis = rightSibling < totalPages - 1;
1596
+ const pages = [1];
1597
+ if (showLeftEllipsis) {
1598
+ pages.push("ellipsis");
1599
+ } else {
1600
+ for (let i = 2; i < leftSibling; i++) pages.push(i);
1601
+ }
1602
+ for (let i = leftSibling; i <= rightSibling; i++) pages.push(i);
1603
+ if (showRightEllipsis) {
1604
+ pages.push("ellipsis");
1605
+ } else {
1606
+ for (let i = rightSibling + 1; i < totalPages; i++) pages.push(i);
1607
+ }
1608
+ pages.push(totalPages);
1609
+ return pages;
1610
+ }
1611
+ function Pagination({
1612
+ page,
1613
+ totalPages,
1614
+ onPageChange,
1615
+ siblingCount = 1,
1616
+ className
1617
+ }) {
1618
+ const pages = getPageRange(page, totalPages, siblingCount);
1619
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("nav", { className: cn("tb-pagination", className), "aria-label": "Pagination", children: [
1620
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1621
+ "button",
1622
+ {
1623
+ className: "tb-pagination__btn tb-pagination__btn--prev",
1624
+ disabled: page <= 1,
1625
+ onClick: () => onPageChange(page - 1),
1626
+ "aria-label": "Previous page",
1627
+ children: "\u2039"
1628
+ }
1629
+ ),
1630
+ pages.map(
1631
+ (p, i) => p === "ellipsis" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "tb-pagination__ellipsis", children: "..." }, `ellipsis-${i}`) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1632
+ "button",
1633
+ {
1634
+ className: cn(
1635
+ "tb-pagination__btn",
1636
+ p === page && "tb-pagination__btn--active"
1637
+ ),
1638
+ onClick: () => onPageChange(p),
1639
+ "aria-current": p === page ? "page" : void 0,
1640
+ children: p
1641
+ },
1642
+ p
1643
+ )
1644
+ ),
1645
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1646
+ "button",
1647
+ {
1648
+ className: "tb-pagination__btn tb-pagination__btn--next",
1649
+ disabled: page >= totalPages,
1650
+ onClick: () => onPageChange(page + 1),
1651
+ "aria-label": "Next page",
1652
+ children: "\u203A"
1653
+ }
1654
+ )
1655
+ ] });
1656
+ }
1657
+
1658
+ // src/components/Breadcrumbs.tsx
1659
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1660
+ function Breadcrumbs({
1661
+ items,
1662
+ separator = "/",
1663
+ linkComponent,
1664
+ className
1665
+ }) {
1666
+ const LinkComponent = linkComponent || "a";
1667
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("nav", { className: cn("tb-breadcrumbs", className), "aria-label": "Breadcrumb", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("ol", { className: "tb-breadcrumbs__list", children: items.map((item, i) => {
1668
+ const isLast = i === items.length - 1;
1669
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("li", { className: "tb-breadcrumbs__item", children: [
1670
+ item.href && !isLast ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(LinkComponent, { href: item.href, className: "tb-breadcrumbs__link", children: item.label }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1671
+ "span",
1672
+ {
1673
+ className: "tb-breadcrumbs__current",
1674
+ "aria-current": isLast ? "page" : void 0,
1675
+ children: item.label
1676
+ }
1677
+ ),
1678
+ !isLast && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "tb-breadcrumbs__separator", "aria-hidden": "true", children: separator })
1679
+ ] }, i);
1680
+ }) }) });
1681
+ }
1682
+
1683
+ // src/components/Toolbar.tsx
1684
+ var import_react13 = require("react");
1685
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1686
+ function ToolbarSelect({
1687
+ options,
1688
+ value: controlledValue,
1689
+ defaultValue,
1690
+ onChange,
1691
+ dropDown = false,
1692
+ minWidth,
1693
+ className
1694
+ }) {
1695
+ const [internalValue, setInternalValue] = (0, import_react13.useState)(defaultValue ?? options[0]?.value ?? "");
1696
+ const [open, setOpen] = (0, import_react13.useState)(false);
1697
+ const ref = (0, import_react13.useRef)(null);
1698
+ const value = controlledValue ?? internalValue;
1699
+ const activeOption = options.find((o) => o.value === value);
1700
+ (0, import_react13.useEffect)(() => {
1701
+ function handleClick(e) {
1702
+ if (ref.current && !ref.current.contains(e.target)) {
1703
+ setOpen(false);
1704
+ }
1705
+ }
1706
+ document.addEventListener("click", handleClick);
1707
+ return () => document.removeEventListener("click", handleClick);
1708
+ }, []);
1709
+ function select(opt) {
1710
+ if (controlledValue === void 0) setInternalValue(opt.value);
1711
+ onChange?.(opt.value);
1712
+ setOpen(false);
1713
+ }
1714
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1715
+ "div",
1716
+ {
1717
+ ref,
1718
+ className: cn("tb-toolbar__select", open && "tb-toolbar__select--open", className),
1719
+ children: [
1720
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1721
+ "button",
1722
+ {
1723
+ type: "button",
1724
+ className: "tb-toolbar__trigger",
1725
+ style: minWidth ? { minWidth } : void 0,
1726
+ onClick: (e) => {
1727
+ e.stopPropagation();
1728
+ setOpen(!open);
1729
+ },
1730
+ children: [
1731
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: activeOption?.label ?? "" }),
1732
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "tb-toolbar__chevron" })
1733
+ ]
1734
+ }
1735
+ ),
1736
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: cn("tb-toolbar__dropdown", dropDown && "tb-toolbar__dropdown--down"), children: options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1737
+ "div",
1738
+ {
1739
+ className: cn("tb-toolbar__option", opt.value === value && "tb-toolbar__option--active"),
1740
+ style: { fontFamily: opt.value },
1741
+ onClick: () => select(opt),
1742
+ children: [
1743
+ opt.label,
1744
+ opt.meta && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "tb-toolbar__option-meta", children: opt.meta })
1745
+ ]
1746
+ },
1747
+ opt.value
1748
+ )) })
1749
+ ]
1750
+ }
1751
+ );
1752
+ }
1753
+ function ToolbarLabel({ children, className, ...props }) {
1754
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: cn("tb-toolbar__label", className), ...props, children });
1755
+ }
1756
+ function ToolbarDivider({ className, ...props }) {
1757
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: cn("tb-toolbar__divider", className), ...props });
1758
+ }
1759
+ function ToolbarRoot({ position, fixed = false, children, className, ref, ...props }) {
1760
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1761
+ "div",
1762
+ {
1763
+ ref,
1764
+ className: cn(
1765
+ "tb-toolbar",
1766
+ fixed && "tb-toolbar--fixed",
1767
+ position && `tb-toolbar--${position}`,
1768
+ className
1769
+ ),
1770
+ ...props,
1771
+ children
1772
+ }
1773
+ );
1774
+ }
1775
+ var Toolbar = Object.assign(ToolbarRoot, {
1776
+ Label: ToolbarLabel,
1777
+ Select: ToolbarSelect,
1778
+ Divider: ToolbarDivider
1779
+ });
1780
+
1781
+ // src/components/Sidenav/Sidenav.tsx
1782
+ var import_react14 = require("react");
1783
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1784
+ var SidenavContext = (0, import_react14.createContext)({
1785
+ iconPosition: "left",
1786
+ borderSide: "left"
1787
+ });
1788
+ function SidenavRoot({
1789
+ iconPosition = "left",
1790
+ borderSide = "left",
1791
+ className,
1792
+ children,
1793
+ ref,
1794
+ ...props
1795
+ }) {
1796
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(SidenavContext.Provider, { value: { iconPosition, borderSide }, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1797
+ "nav",
1798
+ {
1799
+ ref,
1800
+ className: cn(
1801
+ "tb-sidenav",
1802
+ iconPosition === "right" && "tb-sidenav--icon-right",
1803
+ borderSide === "right" && "tb-sidenav--border-right",
1804
+ className
1805
+ ),
1806
+ ...props,
1807
+ children
1808
+ }
1809
+ ) });
1810
+ }
1811
+ function Item({
1812
+ as,
1813
+ active = false,
1814
+ className,
1815
+ children,
1816
+ ref,
1817
+ ...props
1818
+ }) {
1819
+ const Component = as || "a";
1820
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1821
+ Component,
1822
+ {
1823
+ ref,
1824
+ className: cn(
1825
+ "tb-sidenav__item",
1826
+ active && "tb-sidenav__item--active",
1827
+ className
1828
+ ),
1829
+ ...props,
1830
+ children
1831
+ }
1832
+ );
1833
+ }
1834
+ function Icon({ className, ref, ...props }) {
1835
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1836
+ "span",
1837
+ {
1838
+ ref,
1839
+ className: cn("tb-sidenav__icon", className),
1840
+ ...props
1841
+ }
1842
+ );
1843
+ }
1844
+ function Group({
1845
+ label,
1846
+ icon,
1847
+ defaultOpen = false,
1848
+ open: controlledOpen,
1849
+ onOpenChange,
1850
+ className,
1851
+ children,
1852
+ ref,
1853
+ ...props
1854
+ }) {
1855
+ const [internalOpen, setInternalOpen] = (0, import_react14.useState)(defaultOpen);
1856
+ const isControlled = controlledOpen !== void 0;
1857
+ const isOpen = isControlled ? controlledOpen : internalOpen;
1858
+ function toggle() {
1859
+ const next = !isOpen;
1860
+ if (!isControlled) setInternalOpen(next);
1861
+ onOpenChange?.(next);
1862
+ }
1863
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
1864
+ "div",
1865
+ {
1866
+ ref,
1867
+ className: cn(
1868
+ "tb-sidenav__group",
1869
+ isOpen && "tb-sidenav__group--open",
1870
+ className
1871
+ ),
1872
+ ...props,
1873
+ children: [
1874
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
1875
+ "button",
1876
+ {
1877
+ type: "button",
1878
+ className: "tb-sidenav__group-trigger",
1879
+ onClick: toggle,
1880
+ "aria-expanded": isOpen,
1881
+ children: [
1882
+ icon && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "tb-sidenav__icon", children: icon }),
1883
+ label,
1884
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "tb-sidenav__group-chevron material-symbols-outlined", "aria-hidden": "true", children: "expand_more" })
1885
+ ]
1886
+ }
1887
+ ),
1888
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "tb-sidenav__group-content", children })
1889
+ ]
1890
+ }
1891
+ );
1892
+ }
1893
+ var Sidenav = Object.assign(SidenavRoot, {
1894
+ Item,
1895
+ Icon,
1896
+ Group
1897
+ });
1898
+
1899
+ // src/components/CodeBlock.tsx
1900
+ var import_react15 = require("react");
1901
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1902
+ function CodeBlock({ children, copyText, className, ref, ...props }) {
1903
+ const [copied, setCopied] = (0, import_react15.useState)(false);
1904
+ const contentRef = (0, import_react15.useRef)(null);
1905
+ async function handleCopy() {
1906
+ const text = copyText ?? contentRef.current?.textContent ?? "";
1907
+ await navigator.clipboard.writeText(text);
1908
+ setCopied(true);
1909
+ setTimeout(() => setCopied(false), 2e3);
1910
+ }
1911
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { ref, className: cn("tb-code-block", className), ...props, children: [
1912
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { ref: contentRef, children }),
1913
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1914
+ "button",
1915
+ {
1916
+ type: "button",
1917
+ className: cn("tb-code-block__copy", copied && "tb-code-block__copy--copied"),
1918
+ onClick: handleCopy,
1919
+ "aria-label": copied ? "Copied" : "Copy to clipboard",
1920
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 14 }, children: copied ? "check" : "content_copy" })
1921
+ }
1922
+ )
1923
+ ] });
1924
+ }
1925
+
1926
+ // src/components/ThemeProvider.tsx
1927
+ var import_react16 = require("react");
1928
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1929
+ var ThemeContext = (0, import_react16.createContext)(null);
1930
+ function useTheme() {
1931
+ const ctx = (0, import_react16.useContext)(ThemeContext);
1932
+ if (!ctx) throw new Error("useTheme must be used within <ThemeProvider>");
1933
+ return ctx;
1934
+ }
1935
+ function ThemeProvider({
1936
+ theme: controlledTheme,
1937
+ contrast: controlledContrast,
1938
+ defaultTheme = "dark",
1939
+ defaultContrast = "enhanced",
1940
+ onThemeChange,
1941
+ onContrastChange,
1942
+ children
1943
+ }) {
1944
+ const isThemeControlled = controlledTheme !== void 0;
1945
+ const isContrastControlled = controlledContrast !== void 0;
1946
+ const [internalTheme, setInternalTheme] = (0, import_react16.useState)(defaultTheme);
1947
+ const [internalContrast, setInternalContrast] = (0, import_react16.useState)(defaultContrast);
1948
+ const theme = isThemeControlled ? controlledTheme : internalTheme;
1949
+ const contrast = isContrastControlled ? controlledContrast : internalContrast;
1950
+ const setTheme = (0, import_react16.useCallback)(
1951
+ (next) => {
1952
+ if (!isThemeControlled) setInternalTheme(next);
1953
+ onThemeChange?.(next);
1954
+ },
1955
+ [isThemeControlled, onThemeChange]
1956
+ );
1957
+ const setContrast = (0, import_react16.useCallback)(
1958
+ (next) => {
1959
+ if (!isContrastControlled) setInternalContrast(next);
1960
+ onContrastChange?.(next);
1961
+ },
1962
+ [isContrastControlled, onContrastChange]
1963
+ );
1964
+ const toggleTheme = (0, import_react16.useCallback)(
1965
+ () => setTheme(theme === "dark" ? "light" : "dark"),
1966
+ [theme, setTheme]
1967
+ );
1968
+ (0, import_react16.useEffect)(() => {
1969
+ const root = document.documentElement;
1970
+ root.setAttribute("data-theme", theme);
1971
+ if (contrast === "high") {
1972
+ root.setAttribute("data-contrast", "high");
1973
+ } else {
1974
+ root.removeAttribute("data-contrast");
1975
+ }
1976
+ }, [theme, contrast]);
1977
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ThemeContext.Provider, { value: { theme, setTheme, contrast, setContrast, toggleTheme }, children });
1978
+ }
1979
+
1980
+ // src/hooks/useDisclosure.ts
1981
+ var import_react17 = require("react");
1982
+ function useDisclosure(options = {}) {
1983
+ const { defaultOpen = false, onOpen: onOpenCallback, onClose: onCloseCallback } = options;
1984
+ const [isOpen, setIsOpen] = (0, import_react17.useState)(defaultOpen);
1985
+ const onOpen = (0, import_react17.useCallback)(() => {
1986
+ setIsOpen(true);
1987
+ onOpenCallback?.();
1988
+ }, [onOpenCallback]);
1989
+ const onClose = (0, import_react17.useCallback)(() => {
1990
+ setIsOpen(false);
1991
+ onCloseCallback?.();
1992
+ }, [onCloseCallback]);
1993
+ const onToggle = (0, import_react17.useCallback)(() => {
1994
+ if (isOpen) {
1995
+ onClose();
1996
+ } else {
1997
+ onOpen();
1998
+ }
1999
+ }, [isOpen, onOpen, onClose]);
2000
+ return { isOpen, onOpen, onClose, onToggle };
2001
+ }
2002
+
2003
+ // src/hooks/useFocusTrap.ts
2004
+ var import_react18 = require("react");
2005
+ var FOCUSABLE_SELECTOR = [
2006
+ "a[href]",
2007
+ "button:not([disabled])",
2008
+ "input:not([disabled])",
2009
+ "textarea:not([disabled])",
2010
+ "select:not([disabled])",
2011
+ '[tabindex]:not([tabindex="-1"])'
2012
+ ].join(", ");
2013
+ function useFocusTrap(ref, active) {
2014
+ const previouslyFocusedRef = (0, import_react18.useRef)(null);
2015
+ (0, import_react18.useEffect)(() => {
2016
+ if (!active || !ref.current) return;
2017
+ previouslyFocusedRef.current = document.activeElement;
2018
+ const container = ref.current;
2019
+ const focusableElements = container.querySelectorAll(FOCUSABLE_SELECTOR);
2020
+ if (focusableElements.length > 0) {
2021
+ focusableElements[0].focus();
2022
+ }
2023
+ function handleKeyDown(e) {
2024
+ if (e.key !== "Tab") return;
2025
+ const focusable = container.querySelectorAll(FOCUSABLE_SELECTOR);
2026
+ if (focusable.length === 0) return;
2027
+ const first = focusable[0];
2028
+ const last = focusable[focusable.length - 1];
2029
+ if (e.shiftKey) {
2030
+ if (document.activeElement === first) {
2031
+ e.preventDefault();
2032
+ last.focus();
2033
+ }
2034
+ } else {
2035
+ if (document.activeElement === last) {
2036
+ e.preventDefault();
2037
+ first.focus();
2038
+ }
2039
+ }
2040
+ }
2041
+ document.addEventListener("keydown", handleKeyDown);
2042
+ return () => {
2043
+ document.removeEventListener("keydown", handleKeyDown);
2044
+ if (previouslyFocusedRef.current && typeof previouslyFocusedRef.current.focus === "function") {
2045
+ previouslyFocusedRef.current.focus();
2046
+ }
2047
+ };
2048
+ }, [active, ref]);
2049
+ }
2050
+
2051
+ // src/hooks/useKeyboardNav.ts
2052
+ var import_react19 = require("react");
2053
+ function useKeyboardNav(items, options = {}) {
2054
+ const { orientation = "vertical", loop = true, onSelect } = options;
2055
+ const [activeIndex, setActiveIndex] = (0, import_react19.useState)(0);
2056
+ const prevKey = orientation === "vertical" ? "ArrowUp" : "ArrowLeft";
2057
+ const nextKey = orientation === "vertical" ? "ArrowDown" : "ArrowRight";
2058
+ const onKeyDown = (0, import_react19.useCallback)(
2059
+ (e) => {
2060
+ const list = items.current;
2061
+ if (!list || list.length === 0) return;
2062
+ const count = list.length;
2063
+ if (e.key === nextKey) {
2064
+ e.preventDefault();
2065
+ setActiveIndex((prev) => {
2066
+ const next = prev + 1;
2067
+ if (next >= count) {
2068
+ const wrapped = loop ? 0 : prev;
2069
+ list[wrapped]?.focus();
2070
+ return wrapped;
2071
+ }
2072
+ list[next]?.focus();
2073
+ return next;
2074
+ });
2075
+ } else if (e.key === prevKey) {
2076
+ e.preventDefault();
2077
+ setActiveIndex((prev) => {
2078
+ const next = prev - 1;
2079
+ if (next < 0) {
2080
+ const wrapped = loop ? count - 1 : prev;
2081
+ list[wrapped]?.focus();
2082
+ return wrapped;
2083
+ }
2084
+ list[next]?.focus();
2085
+ return next;
2086
+ });
2087
+ } else if (e.key === "Enter" || e.key === " ") {
2088
+ e.preventDefault();
2089
+ onSelect?.(activeIndex);
2090
+ } else if (e.key === "Home") {
2091
+ e.preventDefault();
2092
+ setActiveIndex(0);
2093
+ list[0]?.focus();
2094
+ } else if (e.key === "End") {
2095
+ e.preventDefault();
2096
+ const last = count - 1;
2097
+ setActiveIndex(last);
2098
+ list[last]?.focus();
2099
+ }
2100
+ },
2101
+ [items, activeIndex, prevKey, nextKey, loop, onSelect]
2102
+ );
2103
+ return { activeIndex, setActiveIndex, onKeyDown };
2104
+ }
2105
+
2106
+ // src/hooks/useReducedMotion.ts
2107
+ var import_react20 = require("react");
2108
+ function useReducedMotion() {
2109
+ const [reduced, setReduced] = (0, import_react20.useState)(false);
2110
+ (0, import_react20.useEffect)(() => {
2111
+ const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
2112
+ setReduced(mq.matches);
2113
+ const handler = (e) => setReduced(e.matches);
2114
+ mq.addEventListener("change", handler);
2115
+ return () => mq.removeEventListener("change", handler);
2116
+ }, []);
2117
+ return reduced;
2118
+ }
2119
+
2120
+ // src/hooks/useMergedRef.ts
2121
+ var import_react21 = require("react");
2122
+ function useMergedRef(...refs) {
2123
+ return (0, import_react21.useCallback)((node) => {
2124
+ refs.forEach((ref) => {
2125
+ if (typeof ref === "function") ref(node);
2126
+ else if (ref) ref.current = node;
2127
+ });
2128
+ }, refs);
2129
+ }
2130
+ // Annotate the CommonJS export names for ESM import in node:
2131
+ 0 && (module.exports = {
2132
+ Badge,
2133
+ Battery,
2134
+ BatteryInline,
2135
+ Breadcrumbs,
2136
+ Button,
2137
+ Card,
2138
+ Checkbox,
2139
+ CodeBlock,
2140
+ CornerBrackets,
2141
+ Input,
2142
+ Modal,
2143
+ NavDropdown,
2144
+ Pagination,
2145
+ Progress,
2146
+ RadioGroup,
2147
+ RadioItem,
2148
+ SafePortal,
2149
+ Select,
2150
+ SelectContent,
2151
+ SelectItem,
2152
+ SelectTrigger,
2153
+ Sidenav,
2154
+ Skeleton,
2155
+ Spinner,
2156
+ Table,
2157
+ Tabs,
2158
+ TabsContent,
2159
+ TabsList,
2160
+ TabsTrigger,
2161
+ Tag,
2162
+ Textarea,
2163
+ ThemeProvider,
2164
+ TitleLine,
2165
+ Toaster,
2166
+ Toggle,
2167
+ Toolbar,
2168
+ Tooltip,
2169
+ cn,
2170
+ toast,
2171
+ useDisclosure,
2172
+ useFocusTrap,
2173
+ useKeyboardNav,
2174
+ useMergedRef,
2175
+ useReducedMotion,
2176
+ useTheme
2177
+ });
2178
+ //# sourceMappingURL=index.cjs.map