@zovaris/sephiro 0.4.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,1351 @@
1
+ // src/atoms/Badge/index.tsx
2
+ import { cn } from "cn";
3
+
4
+ // src/lib/node.ts
5
+ var node = (value) => value;
6
+
7
+ // src/atoms/Badge/index.tsx
8
+ import { jsx } from "react/jsx-runtime";
9
+ function Badge({
10
+ variant = "neutral",
11
+ size = "sm",
12
+ className,
13
+ children,
14
+ ...props
15
+ }) {
16
+ return /* @__PURE__ */ jsx(
17
+ "span",
18
+ {
19
+ ...node(props),
20
+ className: cn("sph-badge", className),
21
+ "data-variant": variant,
22
+ "data-size": size,
23
+ children: node(children)
24
+ }
25
+ );
26
+ }
27
+
28
+ // src/atoms/Button/index.tsx
29
+ import { cn as cn3 } from "cn";
30
+
31
+ // src/atoms/Spinner/index.tsx
32
+ import { cn as cn2 } from "cn";
33
+ import { jsx as jsx2 } from "react/jsx-runtime";
34
+ function Spinner({
35
+ size = "md",
36
+ label,
37
+ className,
38
+ ...props
39
+ }) {
40
+ return /* @__PURE__ */ jsx2(
41
+ "span",
42
+ {
43
+ ...node(props),
44
+ className: cn2("sph-spinner", `sph-spinner--${size}`, className),
45
+ role: label ? "status" : void 0,
46
+ "aria-label": label,
47
+ "aria-hidden": label ? void 0 : true
48
+ }
49
+ );
50
+ }
51
+
52
+ // src/atoms/Button/index.tsx
53
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
54
+ function Button({
55
+ variant = "secondary",
56
+ size = "md",
57
+ loading = false,
58
+ disabled,
59
+ className,
60
+ type = "button",
61
+ children,
62
+ "aria-busy": ariaBusy,
63
+ ...props
64
+ }) {
65
+ return /* @__PURE__ */ jsxs(
66
+ "button",
67
+ {
68
+ type,
69
+ className: cn3("sph-button", className),
70
+ "data-variant": variant,
71
+ "data-size": size,
72
+ "data-loading": loading || void 0,
73
+ disabled: disabled || loading,
74
+ ...node(props),
75
+ "aria-busy": ariaBusy ?? (loading || void 0),
76
+ children: [
77
+ loading && /* @__PURE__ */ jsx3(Spinner, { size: "sm" }),
78
+ /* @__PURE__ */ jsx3("span", { className: "sph-button__label", children: node(children) })
79
+ ]
80
+ }
81
+ );
82
+ }
83
+
84
+ // src/atoms/Checkbox/index.tsx
85
+ import { CheckIcon } from "@phosphor-icons/react";
86
+ import { cn as cn4 } from "cn";
87
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
88
+ function Checkbox({
89
+ label,
90
+ size = "md",
91
+ invalid = false,
92
+ className,
93
+ ...props
94
+ }) {
95
+ const control = /* @__PURE__ */ jsx4(
96
+ "input",
97
+ {
98
+ ...node(props),
99
+ type: "checkbox",
100
+ className: "sph-checkbox__input",
101
+ "data-size": size,
102
+ "aria-invalid": invalid ? true : props["aria-invalid"]
103
+ }
104
+ );
105
+ if (label === void 0) return control;
106
+ return /* @__PURE__ */ jsxs2("label", { className: cn4("sph-checkbox", className), "data-size": size, children: [
107
+ control,
108
+ /* @__PURE__ */ jsx4("span", { className: "sph-checkbox__box", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(CheckIcon, { className: "sph-checkbox__check" }) }),
109
+ /* @__PURE__ */ jsx4("span", { className: "sph-checkbox__label", children: node(label) })
110
+ ] });
111
+ }
112
+
113
+ // src/atoms/IconButton/index.tsx
114
+ import { cn as cn5 } from "cn";
115
+ import { jsx as jsx5 } from "react/jsx-runtime";
116
+ function IconButton({
117
+ icon,
118
+ label,
119
+ size = "md",
120
+ variant = "ghost",
121
+ loading = false,
122
+ disabled,
123
+ className,
124
+ type = "button",
125
+ ...props
126
+ }) {
127
+ return /* @__PURE__ */ jsx5(
128
+ "button",
129
+ {
130
+ ...node(props),
131
+ type,
132
+ className: cn5("sph-icon-button", className),
133
+ "data-size": size,
134
+ "data-variant": variant,
135
+ "data-loading": loading || void 0,
136
+ "aria-label": label,
137
+ "aria-busy": loading ? true : props["aria-busy"],
138
+ disabled: disabled || loading,
139
+ children: loading ? /* @__PURE__ */ jsx5(Spinner, { size: size === "lg" ? "md" : "sm" }) : node(icon)
140
+ }
141
+ );
142
+ }
143
+
144
+ // src/atoms/Input/index.tsx
145
+ import { cn as cn6 } from "cn";
146
+ import { jsx as jsx6 } from "react/jsx-runtime";
147
+ function Input({
148
+ invalid = false,
149
+ size = "md",
150
+ className,
151
+ "aria-invalid": ariaInvalid,
152
+ ...props
153
+ }) {
154
+ return /* @__PURE__ */ jsx6(
155
+ "input",
156
+ {
157
+ ...node(props),
158
+ className: cn6("sph-input", className),
159
+ "data-size": size,
160
+ "aria-invalid": ariaInvalid ?? (invalid || void 0)
161
+ }
162
+ );
163
+ }
164
+
165
+ // src/atoms/Separator/index.tsx
166
+ import { cn as cn7 } from "cn";
167
+ import { jsx as jsx7 } from "react/jsx-runtime";
168
+ function Separator({
169
+ orientation = "horizontal",
170
+ decorative = true,
171
+ className,
172
+ ...props
173
+ }) {
174
+ return /* @__PURE__ */ jsx7(
175
+ "hr",
176
+ {
177
+ ...node(props),
178
+ className: cn7("sph-separator", className),
179
+ "data-orientation": orientation,
180
+ role: decorative ? "presentation" : "separator",
181
+ "aria-orientation": decorative ? void 0 : orientation
182
+ }
183
+ );
184
+ }
185
+
186
+ // src/atoms/Skeleton/index.tsx
187
+ import { cn as cn8 } from "cn";
188
+ import { jsx as jsx8 } from "react/jsx-runtime";
189
+ function Skeleton({
190
+ width,
191
+ height,
192
+ className,
193
+ style,
194
+ "aria-label": ariaLabel,
195
+ ...props
196
+ }) {
197
+ return /* @__PURE__ */ jsx8(
198
+ "span",
199
+ {
200
+ ...node(props),
201
+ className: cn8("sph-skeleton", className),
202
+ style: { ...style, width, height },
203
+ "aria-hidden": ariaLabel ? void 0 : true
204
+ }
205
+ );
206
+ }
207
+
208
+ // src/atoms/Slider/index.tsx
209
+ import { cn as cn9 } from "cn";
210
+ import { useId } from "react";
211
+ import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
212
+ function Slider({
213
+ value,
214
+ onValueChange,
215
+ label,
216
+ min = 0,
217
+ max = 100,
218
+ step = 1,
219
+ size = "md",
220
+ valueLabel,
221
+ invalid = false,
222
+ className,
223
+ disabled,
224
+ style,
225
+ id,
226
+ "aria-label": ariaLabel,
227
+ "aria-valuetext": ariaValueText,
228
+ "aria-invalid": ariaInvalid,
229
+ ...props
230
+ }) {
231
+ const generatedId = useId();
232
+ const inputId = id ?? generatedId;
233
+ const range = max - min || 1;
234
+ const progress = Math.min(100, Math.max(0, (value - min) / range * 100));
235
+ const trackStyle = {
236
+ ...style,
237
+ "--sph-slider-progress": `${progress}%`
238
+ };
239
+ return /* @__PURE__ */ jsxs3(
240
+ "div",
241
+ {
242
+ className: cn9("sph-slider", className),
243
+ "data-size": size,
244
+ "data-disabled": disabled || void 0,
245
+ "data-invalid": invalid || void 0,
246
+ children: [
247
+ /* @__PURE__ */ jsxs3("div", { className: "sph-slider__head", children: [
248
+ /* @__PURE__ */ jsx9("label", { className: "sph-slider__label", htmlFor: inputId, children: node(label) }),
249
+ valueLabel !== void 0 && /* @__PURE__ */ jsx9(
250
+ "output",
251
+ {
252
+ className: "sph-slider__value",
253
+ htmlFor: inputId,
254
+ "aria-hidden": "true",
255
+ children: node(valueLabel)
256
+ }
257
+ )
258
+ ] }),
259
+ /* @__PURE__ */ jsx9(
260
+ "input",
261
+ {
262
+ ...node(props),
263
+ id: inputId,
264
+ type: "range",
265
+ className: "sph-slider__input",
266
+ min,
267
+ max,
268
+ step,
269
+ value,
270
+ disabled,
271
+ "aria-label": ariaLabel,
272
+ "aria-valuetext": ariaValueText ?? (typeof valueLabel === "string" ? valueLabel : void 0),
273
+ "aria-invalid": ariaInvalid ?? (invalid || void 0),
274
+ style: trackStyle,
275
+ onInput: (event) => onValueChange(Number(event.currentTarget.value))
276
+ }
277
+ )
278
+ ]
279
+ }
280
+ );
281
+ }
282
+
283
+ // src/atoms/Surface/index.tsx
284
+ import { cn as cn10 } from "cn";
285
+ import { jsx as jsx10 } from "react/jsx-runtime";
286
+ function Surface({
287
+ tone = "base",
288
+ padding = "md",
289
+ className,
290
+ children,
291
+ ...props
292
+ }) {
293
+ return /* @__PURE__ */ jsx10(
294
+ "div",
295
+ {
296
+ ...node(props),
297
+ className: cn10("sph-surface", className),
298
+ "data-tone": tone,
299
+ "data-padding": padding,
300
+ children: node(children)
301
+ }
302
+ );
303
+ }
304
+
305
+ // src/atoms/Textarea/index.tsx
306
+ import { cn as cn11 } from "cn";
307
+ import { jsx as jsx11 } from "react/jsx-runtime";
308
+ function Textarea({
309
+ invalid = false,
310
+ size = "md",
311
+ className,
312
+ "aria-invalid": ariaInvalid,
313
+ ...props
314
+ }) {
315
+ return /* @__PURE__ */ jsx11(
316
+ "textarea",
317
+ {
318
+ ...node(props),
319
+ className: cn11("sph-textarea", className),
320
+ "data-size": size,
321
+ "aria-invalid": ariaInvalid ?? (invalid || void 0)
322
+ }
323
+ );
324
+ }
325
+
326
+ // src/atoms/Toggle/index.tsx
327
+ import { cn as cn12 } from "cn";
328
+ import { jsx as jsx12 } from "react/jsx-runtime";
329
+ function Toggle({
330
+ checked,
331
+ onCheckedChange,
332
+ label,
333
+ className,
334
+ disabled,
335
+ onClick,
336
+ size = "md",
337
+ "aria-checked": ariaChecked,
338
+ "aria-label": ariaLabel = label,
339
+ ...props
340
+ }) {
341
+ return /* @__PURE__ */ jsx12(
342
+ "button",
343
+ {
344
+ type: "button",
345
+ role: "switch",
346
+ "aria-checked": ariaChecked ?? checked,
347
+ "aria-label": ariaLabel ?? label,
348
+ disabled,
349
+ className: cn12("sph-toggle", className),
350
+ "data-state": checked ? "checked" : "unchecked",
351
+ "data-size": size,
352
+ onClick: (event) => {
353
+ onClick?.(event);
354
+ if (!event.defaultPrevented) onCheckedChange(!checked);
355
+ },
356
+ ...node(props),
357
+ children: /* @__PURE__ */ jsx12("span", { className: "sph-toggle__track", children: /* @__PURE__ */ jsx12("span", { className: "sph-toggle__thumb" }) })
358
+ }
359
+ );
360
+ }
361
+
362
+ // src/molecules/Alert/index.tsx
363
+ import { CheckIcon as CheckIcon2, InfoIcon, WarningIcon, XIcon } from "@phosphor-icons/react";
364
+ import { cn as cn13 } from "cn";
365
+ import { jsx as jsx13, jsxs as jsxs4 } from "react/jsx-runtime";
366
+ var alertIcons = {
367
+ info: /* @__PURE__ */ jsx13(InfoIcon, { size: 16 }),
368
+ success: /* @__PURE__ */ jsx13(CheckIcon2, { size: 16 }),
369
+ warning: /* @__PURE__ */ jsx13(WarningIcon, { size: 16 }),
370
+ danger: /* @__PURE__ */ jsx13(XIcon, { size: 16 })
371
+ };
372
+ function Alert({
373
+ variant = "info",
374
+ title,
375
+ children,
376
+ dismissible = false,
377
+ onDismiss,
378
+ className,
379
+ role,
380
+ ...props
381
+ }) {
382
+ if (title === void 0 && children === void 0) return null;
383
+ return /* @__PURE__ */ jsxs4(
384
+ "div",
385
+ {
386
+ ...node(props),
387
+ className: cn13("sph-alert", className),
388
+ "data-variant": variant,
389
+ role: role ?? (variant === "danger" ? "alert" : "status"),
390
+ "aria-live": role ? void 0 : variant === "danger" ? "assertive" : "polite",
391
+ children: [
392
+ /* @__PURE__ */ jsx13("span", { className: "sph-alert__icon", "aria-hidden": "true", children: alertIcons[variant] }),
393
+ /* @__PURE__ */ jsxs4("div", { className: "sph-alert__body", children: [
394
+ title !== void 0 && /* @__PURE__ */ jsx13("p", { className: "sph-alert__title", children: node(title) }),
395
+ children !== void 0 && /* @__PURE__ */ jsx13("div", { className: "sph-alert__content", children: node(children) })
396
+ ] }),
397
+ dismissible && /* @__PURE__ */ jsx13(
398
+ "button",
399
+ {
400
+ type: "button",
401
+ className: "sph-alert__dismiss",
402
+ "aria-label": "Dismiss notification",
403
+ onClick: onDismiss,
404
+ children: /* @__PURE__ */ jsx13(XIcon, { size: 12, "aria-hidden": "true" })
405
+ }
406
+ )
407
+ ]
408
+ }
409
+ );
410
+ }
411
+ var Notice = Alert;
412
+
413
+ // src/molecules/Card/index.tsx
414
+ import { cn as cn14 } from "cn";
415
+ import { jsx as jsx14, jsxs as jsxs5 } from "react/jsx-runtime";
416
+ function Card({
417
+ title,
418
+ description,
419
+ header,
420
+ footer,
421
+ children,
422
+ interactive = false,
423
+ selected = false,
424
+ className,
425
+ ...props
426
+ }) {
427
+ const hasHeader = header !== void 0 || title !== void 0 || description !== void 0;
428
+ return /* @__PURE__ */ jsxs5(
429
+ "article",
430
+ {
431
+ ...node(props),
432
+ className: cn14("sph-card", className),
433
+ "data-interactive": interactive || void 0,
434
+ "data-selected": selected || void 0,
435
+ children: [
436
+ hasHeader && /* @__PURE__ */ jsxs5("header", { className: "sph-card__header", children: [
437
+ node(header),
438
+ title !== void 0 && /* @__PURE__ */ jsx14("h3", { className: "sph-card__title", children: node(title) }),
439
+ description !== void 0 && /* @__PURE__ */ jsx14("p", { className: "sph-card__description", children: node(description) })
440
+ ] }),
441
+ children !== void 0 && /* @__PURE__ */ jsx14("div", { className: "sph-card__content", children: node(children) }),
442
+ footer !== void 0 && /* @__PURE__ */ jsx14("footer", { className: "sph-card__footer", children: node(footer) })
443
+ ]
444
+ }
445
+ );
446
+ }
447
+
448
+ // src/molecules/Dialog/index.tsx
449
+ import { XIcon as XIcon2 } from "@phosphor-icons/react";
450
+ import { cn as cn15 } from "cn";
451
+ import { useEffect, useId as useId2, useRef } from "react";
452
+ import { jsx as jsx15, jsxs as jsxs6 } from "react/jsx-runtime";
453
+ function Dialog({
454
+ open,
455
+ onClose,
456
+ title,
457
+ description,
458
+ children,
459
+ footer,
460
+ closeLabel = "Close dialog",
461
+ closeOnOverlayClick = true,
462
+ className
463
+ }) {
464
+ const id = useId2();
465
+ const titleId = `${id}-title`;
466
+ const descriptionId = description ? `${id}-description` : void 0;
467
+ const dialogRef = useRef(null);
468
+ useEffect(() => {
469
+ if (!open) return;
470
+ const dialog = dialogRef.current;
471
+ const focusable = () => Array.from(
472
+ dialog?.querySelectorAll(
473
+ "button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])"
474
+ ) ?? []
475
+ ).filter((element) => !element.hasAttribute("disabled"));
476
+ requestAnimationFrame(() => focusable()[0]?.focus());
477
+ const handleKeyDown = (event) => {
478
+ if (event.key === "Escape") {
479
+ onClose();
480
+ return;
481
+ }
482
+ if (event.key !== "Tab") return;
483
+ const elements = focusable();
484
+ if (elements.length === 0) {
485
+ event.preventDefault();
486
+ return;
487
+ }
488
+ const first = elements[0];
489
+ const last = elements[elements.length - 1];
490
+ if (event.shiftKey && document.activeElement === first) {
491
+ event.preventDefault();
492
+ last.focus();
493
+ } else if (!event.shiftKey && document.activeElement === last) {
494
+ event.preventDefault();
495
+ first.focus();
496
+ }
497
+ };
498
+ document.addEventListener("keydown", handleKeyDown);
499
+ return () => document.removeEventListener("keydown", handleKeyDown);
500
+ }, [onClose, open]);
501
+ if (!open) return null;
502
+ return /* @__PURE__ */ jsx15(
503
+ "div",
504
+ {
505
+ className: "sph-dialog__backdrop",
506
+ role: "presentation",
507
+ onMouseDown: (event) => {
508
+ if (closeOnOverlayClick && event.target === event.currentTarget)
509
+ onClose();
510
+ },
511
+ children: /* @__PURE__ */ jsxs6(
512
+ "section",
513
+ {
514
+ ref: dialogRef,
515
+ className: cn15("sph-dialog", className),
516
+ role: "dialog",
517
+ "aria-modal": "true",
518
+ "aria-labelledby": titleId,
519
+ "aria-describedby": descriptionId,
520
+ children: [
521
+ /* @__PURE__ */ jsxs6("header", { className: "sph-dialog__header", children: [
522
+ /* @__PURE__ */ jsxs6("div", { className: "sph-dialog__heading", children: [
523
+ /* @__PURE__ */ jsx15("h2", { id: titleId, className: "sph-dialog__title", children: node(title) }),
524
+ description !== void 0 && /* @__PURE__ */ jsx15("p", { id: descriptionId, className: "sph-dialog__description", children: node(description) })
525
+ ] }),
526
+ /* @__PURE__ */ jsx15(
527
+ "button",
528
+ {
529
+ type: "button",
530
+ className: "sph-dialog__close",
531
+ "aria-label": closeLabel,
532
+ onClick: onClose,
533
+ children: /* @__PURE__ */ jsx15(XIcon2, { size: 14, "aria-hidden": "true" })
534
+ }
535
+ )
536
+ ] }),
537
+ children !== void 0 && /* @__PURE__ */ jsx15("div", { className: "sph-dialog__content", children: node(children) }),
538
+ footer !== void 0 && /* @__PURE__ */ jsx15("footer", { className: "sph-dialog__footer", children: node(footer) })
539
+ ]
540
+ }
541
+ )
542
+ }
543
+ );
544
+ }
545
+
546
+ // src/molecules/Field/index.tsx
547
+ import { cn as cn17 } from "cn";
548
+ import { useId as useId3 } from "react";
549
+
550
+ // src/molecules/FieldMessage/index.tsx
551
+ import { cn as cn16 } from "cn";
552
+ import { jsx as jsx16 } from "react/jsx-runtime";
553
+ function FieldMessage({
554
+ variant = "hint",
555
+ className,
556
+ children,
557
+ ...props
558
+ }) {
559
+ if (children === void 0 || children === null) return null;
560
+ return /* @__PURE__ */ jsx16(
561
+ "p",
562
+ {
563
+ ...node(props),
564
+ className: cn16("sph-field-message", className),
565
+ "data-variant": variant,
566
+ role: variant === "error" ? "alert" : void 0,
567
+ children: node(children)
568
+ }
569
+ );
570
+ }
571
+
572
+ // src/molecules/Field/index.tsx
573
+ import { jsx as jsx17, jsxs as jsxs7 } from "react/jsx-runtime";
574
+ function Field({
575
+ label,
576
+ htmlFor,
577
+ description,
578
+ message,
579
+ messageType = "hint",
580
+ required = false,
581
+ className,
582
+ children
583
+ }) {
584
+ const generatedId = useId3();
585
+ const descriptionId = description ? `${generatedId}-description` : void 0;
586
+ const messageId = message ? `${generatedId}-message` : void 0;
587
+ return /* @__PURE__ */ jsxs7("div", { className: cn17("sph-field", className), children: [
588
+ label !== void 0 && /* @__PURE__ */ jsxs7("label", { className: "sph-field__label", htmlFor, children: [
589
+ /* @__PURE__ */ jsx17("span", { children: node(label) }),
590
+ required && /* @__PURE__ */ jsx17("span", { className: "sph-field__required", children: "Required" })
591
+ ] }),
592
+ description !== void 0 && description !== null && /* @__PURE__ */ jsx17("p", { id: descriptionId, className: "sph-field__description", children: node(description) }),
593
+ /* @__PURE__ */ jsx17("div", { className: "sph-field__control", children: node(children) }),
594
+ message !== void 0 && message !== null && /* @__PURE__ */ jsx17(FieldMessage, { id: messageId, variant: messageType, children: node(message) })
595
+ ] });
596
+ }
597
+
598
+ // src/molecules/Menu/index.tsx
599
+ import { cn as cn18 } from "cn";
600
+ import { useEffect as useEffect2, useId as useId4, useRef as useRef2, useState } from "react";
601
+ import { jsx as jsx18, jsxs as jsxs8 } from "react/jsx-runtime";
602
+ function Menu({
603
+ trigger,
604
+ items,
605
+ onSelect,
606
+ label = "Open menu",
607
+ align = "start",
608
+ disabled = false,
609
+ className
610
+ }) {
611
+ const rootRef = useRef2(null);
612
+ const menuId = useId4();
613
+ const [open, setOpen] = useState(false);
614
+ const enabledIndexes = items.flatMap(
615
+ (item, index) => !item.separator && !item.disabled ? [index] : []
616
+ );
617
+ const close = () => setOpen(false);
618
+ const focusItem = (index) => document.getElementById(`${menuId}-${index}`)?.focus();
619
+ useEffect2(() => {
620
+ if (!open) return;
621
+ const handlePointerDown = (event) => {
622
+ if (!rootRef.current?.contains(event.target)) close();
623
+ };
624
+ document.addEventListener("pointerdown", handlePointerDown);
625
+ return () => document.removeEventListener("pointerdown", handlePointerDown);
626
+ }, [open]);
627
+ const choose = (item) => {
628
+ if (item.disabled || item.separator || item.value === void 0) return;
629
+ onSelect?.(item.value);
630
+ close();
631
+ };
632
+ const handleKeyDown = (event) => {
633
+ if (event.key === "Escape") {
634
+ event.preventDefault();
635
+ close();
636
+ return;
637
+ }
638
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
639
+ event.preventDefault();
640
+ setOpen(true);
641
+ const index = enabledIndexes[event.key === "ArrowDown" ? 0 : enabledIndexes.length - 1];
642
+ if (index !== void 0) requestAnimationFrame(() => focusItem(index));
643
+ }
644
+ };
645
+ const handleItemKeyDown = (event, index) => {
646
+ if (event.key === "Escape") {
647
+ event.preventDefault();
648
+ close();
649
+ rootRef.current?.querySelector(".sph-menu__trigger")?.focus();
650
+ return;
651
+ }
652
+ if (event.key === "Enter" || event.key === " ") {
653
+ event.preventDefault();
654
+ choose(items[index]);
655
+ return;
656
+ }
657
+ if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
658
+ event.preventDefault();
659
+ const current = enabledIndexes.indexOf(index);
660
+ const nextPosition = event.key === "Home" ? 0 : event.key === "End" ? enabledIndexes.length - 1 : (current + (event.key === "ArrowDown" ? 1 : -1) + enabledIndexes.length) % enabledIndexes.length;
661
+ const nextIndex = enabledIndexes[nextPosition];
662
+ if (nextIndex !== void 0) focusItem(nextIndex);
663
+ };
664
+ return /* @__PURE__ */ jsxs8("div", { id: menuId, ref: rootRef, className: cn18("sph-menu", className), children: [
665
+ /* @__PURE__ */ jsx18(
666
+ "button",
667
+ {
668
+ type: "button",
669
+ className: "sph-menu__trigger",
670
+ "aria-label": label,
671
+ "aria-haspopup": "menu",
672
+ "aria-expanded": open,
673
+ disabled,
674
+ onClick: () => setOpen((current) => !current),
675
+ onKeyDown: handleKeyDown,
676
+ children: node(trigger)
677
+ }
678
+ ),
679
+ open && /* @__PURE__ */ jsx18("div", { className: "sph-menu__content", "data-align": align, role: "menu", children: items.map(
680
+ (item, index) => item.separator ? /* @__PURE__ */ jsx18(
681
+ "div",
682
+ {
683
+ className: "sph-menu__separator",
684
+ role: "separator"
685
+ },
686
+ `separator-${index}`
687
+ ) : /* @__PURE__ */ jsxs8(
688
+ "button",
689
+ {
690
+ id: `${menuId}-${index}`,
691
+ type: "button",
692
+ role: "menuitem",
693
+ className: "sph-menu__item",
694
+ "data-danger": item.danger || void 0,
695
+ disabled: item.disabled,
696
+ onClick: () => choose(item),
697
+ onKeyDown: (event) => handleItemKeyDown(event, index),
698
+ children: [
699
+ /* @__PURE__ */ jsxs8("span", { className: "sph-menu__item-label", children: [
700
+ node(item.icon),
701
+ /* @__PURE__ */ jsx18("span", { children: node(item.label) })
702
+ ] }),
703
+ item.shortcut !== void 0 && /* @__PURE__ */ jsx18("span", { className: "sph-menu__shortcut", children: node(item.shortcut) })
704
+ ]
705
+ },
706
+ item.value ?? `item-${index}`
707
+ )
708
+ ) })
709
+ ] });
710
+ }
711
+
712
+ // src/molecules/Popover/index.tsx
713
+ import { cn as cn19 } from "cn";
714
+ import { useEffect as useEffect3, useId as useId5, useRef as useRef3, useState as useState2 } from "react";
715
+ import { jsx as jsx19, jsxs as jsxs9 } from "react/jsx-runtime";
716
+ function Popover({
717
+ trigger,
718
+ children,
719
+ open,
720
+ defaultOpen = false,
721
+ onOpenChange,
722
+ ariaLabel = "Popover",
723
+ placement = "start",
724
+ disabled = false,
725
+ className
726
+ }) {
727
+ const id = useId5();
728
+ const rootRef = useRef3(null);
729
+ const [uncontrolledOpen, setUncontrolledOpen] = useState2(defaultOpen);
730
+ const isOpen = open ?? uncontrolledOpen;
731
+ const setOpen = (next) => {
732
+ setUncontrolledOpen(next);
733
+ onOpenChange?.(next);
734
+ };
735
+ useEffect3(() => {
736
+ if (!isOpen) return;
737
+ const handlePointerDown = (event) => {
738
+ if (!rootRef.current?.contains(event.target)) setOpen(false);
739
+ };
740
+ const handleKeyDown = (event) => {
741
+ if (event.key === "Escape") setOpen(false);
742
+ };
743
+ document.addEventListener("pointerdown", handlePointerDown);
744
+ document.addEventListener("keydown", handleKeyDown);
745
+ return () => {
746
+ document.removeEventListener("pointerdown", handlePointerDown);
747
+ document.removeEventListener("keydown", handleKeyDown);
748
+ };
749
+ }, [isOpen]);
750
+ const handleTriggerKeyDown = (event) => {
751
+ if (event.key === "ArrowDown" || event.key === "Enter" || event.key === " ") {
752
+ event.preventDefault();
753
+ setOpen(true);
754
+ }
755
+ };
756
+ return /* @__PURE__ */ jsxs9(
757
+ "div",
758
+ {
759
+ ref: rootRef,
760
+ className: cn19("sph-popover", className),
761
+ "data-open": isOpen || void 0,
762
+ children: [
763
+ /* @__PURE__ */ jsx19(
764
+ "button",
765
+ {
766
+ type: "button",
767
+ className: "sph-popover__trigger",
768
+ "aria-haspopup": "dialog",
769
+ "aria-expanded": isOpen,
770
+ "aria-controls": isOpen ? id : void 0,
771
+ disabled,
772
+ onClick: () => setOpen(!isOpen),
773
+ onKeyDown: handleTriggerKeyDown,
774
+ children: node(trigger)
775
+ }
776
+ ),
777
+ isOpen && /* @__PURE__ */ jsx19(
778
+ "div",
779
+ {
780
+ id,
781
+ className: "sph-popover__content",
782
+ "data-placement": placement,
783
+ role: "dialog",
784
+ "aria-label": ariaLabel,
785
+ children: node(children)
786
+ }
787
+ )
788
+ ]
789
+ }
790
+ );
791
+ }
792
+
793
+ // src/molecules/RadioGroup/index.tsx
794
+ import { cn as cn20 } from "cn";
795
+ import { useId as useId6 } from "react";
796
+ import { jsx as jsx20, jsxs as jsxs10 } from "react/jsx-runtime";
797
+ function RadioGroup({
798
+ value,
799
+ options,
800
+ onValueChange,
801
+ name,
802
+ label,
803
+ description,
804
+ size = "md",
805
+ orientation = "vertical",
806
+ disabled = false,
807
+ className
808
+ }) {
809
+ const groupId = useId6();
810
+ const descriptionId = description ? `${groupId}-description` : void 0;
811
+ return /* @__PURE__ */ jsxs10(
812
+ "fieldset",
813
+ {
814
+ className: cn20("sph-radio-group", className),
815
+ "data-size": size,
816
+ "data-orientation": orientation,
817
+ disabled,
818
+ "aria-describedby": descriptionId,
819
+ children: [
820
+ label !== void 0 && /* @__PURE__ */ jsx20("legend", { className: "sph-radio-group__legend", children: node(label) }),
821
+ description !== void 0 && /* @__PURE__ */ jsx20("p", { id: descriptionId, className: "sph-radio-group__description", children: node(description) }),
822
+ /* @__PURE__ */ jsx20("div", { className: "sph-radio-group__options", children: options.map((option, index) => {
823
+ const optionId = `${groupId}-${index}`;
824
+ const optionDescriptionId = option.description ? `${optionId}-description` : void 0;
825
+ return /* @__PURE__ */ jsxs10(
826
+ "label",
827
+ {
828
+ className: "sph-radio-group__option",
829
+ "data-disabled": option.disabled || void 0,
830
+ children: [
831
+ /* @__PURE__ */ jsx20(
832
+ "input",
833
+ {
834
+ id: optionId,
835
+ type: "radio",
836
+ name,
837
+ value: option.value,
838
+ checked: value === option.value,
839
+ disabled: disabled || option.disabled,
840
+ "aria-describedby": optionDescriptionId,
841
+ onChange: () => onValueChange(option.value)
842
+ }
843
+ ),
844
+ /* @__PURE__ */ jsx20("span", { className: "sph-radio-group__control", "aria-hidden": "true" }),
845
+ /* @__PURE__ */ jsxs10("span", { className: "sph-radio-group__content", children: [
846
+ /* @__PURE__ */ jsx20("span", { className: "sph-radio-group__label", children: node(option.label) }),
847
+ option.description !== void 0 && /* @__PURE__ */ jsx20(
848
+ "span",
849
+ {
850
+ id: optionDescriptionId,
851
+ className: "sph-radio-group__option-description",
852
+ children: node(option.description)
853
+ }
854
+ )
855
+ ] })
856
+ ]
857
+ },
858
+ option.value
859
+ );
860
+ }) })
861
+ ]
862
+ }
863
+ );
864
+ }
865
+
866
+ // src/molecules/Select/index.tsx
867
+ import { cn as cn21 } from "cn";
868
+ import { useEffect as useEffect4, useId as useId7, useRef as useRef4, useState as useState3 } from "react";
869
+ import { jsx as jsx21, jsxs as jsxs11 } from "react/jsx-runtime";
870
+ function nextEnabled(options, start, direction) {
871
+ if (options.length === 0) return -1;
872
+ for (let step = 1; step <= options.length; step += 1) {
873
+ const index = (start + step * direction + options.length) % options.length;
874
+ if (!options[index]?.disabled) return index;
875
+ }
876
+ return -1;
877
+ }
878
+ function Select({
879
+ value,
880
+ options,
881
+ onValueChange,
882
+ id,
883
+ className,
884
+ placeholder = "Select an option",
885
+ ariaLabel,
886
+ ariaLabelledBy,
887
+ disabled = false,
888
+ size = "md"
889
+ }) {
890
+ const generatedId = useId7();
891
+ const triggerId = id ?? `sph-select-${generatedId}`;
892
+ const listboxId = `${triggerId}-listbox`;
893
+ const rootRef = useRef4(null);
894
+ const selectedIndex = options.findIndex((option) => option.value === value);
895
+ const firstEnabled2 = options.findIndex((option) => !option.disabled);
896
+ const [open, setOpen] = useState3(false);
897
+ const [activeIndex, setActiveIndex] = useState3(
898
+ selectedIndex >= 0 ? selectedIndex : firstEnabled2
899
+ );
900
+ useEffect4(() => {
901
+ if (!open) return;
902
+ const close = (event) => {
903
+ if (!rootRef.current?.contains(event.target)) setOpen(false);
904
+ };
905
+ document.addEventListener("pointerdown", close);
906
+ return () => document.removeEventListener("pointerdown", close);
907
+ }, [open]);
908
+ useEffect4(() => {
909
+ if (!open)
910
+ setActiveIndex(selectedIndex >= 0 ? selectedIndex : firstEnabled2);
911
+ }, [firstEnabled2, open, selectedIndex]);
912
+ function choose(index) {
913
+ const option = options[index];
914
+ if (!option || option.disabled) return;
915
+ onValueChange(option.value);
916
+ setOpen(false);
917
+ }
918
+ function handleKeyDown(event) {
919
+ if (event.key === "Escape") {
920
+ setOpen(false);
921
+ return;
922
+ }
923
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
924
+ event.preventDefault();
925
+ const next = nextEnabled(
926
+ options,
927
+ activeIndex,
928
+ event.key === "ArrowDown" ? 1 : -1
929
+ );
930
+ setOpen(true);
931
+ if (next >= 0) setActiveIndex(next);
932
+ return;
933
+ }
934
+ if (event.key === "Home" || event.key === "End") {
935
+ event.preventDefault();
936
+ const edge = event.key === "Home" ? firstEnabled2 : nextEnabled(options, 0, -1);
937
+ setOpen(true);
938
+ if (edge >= 0) setActiveIndex(edge);
939
+ return;
940
+ }
941
+ if (event.key === "Enter" || event.key === " ") {
942
+ event.preventDefault();
943
+ if (open) choose(activeIndex);
944
+ else setOpen(true);
945
+ }
946
+ }
947
+ const selected = selectedIndex >= 0 ? options[selectedIndex] : void 0;
948
+ return /* @__PURE__ */ jsxs11("div", { ref: rootRef, className: cn21("sph-select", className), "data-size": size, children: [
949
+ /* @__PURE__ */ jsxs11(
950
+ "button",
951
+ {
952
+ id: triggerId,
953
+ type: "button",
954
+ className: "sph-select__trigger",
955
+ "aria-label": ariaLabel,
956
+ "aria-labelledby": ariaLabelledBy,
957
+ "aria-haspopup": "listbox",
958
+ "aria-expanded": open,
959
+ "aria-controls": open ? listboxId : void 0,
960
+ "aria-activedescendant": open && activeIndex >= 0 ? `${listboxId}-${activeIndex}` : void 0,
961
+ disabled: disabled || firstEnabled2 < 0,
962
+ onClick: () => setOpen((current) => !current),
963
+ onKeyDown: handleKeyDown,
964
+ children: [
965
+ /* @__PURE__ */ jsx21("span", { className: "sph-select__value", children: node(selected?.label ?? placeholder) }),
966
+ /* @__PURE__ */ jsx21("span", { className: "sph-select__caret", "aria-hidden": "true" })
967
+ ]
968
+ }
969
+ ),
970
+ open && /* @__PURE__ */ jsx21("div", { id: listboxId, role: "listbox", className: "sph-select__listbox", children: options.map((option, index) => /* @__PURE__ */ jsxs11(
971
+ "button",
972
+ {
973
+ id: `${listboxId}-${index}`,
974
+ type: "button",
975
+ role: "option",
976
+ "aria-selected": index === selectedIndex,
977
+ disabled: option.disabled,
978
+ className: "sph-select__option",
979
+ "data-active": index === activeIndex || void 0,
980
+ onPointerMove: () => !option.disabled && setActiveIndex(index),
981
+ onClick: () => choose(index),
982
+ children: [
983
+ /* @__PURE__ */ jsx21("span", { children: node(option.label) }),
984
+ index === selectedIndex && /* @__PURE__ */ jsx21("span", { className: "sph-select__check", "aria-hidden": "true" })
985
+ ]
986
+ },
987
+ option.value
988
+ )) })
989
+ ] });
990
+ }
991
+
992
+ // src/molecules/Tabs/index.tsx
993
+ import { cn as cn22 } from "cn";
994
+ import { useId as useId8, useState as useState4 } from "react";
995
+ import { jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
996
+ function firstEnabled(items) {
997
+ return items.find((item) => !item.disabled)?.value;
998
+ }
999
+ function Tabs({
1000
+ items,
1001
+ value,
1002
+ defaultValue,
1003
+ onValueChange,
1004
+ children,
1005
+ ariaLabel = "Tabs",
1006
+ orientation = "horizontal",
1007
+ className
1008
+ }) {
1009
+ const generatedId = useId8();
1010
+ const [uncontrolledValue, setUncontrolledValue] = useState4(
1011
+ defaultValue ?? firstEnabled(items) ?? ""
1012
+ );
1013
+ const activeValue = value ?? uncontrolledValue;
1014
+ const activeIndex = Math.max(
1015
+ 0,
1016
+ items.findIndex((item) => item.value === activeValue)
1017
+ );
1018
+ const activeItem = items[activeIndex];
1019
+ const setValue = (nextValue) => {
1020
+ setUncontrolledValue(nextValue);
1021
+ onValueChange?.(nextValue);
1022
+ };
1023
+ const move = (event, index) => {
1024
+ const direction = orientation === "vertical" ? event.key === "ArrowDown" ? 1 : -1 : event.key === "ArrowRight" ? 1 : -1;
1025
+ if (!["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(event.key))
1026
+ return;
1027
+ event.preventDefault();
1028
+ for (let step = 1; step <= items.length; step += 1) {
1029
+ const next = (index + step * direction + items.length) % items.length;
1030
+ if (!items[next]?.disabled) {
1031
+ setValue(items[next].value);
1032
+ document.getElementById(`${generatedId}-${next}`)?.focus();
1033
+ return;
1034
+ }
1035
+ }
1036
+ };
1037
+ const panelId = `${generatedId}-panel`;
1038
+ return /* @__PURE__ */ jsxs12("div", { className: cn22("sph-tabs", className), "data-orientation": orientation, children: [
1039
+ /* @__PURE__ */ jsx22(
1040
+ "div",
1041
+ {
1042
+ className: "sph-tabs__list",
1043
+ role: "tablist",
1044
+ "aria-label": ariaLabel,
1045
+ "aria-orientation": orientation,
1046
+ children: items.map((item, index) => {
1047
+ const selected = item.value === activeValue;
1048
+ return /* @__PURE__ */ jsx22(
1049
+ "button",
1050
+ {
1051
+ id: `${generatedId}-${index}`,
1052
+ type: "button",
1053
+ role: "tab",
1054
+ className: "sph-tabs__tab",
1055
+ "aria-selected": selected,
1056
+ "aria-controls": selected ? panelId : void 0,
1057
+ tabIndex: selected ? 0 : -1,
1058
+ disabled: item.disabled,
1059
+ "data-selected": selected || void 0,
1060
+ onClick: () => !item.disabled && setValue(item.value),
1061
+ onKeyDown: (event) => move(event, index),
1062
+ children: node(item.label)
1063
+ },
1064
+ item.value
1065
+ );
1066
+ })
1067
+ }
1068
+ ),
1069
+ activeItem && (activeItem.content !== void 0 || children !== void 0) && /* @__PURE__ */ jsx22(
1070
+ "div",
1071
+ {
1072
+ id: panelId,
1073
+ className: "sph-tabs__panel",
1074
+ role: "tabpanel",
1075
+ "aria-labelledby": `${generatedId}-${activeIndex}`,
1076
+ children: node(activeItem.content ?? children)
1077
+ }
1078
+ )
1079
+ ] });
1080
+ }
1081
+
1082
+ // src/molecules/Toast/index.tsx
1083
+ import { CheckIcon as CheckIcon3, InfoIcon as InfoIcon2, WarningIcon as WarningIcon2, XIcon as XIcon3 } from "@phosphor-icons/react";
1084
+ import { cn as cn23 } from "cn";
1085
+ import { useEffect as useEffect5 } from "react";
1086
+ import {
1087
+ Toaster as SonnerToaster,
1088
+ toast
1089
+ } from "sonner";
1090
+ import { jsx as jsx23 } from "react/jsx-runtime";
1091
+ var toastIcons = {
1092
+ success: /* @__PURE__ */ jsx23("span", { className: "sph-toast__status-icon", children: /* @__PURE__ */ jsx23(CheckIcon3, { size: 20 }) }),
1093
+ info: /* @__PURE__ */ jsx23("span", { className: "sph-toast__status-icon", children: /* @__PURE__ */ jsx23(InfoIcon2, { size: 20 }) }),
1094
+ warning: /* @__PURE__ */ jsx23("span", { className: "sph-toast__status-icon", children: /* @__PURE__ */ jsx23(WarningIcon2, { size: 20 }) }),
1095
+ error: /* @__PURE__ */ jsx23("span", { className: "sph-toast__status-icon", children: /* @__PURE__ */ jsx23(XIcon3, { size: 20 }) })
1096
+ };
1097
+ function Toast({
1098
+ open = true,
1099
+ id,
1100
+ title,
1101
+ description,
1102
+ variant = "neutral",
1103
+ action,
1104
+ duration,
1105
+ closeButton = true,
1106
+ className
1107
+ }) {
1108
+ useEffect5(() => {
1109
+ if (!open) return;
1110
+ const options = {
1111
+ id,
1112
+ action,
1113
+ closeButton,
1114
+ description: node(description),
1115
+ duration,
1116
+ className: cn23("sph-toast", className),
1117
+ unstyled: true
1118
+ };
1119
+ const toastId = variant === "success" ? toast.success(node(title), options) : variant === "warning" ? toast.warning(node(title), options) : variant === "danger" ? toast.error(node(title), options) : toast(node(title), options);
1120
+ return () => {
1121
+ toast.dismiss(toastId);
1122
+ };
1123
+ }, [open, id, action, closeButton, duration, title, description, variant]);
1124
+ return null;
1125
+ }
1126
+ function ToastViewport({
1127
+ label = "Notifications",
1128
+ className,
1129
+ toastOptions,
1130
+ theme = "system",
1131
+ position = "top-right",
1132
+ closeButton = true,
1133
+ expand = false,
1134
+ ...props
1135
+ }) {
1136
+ return /* @__PURE__ */ jsx23(
1137
+ SonnerToaster,
1138
+ {
1139
+ ...node(props),
1140
+ theme,
1141
+ position,
1142
+ closeButton,
1143
+ icons: toastIcons,
1144
+ containerAriaLabel: label,
1145
+ expand,
1146
+ className: cn23("sph-toast-viewport", className),
1147
+ toastOptions: {
1148
+ ...toastOptions,
1149
+ closeButton: toastOptions?.closeButton ?? closeButton,
1150
+ closeButtonAriaLabel: toastOptions?.closeButtonAriaLabel ?? "Dismiss notification",
1151
+ className: cn23("sph-toast", toastOptions?.className),
1152
+ unstyled: true
1153
+ }
1154
+ }
1155
+ );
1156
+ }
1157
+
1158
+ // src/molecules/Toolbar/index.tsx
1159
+ import { cn as cn24 } from "cn";
1160
+ import { jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
1161
+ function Toolbar({
1162
+ label = "Toolbar",
1163
+ orientation = "horizontal",
1164
+ size = "sm",
1165
+ start,
1166
+ end,
1167
+ children,
1168
+ className,
1169
+ ...props
1170
+ }) {
1171
+ return /* @__PURE__ */ jsxs13(
1172
+ "div",
1173
+ {
1174
+ ...node(props),
1175
+ className: cn24("sph-toolbar", className),
1176
+ "data-orientation": orientation,
1177
+ "data-size": size,
1178
+ role: "toolbar",
1179
+ "aria-label": label,
1180
+ "aria-orientation": orientation,
1181
+ children: [
1182
+ start !== void 0 && /* @__PURE__ */ jsx24("div", { className: "sph-toolbar__start", children: node(start) }),
1183
+ children !== void 0 && /* @__PURE__ */ jsx24("div", { className: "sph-toolbar__content", children: node(children) }),
1184
+ end !== void 0 && /* @__PURE__ */ jsx24("div", { className: "sph-toolbar__end", children: node(end) })
1185
+ ]
1186
+ }
1187
+ );
1188
+ }
1189
+
1190
+ // src/molecules/Tooltip/index.tsx
1191
+ import { cn as cn25 } from "cn";
1192
+ import { useId as useId9, useRef as useRef5, useState as useState5 } from "react";
1193
+ import { jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
1194
+ function Tooltip({
1195
+ content,
1196
+ children,
1197
+ side = "top",
1198
+ delay = 400,
1199
+ disabled = false,
1200
+ className
1201
+ }) {
1202
+ const id = useId9();
1203
+ const timerRef = useRef5(void 0);
1204
+ const [visible, setVisible] = useState5(false);
1205
+ const show = () => {
1206
+ if (disabled) return;
1207
+ timerRef.current = setTimeout(() => setVisible(true), delay);
1208
+ };
1209
+ const hide = () => {
1210
+ if (timerRef.current) clearTimeout(timerRef.current);
1211
+ setVisible(false);
1212
+ };
1213
+ return /* @__PURE__ */ jsxs14(
1214
+ "span",
1215
+ {
1216
+ className: cn25("sph-tooltip", className),
1217
+ onMouseEnter: show,
1218
+ onMouseLeave: hide,
1219
+ onFocus: show,
1220
+ onBlur: hide,
1221
+ children: [
1222
+ /* @__PURE__ */ jsx25(
1223
+ "span",
1224
+ {
1225
+ className: "sph-tooltip__trigger",
1226
+ "aria-describedby": visible ? id : void 0,
1227
+ children: node(children)
1228
+ }
1229
+ ),
1230
+ /* @__PURE__ */ jsx25(
1231
+ "span",
1232
+ {
1233
+ id,
1234
+ className: "sph-tooltip__content",
1235
+ "data-side": side,
1236
+ "data-visible": visible || void 0,
1237
+ role: "tooltip",
1238
+ hidden: !visible,
1239
+ children: node(content)
1240
+ }
1241
+ )
1242
+ ]
1243
+ }
1244
+ );
1245
+ }
1246
+
1247
+ // src/organisms/EmptyState/index.tsx
1248
+ import { TrayIcon } from "@phosphor-icons/react";
1249
+ import { cn as cn26 } from "cn";
1250
+ import { jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
1251
+ var emptyStateDefaultIcon = /* @__PURE__ */ jsx26(TrayIcon, { size: 20 });
1252
+ function EmptyState({
1253
+ title,
1254
+ description,
1255
+ icon = emptyStateDefaultIcon,
1256
+ action,
1257
+ compact = false,
1258
+ className,
1259
+ ...props
1260
+ }) {
1261
+ return /* @__PURE__ */ jsxs15(
1262
+ "section",
1263
+ {
1264
+ ...node(props),
1265
+ className: cn26("sph-empty-state", className),
1266
+ "data-compact": compact || void 0,
1267
+ children: [
1268
+ /* @__PURE__ */ jsx26("div", { className: "sph-empty-state__icon", "aria-hidden": "true", children: node(icon) }),
1269
+ /* @__PURE__ */ jsx26("h2", { className: "sph-empty-state__title", children: node(title) }),
1270
+ description !== void 0 && /* @__PURE__ */ jsx26("p", { className: "sph-empty-state__description", children: node(description) }),
1271
+ action !== void 0 && /* @__PURE__ */ jsx26("div", { className: "sph-empty-state__action", children: node(action) })
1272
+ ]
1273
+ }
1274
+ );
1275
+ }
1276
+
1277
+ // src/organisms/Table/index.tsx
1278
+ import { cn as cn27 } from "cn";
1279
+ import { jsx as jsx27, jsxs as jsxs16 } from "react/jsx-runtime";
1280
+ function Table({
1281
+ columns,
1282
+ rows,
1283
+ caption,
1284
+ emptyMessage = "No results",
1285
+ rowKey,
1286
+ density = "comfortable",
1287
+ striped = false,
1288
+ stickyHeader = false,
1289
+ className,
1290
+ ...props
1291
+ }) {
1292
+ return /* @__PURE__ */ jsx27("div", { className: cn27("sph-table-wrap", className), children: /* @__PURE__ */ jsxs16(
1293
+ "table",
1294
+ {
1295
+ ...node(props),
1296
+ className: "sph-table",
1297
+ "data-density": density,
1298
+ "data-striped": striped || void 0,
1299
+ "data-sticky-header": stickyHeader || void 0,
1300
+ children: [
1301
+ caption !== void 0 && /* @__PURE__ */ jsx27("caption", { children: node(caption) }),
1302
+ /* @__PURE__ */ jsx27("thead", { children: /* @__PURE__ */ jsx27("tr", { children: columns.map((column) => /* @__PURE__ */ jsx27(
1303
+ "th",
1304
+ {
1305
+ scope: "col",
1306
+ "data-align": column.align ?? "start",
1307
+ style: { width: column.width },
1308
+ children: node(column.label)
1309
+ },
1310
+ column.key
1311
+ )) }) }),
1312
+ /* @__PURE__ */ jsx27("tbody", { children: rows.length === 0 ? /* @__PURE__ */ jsx27("tr", { children: /* @__PURE__ */ jsx27("td", { className: "sph-table__empty", colSpan: columns.length, children: node(emptyMessage) }) }) : rows.map((row, rowIndex) => /* @__PURE__ */ jsx27("tr", { children: columns.map((column) => /* @__PURE__ */ jsx27("td", { "data-align": column.align ?? "start", children: node(
1313
+ column.render ? column.render(row, rowIndex) : row[column.key]
1314
+ ) }, column.key)) }, rowKey ? String(row[rowKey]) : rowIndex)) })
1315
+ ]
1316
+ }
1317
+ ) });
1318
+ }
1319
+ export {
1320
+ Alert,
1321
+ Badge,
1322
+ Button,
1323
+ Card,
1324
+ Checkbox,
1325
+ Dialog,
1326
+ EmptyState,
1327
+ Field,
1328
+ FieldMessage,
1329
+ IconButton,
1330
+ Input,
1331
+ Menu,
1332
+ Notice,
1333
+ Popover,
1334
+ RadioGroup,
1335
+ Select,
1336
+ Separator,
1337
+ Skeleton,
1338
+ Slider,
1339
+ Spinner,
1340
+ Surface,
1341
+ Table,
1342
+ Tabs,
1343
+ Textarea,
1344
+ Toast,
1345
+ ToastViewport,
1346
+ Toggle,
1347
+ Toolbar,
1348
+ Tooltip,
1349
+ toast
1350
+ };
1351
+ //# sourceMappingURL=index.js.map