@holmdigital/components 1.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.
Files changed (43) hide show
  1. package/README.md +46 -0
  2. package/dist/Button/Button.js +117 -0
  3. package/dist/Button/Button.mjs +6 -0
  4. package/dist/Checkbox/Checkbox.js +82 -0
  5. package/dist/Checkbox/Checkbox.mjs +6 -0
  6. package/dist/Dialog/Dialog.js +129 -0
  7. package/dist/Dialog/Dialog.mjs +6 -0
  8. package/dist/FormField/FormField.js +110 -0
  9. package/dist/FormField/FormField.mjs +6 -0
  10. package/dist/Heading/Heading.js +48 -0
  11. package/dist/Heading/Heading.mjs +6 -0
  12. package/dist/Modal/Modal.js +146 -0
  13. package/dist/Modal/Modal.mjs +7 -0
  14. package/dist/NavigationMenu/NavigationMenu.js +141 -0
  15. package/dist/NavigationMenu/NavigationMenu.mjs +6 -0
  16. package/dist/RadioGroup/RadioGroup.js +103 -0
  17. package/dist/RadioGroup/RadioGroup.mjs +6 -0
  18. package/dist/Select/Select.js +157 -0
  19. package/dist/Select/Select.mjs +12 -0
  20. package/dist/SkipLink/SkipLink.js +59 -0
  21. package/dist/SkipLink/SkipLink.mjs +6 -0
  22. package/dist/Switch/Switch.js +82 -0
  23. package/dist/Switch/Switch.mjs +6 -0
  24. package/dist/Toast/Toast.js +123 -0
  25. package/dist/Toast/Toast.mjs +8 -0
  26. package/dist/Tooltip/Tooltip.js +121 -0
  27. package/dist/Tooltip/Tooltip.mjs +12 -0
  28. package/dist/chunk-2MJRKHPL.mjs +98 -0
  29. package/dist/chunk-5RKBS475.mjs +58 -0
  30. package/dist/chunk-C5M6C7KT.mjs +84 -0
  31. package/dist/chunk-GK4BYT56.mjs +117 -0
  32. package/dist/chunk-HALLFO25.mjs +22 -0
  33. package/dist/chunk-LZ42XDDI.mjs +105 -0
  34. package/dist/chunk-MKKQLWGK.mjs +35 -0
  35. package/dist/chunk-NDYRGXQ6.mjs +93 -0
  36. package/dist/chunk-NOE5QKC2.mjs +58 -0
  37. package/dist/chunk-PLT5CAFO.mjs +86 -0
  38. package/dist/chunk-V2JYAFB7.mjs +130 -0
  39. package/dist/chunk-W4ZHBRFT.mjs +14 -0
  40. package/dist/chunk-YMSNGQN6.mjs +79 -0
  41. package/dist/index.js +1256 -0
  42. package/dist/index.mjs +308 -0
  43. package/package.json +113 -0
