@larose-ui/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.js ADDED
@@ -0,0 +1,1923 @@
1
+ // src/AsyncButton/AsyncButton.tsx
2
+ import { useCallback, useReducer, useRef } from "react";
3
+ import { createAsyncStateMachine } from "@larose-ui/core";
4
+
5
+ // src/Button/Button.tsx
6
+ import { forwardRef } from "react";
7
+ import { resolveUIState } from "@larose-ui/core";
8
+
9
+ // src/Spinner/Spinner.module.css
10
+ var Spinner_default = {};
11
+
12
+ // src/Spinner/Spinner.tsx
13
+ import { jsx } from "react/jsx-runtime";
14
+ function Spinner({ size = "md", label = "Loading" }) {
15
+ return /* @__PURE__ */ jsx(
16
+ "span",
17
+ {
18
+ className: Spinner_default.spinner,
19
+ "data-size": size,
20
+ role: "status",
21
+ "aria-label": label,
22
+ children: /* @__PURE__ */ jsx("span", { className: Spinner_default.circle, "aria-hidden": "true" })
23
+ }
24
+ );
25
+ }
26
+
27
+ // src/Button/Button.module.css
28
+ var Button_default = {};
29
+
30
+ // src/Button/Button.tsx
31
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
32
+ var Button = forwardRef(
33
+ ({
34
+ variant = "primary",
35
+ size = "md",
36
+ state,
37
+ loading = false,
38
+ error = null,
39
+ disabled,
40
+ leftIcon,
41
+ rightIcon,
42
+ children,
43
+ className,
44
+ ...props
45
+ }, ref) => {
46
+ const uiState = resolveUIState({ state, loading, error, disabled });
47
+ const isDisabled = disabled || uiState === "loading" || uiState === "disabled";
48
+ return /* @__PURE__ */ jsxs(
49
+ "button",
50
+ {
51
+ ref,
52
+ type: "button",
53
+ className: [Button_default.button, className].filter(Boolean).join(" "),
54
+ "data-variant": variant,
55
+ "data-size": size,
56
+ "data-state": uiState,
57
+ disabled: isDisabled,
58
+ "aria-busy": uiState === "loading",
59
+ "aria-disabled": isDisabled,
60
+ ...props,
61
+ children: [
62
+ uiState === "loading" && /* @__PURE__ */ jsx2("span", { className: Button_default.spinner, "aria-hidden": "true", children: /* @__PURE__ */ jsx2(Spinner, { size: "sm" }) }),
63
+ leftIcon && /* @__PURE__ */ jsx2("span", { className: Button_default.icon, children: leftIcon }),
64
+ /* @__PURE__ */ jsx2("span", { className: Button_default.content, children }),
65
+ rightIcon && /* @__PURE__ */ jsx2("span", { className: Button_default.icon, children: rightIcon }),
66
+ uiState === "error" && error && /* @__PURE__ */ jsx2("span", { className: Button_default.errorMessage, role: "alert", children: error })
67
+ ]
68
+ }
69
+ );
70
+ }
71
+ );
72
+ Button.displayName = "Button";
73
+
74
+ // src/AsyncButton/AsyncButton.tsx
75
+ import { jsx as jsx3 } from "react/jsx-runtime";
76
+ function AsyncButton({
77
+ action,
78
+ onSuccess,
79
+ onError,
80
+ children,
81
+ variant = "primary",
82
+ size = "md",
83
+ disabled,
84
+ ...props
85
+ }) {
86
+ const machineRef = useRef(createAsyncStateMachine());
87
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
88
+ const machine = machineRef.current;
89
+ const errorMessage = machine.error && typeof machine.error === "object" && "message" in machine.error ? String(machine.error.message) : machine.error ? String(machine.error) : null;
90
+ const handleClick = useCallback(async () => {
91
+ machine.send({ type: "SUBMIT" });
92
+ forceUpdate();
93
+ try {
94
+ await action();
95
+ machine.send({ type: "SUCCESS" });
96
+ onSuccess?.();
97
+ } catch (err) {
98
+ machine.send({ type: "ERROR", error: err });
99
+ onError?.(err);
100
+ } finally {
101
+ forceUpdate();
102
+ }
103
+ }, [action, machine, onSuccess, onError]);
104
+ return /* @__PURE__ */ jsx3(
105
+ Button,
106
+ {
107
+ variant,
108
+ size,
109
+ loading: machine.state === "submitting",
110
+ error: machine.state === "error" ? errorMessage : null,
111
+ disabled,
112
+ onClick: () => void handleClick(),
113
+ ...props,
114
+ children
115
+ }
116
+ );
117
+ }
118
+
119
+ // src/provider/LaRoseProvider.tsx
120
+ import {
121
+ createContext,
122
+ useContext,
123
+ useEffect,
124
+ useRef as useRef2
125
+ } from "react";
126
+ import { applyTokensToElement } from "@larose-ui/tokens";
127
+ import { jsx as jsx4 } from "react/jsx-runtime";
128
+ var LaRoseContext = createContext({
129
+ theme: "light",
130
+ density: "comfortable"
131
+ });
132
+ function useLaRose() {
133
+ return useContext(LaRoseContext);
134
+ }
135
+ function LaRoseProvider({
136
+ children,
137
+ theme = "light",
138
+ density = "comfortable",
139
+ tenantId,
140
+ brandColors
141
+ }) {
142
+ const ref = useRef2(null);
143
+ useEffect(() => {
144
+ if (ref.current) {
145
+ applyTokensToElement(ref.current, theme, density, brandColors);
146
+ if (tenantId) {
147
+ ref.current.dataset.lrTenant = tenantId;
148
+ }
149
+ }
150
+ }, [theme, density, tenantId, brandColors]);
151
+ return /* @__PURE__ */ jsx4(LaRoseContext.Provider, { value: { theme, density, tenantId, brandColors }, children: /* @__PURE__ */ jsx4("div", { ref, "data-lr-provider": true, style: { minHeight: "inherit" }, children }) });
152
+ }
153
+
154
+ // src/Input/Input.tsx
155
+ import { forwardRef as forwardRef2 } from "react";
156
+ import { resolveUIState as resolveUIState2 } from "@larose-ui/core";
157
+
158
+ // src/Input/Input.module.css
159
+ var Input_default = {};
160
+
161
+ // src/Input/Input.tsx
162
+ import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
163
+ var Input = forwardRef2(
164
+ ({
165
+ label,
166
+ hint,
167
+ state,
168
+ loading = false,
169
+ error = null,
170
+ disabled,
171
+ readOnly,
172
+ inputSize = "md",
173
+ className,
174
+ id,
175
+ ...props
176
+ }, ref) => {
177
+ const inputId = id ?? (label ? label.toLowerCase().replace(/\s+/g, "-") : void 0);
178
+ const uiState = resolveUIState2({ state, loading, error, disabled, readonly: readOnly });
179
+ const errorMessage = typeof error === "string" ? error : null;
180
+ return /* @__PURE__ */ jsxs2("div", { className: Input_default.wrapper, "data-state": uiState, children: [
181
+ label && /* @__PURE__ */ jsx5("label", { htmlFor: inputId, className: Input_default.label, children: label }),
182
+ /* @__PURE__ */ jsxs2("div", { className: Input_default.inputContainer, children: [
183
+ /* @__PURE__ */ jsx5(
184
+ "input",
185
+ {
186
+ ref,
187
+ id: inputId,
188
+ className: [Input_default.input, className].filter(Boolean).join(" "),
189
+ "data-size": inputSize,
190
+ "data-state": uiState,
191
+ disabled: disabled || uiState === "disabled",
192
+ readOnly: readOnly || uiState === "readonly",
193
+ "aria-invalid": uiState === "error",
194
+ "aria-busy": uiState === "loading",
195
+ "aria-describedby": errorMessage ? `${inputId}-error` : hint ? `${inputId}-hint` : void 0,
196
+ ...props
197
+ }
198
+ ),
199
+ uiState === "loading" && /* @__PURE__ */ jsx5("span", { className: Input_default.loadingIndicator, "aria-hidden": "true" })
200
+ ] }),
201
+ hint && !errorMessage && /* @__PURE__ */ jsx5("span", { id: `${inputId}-hint`, className: Input_default.hint, children: hint }),
202
+ errorMessage && /* @__PURE__ */ jsx5("span", { id: `${inputId}-error`, className: Input_default.error, role: "alert", children: errorMessage })
203
+ ] });
204
+ }
205
+ );
206
+ Input.displayName = "Input";
207
+
208
+ // src/Textarea/Textarea.tsx
209
+ import { forwardRef as forwardRef3 } from "react";
210
+ import { resolveUIState as resolveUIState3 } from "@larose-ui/core";
211
+
212
+ // src/Textarea/Textarea.module.css
213
+ var Textarea_default = {};
214
+
215
+ // src/Textarea/Textarea.tsx
216
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
217
+ var Textarea = forwardRef3(
218
+ ({
219
+ label,
220
+ hint,
221
+ state,
222
+ loading = false,
223
+ error = null,
224
+ disabled,
225
+ readOnly,
226
+ inputSize = "md",
227
+ className,
228
+ id,
229
+ rows = 4,
230
+ ...props
231
+ }, ref) => {
232
+ const inputId = id ?? (label ? label.toLowerCase().replace(/\s+/g, "-") : void 0);
233
+ const uiState = resolveUIState3({ state, loading, error, disabled, readonly: readOnly });
234
+ const errorMessage = typeof error === "string" ? error : null;
235
+ return /* @__PURE__ */ jsxs3("div", { className: Textarea_default.wrapper, "data-state": uiState, children: [
236
+ label && /* @__PURE__ */ jsx6("label", { htmlFor: inputId, className: Textarea_default.label, children: label }),
237
+ /* @__PURE__ */ jsxs3("div", { className: Textarea_default.inputContainer, children: [
238
+ /* @__PURE__ */ jsx6(
239
+ "textarea",
240
+ {
241
+ ref,
242
+ id: inputId,
243
+ rows,
244
+ className: [Textarea_default.textarea, className].filter(Boolean).join(" "),
245
+ "data-size": inputSize,
246
+ "data-state": uiState,
247
+ disabled: disabled || uiState === "disabled",
248
+ readOnly: readOnly || uiState === "readonly",
249
+ "aria-invalid": uiState === "error",
250
+ "aria-busy": uiState === "loading",
251
+ "aria-describedby": errorMessage ? `${inputId}-error` : hint ? `${inputId}-hint` : void 0,
252
+ ...props
253
+ }
254
+ ),
255
+ uiState === "loading" && /* @__PURE__ */ jsx6("span", { className: Textarea_default.loadingIndicator, "aria-hidden": "true" })
256
+ ] }),
257
+ hint && !errorMessage && /* @__PURE__ */ jsx6("span", { id: `${inputId}-hint`, className: Textarea_default.hint, children: hint }),
258
+ errorMessage && /* @__PURE__ */ jsx6("span", { id: `${inputId}-error`, className: Textarea_default.error, role: "alert", children: errorMessage })
259
+ ] });
260
+ }
261
+ );
262
+ Textarea.displayName = "Textarea";
263
+
264
+ // src/Select/Select.tsx
265
+ import { forwardRef as forwardRef4 } from "react";
266
+ import { resolveUIState as resolveUIState4 } from "@larose-ui/core";
267
+
268
+ // src/Select/Select.module.css
269
+ var Select_default = {};
270
+
271
+ // src/Select/Select.tsx
272
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
273
+ var Select = forwardRef4(
274
+ ({
275
+ label,
276
+ hint,
277
+ options,
278
+ placeholder = "Select...",
279
+ state,
280
+ loading = false,
281
+ error = null,
282
+ disabled,
283
+ inputSize = "md",
284
+ className,
285
+ id,
286
+ ...props
287
+ }, ref) => {
288
+ const inputId = id ?? (label ? label.toLowerCase().replace(/\s+/g, "-") : void 0);
289
+ const uiState = resolveUIState4({ state, loading, error, disabled });
290
+ const errorMessage = typeof error === "string" ? error : null;
291
+ return /* @__PURE__ */ jsxs4("div", { className: Select_default.wrapper, "data-state": uiState, children: [
292
+ label && /* @__PURE__ */ jsx7("label", { htmlFor: inputId, className: Select_default.label, children: label }),
293
+ /* @__PURE__ */ jsxs4("div", { className: Select_default.inputContainer, children: [
294
+ /* @__PURE__ */ jsxs4(
295
+ "select",
296
+ {
297
+ ref,
298
+ id: inputId,
299
+ className: [Select_default.select, className].filter(Boolean).join(" "),
300
+ "data-size": inputSize,
301
+ "data-state": uiState,
302
+ disabled: disabled || uiState === "disabled" || uiState === "loading",
303
+ "aria-invalid": uiState === "error",
304
+ "aria-busy": uiState === "loading",
305
+ "aria-describedby": errorMessage ? `${inputId}-error` : hint ? `${inputId}-hint` : void 0,
306
+ ...props,
307
+ children: [
308
+ /* @__PURE__ */ jsx7("option", { value: "", children: placeholder }),
309
+ options.map((option) => /* @__PURE__ */ jsx7("option", { value: option.value, children: option.label }, option.value))
310
+ ]
311
+ }
312
+ ),
313
+ uiState === "loading" && /* @__PURE__ */ jsx7("span", { className: Select_default.loadingIndicator, "aria-hidden": "true" })
314
+ ] }),
315
+ hint && !errorMessage && /* @__PURE__ */ jsx7("span", { id: `${inputId}-hint`, className: Select_default.hint, children: hint }),
316
+ errorMessage && /* @__PURE__ */ jsx7("span", { id: `${inputId}-error`, className: Select_default.error, role: "alert", children: errorMessage })
317
+ ] });
318
+ }
319
+ );
320
+ Select.displayName = "Select";
321
+
322
+ // src/Checkbox/Checkbox.tsx
323
+ import { forwardRef as forwardRef5 } from "react";
324
+
325
+ // src/Checkbox/Checkbox.module.css
326
+ var Checkbox_default = {};
327
+
328
+ // src/Checkbox/Checkbox.tsx
329
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
330
+ var Checkbox = forwardRef5(
331
+ ({ label, hint, error = null, disabled, boxSize = "md", className, id, ...props }, ref) => {
332
+ const inputId = id ?? label.toLowerCase().replace(/\s+/g, "-");
333
+ const errorMessage = typeof error === "string" ? error : null;
334
+ return /* @__PURE__ */ jsxs5("div", { className: Checkbox_default.wrapper, "data-state": errorMessage ? "error" : "default", children: [
335
+ /* @__PURE__ */ jsxs5("label", { htmlFor: inputId, className: Checkbox_default.row, children: [
336
+ /* @__PURE__ */ jsx8(
337
+ "input",
338
+ {
339
+ ref,
340
+ id: inputId,
341
+ type: "checkbox",
342
+ className: [Checkbox_default.input, className].filter(Boolean).join(" "),
343
+ "data-size": boxSize,
344
+ disabled,
345
+ "aria-invalid": Boolean(errorMessage),
346
+ "aria-describedby": errorMessage ? `${inputId}-error` : hint ? `${inputId}-hint` : void 0,
347
+ ...props
348
+ }
349
+ ),
350
+ /* @__PURE__ */ jsx8("span", { className: Checkbox_default.label, children: label })
351
+ ] }),
352
+ hint && !errorMessage && /* @__PURE__ */ jsx8("span", { id: `${inputId}-hint`, className: Checkbox_default.hint, children: hint }),
353
+ errorMessage && /* @__PURE__ */ jsx8("span", { id: `${inputId}-error`, className: Checkbox_default.error, role: "alert", children: errorMessage })
354
+ ] });
355
+ }
356
+ );
357
+ Checkbox.displayName = "Checkbox";
358
+
359
+ // src/Radio/Radio.tsx
360
+ import { forwardRef as forwardRef6 } from "react";
361
+
362
+ // src/Radio/Radio.module.css
363
+ var Radio_default = {};
364
+
365
+ // src/Radio/Radio.tsx
366
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
367
+ var Radio = forwardRef6(
368
+ ({ label, hint, error = null, disabled, boxSize = "md", className, id, ...props }, ref) => {
369
+ const inputId = id ?? label.toLowerCase().replace(/\s+/g, "-");
370
+ const errorMessage = typeof error === "string" ? error : null;
371
+ return /* @__PURE__ */ jsxs6("div", { className: Radio_default.wrapper, "data-state": errorMessage ? "error" : "default", children: [
372
+ /* @__PURE__ */ jsxs6("label", { htmlFor: inputId, className: Radio_default.row, children: [
373
+ /* @__PURE__ */ jsx9(
374
+ "input",
375
+ {
376
+ ref,
377
+ id: inputId,
378
+ type: "radio",
379
+ className: [Radio_default.input, className].filter(Boolean).join(" "),
380
+ "data-size": boxSize,
381
+ disabled,
382
+ "aria-invalid": Boolean(errorMessage),
383
+ "aria-describedby": errorMessage ? `${inputId}-error` : hint ? `${inputId}-hint` : void 0,
384
+ ...props
385
+ }
386
+ ),
387
+ /* @__PURE__ */ jsx9("span", { className: Radio_default.label, children: label })
388
+ ] }),
389
+ hint && !errorMessage && /* @__PURE__ */ jsx9("span", { id: `${inputId}-hint`, className: Radio_default.hint, children: hint }),
390
+ errorMessage && /* @__PURE__ */ jsx9("span", { id: `${inputId}-error`, className: Radio_default.error, role: "alert", children: errorMessage })
391
+ ] });
392
+ }
393
+ );
394
+ Radio.displayName = "Radio";
395
+
396
+ // src/Switch/Switch.tsx
397
+ import { useCallback as useCallback2 } from "react";
398
+
399
+ // src/Switch/Switch.module.css
400
+ var Switch_default = {};
401
+
402
+ // src/Switch/Switch.tsx
403
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
404
+ function Switch({
405
+ label,
406
+ checked,
407
+ defaultChecked,
408
+ onCheckedChange,
409
+ hint,
410
+ disabled,
411
+ switchSize = "md",
412
+ className,
413
+ id,
414
+ ...props
415
+ }) {
416
+ const inputId = id ?? label.toLowerCase().replace(/\s+/g, "-");
417
+ const isControlled = checked !== void 0;
418
+ const isOn = isControlled ? checked : defaultChecked ?? false;
419
+ const handleClick = useCallback2(() => {
420
+ if (disabled) return;
421
+ const next = isControlled ? !checked : !isOn;
422
+ onCheckedChange?.(next);
423
+ }, [checked, disabled, isControlled, isOn, onCheckedChange]);
424
+ return /* @__PURE__ */ jsxs7("div", { className: Switch_default.wrapper, children: [
425
+ /* @__PURE__ */ jsxs7("div", { className: Switch_default.row, children: [
426
+ /* @__PURE__ */ jsx10(
427
+ "button",
428
+ {
429
+ id: inputId,
430
+ type: "button",
431
+ role: "switch",
432
+ "aria-checked": isOn,
433
+ "aria-label": label,
434
+ "aria-describedby": hint ? `${inputId}-hint` : void 0,
435
+ className: [Switch_default.track, className].filter(Boolean).join(" "),
436
+ "data-size": switchSize,
437
+ "data-state": isOn ? "on" : "off",
438
+ disabled,
439
+ onClick: handleClick,
440
+ ...props,
441
+ children: /* @__PURE__ */ jsx10("span", { className: Switch_default.thumb, "aria-hidden": "true" })
442
+ }
443
+ ),
444
+ /* @__PURE__ */ jsx10("span", { className: Switch_default.label, children: label })
445
+ ] }),
446
+ hint && /* @__PURE__ */ jsx10("span", { className: Switch_default.hint, id: `${inputId}-hint`, children: hint })
447
+ ] });
448
+ }
449
+
450
+ // src/Progress/Progress.module.css
451
+ var Progress_default = {};
452
+
453
+ // src/Progress/Progress.tsx
454
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
455
+ function Progress({
456
+ value,
457
+ max = 100,
458
+ label,
459
+ variant = "default",
460
+ state = "idle",
461
+ showValue = false
462
+ }) {
463
+ const clamped = Math.min(max, Math.max(0, value));
464
+ const percent = max > 0 ? Math.round(clamped / max * 100) : 0;
465
+ return /* @__PURE__ */ jsxs8("div", { className: Progress_default.wrapper, "data-state": state, children: [
466
+ (label || showValue) && /* @__PURE__ */ jsxs8("div", { className: Progress_default.header, children: [
467
+ label && /* @__PURE__ */ jsx11("span", { className: Progress_default.label, children: label }),
468
+ showValue && /* @__PURE__ */ jsxs8("span", { className: Progress_default.value, children: [
469
+ percent,
470
+ "%"
471
+ ] })
472
+ ] }),
473
+ /* @__PURE__ */ jsx11(
474
+ "div",
475
+ {
476
+ className: Progress_default.track,
477
+ role: "progressbar",
478
+ "aria-valuemin": 0,
479
+ "aria-valuemax": max,
480
+ "aria-valuenow": clamped,
481
+ "aria-label": label,
482
+ "data-variant": variant,
483
+ "data-state": state,
484
+ children: /* @__PURE__ */ jsx11("div", { className: Progress_default.bar, style: { width: `${percent}%` } })
485
+ }
486
+ )
487
+ ] });
488
+ }
489
+
490
+ // src/Alert/Alert.module.css
491
+ var Alert_default = {};
492
+
493
+ // src/Alert/Alert.tsx
494
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
495
+ function Alert({
496
+ variant = "info",
497
+ title,
498
+ children,
499
+ onDismiss
500
+ }) {
501
+ return /* @__PURE__ */ jsxs9(
502
+ "div",
503
+ {
504
+ className: Alert_default.alert,
505
+ "data-variant": variant,
506
+ role: "alert",
507
+ children: [
508
+ /* @__PURE__ */ jsxs9("div", { className: Alert_default.content, children: [
509
+ title && /* @__PURE__ */ jsx12("strong", { className: Alert_default.title, children: title }),
510
+ /* @__PURE__ */ jsx12("div", { className: Alert_default.message, children })
511
+ ] }),
512
+ onDismiss && /* @__PURE__ */ jsx12(
513
+ "button",
514
+ {
515
+ type: "button",
516
+ className: Alert_default.dismiss,
517
+ onClick: onDismiss,
518
+ "aria-label": "Dismiss alert",
519
+ children: "\xD7"
520
+ }
521
+ )
522
+ ]
523
+ }
524
+ );
525
+ }
526
+
527
+ // src/Modal/Modal.tsx
528
+ import {
529
+ useEffect as useEffect2,
530
+ useRef as useRef3
531
+ } from "react";
532
+ import { createPortal } from "react-dom";
533
+
534
+ // src/Modal/Modal.module.css
535
+ var Modal_default = {};
536
+
537
+ // src/Modal/Modal.tsx
538
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
539
+ function Modal({
540
+ open,
541
+ onClose,
542
+ children,
543
+ title,
544
+ description,
545
+ closeOnOverlay = true
546
+ }) {
547
+ const dialogRef = useRef3(null);
548
+ const previousFocus = useRef3(null);
549
+ useEffect2(() => {
550
+ if (!open) return;
551
+ previousFocus.current = document.activeElement;
552
+ const focusable = dialogRef.current?.querySelector(
553
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
554
+ );
555
+ focusable?.focus();
556
+ const onKeyDown = (e) => {
557
+ if (e.key === "Escape") onClose();
558
+ };
559
+ document.addEventListener("keydown", onKeyDown);
560
+ document.body.style.overflow = "hidden";
561
+ return () => {
562
+ document.removeEventListener("keydown", onKeyDown);
563
+ document.body.style.overflow = "";
564
+ previousFocus.current?.focus();
565
+ };
566
+ }, [open, onClose]);
567
+ if (!open) return null;
568
+ const handleOverlayClick = (e) => {
569
+ if (closeOnOverlay && e.target === e.currentTarget) onClose();
570
+ };
571
+ return createPortal(
572
+ /* @__PURE__ */ jsx13(
573
+ "div",
574
+ {
575
+ className: Modal_default.overlay,
576
+ onClick: handleOverlayClick,
577
+ role: "presentation",
578
+ children: /* @__PURE__ */ jsxs10(
579
+ "div",
580
+ {
581
+ ref: dialogRef,
582
+ className: Modal_default.modal,
583
+ role: "dialog",
584
+ "aria-modal": "true",
585
+ "aria-labelledby": title ? "lr-modal-title" : void 0,
586
+ "aria-describedby": description ? "lr-modal-desc" : void 0,
587
+ children: [
588
+ title && /* @__PURE__ */ jsx13("h2", { id: "lr-modal-title", className: Modal_default.title, children: title }),
589
+ description && /* @__PURE__ */ jsx13("p", { id: "lr-modal-desc", className: Modal_default.description, children: description }),
590
+ /* @__PURE__ */ jsx13("div", { className: Modal_default.content, children })
591
+ ]
592
+ }
593
+ )
594
+ }
595
+ ),
596
+ document.body
597
+ );
598
+ }
599
+
600
+ // src/Dialog/Dialog.module.css
601
+ var Dialog_default = {};
602
+
603
+ // src/Dialog/Dialog.tsx
604
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
605
+ function Dialog({
606
+ open,
607
+ onClose,
608
+ title,
609
+ description,
610
+ children,
611
+ confirmLabel = "Confirm",
612
+ cancelLabel = "Cancel",
613
+ onConfirm,
614
+ loading,
615
+ variant = "default"
616
+ }) {
617
+ return /* @__PURE__ */ jsxs11(Modal, { open, onClose, title, description, children: [
618
+ children && /* @__PURE__ */ jsx14("div", { className: Dialog_default.body, children }),
619
+ /* @__PURE__ */ jsxs11("div", { className: Dialog_default.actions, children: [
620
+ /* @__PURE__ */ jsx14(Button, { variant: "secondary", onClick: onClose, disabled: loading, children: cancelLabel }),
621
+ onConfirm && /* @__PURE__ */ jsx14(
622
+ Button,
623
+ {
624
+ variant: variant === "destructive" ? "destructive" : "primary",
625
+ onClick: onConfirm,
626
+ loading,
627
+ children: confirmLabel
628
+ }
629
+ )
630
+ ] })
631
+ ] });
632
+ }
633
+
634
+ // src/Card/Card.module.css
635
+ var Card_default = {};
636
+
637
+ // src/Card/Card.tsx
638
+ import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
639
+ function Card({
640
+ title,
641
+ description,
642
+ children,
643
+ footer,
644
+ padding = "md"
645
+ }) {
646
+ return /* @__PURE__ */ jsxs12("article", { className: Card_default.card, "data-padding": padding, children: [
647
+ (title || description) && /* @__PURE__ */ jsxs12("header", { className: Card_default.header, children: [
648
+ title && /* @__PURE__ */ jsx15("h3", { className: Card_default.title, children: title }),
649
+ description && /* @__PURE__ */ jsx15("p", { className: Card_default.description, children: description })
650
+ ] }),
651
+ children && /* @__PURE__ */ jsx15("div", { className: Card_default.body, children }),
652
+ footer && /* @__PURE__ */ jsx15("footer", { className: Card_default.footer, children: footer })
653
+ ] });
654
+ }
655
+
656
+ // src/Badge/Badge.module.css
657
+ var Badge_default = {};
658
+
659
+ // src/Badge/Badge.tsx
660
+ import { jsx as jsx16 } from "react/jsx-runtime";
661
+ function Badge({ variant = "default", children }) {
662
+ return /* @__PURE__ */ jsx16("span", { className: Badge_default.badge, "data-variant": variant, children });
663
+ }
664
+
665
+ // src/Skeleton/Skeleton.module.css
666
+ var Skeleton_default = {};
667
+
668
+ // src/Skeleton/Skeleton.tsx
669
+ import { jsx as jsx17 } from "react/jsx-runtime";
670
+ function Skeleton({
671
+ width = "100%",
672
+ height = "1rem",
673
+ variant = "text",
674
+ lines = 1
675
+ }) {
676
+ if (lines > 1) {
677
+ return /* @__PURE__ */ jsx17("div", { className: Skeleton_default.group, "aria-hidden": "true", children: Array.from({ length: lines }).map((_, i) => /* @__PURE__ */ jsx17(
678
+ "div",
679
+ {
680
+ className: Skeleton_default.skeleton,
681
+ "data-variant": "text",
682
+ style: {
683
+ width: i === lines - 1 ? "70%" : width,
684
+ height
685
+ }
686
+ },
687
+ i
688
+ )) });
689
+ }
690
+ return /* @__PURE__ */ jsx17(
691
+ "div",
692
+ {
693
+ className: Skeleton_default.skeleton,
694
+ "data-variant": variant,
695
+ style: { width, height: variant === "circular" ? width : height },
696
+ "aria-hidden": "true"
697
+ }
698
+ );
699
+ }
700
+
701
+ // src/EmptyState/EmptyState.module.css
702
+ var EmptyState_default = {};
703
+
704
+ // src/EmptyState/EmptyState.tsx
705
+ import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
706
+ function EmptyState({
707
+ title,
708
+ description,
709
+ icon,
710
+ actionLabel,
711
+ onAction,
712
+ state = "empty"
713
+ }) {
714
+ return /* @__PURE__ */ jsxs13("div", { className: EmptyState_default.empty, "data-state": state, role: "status", children: [
715
+ icon && /* @__PURE__ */ jsx18("div", { className: EmptyState_default.icon, children: icon }),
716
+ /* @__PURE__ */ jsx18("h3", { className: EmptyState_default.title, children: title }),
717
+ description && /* @__PURE__ */ jsx18("p", { className: EmptyState_default.description, children: description }),
718
+ actionLabel && onAction && /* @__PURE__ */ jsx18(Button, { variant: "primary", onClick: onAction, children: actionLabel })
719
+ ] });
720
+ }
721
+
722
+ // src/Tooltip/Tooltip.tsx
723
+ import { useId, useState } from "react";
724
+
725
+ // src/Tooltip/Tooltip.module.css
726
+ var Tooltip_default = {};
727
+
728
+ // src/Tooltip/Tooltip.tsx
729
+ import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
730
+ function Tooltip({ content, children, side = "top" }) {
731
+ const [visible, setVisible] = useState(false);
732
+ const tooltipId = useId();
733
+ return /* @__PURE__ */ jsxs14(
734
+ "span",
735
+ {
736
+ className: Tooltip_default.wrapper,
737
+ onMouseEnter: () => setVisible(true),
738
+ onMouseLeave: () => setVisible(false),
739
+ onFocusCapture: () => setVisible(true),
740
+ onBlurCapture: () => setVisible(false),
741
+ children: [
742
+ /* @__PURE__ */ jsx19("span", { "aria-describedby": visible ? tooltipId : void 0, children }),
743
+ visible && /* @__PURE__ */ jsx19("span", { id: tooltipId, role: "tooltip", className: Tooltip_default.tooltip, "data-side": side, children: content })
744
+ ]
745
+ }
746
+ );
747
+ }
748
+
749
+ // src/Toast/Toast.tsx
750
+ import {
751
+ createContext as createContext2,
752
+ useCallback as useCallback3,
753
+ useContext as useContext2,
754
+ useMemo,
755
+ useState as useState2
756
+ } from "react";
757
+ import { createPortal as createPortal2 } from "react-dom";
758
+
759
+ // src/Toast/Toast.module.css
760
+ var Toast_default = {};
761
+
762
+ // src/Toast/Toast.tsx
763
+ import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
764
+ var ToastContext = createContext2(null);
765
+ function ToastProvider({
766
+ children,
767
+ placement = "bottom-right"
768
+ }) {
769
+ const [toasts, setToasts] = useState2([]);
770
+ const dismiss = useCallback3((id) => {
771
+ setToasts((prev) => prev.filter((toast2) => toast2.id !== id));
772
+ }, []);
773
+ const toast = useCallback3(
774
+ (input) => {
775
+ const id = crypto.randomUUID();
776
+ setToasts((prev) => [...prev, { ...input, id }]);
777
+ window.setTimeout(() => dismiss(id), input.duration ?? 5e3);
778
+ return id;
779
+ },
780
+ [dismiss]
781
+ );
782
+ const value = useMemo(() => ({ toast, dismiss }), [toast, dismiss]);
783
+ return /* @__PURE__ */ jsxs15(ToastContext.Provider, { value, children: [
784
+ children,
785
+ createPortal2(
786
+ /* @__PURE__ */ jsx20(
787
+ "div",
788
+ {
789
+ className: Toast_default.viewport,
790
+ "data-placement": placement,
791
+ "aria-live": "polite",
792
+ "aria-relevant": "additions",
793
+ children: toasts.map((item) => /* @__PURE__ */ jsx20(Toast, { item, onDismiss: () => dismiss(item.id) }, item.id))
794
+ }
795
+ ),
796
+ document.body
797
+ )
798
+ ] });
799
+ }
800
+ function useToast() {
801
+ const context = useContext2(ToastContext);
802
+ if (!context) {
803
+ throw new Error("useToast must be used within ToastProvider");
804
+ }
805
+ return context;
806
+ }
807
+ function Toast({ item, onDismiss }) {
808
+ const variant = item.variant ?? "info";
809
+ return /* @__PURE__ */ jsxs15(
810
+ "div",
811
+ {
812
+ className: Toast_default.toast,
813
+ "data-variant": variant,
814
+ role: variant === "error" ? "alert" : "status",
815
+ children: [
816
+ /* @__PURE__ */ jsxs15("div", { className: Toast_default.content, children: [
817
+ item.title && /* @__PURE__ */ jsx20("strong", { className: Toast_default.title, children: item.title }),
818
+ /* @__PURE__ */ jsx20("span", { className: Toast_default.message, children: item.message })
819
+ ] }),
820
+ /* @__PURE__ */ jsx20("button", { type: "button", className: Toast_default.dismiss, onClick: onDismiss, "aria-label": "Dismiss", children: "\xD7" })
821
+ ]
822
+ }
823
+ );
824
+ }
825
+
826
+ // src/Tabs/Tabs.tsx
827
+ import {
828
+ createContext as createContext3,
829
+ useCallback as useCallback4,
830
+ useContext as useContext3,
831
+ useId as useId2,
832
+ useMemo as useMemo2,
833
+ useState as useState3
834
+ } from "react";
835
+
836
+ // src/Tabs/Tabs.module.css
837
+ var Tabs_default = {};
838
+
839
+ // src/Tabs/Tabs.tsx
840
+ import { jsx as jsx21 } from "react/jsx-runtime";
841
+ var TabsContext = createContext3(null);
842
+ function useTabsContext(component) {
843
+ const context = useContext3(TabsContext);
844
+ if (!context) {
845
+ throw new Error(`${component} must be used within Tabs`);
846
+ }
847
+ return context;
848
+ }
849
+ function Tabs({
850
+ value,
851
+ defaultValue = "",
852
+ onValueChange,
853
+ children,
854
+ className
855
+ }) {
856
+ const [internalValue, setInternalValue] = useState3(defaultValue);
857
+ const isControlled = value !== void 0;
858
+ const currentValue = isControlled ? value : internalValue;
859
+ const baseId = useId2();
860
+ const handleChange = useCallback4(
861
+ (next) => {
862
+ if (!isControlled) setInternalValue(next);
863
+ onValueChange?.(next);
864
+ },
865
+ [isControlled, onValueChange]
866
+ );
867
+ const context = useMemo2(
868
+ () => ({
869
+ value: currentValue,
870
+ onValueChange: handleChange,
871
+ baseId
872
+ }),
873
+ [baseId, currentValue, handleChange]
874
+ );
875
+ return /* @__PURE__ */ jsx21(TabsContext.Provider, { value: context, children: /* @__PURE__ */ jsx21("div", { className: [Tabs_default.tabs, className].filter(Boolean).join(" "), children }) });
876
+ }
877
+ function TabsList({ children, "aria-label": ariaLabel = "Tabs" }) {
878
+ return /* @__PURE__ */ jsx21("div", { className: Tabs_default.list, role: "tablist", "aria-label": ariaLabel, children });
879
+ }
880
+ function TabsTrigger({ value, children, disabled }) {
881
+ const { value: activeValue, onValueChange, baseId } = useTabsContext("TabsTrigger");
882
+ const selected = activeValue === value;
883
+ const tabId = `${baseId}-tab-${value}`;
884
+ const panelId = `${baseId}-panel-${value}`;
885
+ return /* @__PURE__ */ jsx21(
886
+ "button",
887
+ {
888
+ type: "button",
889
+ id: tabId,
890
+ role: "tab",
891
+ className: Tabs_default.trigger,
892
+ "aria-selected": selected,
893
+ "aria-controls": panelId,
894
+ tabIndex: selected ? 0 : -1,
895
+ "data-state": selected ? "active" : "inactive",
896
+ disabled,
897
+ onClick: () => onValueChange(value),
898
+ children
899
+ }
900
+ );
901
+ }
902
+ function TabsPanel({ value, children }) {
903
+ const { value: activeValue, baseId } = useTabsContext("TabsPanel");
904
+ const selected = activeValue === value;
905
+ const tabId = `${baseId}-tab-${value}`;
906
+ const panelId = `${baseId}-panel-${value}`;
907
+ if (!selected) return null;
908
+ return /* @__PURE__ */ jsx21(
909
+ "div",
910
+ {
911
+ id: panelId,
912
+ role: "tabpanel",
913
+ className: Tabs_default.panel,
914
+ "aria-labelledby": tabId,
915
+ tabIndex: 0,
916
+ children
917
+ }
918
+ );
919
+ }
920
+
921
+ // src/Drawer/Drawer.tsx
922
+ import {
923
+ useEffect as useEffect3,
924
+ useRef as useRef4
925
+ } from "react";
926
+ import { createPortal as createPortal3 } from "react-dom";
927
+
928
+ // src/Drawer/Drawer.module.css
929
+ var Drawer_default = {};
930
+
931
+ // src/Drawer/Drawer.tsx
932
+ import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
933
+ function Drawer({
934
+ open,
935
+ onClose,
936
+ children,
937
+ title,
938
+ description,
939
+ side = "right",
940
+ closeOnOverlay = true
941
+ }) {
942
+ const panelRef = useRef4(null);
943
+ const previousFocus = useRef4(null);
944
+ useEffect3(() => {
945
+ if (!open) return;
946
+ previousFocus.current = document.activeElement;
947
+ panelRef.current?.focus();
948
+ const onKeyDown = (e) => {
949
+ if (e.key === "Escape") onClose();
950
+ };
951
+ document.addEventListener("keydown", onKeyDown);
952
+ document.body.style.overflow = "hidden";
953
+ return () => {
954
+ document.removeEventListener("keydown", onKeyDown);
955
+ document.body.style.overflow = "";
956
+ previousFocus.current?.focus();
957
+ };
958
+ }, [open, onClose]);
959
+ if (!open) return null;
960
+ const handleOverlayClick = (e) => {
961
+ if (closeOnOverlay && e.target === e.currentTarget) onClose();
962
+ };
963
+ return createPortal3(
964
+ /* @__PURE__ */ jsx22("div", { className: Drawer_default.overlay, onClick: handleOverlayClick, role: "presentation", children: /* @__PURE__ */ jsxs16(
965
+ "aside",
966
+ {
967
+ ref: panelRef,
968
+ className: Drawer_default.panel,
969
+ "data-side": side,
970
+ role: "dialog",
971
+ "aria-modal": "true",
972
+ "aria-labelledby": title ? "lr-drawer-title" : void 0,
973
+ "aria-describedby": description ? "lr-drawer-desc" : void 0,
974
+ tabIndex: -1,
975
+ children: [
976
+ title && /* @__PURE__ */ jsx22("h2", { id: "lr-drawer-title", className: Drawer_default.title, children: title }),
977
+ description && /* @__PURE__ */ jsx22("p", { id: "lr-drawer-desc", className: Drawer_default.description, children: description }),
978
+ /* @__PURE__ */ jsx22("div", { className: Drawer_default.content, children })
979
+ ]
980
+ }
981
+ ) }),
982
+ document.body
983
+ );
984
+ }
985
+
986
+ // src/Popover/Popover.tsx
987
+ import {
988
+ useCallback as useCallback5,
989
+ useEffect as useEffect4,
990
+ useId as useId3,
991
+ useRef as useRef5,
992
+ useState as useState4
993
+ } from "react";
994
+
995
+ // src/Popover/Popover.module.css
996
+ var Popover_default = {};
997
+
998
+ // src/Popover/Popover.tsx
999
+ import { jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
1000
+ function Popover({
1001
+ trigger,
1002
+ content,
1003
+ open,
1004
+ defaultOpen = false,
1005
+ onOpenChange,
1006
+ side = "bottom",
1007
+ "aria-label": ariaLabel = "Popover"
1008
+ }) {
1009
+ const [internalOpen, setInternalOpen] = useState4(defaultOpen);
1010
+ const isControlled = open !== void 0;
1011
+ const isOpen = isControlled ? open : internalOpen;
1012
+ const popoverId = useId3();
1013
+ const rootRef = useRef5(null);
1014
+ const setOpen = useCallback5(
1015
+ (next) => {
1016
+ if (!isControlled) setInternalOpen(next);
1017
+ onOpenChange?.(next);
1018
+ },
1019
+ [isControlled, onOpenChange]
1020
+ );
1021
+ useEffect4(() => {
1022
+ if (!isOpen) return;
1023
+ const onPointerDown = (event) => {
1024
+ if (!rootRef.current?.contains(event.target)) {
1025
+ setOpen(false);
1026
+ }
1027
+ };
1028
+ const onKeyDown = (event) => {
1029
+ if (event.key === "Escape") setOpen(false);
1030
+ };
1031
+ document.addEventListener("mousedown", onPointerDown);
1032
+ document.addEventListener("keydown", onKeyDown);
1033
+ return () => {
1034
+ document.removeEventListener("mousedown", onPointerDown);
1035
+ document.removeEventListener("keydown", onKeyDown);
1036
+ };
1037
+ }, [isOpen, setOpen]);
1038
+ return /* @__PURE__ */ jsxs17("span", { ref: rootRef, className: Popover_default.wrapper, children: [
1039
+ /* @__PURE__ */ jsx23(
1040
+ "span",
1041
+ {
1042
+ onClick: () => setOpen(!isOpen),
1043
+ "aria-expanded": isOpen,
1044
+ "aria-controls": isOpen ? popoverId : void 0,
1045
+ children: trigger
1046
+ }
1047
+ ),
1048
+ isOpen && /* @__PURE__ */ jsx23(
1049
+ "div",
1050
+ {
1051
+ id: popoverId,
1052
+ role: "dialog",
1053
+ "aria-label": ariaLabel,
1054
+ className: Popover_default.popover,
1055
+ "data-side": side,
1056
+ children: content
1057
+ }
1058
+ )
1059
+ ] });
1060
+ }
1061
+
1062
+ // src/Breadcrumb/Breadcrumb.module.css
1063
+ var Breadcrumb_default = {};
1064
+
1065
+ // src/Breadcrumb/Breadcrumb.tsx
1066
+ import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
1067
+ function Breadcrumb({ items, "aria-label": ariaLabel = "Breadcrumb" }) {
1068
+ return /* @__PURE__ */ jsx24("nav", { className: Breadcrumb_default.nav, "aria-label": ariaLabel, children: /* @__PURE__ */ jsx24("ol", { className: Breadcrumb_default.list, children: items.map((item, index) => {
1069
+ const isLast = index === items.length - 1;
1070
+ const isCurrent = item.current ?? isLast;
1071
+ return /* @__PURE__ */ jsxs18("li", { className: Breadcrumb_default.item, children: [
1072
+ isCurrent ? /* @__PURE__ */ jsx24("span", { className: Breadcrumb_default.current, "aria-current": "page", children: item.label }) : item.href ? /* @__PURE__ */ jsx24("a", { href: item.href, className: Breadcrumb_default.link, onClick: item.onClick, children: item.label }) : /* @__PURE__ */ jsx24("button", { type: "button", className: Breadcrumb_default.linkButton, onClick: item.onClick, children: item.label }),
1073
+ !isLast && /* @__PURE__ */ jsx24("span", { className: Breadcrumb_default.separator, "aria-hidden": "true", children: "/" })
1074
+ ] }, `${item.label}-${index}`);
1075
+ }) }) });
1076
+ }
1077
+
1078
+ // src/Accordion/Accordion.tsx
1079
+ import {
1080
+ createContext as createContext4,
1081
+ useCallback as useCallback6,
1082
+ useContext as useContext4,
1083
+ useId as useId4,
1084
+ useMemo as useMemo3,
1085
+ useState as useState5
1086
+ } from "react";
1087
+
1088
+ // src/Accordion/Accordion.module.css
1089
+ var Accordion_default = {};
1090
+
1091
+ // src/Accordion/Accordion.tsx
1092
+ import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
1093
+ var AccordionContext = createContext4(null);
1094
+ var AccordionItemContext = createContext4(null);
1095
+ function useAccordionContext(component) {
1096
+ const context = useContext4(AccordionContext);
1097
+ if (!context) {
1098
+ throw new Error(`${component} must be used within Accordion`);
1099
+ }
1100
+ return context;
1101
+ }
1102
+ function useAccordionItemContext(component) {
1103
+ const value = useContext4(AccordionItemContext);
1104
+ if (!value) {
1105
+ throw new Error(`${component} must be used within AccordionItem`);
1106
+ }
1107
+ return value;
1108
+ }
1109
+ function Accordion({
1110
+ type = "single",
1111
+ collapsible = false,
1112
+ value,
1113
+ defaultValue = [],
1114
+ onValueChange,
1115
+ children,
1116
+ className
1117
+ }) {
1118
+ const [internalValue, setInternalValue] = useState5(defaultValue);
1119
+ const isControlled = value !== void 0;
1120
+ const openItems = useMemo3(
1121
+ () => new Set(isControlled ? value : internalValue),
1122
+ [internalValue, isControlled, value]
1123
+ );
1124
+ const baseId = useId4();
1125
+ const toggleItem = useCallback6(
1126
+ (itemValue) => {
1127
+ const next = new Set(openItems);
1128
+ const isOpen = next.has(itemValue);
1129
+ if (type === "single") {
1130
+ next.clear();
1131
+ if (!isOpen || !collapsible) {
1132
+ next.add(itemValue);
1133
+ }
1134
+ } else if (isOpen) {
1135
+ next.delete(itemValue);
1136
+ } else {
1137
+ next.add(itemValue);
1138
+ }
1139
+ const nextValue = Array.from(next);
1140
+ if (!isControlled) setInternalValue(nextValue);
1141
+ onValueChange?.(nextValue);
1142
+ },
1143
+ [collapsible, isControlled, onValueChange, openItems, type]
1144
+ );
1145
+ const context = useMemo3(
1146
+ () => ({
1147
+ type,
1148
+ collapsible,
1149
+ openItems,
1150
+ toggleItem,
1151
+ baseId
1152
+ }),
1153
+ [baseId, collapsible, openItems, toggleItem, type]
1154
+ );
1155
+ return /* @__PURE__ */ jsx25(AccordionContext.Provider, { value: context, children: /* @__PURE__ */ jsx25("div", { className: [Accordion_default.accordion, className].filter(Boolean).join(" "), children }) });
1156
+ }
1157
+ function AccordionItem({ value, children, disabled }) {
1158
+ return /* @__PURE__ */ jsx25(AccordionItemContext.Provider, { value, children: /* @__PURE__ */ jsx25("div", { className: Accordion_default.item, "data-disabled": disabled ? "true" : void 0, children }) });
1159
+ }
1160
+ function AccordionTrigger({ children }) {
1161
+ const itemValue = useAccordionItemContext("AccordionTrigger");
1162
+ const { openItems, toggleItem, baseId } = useAccordionContext("AccordionTrigger");
1163
+ const isOpen = openItems.has(itemValue);
1164
+ const triggerId = `${baseId}-trigger-${itemValue}`;
1165
+ const panelId = `${baseId}-panel-${itemValue}`;
1166
+ return /* @__PURE__ */ jsxs19(
1167
+ "button",
1168
+ {
1169
+ type: "button",
1170
+ id: triggerId,
1171
+ className: Accordion_default.trigger,
1172
+ "aria-expanded": isOpen,
1173
+ "aria-controls": panelId,
1174
+ "data-state": isOpen ? "open" : "closed",
1175
+ onClick: () => toggleItem(itemValue),
1176
+ children: [
1177
+ /* @__PURE__ */ jsx25("span", { children }),
1178
+ /* @__PURE__ */ jsx25("span", { className: Accordion_default.icon, "aria-hidden": "true", children: "\u25BE" })
1179
+ ]
1180
+ }
1181
+ );
1182
+ }
1183
+ function AccordionContent({ children }) {
1184
+ const itemValue = useAccordionItemContext("AccordionContent");
1185
+ const { openItems, baseId } = useAccordionContext("AccordionContent");
1186
+ const isOpen = openItems.has(itemValue);
1187
+ const triggerId = `${baseId}-trigger-${itemValue}`;
1188
+ const panelId = `${baseId}-panel-${itemValue}`;
1189
+ return /* @__PURE__ */ jsx25(
1190
+ "div",
1191
+ {
1192
+ id: panelId,
1193
+ role: "region",
1194
+ className: Accordion_default.content,
1195
+ "aria-labelledby": triggerId,
1196
+ "data-state": isOpen ? "open" : "closed",
1197
+ hidden: !isOpen,
1198
+ children
1199
+ }
1200
+ );
1201
+ }
1202
+
1203
+ // src/Pagination/Pagination.tsx
1204
+ import { useMemo as useMemo4 } from "react";
1205
+
1206
+ // src/Pagination/Pagination.module.css
1207
+ var Pagination_default = {};
1208
+
1209
+ // src/Pagination/Pagination.tsx
1210
+ import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
1211
+ function range(start, end) {
1212
+ const items = [];
1213
+ for (let i = start; i <= end; i += 1) {
1214
+ items.push(i);
1215
+ }
1216
+ return items;
1217
+ }
1218
+ function getPageItems(page, totalPages, siblingCount) {
1219
+ if (totalPages <= 1) return [1];
1220
+ const totalNumbers = siblingCount * 2 + 5;
1221
+ if (totalPages <= totalNumbers) {
1222
+ return range(1, totalPages);
1223
+ }
1224
+ const leftSibling = Math.max(page - siblingCount, 1);
1225
+ const rightSibling = Math.min(page + siblingCount, totalPages);
1226
+ const showLeftEllipsis = leftSibling > 2;
1227
+ const showRightEllipsis = rightSibling < totalPages - 1;
1228
+ if (!showLeftEllipsis && showRightEllipsis) {
1229
+ return [...range(1, 3 + siblingCount * 2), "ellipsis", totalPages];
1230
+ }
1231
+ if (showLeftEllipsis && !showRightEllipsis) {
1232
+ return [1, "ellipsis", ...range(totalPages - (3 + siblingCount * 2), totalPages)];
1233
+ }
1234
+ if (showLeftEllipsis && showRightEllipsis) {
1235
+ return [1, "ellipsis", ...range(leftSibling, rightSibling), "ellipsis", totalPages];
1236
+ }
1237
+ return range(1, totalPages);
1238
+ }
1239
+ function Pagination({
1240
+ page,
1241
+ totalPages,
1242
+ onPageChange,
1243
+ siblingCount = 1,
1244
+ previousLabel = "Previous page",
1245
+ nextLabel = "Next page",
1246
+ "aria-label": ariaLabel = "Pagination",
1247
+ className
1248
+ }) {
1249
+ const items = useMemo4(
1250
+ () => getPageItems(page, totalPages, siblingCount),
1251
+ [page, siblingCount, totalPages]
1252
+ );
1253
+ if (totalPages < 1) return null;
1254
+ return /* @__PURE__ */ jsxs20("nav", { className: [Pagination_default.pagination, className].filter(Boolean).join(" "), "aria-label": ariaLabel, children: [
1255
+ /* @__PURE__ */ jsx26(
1256
+ "button",
1257
+ {
1258
+ type: "button",
1259
+ className: Pagination_default.pageButton,
1260
+ "aria-label": previousLabel,
1261
+ disabled: page <= 1,
1262
+ onClick: () => onPageChange(page - 1),
1263
+ children: "\u2039"
1264
+ }
1265
+ ),
1266
+ items.map(
1267
+ (item, index) => item === "ellipsis" ? /* @__PURE__ */ jsx26("span", { className: Pagination_default.ellipsis, "aria-hidden": "true", children: "\u2026" }, `ellipsis-${index}`) : /* @__PURE__ */ jsx26(
1268
+ "button",
1269
+ {
1270
+ type: "button",
1271
+ className: Pagination_default.pageButton,
1272
+ "aria-label": `Page ${item}`,
1273
+ "aria-current": item === page ? "page" : void 0,
1274
+ "data-state": item === page ? "active" : "inactive",
1275
+ onClick: () => onPageChange(item),
1276
+ children: item
1277
+ },
1278
+ item
1279
+ )
1280
+ ),
1281
+ /* @__PURE__ */ jsx26(
1282
+ "button",
1283
+ {
1284
+ type: "button",
1285
+ className: Pagination_default.pageButton,
1286
+ "aria-label": nextLabel,
1287
+ disabled: page >= totalPages,
1288
+ onClick: () => onPageChange(page + 1),
1289
+ children: "\u203A"
1290
+ }
1291
+ )
1292
+ ] });
1293
+ }
1294
+
1295
+ // src/DataTable/DataTable.module.css
1296
+ var DataTable_default = {};
1297
+
1298
+ // src/DataTable/DataTable.tsx
1299
+ import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
1300
+ function renderCell(row, column) {
1301
+ if (column.render) return column.render(row);
1302
+ if (column.accessor) return column.accessor(row);
1303
+ return null;
1304
+ }
1305
+ function DataTable({
1306
+ data,
1307
+ columns,
1308
+ keyExtractor,
1309
+ caption,
1310
+ "aria-label": ariaLabel,
1311
+ loading = false,
1312
+ emptyTitle = "No data",
1313
+ emptyDescription,
1314
+ emptyMessage,
1315
+ striped = false,
1316
+ skeletonRows = 3,
1317
+ className
1318
+ }) {
1319
+ if (loading) {
1320
+ return /* @__PURE__ */ jsx27(
1321
+ "div",
1322
+ {
1323
+ className: [DataTable_default.wrapper, className].filter(Boolean).join(" "),
1324
+ "data-state": "loading",
1325
+ "aria-busy": "true",
1326
+ "aria-label": ariaLabel ?? caption ?? "Loading table",
1327
+ children: Array.from({ length: skeletonRows }).map((_, index) => /* @__PURE__ */ jsx27("div", { className: DataTable_default.skeletonRow, children: columns.map((column) => /* @__PURE__ */ jsx27(Skeleton, { height: "1rem", width: `${100 / columns.length}%` }, column.key)) }, index))
1328
+ }
1329
+ );
1330
+ }
1331
+ if (data.length === 0) {
1332
+ return /* @__PURE__ */ jsx27(
1333
+ "div",
1334
+ {
1335
+ className: [DataTable_default.wrapper, className].filter(Boolean).join(" "),
1336
+ "data-state": "empty",
1337
+ children: /* @__PURE__ */ jsx27("div", { className: DataTable_default.empty, children: /* @__PURE__ */ jsx27(
1338
+ EmptyState,
1339
+ {
1340
+ title: emptyTitle,
1341
+ description: emptyDescription ?? emptyMessage,
1342
+ state: "empty"
1343
+ }
1344
+ ) })
1345
+ }
1346
+ );
1347
+ }
1348
+ return /* @__PURE__ */ jsx27("div", { className: [DataTable_default.wrapper, className].filter(Boolean).join(" "), "data-state": "ready", children: /* @__PURE__ */ jsxs21("table", { className: DataTable_default.table, "aria-label": ariaLabel, children: [
1349
+ caption && /* @__PURE__ */ jsx27("caption", { className: DataTable_default.caption, children: caption }),
1350
+ /* @__PURE__ */ jsx27("thead", { children: /* @__PURE__ */ jsx27("tr", { children: columns.map((column) => /* @__PURE__ */ jsx27("th", { scope: "col", className: DataTable_default.headCell, children: column.header }, column.key)) }) }),
1351
+ /* @__PURE__ */ jsx27("tbody", { children: data.map((row) => /* @__PURE__ */ jsx27("tr", { className: DataTable_default.row, "data-striped": striped ? "true" : void 0, children: columns.map((column) => /* @__PURE__ */ jsx27("td", { className: DataTable_default.cell, children: renderCell(row, column) }, column.key)) }, keyExtractor(row))) })
1352
+ ] }) });
1353
+ }
1354
+
1355
+ // src/FileUpload/FileUpload.tsx
1356
+ import { useCallback as useCallback7, useId as useId5, useRef as useRef6, useState as useState6 } from "react";
1357
+
1358
+ // src/FileUpload/FileUpload.module.css
1359
+ var FileUpload_default = {};
1360
+
1361
+ // src/FileUpload/FileUpload.tsx
1362
+ import { jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
1363
+ function FileUpload({
1364
+ label,
1365
+ hint,
1366
+ error = null,
1367
+ accept,
1368
+ multiple = false,
1369
+ disabled = false,
1370
+ buttonLabel = "Choose files or drag here",
1371
+ onFilesChange,
1372
+ className
1373
+ }) {
1374
+ const inputId = useId5();
1375
+ const inputRef = useRef6(null);
1376
+ const [files, setFiles] = useState6([]);
1377
+ const [dragOver, setDragOver] = useState6(false);
1378
+ const errorMessage = typeof error === "string" ? error : null;
1379
+ const uiState = disabled ? "disabled" : errorMessage ? "error" : dragOver ? "dragover" : "default";
1380
+ const updateFiles = useCallback7(
1381
+ (next) => {
1382
+ setFiles(next);
1383
+ onFilesChange?.(next);
1384
+ },
1385
+ [onFilesChange]
1386
+ );
1387
+ const handleFiles = useCallback7(
1388
+ (fileList) => {
1389
+ if (!fileList || disabled) return;
1390
+ updateFiles(Array.from(fileList));
1391
+ },
1392
+ [disabled, updateFiles]
1393
+ );
1394
+ const onDrop = useCallback7(
1395
+ (event) => {
1396
+ event.preventDefault();
1397
+ setDragOver(false);
1398
+ handleFiles(event.dataTransfer.files);
1399
+ },
1400
+ [handleFiles]
1401
+ );
1402
+ return /* @__PURE__ */ jsxs22("div", { className: [FileUpload_default.wrapper, className].filter(Boolean).join(" "), "data-state": uiState, children: [
1403
+ label && /* @__PURE__ */ jsx28("span", { id: `${inputId}-label`, className: FileUpload_default.label, children: label }),
1404
+ /* @__PURE__ */ jsxs22(
1405
+ "label",
1406
+ {
1407
+ htmlFor: inputId,
1408
+ className: FileUpload_default.dropzone,
1409
+ "data-state": uiState,
1410
+ onDragOver: (event) => {
1411
+ event.preventDefault();
1412
+ if (!disabled) setDragOver(true);
1413
+ },
1414
+ onDragLeave: () => setDragOver(false),
1415
+ onDrop,
1416
+ children: [
1417
+ /* @__PURE__ */ jsx28(
1418
+ "input",
1419
+ {
1420
+ ref: inputRef,
1421
+ id: inputId,
1422
+ type: "file",
1423
+ className: FileUpload_default.input,
1424
+ accept,
1425
+ multiple,
1426
+ disabled,
1427
+ "aria-invalid": Boolean(errorMessage),
1428
+ "aria-describedby": errorMessage ? `${inputId}-error` : hint ? `${inputId}-hint` : void 0,
1429
+ "aria-labelledby": label ? `${inputId}-label` : void 0,
1430
+ onChange: (event) => handleFiles(event.target.files)
1431
+ }
1432
+ ),
1433
+ /* @__PURE__ */ jsx28("span", { children: buttonLabel })
1434
+ ]
1435
+ }
1436
+ ),
1437
+ files.length > 0 && /* @__PURE__ */ jsx28("ul", { className: FileUpload_default.fileList, "aria-label": "Selected files", children: files.map((file) => /* @__PURE__ */ jsx28("li", { className: FileUpload_default.fileItem, children: file.name }, `${file.name}-${file.lastModified}`)) }),
1438
+ hint && !errorMessage && /* @__PURE__ */ jsx28("span", { id: `${inputId}-hint`, className: FileUpload_default.hint, children: hint }),
1439
+ errorMessage && /* @__PURE__ */ jsx28("span", { id: `${inputId}-error`, className: FileUpload_default.error, role: "alert", children: errorMessage })
1440
+ ] });
1441
+ }
1442
+
1443
+ // src/Sidebar/Sidebar.module.css
1444
+ var Sidebar_default = {};
1445
+
1446
+ // src/Sidebar/Sidebar.tsx
1447
+ import { jsx as jsx29, jsxs as jsxs23 } from "react/jsx-runtime";
1448
+ function Sidebar({
1449
+ children,
1450
+ "aria-label": ariaLabel = "Sidebar",
1451
+ className
1452
+ }) {
1453
+ return /* @__PURE__ */ jsx29("aside", { className: [Sidebar_default.sidebar, className].filter(Boolean).join(" "), "aria-label": ariaLabel, children });
1454
+ }
1455
+ function SidebarHeader({ children }) {
1456
+ return /* @__PURE__ */ jsx29("div", { className: Sidebar_default.header, children });
1457
+ }
1458
+ function SidebarNav({ children, "aria-label": ariaLabel = "Sidebar navigation" }) {
1459
+ return /* @__PURE__ */ jsx29("nav", { className: Sidebar_default.nav, "aria-label": ariaLabel, children });
1460
+ }
1461
+ function SidebarGroup({ label, children }) {
1462
+ return /* @__PURE__ */ jsxs23("div", { role: "group", "aria-label": label, children: [
1463
+ /* @__PURE__ */ jsx29("div", { className: Sidebar_default.groupLabel, children: label }),
1464
+ children
1465
+ ] });
1466
+ }
1467
+ function SidebarItem({
1468
+ children,
1469
+ href,
1470
+ active = false,
1471
+ disabled = false,
1472
+ onClick
1473
+ }) {
1474
+ const state = disabled ? "disabled" : active ? "active" : "inactive";
1475
+ if (href && !disabled) {
1476
+ return /* @__PURE__ */ jsx29("a", { href, className: Sidebar_default.item, "data-state": state, "aria-current": active ? "page" : void 0, children });
1477
+ }
1478
+ return /* @__PURE__ */ jsx29(
1479
+ "button",
1480
+ {
1481
+ type: "button",
1482
+ className: Sidebar_default.item,
1483
+ "data-state": state,
1484
+ "aria-current": active ? "page" : void 0,
1485
+ disabled,
1486
+ onClick,
1487
+ children
1488
+ }
1489
+ );
1490
+ }
1491
+
1492
+ // src/Header/Header.module.css
1493
+ var Header_default = {};
1494
+
1495
+ // src/Header/Header.tsx
1496
+ import { jsx as jsx30 } from "react/jsx-runtime";
1497
+ function Header({ children, className }) {
1498
+ return /* @__PURE__ */ jsx30("header", { className: [Header_default.header, className].filter(Boolean).join(" "), children });
1499
+ }
1500
+ function HeaderTitle({ children }) {
1501
+ return /* @__PURE__ */ jsx30("h1", { className: Header_default.title, children });
1502
+ }
1503
+ function HeaderBrand({ children }) {
1504
+ return /* @__PURE__ */ jsx30("div", { className: Header_default.brand, children });
1505
+ }
1506
+ function HeaderActions({ children }) {
1507
+ return /* @__PURE__ */ jsx30("div", { className: Header_default.actions, children });
1508
+ }
1509
+
1510
+ // src/CommandPalette/CommandPalette.tsx
1511
+ import { useCallback as useCallback8, useEffect as useEffect5, useMemo as useMemo5, useRef as useRef7, useState as useState7 } from "react";
1512
+
1513
+ // src/CommandPalette/CommandPalette.module.css
1514
+ var CommandPalette_default = {};
1515
+
1516
+ // src/CommandPalette/CommandPalette.tsx
1517
+ import { jsx as jsx31, jsxs as jsxs24 } from "react/jsx-runtime";
1518
+ function matchesQuery(item, query) {
1519
+ if (!query) return true;
1520
+ const haystack = [item.label, ...item.keywords ?? []].join(" ").toLowerCase();
1521
+ return haystack.includes(query.toLowerCase());
1522
+ }
1523
+ function CommandPalette({
1524
+ open,
1525
+ onOpenChange,
1526
+ items,
1527
+ placeholder = "Search commands\u2026",
1528
+ emptyMessage = "No commands found",
1529
+ "aria-label": ariaLabel = "Command palette"
1530
+ }) {
1531
+ const [query, setQuery] = useState7("");
1532
+ const [activeIndex, setActiveIndex] = useState7(0);
1533
+ const inputRef = useRef7(null);
1534
+ const filtered = useMemo5(
1535
+ () => items.filter((item) => matchesQuery(item, query.trim())),
1536
+ [items, query]
1537
+ );
1538
+ const close = useCallback8(() => {
1539
+ onOpenChange(false);
1540
+ setQuery("");
1541
+ setActiveIndex(0);
1542
+ }, [onOpenChange]);
1543
+ const selectItem = useCallback8(
1544
+ (item) => {
1545
+ item.onSelect();
1546
+ close();
1547
+ },
1548
+ [close]
1549
+ );
1550
+ useEffect5(() => {
1551
+ if (!open) return;
1552
+ setQuery("");
1553
+ setActiveIndex(0);
1554
+ inputRef.current?.focus();
1555
+ }, [open]);
1556
+ useEffect5(() => {
1557
+ if (activeIndex >= filtered.length) {
1558
+ setActiveIndex(Math.max(filtered.length - 1, 0));
1559
+ }
1560
+ }, [activeIndex, filtered.length]);
1561
+ useEffect5(() => {
1562
+ if (!open) return;
1563
+ const onKeyDown = (event) => {
1564
+ if (event.key === "Escape") {
1565
+ event.preventDefault();
1566
+ close();
1567
+ return;
1568
+ }
1569
+ if (event.key === "ArrowDown") {
1570
+ event.preventDefault();
1571
+ setActiveIndex((index) => (index + 1) % Math.max(filtered.length, 1));
1572
+ }
1573
+ if (event.key === "ArrowUp") {
1574
+ event.preventDefault();
1575
+ setActiveIndex(
1576
+ (index) => (index - 1 + Math.max(filtered.length, 1)) % Math.max(filtered.length, 1)
1577
+ );
1578
+ }
1579
+ if (event.key === "Enter" && filtered[activeIndex]) {
1580
+ event.preventDefault();
1581
+ selectItem(filtered[activeIndex]);
1582
+ }
1583
+ };
1584
+ window.addEventListener("keydown", onKeyDown);
1585
+ return () => window.removeEventListener("keydown", onKeyDown);
1586
+ }, [activeIndex, close, filtered, open, selectItem]);
1587
+ if (!open) return null;
1588
+ const grouped = filtered.reduce((acc, item) => {
1589
+ const group = item.group ?? "Commands";
1590
+ acc[group] = acc[group] ?? [];
1591
+ acc[group].push(item);
1592
+ return acc;
1593
+ }, {});
1594
+ let itemIndex = -1;
1595
+ return /* @__PURE__ */ jsx31("div", { className: CommandPalette_default.overlay, onClick: close, children: /* @__PURE__ */ jsxs24(
1596
+ "div",
1597
+ {
1598
+ role: "dialog",
1599
+ "aria-label": ariaLabel,
1600
+ className: CommandPalette_default.dialog,
1601
+ onClick: (event) => event.stopPropagation(),
1602
+ children: [
1603
+ /* @__PURE__ */ jsx31(
1604
+ "input",
1605
+ {
1606
+ ref: inputRef,
1607
+ type: "search",
1608
+ className: CommandPalette_default.search,
1609
+ placeholder,
1610
+ value: query,
1611
+ "aria-controls": "larose-command-list",
1612
+ "aria-activedescendant": filtered[activeIndex] ? `larose-command-${filtered[activeIndex].id}` : void 0,
1613
+ onChange: (event) => {
1614
+ setQuery(event.target.value);
1615
+ setActiveIndex(0);
1616
+ }
1617
+ }
1618
+ ),
1619
+ /* @__PURE__ */ jsx31(
1620
+ "ul",
1621
+ {
1622
+ id: "larose-command-list",
1623
+ className: CommandPalette_default.list,
1624
+ role: "listbox",
1625
+ "aria-label": ariaLabel,
1626
+ children: filtered.length === 0 ? /* @__PURE__ */ jsx31("li", { className: CommandPalette_default.empty, role: "presentation", children: emptyMessage }) : Object.entries(grouped).map(([group, groupItems]) => /* @__PURE__ */ jsxs24("li", { role: "presentation", children: [
1627
+ /* @__PURE__ */ jsx31("div", { className: CommandPalette_default.groupLabel, children: group }),
1628
+ /* @__PURE__ */ jsx31("ul", { role: "group", "aria-label": group, children: groupItems.map((item) => {
1629
+ itemIndex += 1;
1630
+ const isActive = itemIndex === activeIndex;
1631
+ return /* @__PURE__ */ jsx31("li", { role: "presentation", children: /* @__PURE__ */ jsx31(
1632
+ "button",
1633
+ {
1634
+ id: `larose-command-${item.id}`,
1635
+ type: "button",
1636
+ role: "option",
1637
+ "aria-selected": isActive,
1638
+ className: CommandPalette_default.item,
1639
+ "data-state": isActive ? "active" : "inactive",
1640
+ onMouseEnter: () => setActiveIndex(itemIndex),
1641
+ onClick: () => selectItem(item),
1642
+ children: item.label
1643
+ }
1644
+ ) }, item.id);
1645
+ }) })
1646
+ ] }, group))
1647
+ }
1648
+ )
1649
+ ]
1650
+ }
1651
+ ) });
1652
+ }
1653
+ function useCommandPaletteShortcut(onOpen, enabled = true) {
1654
+ useEffect5(() => {
1655
+ if (!enabled) return;
1656
+ const onKeyDown = (event) => {
1657
+ if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
1658
+ event.preventDefault();
1659
+ onOpen();
1660
+ }
1661
+ };
1662
+ window.addEventListener("keydown", onKeyDown);
1663
+ return () => window.removeEventListener("keydown", onKeyDown);
1664
+ }, [enabled, onOpen]);
1665
+ }
1666
+
1667
+ // src/DatePicker/DatePicker.tsx
1668
+ import { forwardRef as forwardRef7 } from "react";
1669
+ import { resolveUIState as resolveUIState5 } from "@larose-ui/core";
1670
+
1671
+ // src/DatePicker/datetime-field.module.css
1672
+ var datetime_field_default = {};
1673
+
1674
+ // src/DatePicker/DatePicker.tsx
1675
+ import { jsx as jsx32, jsxs as jsxs25 } from "react/jsx-runtime";
1676
+ var DatePicker = forwardRef7(
1677
+ ({
1678
+ label,
1679
+ hint,
1680
+ state,
1681
+ loading = false,
1682
+ error = null,
1683
+ disabled,
1684
+ readOnly,
1685
+ inputSize = "md",
1686
+ className,
1687
+ id,
1688
+ value = "",
1689
+ onChange,
1690
+ ...props
1691
+ }, ref) => {
1692
+ const inputId = id ?? (label ? label.toLowerCase().replace(/\s+/g, "-") : void 0);
1693
+ const uiState = resolveUIState5({ state, loading, error, disabled, readonly: readOnly });
1694
+ const errorMessage = typeof error === "string" ? error : null;
1695
+ return /* @__PURE__ */ jsxs25("div", { className: datetime_field_default.wrapper, "data-state": uiState, children: [
1696
+ label && /* @__PURE__ */ jsx32("label", { htmlFor: inputId, className: datetime_field_default.label, children: label }),
1697
+ /* @__PURE__ */ jsx32("div", { className: datetime_field_default.inputContainer, children: /* @__PURE__ */ jsx32(
1698
+ "input",
1699
+ {
1700
+ ref,
1701
+ id: inputId,
1702
+ type: "date",
1703
+ className: [datetime_field_default.input, className].filter(Boolean).join(" "),
1704
+ "data-size": inputSize,
1705
+ "data-state": uiState,
1706
+ value,
1707
+ disabled: disabled || uiState === "disabled" || uiState === "loading",
1708
+ readOnly: readOnly || uiState === "readonly",
1709
+ "aria-invalid": uiState === "error",
1710
+ "aria-busy": uiState === "loading",
1711
+ "aria-describedby": errorMessage ? `${inputId}-error` : hint ? `${inputId}-hint` : void 0,
1712
+ onChange: (event) => onChange?.(event.target.value),
1713
+ ...props
1714
+ }
1715
+ ) }),
1716
+ hint && !errorMessage && /* @__PURE__ */ jsx32("span", { id: `${inputId}-hint`, className: datetime_field_default.hint, children: hint }),
1717
+ errorMessage && /* @__PURE__ */ jsx32("span", { id: `${inputId}-error`, className: datetime_field_default.error, role: "alert", children: errorMessage })
1718
+ ] });
1719
+ }
1720
+ );
1721
+ DatePicker.displayName = "DatePicker";
1722
+
1723
+ // src/TimePicker/TimePicker.tsx
1724
+ import { forwardRef as forwardRef8 } from "react";
1725
+ import { resolveUIState as resolveUIState6 } from "@larose-ui/core";
1726
+ import { jsx as jsx33, jsxs as jsxs26 } from "react/jsx-runtime";
1727
+ var TimePicker = forwardRef8(
1728
+ ({
1729
+ label,
1730
+ hint,
1731
+ state,
1732
+ loading = false,
1733
+ error = null,
1734
+ disabled,
1735
+ readOnly,
1736
+ inputSize = "md",
1737
+ className,
1738
+ id,
1739
+ value = "",
1740
+ onChange,
1741
+ ...props
1742
+ }, ref) => {
1743
+ const inputId = id ?? (label ? label.toLowerCase().replace(/\s+/g, "-") : void 0);
1744
+ const uiState = resolveUIState6({ state, loading, error, disabled, readonly: readOnly });
1745
+ const errorMessage = typeof error === "string" ? error : null;
1746
+ return /* @__PURE__ */ jsxs26("div", { className: datetime_field_default.wrapper, "data-state": uiState, children: [
1747
+ label && /* @__PURE__ */ jsx33("label", { htmlFor: inputId, className: datetime_field_default.label, children: label }),
1748
+ /* @__PURE__ */ jsx33("div", { className: datetime_field_default.inputContainer, children: /* @__PURE__ */ jsx33(
1749
+ "input",
1750
+ {
1751
+ ref,
1752
+ id: inputId,
1753
+ type: "time",
1754
+ className: [datetime_field_default.input, className].filter(Boolean).join(" "),
1755
+ "data-size": inputSize,
1756
+ "data-state": uiState,
1757
+ value,
1758
+ disabled: disabled || uiState === "disabled" || uiState === "loading",
1759
+ readOnly: readOnly || uiState === "readonly",
1760
+ "aria-invalid": uiState === "error",
1761
+ "aria-busy": uiState === "loading",
1762
+ "aria-describedby": errorMessage ? `${inputId}-error` : hint ? `${inputId}-hint` : void 0,
1763
+ onChange: (event) => onChange?.(event.target.value),
1764
+ ...props
1765
+ }
1766
+ ) }),
1767
+ hint && !errorMessage && /* @__PURE__ */ jsx33("span", { id: `${inputId}-hint`, className: datetime_field_default.hint, children: hint }),
1768
+ errorMessage && /* @__PURE__ */ jsx33("span", { id: `${inputId}-error`, className: datetime_field_default.error, role: "alert", children: errorMessage })
1769
+ ] });
1770
+ }
1771
+ );
1772
+ TimePicker.displayName = "TimePicker";
1773
+
1774
+ // src/DateRangePicker/DateRangePicker.tsx
1775
+ import { useId as useId6 } from "react";
1776
+ import { resolveUIState as resolveUIState7 } from "@larose-ui/core";
1777
+ import { jsx as jsx34, jsxs as jsxs27 } from "react/jsx-runtime";
1778
+ function DateRangePicker({
1779
+ label,
1780
+ startLabel = "Start date",
1781
+ endLabel = "End date",
1782
+ hint,
1783
+ state,
1784
+ loading = false,
1785
+ error = null,
1786
+ inputSize = "md",
1787
+ value = { startDate: "", endDate: "" },
1788
+ onChange,
1789
+ min,
1790
+ max,
1791
+ disabled,
1792
+ readOnly,
1793
+ className,
1794
+ id
1795
+ }) {
1796
+ const generatedId = useId6();
1797
+ const groupId = id ?? generatedId;
1798
+ const startId = `${groupId}-start`;
1799
+ const endId = `${groupId}-end`;
1800
+ const uiState = resolveUIState7({ state, loading, error, disabled, readonly: readOnly });
1801
+ const errorMessage = typeof error === "string" ? error : null;
1802
+ const updateRange = (partial) => {
1803
+ onChange?.({ ...value, ...partial });
1804
+ };
1805
+ return /* @__PURE__ */ jsxs27(
1806
+ "fieldset",
1807
+ {
1808
+ className: [datetime_field_default.wrapper, className].filter(Boolean).join(" "),
1809
+ "data-state": uiState,
1810
+ "aria-describedby": errorMessage ? `${groupId}-error` : hint ? `${groupId}-hint` : void 0,
1811
+ children: [
1812
+ label && /* @__PURE__ */ jsx34("legend", { className: datetime_field_default.label, id: `${groupId}-legend`, children: label }),
1813
+ /* @__PURE__ */ jsxs27("div", { className: datetime_field_default.range, children: [
1814
+ /* @__PURE__ */ jsxs27("div", { className: datetime_field_default.rangeField, children: [
1815
+ /* @__PURE__ */ jsx34("label", { htmlFor: startId, className: datetime_field_default.label, children: startLabel }),
1816
+ /* @__PURE__ */ jsx34("div", { className: datetime_field_default.inputContainer, children: /* @__PURE__ */ jsx34(
1817
+ "input",
1818
+ {
1819
+ id: startId,
1820
+ type: "date",
1821
+ className: datetime_field_default.input,
1822
+ "data-size": inputSize,
1823
+ "data-state": uiState,
1824
+ value: value.startDate,
1825
+ min,
1826
+ max: value.endDate || max,
1827
+ disabled: disabled || uiState === "disabled" || uiState === "loading",
1828
+ readOnly: readOnly || uiState === "readonly",
1829
+ "aria-invalid": uiState === "error",
1830
+ "aria-busy": uiState === "loading",
1831
+ onChange: (event) => updateRange({ startDate: event.target.value })
1832
+ }
1833
+ ) })
1834
+ ] }),
1835
+ /* @__PURE__ */ jsx34("span", { className: datetime_field_default.separator, "aria-hidden": "true", children: "to" }),
1836
+ /* @__PURE__ */ jsxs27("div", { className: datetime_field_default.rangeField, children: [
1837
+ /* @__PURE__ */ jsx34("label", { htmlFor: endId, className: datetime_field_default.label, children: endLabel }),
1838
+ /* @__PURE__ */ jsx34("div", { className: datetime_field_default.inputContainer, children: /* @__PURE__ */ jsx34(
1839
+ "input",
1840
+ {
1841
+ id: endId,
1842
+ type: "date",
1843
+ className: datetime_field_default.input,
1844
+ "data-size": inputSize,
1845
+ "data-state": uiState,
1846
+ value: value.endDate,
1847
+ min: value.startDate || min,
1848
+ max,
1849
+ disabled: disabled || uiState === "disabled" || uiState === "loading",
1850
+ readOnly: readOnly || uiState === "readonly",
1851
+ "aria-invalid": uiState === "error",
1852
+ "aria-busy": uiState === "loading",
1853
+ onChange: (event) => updateRange({ endDate: event.target.value })
1854
+ }
1855
+ ) })
1856
+ ] })
1857
+ ] }),
1858
+ hint && !errorMessage && /* @__PURE__ */ jsx34("span", { id: `${groupId}-hint`, className: datetime_field_default.hint, children: hint }),
1859
+ errorMessage && /* @__PURE__ */ jsx34("span", { id: `${groupId}-error`, className: datetime_field_default.error, role: "alert", children: errorMessage })
1860
+ ]
1861
+ }
1862
+ );
1863
+ }
1864
+
1865
+ // src/index.ts
1866
+ import { LAROSE_VERSION } from "@larose-ui/core";
1867
+ import { applyTokensToElement as applyTokensToElement2, getTokens, tokensToCSSVariables } from "@larose-ui/tokens";
1868
+ export {
1869
+ Accordion,
1870
+ AccordionContent,
1871
+ AccordionItem,
1872
+ AccordionTrigger,
1873
+ Alert,
1874
+ AsyncButton,
1875
+ Badge,
1876
+ Breadcrumb,
1877
+ Button,
1878
+ Card,
1879
+ Checkbox,
1880
+ CommandPalette,
1881
+ DataTable,
1882
+ DatePicker,
1883
+ DateRangePicker,
1884
+ Dialog,
1885
+ Drawer,
1886
+ EmptyState,
1887
+ FileUpload,
1888
+ Header,
1889
+ HeaderActions,
1890
+ HeaderBrand,
1891
+ HeaderTitle,
1892
+ Input,
1893
+ LAROSE_VERSION,
1894
+ LaRoseProvider,
1895
+ Modal,
1896
+ Pagination,
1897
+ Popover,
1898
+ Progress,
1899
+ Radio,
1900
+ Select,
1901
+ Sidebar,
1902
+ SidebarGroup,
1903
+ SidebarHeader,
1904
+ SidebarItem,
1905
+ SidebarNav,
1906
+ Skeleton,
1907
+ Spinner,
1908
+ Switch,
1909
+ Tabs,
1910
+ TabsList,
1911
+ TabsPanel,
1912
+ TabsTrigger,
1913
+ Textarea,
1914
+ TimePicker,
1915
+ ToastProvider,
1916
+ Tooltip,
1917
+ applyTokensToElement2 as applyTokensToElement,
1918
+ getTokens,
1919
+ tokensToCSSVariables,
1920
+ useCommandPaletteShortcut,
1921
+ useLaRose,
1922
+ useToast
1923
+ };