package/dist/index.js ADDED
@@ -0,0 +1,1256 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ Accordion: () => Accordion,
34
+ AccordionContent: () => AccordionContent,
35
+ AccordionItem: () => AccordionItem,
36
+ AccordionTrigger: () => AccordionTrigger,
37
+ BreadcrumbItem: () => BreadcrumbItem,
38
+ Breadcrumbs: () => Breadcrumbs,
39
+ Button: () => Button,
40
+ Checkbox: () => Checkbox,
41
+ Dialog: () => Dialog,
42
+ FormField: () => FormField,
43
+ Heading: () => Heading,
44
+ Modal: () => Modal,
45
+ NavigationMenu: () => NavigationMenu,
46
+ RadioGroup: () => RadioGroup,
47
+ Select: () => Select,
48
+ SelectContent: () => SelectContent,
49
+ SelectItem: () => SelectItem,
50
+ SelectTrigger: () => SelectTrigger,
51
+ SkipLink: () => SkipLink,
52
+ Switch: () => Switch,
53
+ TabTrigger: () => TabTrigger,
54
+ Tabs: () => Tabs,
55
+ TabsContent: () => TabsContent,
56
+ TabsList: () => TabsList,
57
+ ToastProvider: () => ToastProvider,
58
+ Tooltip: () => Tooltip,
59
+ TooltipContent: () => TooltipContent,
60
+ TooltipProvider: () => TooltipProvider,
61
+ TooltipTrigger: () => TooltipTrigger,
62
+ useToast: () => useToast
63
+ });
64
+ module.exports = __toCommonJS(index_exports);
65
+
66
+ // src/Button/Button.tsx
67
+ var import_react = require("react");
68
+ var import_jsx_runtime = require("react/jsx-runtime");
69
+ var Button = (0, import_react.forwardRef)(
70
+ ({
71
+ children,
72
+ variant = "primary",
73
+ size = "medium",
74
+ isLoading,
75
+ disabled,
76
+ className = "",
77
+ ...props
78
+ }, ref) => {
79
+ const baseStyles = {
80
+ display: "inline-flex",
81
+ alignItems: "center",
82
+ justifyContent: "center",
83
+ borderRadius: "4px",
84
+ border: "none",
85
+ cursor: disabled || isLoading ? "not-allowed" : "pointer",
86
+ fontFamily: "inherit",
87
+ fontWeight: "600",
88
+ transition: "all 0.2s ease",
89
+ // Garantera synlig fokusindikator (WCAG 2.4.7)
90
+ outlineOffset: "2px"
91
+ };
92
+ const variants = {
93
+ primary: {
94
+ background: "#0056b3",
95
+ // AA Large, AAA Normal mot vit text
96
+ color: "#ffffff"
97
+ },
98
+ secondary: {
99
+ background: "#f8f9fa",
100
+ color: "#212529",
101
+ border: "1px solid #dee2e6"
102
+ },
103
+ danger: {
104
+ background: "#dc3545",
105
+ color: "#ffffff"
106
+ },
107
+ ghost: {
108
+ background: "transparent",
109
+ color: "#0056b3"
110
+ }
111
+ };
112
+ const sizes = {
113
+ small: {
114
+ padding: "0.25rem 0.5rem",
115
+ fontSize: "0.875rem",
116
+ minHeight: "32px"
117
+ // OBS: Kan bryta mot 44px om inte hanteras med margin
118
+ },
119
+ medium: {
120
+ padding: "0.5rem 1rem",
121
+ fontSize: "1rem",
122
+ minHeight: "44px"
123
+ // Touch target safe
124
+ },
125
+ large: {
126
+ padding: "0.75rem 1.5rem",
127
+ fontSize: "1.25rem",
128
+ minHeight: "56px"
129
+ }
130
+ };
131
+ const style = {
132
+ ...baseStyles,
133
+ ...variants[variant],
134
+ ...sizes[size],
135
+ opacity: disabled || isLoading ? 0.65 : 1
136
+ };
137
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
138
+ "button",
139
+ {
140
+ ref,
141
+ style,
142
+ disabled: disabled || isLoading,
143
+ "aria-busy": isLoading,
144
+ tabIndex: props.tabIndex,
145
+ ...props,
146
+ children: [
147
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", style: { marginRight: "8px" }, children: "\u23F3" }) : null,
148
+ children
149
+ ]
150
+ }
151
+ );
152
+ }
153
+ );
154
+ Button.displayName = "Button";
155
+
156
+ // src/FormField/FormField.tsx
157
+ var import_react2 = require("react");
158
+ var import_jsx_runtime2 = require("react/jsx-runtime");
159
+ var FormField = (0, import_react2.forwardRef)(
160
+ ({
161
+ label,
162
+ error,
163
+ helpText,
164
+ required,
165
+ id,
166
+ className = "",
167
+ style,
168
+ ...props
169
+ }, ref) => {
170
+ const generatedId = (0, import_react2.useId)();
171
+ const inputId = id || `input-${generatedId}`;
172
+ const helpTextId = `help-${generatedId}`;
173
+ const errorId = `error-${generatedId}`;
174
+ const describedBy = [
175
+ helpText ? helpTextId : null,
176
+ error ? errorId : null
177
+ ].filter(Boolean).join(" ");
178
+ const containerStyle = {
179
+ display: "flex",
180
+ flexDirection: "column",
181
+ marginBottom: "1rem",
182
+ fontFamily: "system-ui, sans-serif",
183
+ ...style
184
+ };
185
+ const labelStyle = {
186
+ marginBottom: "0.5rem",
187
+ fontWeight: "600",
188
+ color: "#333"
189
+ };
190
+ const inputStyle = {
191
+ padding: "0.5rem",
192
+ borderRadius: "4px",
193
+ border: error ? "2px solid #dc3545" : "1px solid #ced4da",
194
+ fontSize: "1rem",
195
+ minHeight: "44px"
196
+ // Touch target
197
+ };
198
+ const errorStyle = {
199
+ color: "#dc3545",
200
+ fontSize: "0.875rem",
201
+ marginTop: "0.25rem",
202
+ display: "flex",
203
+ alignItems: "center"
204
+ };
205
+ const helpStyle = {
206
+ color: "#6c757d",
207
+ fontSize: "0.875rem",
208
+ marginTop: "0.25rem"
209
+ };
210
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: containerStyle, className, children: [
211
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { htmlFor: inputId, style: labelStyle, children: [
212
+ label,
213
+ required && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { "aria-hidden": "true", style: { color: "#dc3545", marginLeft: "4px" }, children: "*" }),
214
+ required && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "sr-only", children: " (obligatoriskt)" })
215
+ ] }),
216
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
217
+ "input",
218
+ {
219
+ ref,
220
+ id: inputId,
221
+ "aria-invalid": !!error,
222
+ "aria-describedby": describedBy || void 0,
223
+ "aria-required": required,
224
+ required,
225
+ style: inputStyle,
226
+ ...props
227
+ }
228
+ ),
229
+ error && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { id: errorId, style: errorStyle, role: "alert", children: [
230
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { "aria-hidden": "true", style: { marginRight: "4px" }, children: "\u26A0\uFE0F" }),
231
+ error
232
+ ] }),
233
+ helpText && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { id: helpTextId, style: helpStyle, children: helpText })
234
+ ] });
235
+ }
236
+ );
237
+ FormField.displayName = "FormField";
238
+
239
+ // src/Dialog/Dialog.tsx
240
+ var import_react3 = require("react");
241
+ var import_jsx_runtime3 = require("react/jsx-runtime");
242
+ var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
243
+ "svg",
244
+ {
245
+ xmlns: "http://www.w3.org/2000/svg",
246
+ width: "24",
247
+ height: "24",
248
+ viewBox: "0 0 24 24",
249
+ fill: "none",
250
+ stroke: "currentColor",
251
+ strokeWidth: "2",
252
+ strokeLinecap: "round",
253
+ strokeLinejoin: "round",
254
+ className: "h-5 w-5",
255
+ children: [
256
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M18 6 6 18" }),
257
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m6 6 12 12" })
258
+ ]
259
+ }
260
+ );
261
+ var Dialog = (0, import_react3.forwardRef)(
262
+ ({ isOpen, onClose, title, children, variant = "default", description, className, ...props }, ref) => {
263
+ const dialogRef = (0, import_react3.useRef)(null);
264
+ (0, import_react3.useImperativeHandle)(ref, () => dialogRef.current);
265
+ (0, import_react3.useEffect)(() => {
266
+ const dialog = dialogRef.current;
267
+ if (!dialog) return;
268
+ if (isOpen) {
269
+ if (!dialog.open) {
270
+ dialog.showModal();
271
+ document.body.style.overflow = "hidden";
272
+ }
273
+ } else {
274
+ if (dialog.open) {
275
+ dialog.close();
276
+ document.body.style.overflow = "";
277
+ }
278
+ }
279
+ }, [isOpen]);
280
+ (0, import_react3.useEffect)(() => {
281
+ const dialog = dialogRef.current;
282
+ if (!dialog) return;
283
+ const handleClose = () => {
284
+ onClose();
285
+ document.body.style.overflow = "";
286
+ };
287
+ dialog.addEventListener("close", handleClose);
288
+ const handleBackdropClick = (e) => {
289
+ const rect = dialog.getBoundingClientRect();
290
+ const isInDialog = rect.top <= e.clientY && e.clientY <= rect.top + rect.height && rect.left <= e.clientX && e.clientX <= rect.left + rect.width;
291
+ if (!isInDialog) {
292
+ dialog.close();
293
+ }
294
+ };
295
+ dialog.addEventListener("click", handleBackdropClick);
296
+ return () => {
297
+ dialog.removeEventListener("close", handleClose);
298
+ dialog.removeEventListener("click", handleBackdropClick);
299
+ };
300
+ }, [onClose]);
301
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
302
+ "dialog",
303
+ {
304
+ ref: dialogRef,
305
+ className: `
306
+ backdrop:bg-slate-900/50 backdrop:backdrop-blur-sm
307
+ open:animate-in open:fade-in-0 open:zoom-in-95
308
+ bg-white rounded-xl shadow-2xl ring-1 ring-slate-900/5
309
+ w-full max-w-lg p-0
310
+ ${className || ""}
311
+ `,
312
+ "aria-labelledby": "dialog-title",
313
+ "aria-describedby": description ? "dialog-desc" : void 0,
314
+ ...props,
315
+ children: [
316
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center justify-between px-6 py-4 border-b border-slate-100", children: [
317
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { id: "dialog-title", className: `text-lg font-semibold ${variant === "alert" ? "text-red-600" : "text-slate-900"}`, children: title }),
318
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
319
+ "button",
320
+ {
321
+ onClick: () => {
322
+ dialogRef.current?.close();
323
+ },
324
+ className: "p-1 rounded-md text-slate-400 hover:text-slate-500 hover:bg-slate-100 focus:outline-none focus:ring-2 focus:ring-primary-500 transition-colors",
325
+ "aria-label": "Close dialog",
326
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CloseIcon, {})
327
+ }
328
+ )
329
+ ] }),
330
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "px-6 py-4", children: [
331
+ description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { id: "dialog-desc", className: "text-sm text-slate-500 mb-4", children: description }),
332
+ children
333
+ ] })
334
+ ]
335
+ }
336
+ );
337
+ }
338
+ );
339
+ Dialog.displayName = "Dialog";
340
+
341
+ // src/Modal/Modal.tsx
342
+ var import_react4 = require("react");
343
+ var import_jsx_runtime4 = require("react/jsx-runtime");
344
+ var Modal = (0, import_react4.forwardRef)((props, ref) => {
345
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
346
+ Dialog,
347
+ {
348
+ ref,
349
+ ...props,
350
+ className: `max-w-2xl ${props.className || ""}`
351
+ }
352
+ );
353
+ });
354
+ Modal.displayName = "Modal";
355
+
356
+ // src/SkipLink/SkipLink.tsx
357
+ var import_react5 = require("react");
358
+ var import_jsx_runtime5 = require("react/jsx-runtime");
359
+ var SkipLink = (0, import_react5.forwardRef)(
360
+ ({ targetId = "main", className, style, children, ...props }, ref) => {
361
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
362
+ "a",
363
+ {
364
+ ref,
365
+ href: `#${targetId}`,
366
+ className: `
367
+ fixed top-4 left-4 z-50
368
+ px-4 py-3
369
+ bg-white text-slate-900 font-medium
370
+ rounded-md shadow-lg ring-2 ring-slate-900
371
+ transition-transform duration-200
372
+ -translate-y-[150%] focus:translate-y-0
373
+ ${className || ""}
374
+ `,
375
+ style: {
376
+ // Ensure it stays on top of everything
377
+ zIndex: 9999,
378
+ ...style
379
+ },
380
+ ...props,
381
+ children: children || "Hoppa till huvudinneh\xE5ll"
382
+ }
383
+ );
384
+ }
385
+ );
386
+ SkipLink.displayName = "SkipLink";
387
+
388
+ // src/NavigationMenu/NavigationMenu.tsx
389
+ var import_react6 = require("react");
390
+ var import_jsx_runtime6 = require("react/jsx-runtime");
391
+ var NavigationMenu = (0, import_react6.forwardRef)(
392
+ ({ items, className, "aria-label": ariaLabel = "Main Navigation" }, ref) => {
393
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
394
+ "nav",
395
+ {
396
+ ref,
397
+ className: `flex items-center ${className || ""}`,
398
+ "aria-label": ariaLabel,
399
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "flex flex-wrap gap-2 m-0 p-0 list-none", children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MenuItem, { item }, index)) })
400
+ }
401
+ );
402
+ }
403
+ );
404
+ NavigationMenu.displayName = "NavigationMenu";
405
+ var MenuItem = ({ item }) => {
406
+ const [isOpen, setIsOpen] = (0, import_react6.useState)(false);
407
+ const containerRef = (0, import_react6.useRef)(null);
408
+ const timeoutRef = (0, import_react6.useRef)();
409
+ const hasChildren = item.children && item.children.length > 0;
410
+ (0, import_react6.useEffect)(() => {
411
+ const handleClickOutside = (event) => {
412
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
413
+ setIsOpen(false);
414
+ }
415
+ };
416
+ if (isOpen) {
417
+ document.addEventListener("click", handleClickOutside);
418
+ }
419
+ return () => document.removeEventListener("click", handleClickOutside);
420
+ }, [isOpen]);
421
+ const handleKeyDown = (e) => {
422
+ if (e.key === "Escape" && isOpen) {
423
+ setIsOpen(false);
424
+ const trigger = containerRef.current?.querySelector("button");
425
+ trigger?.focus();
426
+ }
427
+ };
428
+ const handleMouseEnter = () => {
429
+ clearTimeout(timeoutRef.current);
430
+ setIsOpen(true);
431
+ };
432
+ const handleMouseLeave = () => {
433
+ timeoutRef.current = setTimeout(() => setIsOpen(false), 200);
434
+ };
435
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
436
+ "li",
437
+ {
438
+ ref: containerRef,
439
+ className: "relative group",
440
+ onKeyDown: handleKeyDown,
441
+ onMouseEnter: hasChildren ? handleMouseEnter : void 0,
442
+ onMouseLeave: hasChildren ? handleMouseLeave : void 0,
443
+ children: hasChildren ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
444
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
445
+ "button",
446
+ {
447
+ onClick: () => setIsOpen(!isOpen),
448
+ "aria-expanded": isOpen,
449
+ "aria-haspopup": "true",
450
+ className: `
451
+ flex items-center gap-1 px-4 py-2 rounded-md
452
+ text-slate-700 font-medium hover:bg-slate-100 focus:bg-slate-100
453
+ transition-colors focus:outline-none focus:ring-2 focus:ring-primary-500
454
+ `,
455
+ children: [
456
+ item.label,
457
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
458
+ "svg",
459
+ {
460
+ className: `w-4 h-4 transition-transform ${isOpen ? "rotate-180" : ""}`,
461
+ fill: "none",
462
+ viewBox: "0 0 24 24",
463
+ stroke: "currentColor",
464
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" })
465
+ }
466
+ )
467
+ ]
468
+ }
469
+ ),
470
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
471
+ "ul",
472
+ {
473
+ className: `
474
+ absolute top-full left-0 mt-1 min-w-[200px]
475
+ bg-white border border-slate-200 rounded-lg shadow-xl
476
+ py-2 z-50
477
+ transform origin-top transition-all duration-200
478
+ ${isOpen ? "opacity-100 scale-100 visible" : "opacity-0 scale-95 invisible"}
479
+ `,
480
+ children: item.children?.map((child, idx) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
481
+ "a",
482
+ {
483
+ href: child.href,
484
+ className: "block px-4 py-2 text-slate-700 hover:bg-slate-50 hover:text-primary-600 focus:bg-slate-50 focus:text-primary-600 focus:outline-none",
485
+ children: child.label
486
+ }
487
+ ) }, idx))
488
+ }
489
+ )
490
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
491
+ "a",
492
+ {
493
+ href: item.href,
494
+ className: "block px-4 py-2 text-slate-700 font-medium rounded-md hover:bg-slate-100 focus:bg-slate-100 transition-colors focus:outline-none focus:ring-2 focus:ring-primary-500",
495
+ children: item.label
496
+ }
497
+ )
498
+ }
499
+ );
500
+ };
501
+
502
+ // src/Checkbox/Checkbox.tsx
503
+ var import_react7 = require("react");
504
+ var import_lucide_react = require("lucide-react");
505
+ var import_jsx_runtime7 = require("react/jsx-runtime");
506
+ var Checkbox = (0, import_react7.forwardRef)(
507
+ ({ className = "", checked, onCheckedChange, onChange, label, disabled, id, ...props }, ref) => {
508
+ const handleChange = (e) => {
509
+ onCheckedChange?.(e.target.checked);
510
+ onChange?.(e);
511
+ };
512
+ const generatedId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
513
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `flex items-start ${className}`, children: [
514
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex items-center h-5", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "relative", children: [
515
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
516
+ "input",
517
+ {
518
+ id: generatedId,
519
+ type: "checkbox",
520
+ ref,
521
+ className: "peer sr-only",
522
+ checked,
523
+ onChange: handleChange,
524
+ disabled,
525
+ ...props
526
+ }
527
+ ),
528
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
529
+ "div",
530
+ {
531
+ className: `
532
+ h-5 w-5 rounded border border-slate-300 bg-white shadow-sm transition-all
533
+ peer-focus:ring-2 peer-focus:ring-primary-500 peer-focus:ring-offset-2
534
+ peer-checked:bg-primary-600 peer-checked:border-primary-600
535
+ peer-disabled:cursor-not-allowed peer-disabled:opacity-50
536
+ hover:border-primary-400
537
+ flex items-center justify-center
538
+ `,
539
+ "aria-hidden": "true",
540
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react.Check, { className: `h-3.5 w-3.5 text-white transition-opacity ${checked ? "opacity-100" : "opacity-0"}`, strokeWidth: 3 })
541
+ }
542
+ )
543
+ ] }) }),
544
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
545
+ "label",
546
+ {
547
+ htmlFor: generatedId,
548
+ className: `ml-3 text-sm font-medium ${disabled ? "text-slate-400" : "text-slate-700"} cursor-pointer select-none`,
549
+ children: label
550
+ }
551
+ )
552
+ ] });
553
+ }
554
+ );
555
+ Checkbox.displayName = "Checkbox";
556
+
557
+ // src/RadioGroup/RadioGroup.tsx
558
+ var import_react8 = require("react");
559
+ var import_jsx_runtime8 = require("react/jsx-runtime");
560
+ var RadioGroup = (0, import_react8.forwardRef)(
561
+ ({ name, options, value, onChange, orientation = "vertical", className = "", label }, ref) => {
562
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
563
+ "div",
564
+ {
565
+ ref,
566
+ className: `${className}`,
567
+ role: "radiogroup",
568
+ "aria-labelledby": label ? `${name}-label` : void 0,
569
+ children: [
570
+ label && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { id: `${name}-label`, className: "text-sm font-medium text-slate-900 mb-2", children: label }),
571
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: `flex ${orientation === "vertical" ? "flex-col space-y-3" : "flex-row space-x-6"}`, children: options.map((option) => {
572
+ const optionId = `${name}-${option.value}`;
573
+ const isChecked = value === option.value;
574
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center", children: [
575
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "relative flex items-center justify-center", children: [
576
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
577
+ "input",
578
+ {
579
+ id: optionId,
580
+ name,
581
+ type: "radio",
582
+ value: option.value,
583
+ checked: isChecked,
584
+ disabled: option.disabled,
585
+ onChange: (e) => {
586
+ if (e.target.checked) {
587
+ onChange?.(option.value);
588
+ }
589
+ },
590
+ className: "peer sr-only"
591
+ }
592
+ ),
593
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
594
+ "div",
595
+ {
596
+ className: `
597
+ h-5 w-5 rounded-full border border-slate-300 bg-white shadow-sm transition-all
598
+ peer-focus:ring-2 peer-focus:ring-primary-500 peer-focus:ring-offset-2
599
+ peer-checked:border-primary-600 peer-checked:bg-white
600
+ peer-disabled:cursor-not-allowed peer-disabled:opacity-50
601
+ hover:border-primary-400
602
+ `,
603
+ "aria-hidden": "true"
604
+ }
605
+ ),
606
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
607
+ "div",
608
+ {
609
+ className: `
610
+ absolute h-2.5 w-2.5 rounded-full bg-primary-600 transition-transform duration-200 scale-0
611
+ ${isChecked ? "scale-100" : ""}
612
+ `
613
+ }
614
+ )
615
+ ] }),
616
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
617
+ "label",
618
+ {
619
+ htmlFor: optionId,
620
+ className: `ml-3 text-sm font-medium ${option.disabled ? "text-slate-400" : "text-slate-700"} cursor-pointer select-none`,
621
+ children: option.label
622
+ }
623
+ )
624
+ ] }, option.value);
625
+ }) })
626
+ ]
627
+ }
628
+ );
629
+ }
630
+ );
631
+ RadioGroup.displayName = "RadioGroup";
632
+
633
+ // src/Breadcrumbs/Breadcrumbs.tsx
634
+ var import_react9 = __toESM(require("react"));
635
+ var import_jsx_runtime9 = require("react/jsx-runtime");
636
+ var BreadcrumbItem = ({ href, isCurrent, children, className, ...props }) => {
637
+ if (isCurrent) {
638
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("li", { className: `flex items-center text-slate-900 font-semibold ${className || ""}`, "aria-current": "page", ...props, children });
639
+ }
640
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("li", { className: `flex items-center text-slate-500 hover:text-slate-700 transition-colors ${className || ""}`, ...props, children: href ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("a", { href, className: "hover:underline focus:outline-none focus:ring-2 focus:ring-primary-500 rounded-sm", children }) : children });
641
+ };
642
+ var Breadcrumbs = ({ separator, children, className, ...props }) => {
643
+ const separatorIcon = separator || /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-slate-400 mx-2", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "m9 18 6-6-6-6" }) });
644
+ const items = import_react9.Children.toArray(children).filter(import_react9.isValidElement);
645
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("nav", { "aria-label": "Breadcrumb", className, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ol", { className: "flex items-center flex-wrap", children: items.map((child, index) => {
646
+ const isLast = index === items.length - 1;
647
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react9.default.Fragment, { children: [
648
+ (0, import_react9.cloneElement)(child, {
649
+ isCurrent: isLast || child.props.isCurrent
650
+ }),
651
+ !isLast && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("li", { "aria-hidden": "true", className: "flex items-center select-none", children: separatorIcon })
652
+ ] }, index);
653
+ }) }) });
654
+ };
655
+
656
+ // src/Accordion/Accordion.tsx
657
+ var import_react10 = __toESM(require("react"));
658
+ var import_jsx_runtime10 = require("react/jsx-runtime");
659
+ var ChevronIcon = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
660
+ "svg",
661
+ {
662
+ xmlns: "http://www.w3.org/2000/svg",
663
+ width: "24",
664
+ height: "24",
665
+ viewBox: "0 0 24 24",
666
+ fill: "none",
667
+ stroke: "currentColor",
668
+ strokeWidth: "2",
669
+ strokeLinecap: "round",
670
+ strokeLinejoin: "round",
671
+ className,
672
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "m6 9 6 6 6-6" })
673
+ }
674
+ );
675
+ var AccordionContext = (0, import_react10.createContext)(void 0);
676
+ var Accordion = ({ type = "single", defaultValue, children, className }) => {
677
+ const [openItems, setOpenItems] = (0, import_react10.useState)(() => {
678
+ if (Array.isArray(defaultValue)) return defaultValue;
679
+ if (defaultValue) return [defaultValue];
680
+ return [];
681
+ });
682
+ const toggleItem = (value) => {
683
+ setOpenItems((prev) => {
684
+ if (type === "single") {
685
+ return prev.includes(value) ? [] : [value];
686
+ }
687
+ return prev.includes(value) ? prev.filter((item) => item !== value) : [...prev, value];
688
+ });
689
+ };
690
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AccordionContext.Provider, { value: { openItems, toggleItem }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: `space-y-1 ${className || ""}`, children }) });
691
+ };
692
+ var AccordionItem = ({ value, children, className }) => {
693
+ const context = (0, import_react10.useContext)(AccordionContext);
694
+ if (!context) throw new Error("AccordionItem must be used within an Accordion");
695
+ const isOpen = context.openItems.includes(value);
696
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: `border border-slate-200 rounded-lg overflow-hidden ${className || ""}`, children: import_react10.default.Children.map(children, (child) => {
697
+ if (import_react10.default.isValidElement(child)) {
698
+ return import_react10.default.cloneElement(child, {
699
+ ...child.props,
700
+ value,
701
+ // Pass value down to Trigger and Content
702
+ isOpen
703
+ });
704
+ }
705
+ return child;
706
+ }) });
707
+ };
708
+ var AccordionTrigger = ({ children, className, value, isOpen, ...props }) => {
709
+ const context = (0, import_react10.useContext)(AccordionContext);
710
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
711
+ "button",
712
+ {
713
+ type: "button",
714
+ className: `w-full flex items-center justify-between px-4 py-3 text-left font-medium text-slate-900 bg-white hover:bg-slate-50 transition-colors focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-inset ${className || ""}`,
715
+ onClick: () => value && context?.toggleItem(value),
716
+ "aria-expanded": isOpen,
717
+ "aria-controls": `accordion-content-${value}`,
718
+ id: `accordion-trigger-${value}`,
719
+ ...props,
720
+ children: [
721
+ children,
722
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChevronIcon, { className: `h-4 w-4 text-slate-500 transition-transform duration-200 ${isOpen ? "rotate-180" : ""}` })
723
+ ]
724
+ }
725
+ );
726
+ };
727
+ var AccordionContent = ({ children, className, value, isOpen }) => {
728
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
729
+ "div",
730
+ {
731
+ id: `accordion-content-${value}`,
732
+ role: "region",
733
+ "aria-labelledby": `accordion-trigger-${value}`,
734
+ hidden: !isOpen,
735
+ className: `px-4 py-3 bg-white text-slate-600 border-t border-slate-100 text-sm leading-relaxed ${!isOpen ? "hidden" : ""} ${className || ""}`,
736
+ children
737
+ }
738
+ );
739
+ };
740
+
741
+ // src/Tabs/Tabs.tsx
742
+ var import_react11 = require("react");
743
+ var import_jsx_runtime11 = require("react/jsx-runtime");
744
+ var TabsContext = (0, import_react11.createContext)(void 0);
745
+ var Tabs = ({
746
+ defaultValue,
747
+ value,
748
+ onValueChange,
749
+ orientation = "horizontal",
750
+ activationMode = "automatic",
751
+ children,
752
+ className
753
+ }) => {
754
+ const [baseId] = (0, import_react11.useState)(() => Math.random().toString(36).substr(2, 9));
755
+ const [internalValue, setInternalValue] = (0, import_react11.useState)(defaultValue || "");
756
+ const isControlled = value !== void 0;
757
+ const activeTab = isControlled ? value : internalValue;
758
+ const setActiveTab = (newValue) => {
759
+ if (!isControlled) {
760
+ setInternalValue(newValue);
761
+ }
762
+ onValueChange?.(newValue);
763
+ };
764
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TabsContext.Provider, { value: { activeTab, setActiveTab, orientation, activationMode, baseId }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: `flex ${orientation === "vertical" ? "flex-col md:flex-row gap-4" : "flex-col"} ${className || ""}`, children }) });
765
+ };
766
+ var TabsList = ({ children, className, ariaLabel }) => {
767
+ const context = (0, import_react11.useContext)(TabsContext);
768
+ if (!context) throw new Error("TabsList must be used within Tabs");
769
+ const listRef = (0, import_react11.useRef)(null);
770
+ const handleKeyDown = (e) => {
771
+ const list = listRef.current;
772
+ if (!list) return;
773
+ const tabs = Array.from(list.querySelectorAll('[role="tab"]:not([disabled])'));
774
+ const index = tabs.indexOf(document.activeElement);
775
+ if (index === -1) return;
776
+ let nextIndex = index;
777
+ const lastIndex = tabs.length - 1;
778
+ switch (e.key) {
779
+ case "ArrowLeft":
780
+ case "ArrowUp":
781
+ nextIndex = index === 0 ? lastIndex : index - 1;
782
+ break;
783
+ case "ArrowRight":
784
+ case "ArrowDown":
785
+ nextIndex = index === lastIndex ? 0 : index + 1;
786
+ break;
787
+ case "Home":
788
+ nextIndex = 0;
789
+ break;
790
+ case "End":
791
+ nextIndex = lastIndex;
792
+ break;
793
+ default:
794
+ return;
795
+ }
796
+ e.preventDefault();
797
+ const nextTab = tabs[nextIndex];
798
+ nextTab.focus();
799
+ if (context.activationMode === "automatic") {
800
+ nextTab.click();
801
+ }
802
+ };
803
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
804
+ "div",
805
+ {
806
+ ref: listRef,
807
+ role: "tablist",
808
+ "aria-orientation": context.orientation,
809
+ "aria-label": ariaLabel,
810
+ className: `flex ${context.orientation === "vertical" ? "flex-col border-r border-slate-200" : "border-b border-slate-200"} ${className || ""}`,
811
+ onKeyDown: handleKeyDown,
812
+ tabIndex: -1,
813
+ children
814
+ }
815
+ );
816
+ };
817
+ var TabTrigger = ({ value, children, className, ...props }) => {
818
+ const context = (0, import_react11.useContext)(TabsContext);
819
+ if (!context) throw new Error("TabTrigger must be used within Tabs");
820
+ const isActive = context.activeTab === value;
821
+ const triggerId = `tab-${context.baseId}-${value}`;
822
+ const contentId = `content-${context.baseId}-${value}`;
823
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
824
+ "button",
825
+ {
826
+ id: triggerId,
827
+ role: "tab",
828
+ "aria-selected": isActive,
829
+ "aria-controls": contentId,
830
+ tabIndex: isActive ? 0 : -1,
831
+ onClick: () => context.setActiveTab(value),
832
+ className: `
833
+ px-4 py-2 text-sm font-medium transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500
834
+ ${context.orientation === "horizontal" ? "border-b-2" : "border-r-2 text-left"}
835
+ ${isActive ? `border-primary-500 text-primary-600 bg-primary-50/50` : `border-transparent text-slate-500 hover:text-slate-700 hover:bg-slate-50`}
836
+ ${className || ""}
837
+ `,
838
+ ...props,
839
+ children
840
+ }
841
+ );
842
+ };
843
+ var TabsContent = ({ value, children, className }) => {
844
+ const context = (0, import_react11.useContext)(TabsContext);
845
+ if (!context) throw new Error("TabsContent must be used within Tabs");
846
+ const isActive = context.activeTab === value;
847
+ const triggerId = `tab-${context.baseId}-${value}`;
848
+ const contentId = `content-${context.baseId}-${value}`;
849
+ if (!isActive) return null;
850
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
851
+ "div",
852
+ {
853
+ id: contentId,
854
+ role: "tabpanel",
855
+ "aria-labelledby": triggerId,
856
+ tabIndex: 0,
857
+ className: `py-4 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 rounded-md ${className || ""}`,
858
+ children
859
+ }
860
+ );
861
+ };
862
+
863
+ // src/Select/Select.tsx
864
+ var import_react12 = require("react");
865
+ var import_lucide_react2 = require("lucide-react");
866
+ var import_jsx_runtime12 = require("react/jsx-runtime");
867
+ var SelectContext = (0, import_react12.createContext)(void 0);
868
+ var Select = ({ value, onChange, children }) => {
869
+ const [isOpen, setIsOpen] = (0, import_react12.useState)(false);
870
+ const [highlightedIndex, setHighlightedIndex] = (0, import_react12.useState)(-1);
871
+ const optionsRef = (0, import_react12.useRef)([]);
872
+ const containerRef = (0, import_react12.useRef)(null);
873
+ (0, import_react12.useEffect)(() => {
874
+ const handleClickOutside = (event) => {
875
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
876
+ setIsOpen(false);
877
+ }
878
+ };
879
+ document.addEventListener("mousedown", handleClickOutside);
880
+ return () => document.removeEventListener("mousedown", handleClickOutside);
881
+ }, []);
882
+ const handleKeyDown = (e) => {
883
+ if (!isOpen) {
884
+ if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
885
+ e.preventDefault();
886
+ setIsOpen(true);
887
+ setHighlightedIndex(0);
888
+ }
889
+ return;
890
+ }
891
+ switch (e.key) {
892
+ case "ArrowDown":
893
+ e.preventDefault();
894
+ setHighlightedIndex((prev) => Math.min(prev + 1, optionsRef.current.length - 1));
895
+ break;
896
+ case "ArrowUp":
897
+ e.preventDefault();
898
+ setHighlightedIndex((prev) => Math.max(prev - 1, 0));
899
+ break;
900
+ case "Enter":
901
+ case " ":
902
+ e.preventDefault();
903
+ if (highlightedIndex >= 0 && highlightedIndex < optionsRef.current.length) {
904
+ const option = optionsRef.current[highlightedIndex];
905
+ if (option) {
906
+ option.click();
907
+ }
908
+ }
909
+ break;
910
+ case "Escape":
911
+ e.preventDefault();
912
+ setIsOpen(false);
913
+ break;
914
+ }
915
+ };
916
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SelectContext.Provider, { value: { value, onChange, isOpen, setIsOpen, highlightedIndex, setHighlightedIndex, optionsRef }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
917
+ "div",
918
+ {
919
+ ref: containerRef,
920
+ className: "relative inline-block text-left w-full",
921
+ onKeyDown: handleKeyDown,
922
+ children
923
+ }
924
+ ) });
925
+ };
926
+ var SelectTrigger = ({ children, className = "", placeholder = "Select..." }) => {
927
+ const context = (0, import_react12.useContext)(SelectContext);
928
+ if (!context) throw new Error("SelectTrigger must be used within Select");
929
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
930
+ "button",
931
+ {
932
+ type: "button",
933
+ onClick: () => context.setIsOpen(!context.isOpen),
934
+ "aria-haspopup": "listbox",
935
+ "aria-expanded": context.isOpen,
936
+ className: `flex items-center justify-between w-full px-4 py-2 text-sm bg-white border border-slate-300 rounded-md focus:outline-none focus:ring-2 focus:ring-slate-900 focus:border-transparent ${className}`,
937
+ children: [
938
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: context.value ? "text-slate-900" : "text-slate-500", children: children || placeholder }),
939
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react2.ChevronDown, { className: "w-4 h-4 ml-2 opacity-50" })
940
+ ]
941
+ }
942
+ );
943
+ };
944
+ var SelectContent = ({ children }) => {
945
+ const context = (0, import_react12.useContext)(SelectContext);
946
+ (0, import_react12.useEffect)(() => {
947
+ if (context && context.isOpen) {
948
+ context.optionsRef.current = [];
949
+ }
950
+ }, [context?.isOpen]);
951
+ if (!context || !context.isOpen) return null;
952
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
953
+ "div",
954
+ {
955
+ className: "absolute z-10 w-full mt-1 bg-white border border-slate-200 rounded-md shadow-lg max-h-60 overflow-auto focus:outline-none",
956
+ role: "listbox",
957
+ children
958
+ }
959
+ );
960
+ };
961
+ var SelectItem = ({ value, children }) => {
962
+ const context = (0, import_react12.useContext)(SelectContext);
963
+ if (!context) throw new Error("SelectItem must be used within Select");
964
+ const isSelected = context.value === value;
965
+ const index = context.optionsRef.current.length;
966
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
967
+ "div",
968
+ {
969
+ ref: (el) => {
970
+ context.optionsRef.current[index] = el;
971
+ },
972
+ role: "option",
973
+ "aria-selected": isSelected,
974
+ onClick: () => {
975
+ context.onChange(value);
976
+ context.setIsOpen(false);
977
+ },
978
+ className: `flex items-center justify-between px-4 py-2 text-sm cursor-pointer ${context.highlightedIndex === index ? "bg-slate-100" : ""} ${isSelected ? "bg-slate-50 text-slate-900 font-medium" : "text-slate-700"}`,
979
+ children: [
980
+ children,
981
+ isSelected && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react2.Check, { className: "w-4 h-4 text-slate-900" })
982
+ ]
983
+ }
984
+ );
985
+ };
986
+
987
+ // src/Switch/Switch.tsx
988
+ var import_jsx_runtime13 = require("react/jsx-runtime");
989
+ var Switch = ({ checked, onCheckedChange, disabled = false, label, id }) => {
990
+ const generatedId = id || `switch-${Math.random().toString(36).substr(2, 9)}`;
991
+ const handleClick = () => {
992
+ if (!disabled) {
993
+ onCheckedChange(!checked);
994
+ }
995
+ };
996
+ const handleKeyDown = (e) => {
997
+ if (disabled) return;
998
+ if (e.key === "Enter" || e.key === " ") {
999
+ e.preventDefault();
1000
+ onCheckedChange(!checked);
1001
+ }
1002
+ };
1003
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-3", children: [
1004
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1005
+ "button",
1006
+ {
1007
+ type: "button",
1008
+ role: "switch",
1009
+ "aria-checked": checked,
1010
+ id: generatedId,
1011
+ disabled,
1012
+ onClick: handleClick,
1013
+ onKeyDown: handleKeyDown,
1014
+ className: `
1015
+ relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-slate-900 focus:ring-offset-2
1016
+ ${checked ? "bg-primary-600" : "bg-slate-200"}
1017
+ ${disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}
1018
+ `,
1019
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1020
+ "span",
1021
+ {
1022
+ className: `
1023
+ inline-block h-4 w-4 transform rounded-full bg-white transition-transform
1024
+ ${checked ? "translate-x-6" : "translate-x-1"}
1025
+ `
1026
+ }
1027
+ )
1028
+ }
1029
+ ),
1030
+ label && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1031
+ "label",
1032
+ {
1033
+ htmlFor: generatedId,
1034
+ className: `text-sm font-medium text-slate-700 cursor-pointer ${disabled ? "opacity-50 cursor-not-allowed" : ""}`,
1035
+ onClick: handleClick,
1036
+ children: label
1037
+ }
1038
+ )
1039
+ ] });
1040
+ };
1041
+
1042
+ // src/Toast/Toast.tsx
1043
+ var import_react13 = require("react");
1044
+ var import_lucide_react3 = require("lucide-react");
1045
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1046
+ var ToastContext = (0, import_react13.createContext)(void 0);
1047
+ var ToastProvider = ({ children }) => {
1048
+ const [toasts, setToasts] = (0, import_react13.useState)([]);
1049
+ const addToast = (0, import_react13.useCallback)((toast) => {
1050
+ const id = Math.random().toString(36).substr(2, 9);
1051
+ setToasts((prev) => [...prev, { ...toast, id }]);
1052
+ }, []);
1053
+ const removeToast = (0, import_react13.useCallback)((id) => {
1054
+ setToasts((prev) => prev.filter((t) => t.id !== id));
1055
+ }, []);
1056
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(ToastContext.Provider, { value: { toasts, addToast, removeToast }, children: [
1057
+ children,
1058
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ToastViewport, {})
1059
+ ] });
1060
+ };
1061
+ var useToast = () => {
1062
+ const context = (0, import_react13.useContext)(ToastContext);
1063
+ if (!context) {
1064
+ throw new Error("useToast must be used within a ToastProvider");
1065
+ }
1066
+ return context;
1067
+ };
1068
+ var ToastViewport = () => {
1069
+ const { toasts, removeToast } = useToast();
1070
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1071
+ "div",
1072
+ {
1073
+ className: "fixed bottom-0 right-0 z-50 p-4 w-full md:max-w-sm flex flex-col gap-2",
1074
+ role: "region",
1075
+ "aria-label": "Notifications",
1076
+ children: toasts.map((toast) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ToastItem, { toast, onRemove: () => removeToast(toast.id) }, toast.id))
1077
+ }
1078
+ );
1079
+ };
1080
+ var ToastItem = ({ toast, onRemove }) => {
1081
+ (0, import_react13.useEffect)(() => {
1082
+ if (toast.duration === Infinity) return;
1083
+ const timer = setTimeout(() => {
1084
+ onRemove();
1085
+ }, toast.duration || 5e3);
1086
+ return () => clearTimeout(timer);
1087
+ }, [toast, onRemove]);
1088
+ const icons = {
1089
+ info: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react3.Info, { className: "w-5 h-5 text-blue-500" }),
1090
+ success: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react3.CheckCircle, { className: "w-5 h-5 text-green-500" }),
1091
+ warning: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react3.AlertTriangle, { className: "w-5 h-5 text-amber-500" }),
1092
+ error: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react3.AlertCircle, { className: "w-5 h-5 text-red-500" })
1093
+ };
1094
+ const bgColors = {
1095
+ info: "bg-white border-blue-100",
1096
+ success: "bg-white border-green-100",
1097
+ warning: "bg-white border-amber-100",
1098
+ error: "bg-white border-red-100"
1099
+ };
1100
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1101
+ "div",
1102
+ {
1103
+ role: "alert",
1104
+ className: `
1105
+ flex items-start gap-3 p-4 rounded-lg shadow-lg border transition-all animate-in slide-in-from-right-full fade-in duration-300
1106
+ ${bgColors[toast.type || "info"]}
1107
+ `,
1108
+ children: [
1109
+ icons[toast.type || "info"],
1110
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex-1", children: [
1111
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h4", { className: "text-sm font-medium text-slate-900", children: toast.title }),
1112
+ toast.description && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm text-slate-600 mt-1", children: toast.description }),
1113
+ toast.action && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1114
+ "button",
1115
+ {
1116
+ onClick: toast.action.onClick,
1117
+ className: "mt-2 text-sm font-medium text-slate-900 underline hover:no-underline",
1118
+ children: toast.action.label
1119
+ }
1120
+ )
1121
+ ] }),
1122
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1123
+ "button",
1124
+ {
1125
+ onClick: onRemove,
1126
+ className: "text-slate-400 hover:text-slate-900 transition-colors",
1127
+ "aria-label": "Close",
1128
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react3.X, { className: "w-4 h-4" })
1129
+ }
1130
+ )
1131
+ ]
1132
+ }
1133
+ );
1134
+ };
1135
+
1136
+ // src/Tooltip/Tooltip.tsx
1137
+ var import_react14 = __toESM(require("react"));
1138
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1139
+ var TooltipContext = (0, import_react14.createContext)(void 0);
1140
+ var TooltipProvider = ({ children }) => {
1141
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
1142
+ };
1143
+ var Tooltip = ({ children }) => {
1144
+ const [open, setOpen] = (0, import_react14.useState)(false);
1145
+ const id = (0, import_react14.useRef)(`tooltip-${Math.random().toString(36).substr(2, 9)}`).current;
1146
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipContext.Provider, { value: { open, setOpen, id }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "relative inline-block group", onMouseLeave: () => setOpen(false), children }) });
1147
+ };
1148
+ var TooltipTrigger = ({ children, asChild = false, ...props }) => {
1149
+ const context = (0, import_react14.useContext)(TooltipContext);
1150
+ if (!context) throw new Error("TooltipTrigger must be used within Tooltip");
1151
+ const { setOpen, id } = context;
1152
+ const handleOpen = () => setOpen(true);
1153
+ const handleClose = () => setOpen(false);
1154
+ if (import_react14.default.isValidElement(children)) {
1155
+ return import_react14.default.cloneElement(children, {
1156
+ "aria-describedby": context.open ? id : void 0,
1157
+ onMouseEnter: (e) => {
1158
+ handleOpen();
1159
+ children.props.onMouseEnter?.(e);
1160
+ },
1161
+ onMouseLeave: (e) => {
1162
+ handleClose();
1163
+ children.props.onMouseLeave?.(e);
1164
+ },
1165
+ onFocus: (e) => {
1166
+ handleOpen();
1167
+ children.props.onFocus?.(e);
1168
+ },
1169
+ onBlur: (e) => {
1170
+ handleClose();
1171
+ children.props.onBlur?.(e);
1172
+ },
1173
+ ...props
1174
+ });
1175
+ }
1176
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1177
+ "span",
1178
+ {
1179
+ "aria-describedby": context.open ? id : void 0,
1180
+ onMouseEnter: handleOpen,
1181
+ onMouseLeave: handleClose,
1182
+ onFocus: handleOpen,
1183
+ onBlur: handleClose,
1184
+ tabIndex: 0,
1185
+ className: "cursor-default",
1186
+ ...props,
1187
+ children
1188
+ }
1189
+ );
1190
+ };
1191
+ var TooltipContent = ({ children, className = "" }) => {
1192
+ const context = (0, import_react14.useContext)(TooltipContext);
1193
+ if (!context) throw new Error("TooltipContent must be used within Tooltip");
1194
+ if (!context.open) return null;
1195
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1196
+ "div",
1197
+ {
1198
+ id: context.id,
1199
+ role: "tooltip",
1200
+ className: `
1201
+ absolute z-50 px-3 py-2 text-sm font-medium text-white bg-slate-900 rounded shadow-lg
1202
+ bottom-full left-1/2 transform -translate-x-1/2 mb-2 whitespace-nowrap
1203
+ animate-in fade-in zoom-in-95 duration-200
1204
+ ${className}
1205
+ `,
1206
+ children: [
1207
+ children,
1208
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "absolute w-2 h-2 bg-slate-900 transform rotate-45 left-1/2 -translate-x-1/2 -bottom-1" })
1209
+ ]
1210
+ }
1211
+ );
1212
+ };
1213
+
1214
+ // src/Heading/Heading.tsx
1215
+ var import_react15 = __toESM(require("react"));
1216
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1217
+ var Heading = import_react15.default.forwardRef(
1218
+ ({ level, children, className, ...props }, ref) => {
1219
+ const Tag = `h${level}`;
1220
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Tag, { ref, className, ...props, children });
1221
+ }
1222
+ );
1223
+ Heading.displayName = "Heading";
1224
+ // Annotate the CommonJS export names for ESM import in node:
1225
+ 0 && (module.exports = {
1226
+ Accordion,
1227
+ AccordionContent,
1228
+ AccordionItem,
1229
+ AccordionTrigger,
1230
+ BreadcrumbItem,
1231
+ Breadcrumbs,
1232
+ Button,
1233
+ Checkbox,
1234
+ Dialog,
1235
+ FormField,
1236
+ Heading,
1237
+ Modal,
1238
+ NavigationMenu,
1239
+ RadioGroup,
1240
+ Select,
1241
+ SelectContent,
1242
+ SelectItem,
1243
+ SelectTrigger,
1244
+ SkipLink,
1245
+ Switch,
1246
+ TabTrigger,
1247
+ Tabs,
1248
+ TabsContent,
1249
+ TabsList,
1250
+ ToastProvider,
1251
+ Tooltip,
1252
+ TooltipContent,
1253
+ TooltipProvider,
1254
+ TooltipTrigger,
1255
+ useToast
1256
+ });