@galyan/ui 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/.turbo/turbo-build.log +20 -0
  2. package/dist/index.cjs +2291 -0
  3. package/dist/index.css +2558 -0
  4. package/dist/index.d.cts +498 -0
  5. package/dist/index.d.ts +498 -0
  6. package/dist/index.js +2235 -0
  7. package/eslint.config.mjs +4 -0
  8. package/package.json +43 -0
  9. package/src/accordion/Accordion.tsx +88 -0
  10. package/src/accordion/accordion.css +78 -0
  11. package/src/accordion/index.ts +2 -0
  12. package/src/animatednumber/AnimatedNumber.tsx +71 -0
  13. package/src/animatednumber/index.ts +2 -0
  14. package/src/banner/Banner.tsx +84 -0
  15. package/src/banner/banner.css +56 -0
  16. package/src/banner/index.ts +2 -0
  17. package/src/breadcrumb/Breadcrumb.tsx +94 -0
  18. package/src/breadcrumb/breadcrumb.css +58 -0
  19. package/src/breadcrumb/index.ts +2 -0
  20. package/src/button/Button.tsx +98 -0
  21. package/src/button/button.css +190 -0
  22. package/src/button/index.ts +2 -0
  23. package/src/button.tsx +20 -0
  24. package/src/calendar/Calendar.tsx +190 -0
  25. package/src/calendar/calendar.css +142 -0
  26. package/src/calendar/index.ts +2 -0
  27. package/src/card/Card.tsx +88 -0
  28. package/src/card/card.css +115 -0
  29. package/src/card/index.ts +2 -0
  30. package/src/card.tsx +27 -0
  31. package/src/chart/Chart.tsx +186 -0
  32. package/src/chart/index.ts +2 -0
  33. package/src/checkbox/Checkbox.tsx +101 -0
  34. package/src/checkbox/checkbox.css +76 -0
  35. package/src/checkbox/index.ts +2 -0
  36. package/src/chips/Chips.tsx +146 -0
  37. package/src/chips/chips.css +90 -0
  38. package/src/chips/index.ts +2 -0
  39. package/src/code.tsx +11 -0
  40. package/src/datepicker/DatePicker.tsx +104 -0
  41. package/src/datepicker/datepicker.css +22 -0
  42. package/src/datepicker/index.ts +2 -0
  43. package/src/dragdrop/DragDrop.tsx +168 -0
  44. package/src/dragdrop/dragdrop.css +122 -0
  45. package/src/dragdrop/index.ts +2 -0
  46. package/src/dropdown/Dropdown.tsx +176 -0
  47. package/src/dropdown/dropdown.css +118 -0
  48. package/src/dropdown/index.ts +2 -0
  49. package/src/fileupload/FileUpload.tsx +144 -0
  50. package/src/fileupload/fileupload.css +118 -0
  51. package/src/fileupload/index.ts +2 -0
  52. package/src/index.ts +28 -0
  53. package/src/input/Input.tsx +121 -0
  54. package/src/input/index.ts +2 -0
  55. package/src/input/input.css +120 -0
  56. package/src/menu/Menu.tsx +118 -0
  57. package/src/menu/index.ts +2 -0
  58. package/src/menu/menu.css +117 -0
  59. package/src/modal/Modal.tsx +103 -0
  60. package/src/modal/index.ts +2 -0
  61. package/src/modal/modal.css +79 -0
  62. package/src/progressbar/ProgressBar.tsx +68 -0
  63. package/src/progressbar/index.ts +2 -0
  64. package/src/progressbar/progressbar.css +73 -0
  65. package/src/radiogroup/RadioGroup.tsx +73 -0
  66. package/src/radiogroup/index.ts +2 -0
  67. package/src/radiogroup/radiogroup.css +80 -0
  68. package/src/skeleton/Skeleton.tsx +61 -0
  69. package/src/skeleton/index.ts +2 -0
  70. package/src/skeleton/skeleton.css +46 -0
  71. package/src/spinner/Spinner.tsx +29 -0
  72. package/src/spinner/index.ts +2 -0
  73. package/src/spinner/spinner.css +39 -0
  74. package/src/stepper/Stepper.tsx +127 -0
  75. package/src/stepper/index.ts +2 -0
  76. package/src/stepper/stepper.css +141 -0
  77. package/src/tab/Tabs.tsx +71 -0
  78. package/src/tab/index.ts +2 -0
  79. package/src/tab/tab.css +92 -0
  80. package/src/table/Table.tsx +205 -0
  81. package/src/table/index.ts +2 -0
  82. package/src/table/table.css +119 -0
  83. package/src/textarea/Textarea.tsx +102 -0
  84. package/src/textarea/index.ts +2 -0
  85. package/src/textarea/textarea.css +85 -0
  86. package/src/toaster/Toaster.tsx +108 -0
  87. package/src/toaster/index.ts +2 -0
  88. package/src/toaster/toaster.css +113 -0
  89. package/src/toggle/Toggle.tsx +88 -0
  90. package/src/toggle/index.ts +2 -0
  91. package/src/toggle/toggle.css +63 -0
  92. package/src/typography/Typography.tsx +58 -0
  93. package/src/typography/index.ts +2 -0
  94. package/src/typography/typography.css +102 -0
  95. package/tsconfig.json +13 -0
package/dist/index.js ADDED
@@ -0,0 +1,2235 @@
1
+ // src/button/Button.tsx
2
+ import { forwardRef, useCallback, useRef } from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ var Button = forwardRef(function Button2({
5
+ variant = "solid",
6
+ size = "md",
7
+ loading = false,
8
+ fullWidth = false,
9
+ leftIcon,
10
+ rightIcon,
11
+ disabled,
12
+ children,
13
+ className = "",
14
+ onClick,
15
+ as: Component = "button",
16
+ ...rest
17
+ }, ref) {
18
+ const rippleRef = useRef(null);
19
+ const handleClick = useCallback(
20
+ (e) => {
21
+ const btn = e.currentTarget;
22
+ const rect = btn.getBoundingClientRect();
23
+ const size2 = Math.max(rect.width, rect.height);
24
+ const x = e.clientX - rect.left - size2 / 2;
25
+ const y = e.clientY - rect.top - size2 / 2;
26
+ const ripple = document.createElement("span");
27
+ ripple.className = "gy-btn__ripple";
28
+ ripple.style.width = ripple.style.height = `${size2}px`;
29
+ ripple.style.left = `${x}px`;
30
+ ripple.style.top = `${y}px`;
31
+ btn.appendChild(ripple);
32
+ setTimeout(() => ripple.remove(), 600);
33
+ onClick?.(e);
34
+ },
35
+ [onClick]
36
+ );
37
+ const isDisabled = disabled || loading;
38
+ const iconOnly = !children && (leftIcon || rightIcon);
39
+ const classes = [
40
+ "gy-btn",
41
+ `gy-btn--${variant}`,
42
+ `gy-btn--${size}`,
43
+ fullWidth ? "gy-btn--full" : "",
44
+ loading ? "gy-btn--loading" : "",
45
+ iconOnly ? "gy-btn--icon-only" : "",
46
+ isDisabled ? "gy-btn--disabled" : "",
47
+ className
48
+ ].filter(Boolean).join(" ");
49
+ return /* @__PURE__ */ jsxs(
50
+ Component,
51
+ {
52
+ ref,
53
+ className: classes,
54
+ disabled: isDisabled,
55
+ onClick: handleClick,
56
+ "aria-busy": loading,
57
+ ...rest,
58
+ children: [
59
+ loading ? /* @__PURE__ */ jsx("span", { className: "gy-btn__spinner", "aria-hidden": "true" }) : leftIcon && /* @__PURE__ */ jsx("span", { className: "gy-btn__icon gy-btn__icon--left", "aria-hidden": "true", children: leftIcon }),
60
+ children && /* @__PURE__ */ jsx("span", { children }),
61
+ !loading && rightIcon && /* @__PURE__ */ jsx("span", { className: "gy-btn__icon gy-btn__icon--right", "aria-hidden": "true", children: rightIcon })
62
+ ]
63
+ }
64
+ );
65
+ });
66
+
67
+ // src/typography/Typography.tsx
68
+ import { jsx as jsx2 } from "react/jsx-runtime";
69
+ var variantTagMap = {
70
+ h1: "h1",
71
+ h2: "h2",
72
+ h3: "h3",
73
+ h4: "h4",
74
+ h5: "h5",
75
+ h6: "h6",
76
+ "body-xl": "p",
77
+ "body-lg": "p",
78
+ "body-md": "p",
79
+ "body-sm": "p",
80
+ "body-xs": "p",
81
+ "caption-lg": "span",
82
+ "caption-md": "span",
83
+ label: "label",
84
+ code: "code"
85
+ };
86
+ function Typography({
87
+ variant = "body-md",
88
+ color = "default",
89
+ as,
90
+ truncate = false,
91
+ className = "",
92
+ children,
93
+ ...rest
94
+ }) {
95
+ const Tag = as ?? variantTagMap[variant];
96
+ const classes = [
97
+ "gy-text",
98
+ `gy-text--${variant}`,
99
+ `gy-text--color-${color}`,
100
+ truncate ? "gy-text--truncate" : "",
101
+ className
102
+ ].filter(Boolean).join(" ");
103
+ return /* @__PURE__ */ jsx2(Tag, { className: classes, ...rest, children });
104
+ }
105
+
106
+ // src/input/Input.tsx
107
+ import { forwardRef as forwardRef2, useId } from "react";
108
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
109
+ var Input = forwardRef2(function Input2({
110
+ label,
111
+ size = "md",
112
+ error,
113
+ helperText,
114
+ leftIcon,
115
+ rightIcon,
116
+ clearable,
117
+ onClear,
118
+ required,
119
+ fullWidth = true,
120
+ disabled,
121
+ className = "",
122
+ id,
123
+ value,
124
+ onChange,
125
+ ...rest
126
+ }, ref) {
127
+ const uid = useId();
128
+ const inputId = id ?? uid;
129
+ const wrapperClasses = [
130
+ "gy-input-wrapper",
131
+ `gy-input-wrapper--${size}`,
132
+ error ? "gy-input-wrapper--error" : "",
133
+ disabled ? "gy-input-wrapper--disabled" : ""
134
+ ].filter(Boolean).join(" ");
135
+ const showClear = clearable && value && !disabled;
136
+ return /* @__PURE__ */ jsxs2("div", { className: `gy-input-root ${fullWidth ? "" : "gy-input-root--inline"} ${className}`, children: [
137
+ label && /* @__PURE__ */ jsx3(
138
+ "label",
139
+ {
140
+ className: `gy-input-label ${required ? "gy-input-label--required" : ""}`,
141
+ htmlFor: inputId,
142
+ children: label
143
+ }
144
+ ),
145
+ /* @__PURE__ */ jsxs2("div", { className: wrapperClasses, children: [
146
+ leftIcon && /* @__PURE__ */ jsx3("span", { className: "gy-input-addon gy-input-addon--left", "aria-hidden": "true", children: leftIcon }),
147
+ /* @__PURE__ */ jsx3(
148
+ "input",
149
+ {
150
+ ref,
151
+ id: inputId,
152
+ className: "gy-input",
153
+ disabled,
154
+ required,
155
+ "aria-invalid": !!error,
156
+ "aria-describedby": error ? `${inputId}-error` : helperText ? `${inputId}-helper` : void 0,
157
+ value,
158
+ onChange,
159
+ ...rest
160
+ }
161
+ ),
162
+ showClear && /* @__PURE__ */ jsx3(
163
+ "button",
164
+ {
165
+ type: "button",
166
+ className: "gy-input-clear",
167
+ onClick: onClear,
168
+ "aria-label": "Clear input",
169
+ tabIndex: -1,
170
+ children: /* @__PURE__ */ jsxs2("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
171
+ /* @__PURE__ */ jsx3("line", { x1: "1", y1: "1", x2: "13", y2: "13" }),
172
+ /* @__PURE__ */ jsx3("line", { x1: "13", y1: "1", x2: "1", y2: "13" })
173
+ ] })
174
+ }
175
+ ),
176
+ rightIcon && !showClear && /* @__PURE__ */ jsx3("span", { className: "gy-input-addon gy-input-addon--right", "aria-hidden": "true", children: rightIcon })
177
+ ] }),
178
+ error && /* @__PURE__ */ jsx3("span", { id: `${inputId}-error`, className: "gy-input-helper gy-input-helper--error", role: "alert", children: error }),
179
+ !error && helperText && /* @__PURE__ */ jsx3("span", { id: `${inputId}-helper`, className: "gy-input-helper", children: helperText })
180
+ ] });
181
+ });
182
+
183
+ // src/textarea/Textarea.tsx
184
+ import { forwardRef as forwardRef3, useCallback as useCallback2, useEffect, useId as useId2, useRef as useRef2 } from "react";
185
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
186
+ var Textarea = forwardRef3(function Textarea2({
187
+ label,
188
+ error,
189
+ helperText,
190
+ maxCharCount,
191
+ autoResize = false,
192
+ required,
193
+ disabled,
194
+ value,
195
+ onChange,
196
+ className = "",
197
+ id,
198
+ ...rest
199
+ }, ref) {
200
+ const uid = useId2();
201
+ const inputId = id ?? uid;
202
+ const innerRef = useRef2(null);
203
+ const textareaRef = ref ?? innerRef;
204
+ const charCount = typeof value === "string" ? value.length : 0;
205
+ const isOver = maxCharCount ? charCount > maxCharCount : false;
206
+ const adjustHeight = useCallback2(() => {
207
+ const el = textareaRef.current;
208
+ if (!el || !autoResize) return;
209
+ el.style.height = "auto";
210
+ el.style.height = `${el.scrollHeight}px`;
211
+ }, [autoResize, textareaRef]);
212
+ useEffect(() => {
213
+ adjustHeight();
214
+ }, [value, adjustHeight]);
215
+ const handleChange = (e) => {
216
+ adjustHeight();
217
+ onChange?.(e);
218
+ };
219
+ return /* @__PURE__ */ jsxs3("div", { className: `gy-textarea-root ${className}`, children: [
220
+ label && /* @__PURE__ */ jsx4(
221
+ "label",
222
+ {
223
+ className: `gy-textarea-label ${required ? "gy-textarea-label--required" : ""}`,
224
+ htmlFor: inputId,
225
+ children: label
226
+ }
227
+ ),
228
+ /* @__PURE__ */ jsx4(
229
+ "textarea",
230
+ {
231
+ ref: textareaRef,
232
+ id: inputId,
233
+ className: [
234
+ "gy-textarea",
235
+ error ? "gy-textarea--error" : "",
236
+ autoResize ? "gy-textarea--auto-resize" : ""
237
+ ].filter(Boolean).join(" "),
238
+ disabled,
239
+ required,
240
+ "aria-invalid": !!error,
241
+ value,
242
+ onChange: handleChange,
243
+ ...rest
244
+ }
245
+ ),
246
+ /* @__PURE__ */ jsxs3("div", { className: "gy-textarea-footer", children: [
247
+ error ? /* @__PURE__ */ jsx4("span", { className: "gy-textarea-helper gy-textarea-helper--error", role: "alert", children: error }) : helperText ? /* @__PURE__ */ jsx4("span", { className: "gy-textarea-helper", children: helperText }) : /* @__PURE__ */ jsx4("span", {}),
248
+ maxCharCount !== void 0 && /* @__PURE__ */ jsxs3("span", { className: `gy-textarea-count ${isOver ? "gy-textarea-count--over" : ""}`, children: [
249
+ charCount,
250
+ "/",
251
+ maxCharCount
252
+ ] })
253
+ ] })
254
+ ] });
255
+ });
256
+
257
+ // src/checkbox/Checkbox.tsx
258
+ import { forwardRef as forwardRef4, useId as useId3 } from "react";
259
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
260
+ var Checkbox = forwardRef4(function Checkbox2({
261
+ checked,
262
+ defaultChecked,
263
+ indeterminate = false,
264
+ onChange,
265
+ disabled = false,
266
+ label,
267
+ description,
268
+ size = "md",
269
+ id,
270
+ name,
271
+ value,
272
+ className = ""
273
+ }, ref) {
274
+ const uid = useId3();
275
+ const inputId = id ?? uid;
276
+ const isChecked = checked ?? defaultChecked ?? false;
277
+ const boxClasses = [
278
+ "gy-checkbox-box",
279
+ `gy-checkbox-box--${size}`,
280
+ isChecked ? "gy-checkbox-box--checked" : "",
281
+ indeterminate ? "gy-checkbox-box--indeterminate" : ""
282
+ ].filter(Boolean).join(" ");
283
+ return /* @__PURE__ */ jsxs4(
284
+ "label",
285
+ {
286
+ className: [
287
+ "gy-checkbox-root",
288
+ disabled ? "gy-checkbox-root--disabled" : "",
289
+ className
290
+ ].filter(Boolean).join(" "),
291
+ htmlFor: inputId,
292
+ children: [
293
+ /* @__PURE__ */ jsx5(
294
+ "input",
295
+ {
296
+ ref,
297
+ type: "checkbox",
298
+ id: inputId,
299
+ name,
300
+ value,
301
+ checked,
302
+ defaultChecked,
303
+ disabled,
304
+ className: "gy-checkbox-input",
305
+ onChange: (e) => onChange?.(e.target.checked),
306
+ "aria-checked": indeterminate ? "mixed" : checked
307
+ }
308
+ ),
309
+ /* @__PURE__ */ jsx5("span", { className: boxClasses, "aria-hidden": "true", children: (isChecked || indeterminate) && /* @__PURE__ */ jsx5("span", { className: "gy-checkbox-icon", children: indeterminate ? /* @__PURE__ */ jsx5("svg", { width: "10", height: "2", viewBox: "0 0 10 2", fill: "currentColor", children: /* @__PURE__ */ jsx5("rect", { x: "0", y: "0", width: "10", height: "2", rx: "1" }) }) : /* @__PURE__ */ jsx5("svg", { width: "10", height: "8", viewBox: "0 0 10 8", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx5("polyline", { points: "1,4 4,7 9,1" }) }) }) }),
310
+ (label || description) && /* @__PURE__ */ jsxs4("span", { className: "gy-checkbox-content", children: [
311
+ label && /* @__PURE__ */ jsx5("span", { className: "gy-checkbox-label", children: label }),
312
+ description && /* @__PURE__ */ jsx5("span", { className: "gy-checkbox-description", children: description })
313
+ ] })
314
+ ]
315
+ }
316
+ );
317
+ });
318
+
319
+ // src/radiogroup/RadioGroup.tsx
320
+ import { useId as useId4 } from "react";
321
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
322
+ function RadioGroup({
323
+ options,
324
+ value,
325
+ defaultValue,
326
+ onChange,
327
+ orientation = "vertical",
328
+ groupLabel,
329
+ name,
330
+ disabled = false,
331
+ className = ""
332
+ }) {
333
+ const uid = useId4();
334
+ const groupName = name ?? uid;
335
+ return /* @__PURE__ */ jsxs5(
336
+ "div",
337
+ {
338
+ role: "radiogroup",
339
+ "aria-label": typeof groupLabel === "string" ? groupLabel : void 0,
340
+ className: `gy-radio-group ${orientation === "horizontal" ? "gy-radio-group--horizontal" : ""} ${className}`,
341
+ children: [
342
+ groupLabel && /* @__PURE__ */ jsx6("div", { className: "gy-radio-group-label", children: groupLabel }),
343
+ options.map((opt) => {
344
+ const isChecked = value !== void 0 ? value === opt.value : void 0;
345
+ const isDisabled = disabled || opt.disabled;
346
+ return /* @__PURE__ */ jsxs5(
347
+ "label",
348
+ {
349
+ className: `gy-radio ${isDisabled ? "gy-radio--disabled" : ""}`,
350
+ children: [
351
+ /* @__PURE__ */ jsx6(
352
+ "input",
353
+ {
354
+ type: "radio",
355
+ name: groupName,
356
+ value: opt.value,
357
+ checked: isChecked,
358
+ defaultChecked: defaultValue === opt.value,
359
+ disabled: isDisabled,
360
+ className: "gy-radio-input",
361
+ onChange: () => onChange?.(opt.value)
362
+ }
363
+ ),
364
+ /* @__PURE__ */ jsx6("span", { className: `gy-radio-circle ${isChecked ? "gy-radio-circle--checked" : ""}`, children: isChecked && /* @__PURE__ */ jsx6("span", { className: "gy-radio-dot" }) }),
365
+ /* @__PURE__ */ jsx6("span", { className: "gy-radio-label", children: opt.label })
366
+ ]
367
+ },
368
+ opt.value
369
+ );
370
+ })
371
+ ]
372
+ }
373
+ );
374
+ }
375
+
376
+ // src/toggle/Toggle.tsx
377
+ import { forwardRef as forwardRef5, useId as useId5 } from "react";
378
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
379
+ var Toggle = forwardRef5(function Toggle2({
380
+ checked,
381
+ defaultChecked,
382
+ onChange,
383
+ disabled = false,
384
+ label,
385
+ labelPosition = "right",
386
+ size = "md",
387
+ id,
388
+ name,
389
+ className = ""
390
+ }, ref) {
391
+ const uid = useId5();
392
+ const inputId = id ?? uid;
393
+ const isChecked = checked ?? defaultChecked ?? false;
394
+ const track = /* @__PURE__ */ jsx7(
395
+ "span",
396
+ {
397
+ className: [
398
+ "gy-toggle-track",
399
+ `gy-toggle-track--${size}`,
400
+ isChecked ? "gy-toggle-track--checked" : ""
401
+ ].filter(Boolean).join(" "),
402
+ "aria-hidden": "true",
403
+ children: /* @__PURE__ */ jsx7("span", { className: "gy-toggle-thumb" })
404
+ }
405
+ );
406
+ const labelEl = label && /* @__PURE__ */ jsx7("span", { className: "gy-toggle-label", children: label });
407
+ return /* @__PURE__ */ jsxs6(
408
+ "label",
409
+ {
410
+ htmlFor: inputId,
411
+ className: [
412
+ "gy-toggle-root",
413
+ disabled ? "gy-toggle-root--disabled" : "",
414
+ className
415
+ ].filter(Boolean).join(" "),
416
+ children: [
417
+ /* @__PURE__ */ jsx7(
418
+ "input",
419
+ {
420
+ ref,
421
+ id: inputId,
422
+ type: "checkbox",
423
+ role: "switch",
424
+ name,
425
+ checked,
426
+ defaultChecked,
427
+ disabled,
428
+ className: "gy-toggle-input",
429
+ "aria-checked": isChecked,
430
+ onChange: (e) => onChange?.(e.target.checked)
431
+ }
432
+ ),
433
+ labelPosition === "left" && labelEl,
434
+ track,
435
+ labelPosition === "right" && labelEl
436
+ ]
437
+ }
438
+ );
439
+ });
440
+
441
+ // src/chips/Chips.tsx
442
+ import { useRef as useRef3, useState } from "react";
443
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
444
+ function Chip({
445
+ children,
446
+ variant = "soft",
447
+ size = "md",
448
+ removable = false,
449
+ onRemove,
450
+ clickable = false,
451
+ selected = false,
452
+ onClick,
453
+ icon,
454
+ className = ""
455
+ }) {
456
+ return /* @__PURE__ */ jsxs7(
457
+ "span",
458
+ {
459
+ className: [
460
+ "gy-chip",
461
+ `gy-chip--${variant}`,
462
+ `gy-chip--${size}`,
463
+ clickable ? "gy-chip--clickable" : "",
464
+ selected ? "gy-chip--selected" : "",
465
+ className
466
+ ].filter(Boolean).join(" "),
467
+ role: clickable ? "button" : void 0,
468
+ tabIndex: clickable ? 0 : void 0,
469
+ onClick: clickable ? onClick : void 0,
470
+ onKeyDown: clickable ? (e) => {
471
+ if (e.key === "Enter" || e.key === " ") onClick?.();
472
+ } : void 0,
473
+ children: [
474
+ icon && /* @__PURE__ */ jsx8("span", { "aria-hidden": "true", children: icon }),
475
+ children,
476
+ removable && /* @__PURE__ */ jsx8(
477
+ "button",
478
+ {
479
+ type: "button",
480
+ className: "gy-chip__remove",
481
+ onClick: (e) => {
482
+ e.stopPropagation();
483
+ onRemove?.();
484
+ },
485
+ "aria-label": "Remove",
486
+ children: /* @__PURE__ */ jsxs7("svg", { width: "8", height: "8", viewBox: "0 0 8 8", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", children: [
487
+ /* @__PURE__ */ jsx8("line", { x1: "1", y1: "1", x2: "7", y2: "7" }),
488
+ /* @__PURE__ */ jsx8("line", { x1: "7", y1: "1", x2: "1", y2: "7" })
489
+ ] })
490
+ }
491
+ )
492
+ ]
493
+ }
494
+ );
495
+ }
496
+ function ChipsInput({
497
+ values,
498
+ onChange,
499
+ placeholder = "Add a tag...",
500
+ disabled = false,
501
+ maxItems,
502
+ chipVariant = "soft",
503
+ className = ""
504
+ }) {
505
+ const [input, setInput] = useState("");
506
+ const inputRef = useRef3(null);
507
+ const addChip = (val) => {
508
+ const trimmed = val.trim();
509
+ if (!trimmed || values.includes(trimmed)) return;
510
+ if (maxItems && values.length >= maxItems) return;
511
+ onChange([...values, trimmed]);
512
+ setInput("");
513
+ };
514
+ const removeChip = (idx) => {
515
+ onChange(values.filter((_, i) => i !== idx));
516
+ };
517
+ const handleKeyDown = (e) => {
518
+ if (e.key === "Enter" || e.key === ",") {
519
+ e.preventDefault();
520
+ addChip(input);
521
+ }
522
+ if (e.key === "Backspace" && !input && values.length > 0) {
523
+ removeChip(values.length - 1);
524
+ }
525
+ };
526
+ return /* @__PURE__ */ jsxs7(
527
+ "div",
528
+ {
529
+ className: `gy-chips-input ${className}`,
530
+ onClick: () => inputRef.current?.focus(),
531
+ children: [
532
+ values.map((val, i) => /* @__PURE__ */ jsx8(
533
+ Chip,
534
+ {
535
+ variant: chipVariant,
536
+ size: "sm",
537
+ removable: !disabled,
538
+ onRemove: () => removeChip(i),
539
+ children: val
540
+ },
541
+ i
542
+ )),
543
+ (!maxItems || values.length < maxItems) && /* @__PURE__ */ jsx8(
544
+ "input",
545
+ {
546
+ ref: inputRef,
547
+ className: "gy-chips-input__field",
548
+ value: input,
549
+ onChange: (e) => setInput(e.target.value),
550
+ onKeyDown: handleKeyDown,
551
+ onBlur: () => addChip(input),
552
+ placeholder: values.length === 0 ? placeholder : "",
553
+ disabled,
554
+ "aria-label": placeholder
555
+ }
556
+ )
557
+ ]
558
+ }
559
+ );
560
+ }
561
+
562
+ // src/card/Card.tsx
563
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
564
+ function Card({ variant = "default", size = "md", hoverable = false, className = "", children, onClick, style }) {
565
+ return /* @__PURE__ */ jsx9(
566
+ "div",
567
+ {
568
+ className: [
569
+ "gy-card",
570
+ variant !== "default" ? `gy-card--${variant}` : "",
571
+ size !== "md" ? `gy-card--${size}` : "",
572
+ hoverable ? "gy-card--hoverable" : "",
573
+ className
574
+ ].filter(Boolean).join(" "),
575
+ onClick,
576
+ style,
577
+ role: onClick ? "button" : void 0,
578
+ tabIndex: onClick ? 0 : void 0,
579
+ children
580
+ }
581
+ );
582
+ }
583
+ function CardHeader({ children, className = "" }) {
584
+ return /* @__PURE__ */ jsx9("div", { className: `gy-card-header ${className}`, children });
585
+ }
586
+ function CardBody({ children, size, className = "" }) {
587
+ return /* @__PURE__ */ jsx9("div", { className: ["gy-card-body", size ? `gy-card-body--${size}` : "", className].filter(Boolean).join(" "), children });
588
+ }
589
+ function CardFooter({ children, className = "" }) {
590
+ return /* @__PURE__ */ jsx9("div", { className: `gy-card-footer ${className}`, children });
591
+ }
592
+ function CardInfo({ title, value, icon, trend, footer, className = "" }) {
593
+ const isUp = trend ? trend.value >= 0 : null;
594
+ return /* @__PURE__ */ jsxs8("div", { className: `gy-card-info ${className}`, children: [
595
+ /* @__PURE__ */ jsxs8("div", { className: "gy-card-info__header", children: [
596
+ /* @__PURE__ */ jsx9("span", { className: "gy-card-info__title", children: title }),
597
+ icon && /* @__PURE__ */ jsx9("span", { className: "gy-card-info__icon", children: icon })
598
+ ] }),
599
+ /* @__PURE__ */ jsx9("div", { className: "gy-card-info__value", children: value }),
600
+ trend && /* @__PURE__ */ jsx9("div", { children: /* @__PURE__ */ jsxs8("span", { className: `gy-card-info__trend gy-card-info__trend--${isUp ? "up" : "down"}`, children: [
601
+ isUp ? "\u2191" : "\u2193",
602
+ " ",
603
+ Math.abs(trend.value),
604
+ "%",
605
+ trend.label && ` ${trend.label}`
606
+ ] }) }),
607
+ footer && /* @__PURE__ */ jsx9("div", { className: "gy-card-info__footer", children: footer })
608
+ ] });
609
+ }
610
+
611
+ // src/spinner/Spinner.tsx
612
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
613
+ function Spinner({ size = "md", color = "primary", label, className = "" }) {
614
+ return /* @__PURE__ */ jsxs9("div", { className: `gy-spinner-container ${className}`, children: [
615
+ /* @__PURE__ */ jsx10(
616
+ "span",
617
+ {
618
+ className: `gy-spinner gy-spinner--${size} gy-spinner--${color}`,
619
+ role: "status",
620
+ "aria-label": label ?? "Loading...",
621
+ children: /* @__PURE__ */ jsx10("span", { className: "gy-spinner__circle", "aria-hidden": "true" })
622
+ }
623
+ ),
624
+ label && /* @__PURE__ */ jsx10("span", { className: "gy-spinner__label", children: label })
625
+ ] });
626
+ }
627
+
628
+ // src/progressbar/ProgressBar.tsx
629
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
630
+ function ProgressBar({
631
+ value = 0,
632
+ max = 100,
633
+ size = "md",
634
+ color = "primary",
635
+ label,
636
+ showValue = false,
637
+ striped = false,
638
+ indeterminate = false,
639
+ className = ""
640
+ }) {
641
+ const pct = Math.min(Math.max(value / max * 100, 0), 100);
642
+ const fillClasses = [
643
+ "gy-progress-fill",
644
+ color !== "primary" ? `gy-progress-fill--${color}` : "",
645
+ striped ? "gy-progress-fill--striped" : "",
646
+ indeterminate ? "gy-progress-fill--indeterminate" : ""
647
+ ].filter(Boolean).join(" ");
648
+ return /* @__PURE__ */ jsxs10("div", { className: `gy-progress ${className}`, children: [
649
+ (label || showValue) && /* @__PURE__ */ jsxs10("div", { className: "gy-progress-header", children: [
650
+ label && /* @__PURE__ */ jsx11("span", { className: "gy-progress-label", children: label }),
651
+ showValue && !indeterminate && /* @__PURE__ */ jsxs10("span", { className: "gy-progress-value", children: [
652
+ Math.round(pct),
653
+ "%"
654
+ ] })
655
+ ] }),
656
+ /* @__PURE__ */ jsx11(
657
+ "div",
658
+ {
659
+ className: `gy-progress-track gy-progress-track--${size}`,
660
+ role: "progressbar",
661
+ "aria-valuenow": indeterminate ? void 0 : value,
662
+ "aria-valuemin": 0,
663
+ "aria-valuemax": max,
664
+ "aria-label": label ?? "Progress",
665
+ children: /* @__PURE__ */ jsx11(
666
+ "div",
667
+ {
668
+ className: fillClasses,
669
+ style: { width: indeterminate ? void 0 : `${pct}%` }
670
+ }
671
+ )
672
+ }
673
+ )
674
+ ] });
675
+ }
676
+
677
+ // src/skeleton/Skeleton.tsx
678
+ import { jsx as jsx12 } from "react/jsx-runtime";
679
+ function Skeleton({
680
+ shape = "rect",
681
+ animation = "wave",
682
+ width,
683
+ height,
684
+ className = "",
685
+ lines,
686
+ gap = "0.5rem"
687
+ }) {
688
+ const classes = [
689
+ "gy-skeleton",
690
+ `gy-skeleton--${shape}`,
691
+ animation !== "none" ? `gy-skeleton--${animation}` : "",
692
+ !width ? "gy-skeleton--w-full" : "",
693
+ className
694
+ ].filter(Boolean).join(" ");
695
+ const style = {
696
+ width,
697
+ height
698
+ };
699
+ if (lines) {
700
+ return /* @__PURE__ */ jsx12("div", { style: { display: "flex", flexDirection: "column", gap }, children: Array.from({ length: lines }).map((_, i) => /* @__PURE__ */ jsx12(
701
+ "div",
702
+ {
703
+ className: `gy-skeleton gy-skeleton--text ${animation !== "none" ? `gy-skeleton--${animation}` : ""} ${i === lines - 1 ? "gy-skeleton--w-3-4" : "gy-skeleton--w-full"}`,
704
+ style: { height: height ?? "1em" },
705
+ "aria-hidden": "true"
706
+ },
707
+ i
708
+ )) });
709
+ }
710
+ return /* @__PURE__ */ jsx12("div", { className: classes, style, "aria-hidden": "true" });
711
+ }
712
+
713
+ // src/banner/Banner.tsx
714
+ import { useState as useState2 } from "react";
715
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
716
+ var icons = {
717
+ info: /* @__PURE__ */ jsx13("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx13("path", { d: "M8 1a7 7 0 100 14A7 7 0 008 1zm0 3a1 1 0 110 2 1 1 0 010-2zm0 3a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 018 7z" }) }),
718
+ success: /* @__PURE__ */ jsx13("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx13("path", { d: "M8 1a7 7 0 100 14A7 7 0 008 1zm3.78 5.78a.75.75 0 00-1.06-1.06L7 9.44 5.28 7.72a.75.75 0 00-1.06 1.06l2.25 2.25a.75.75 0 001.06 0l4.25-4.25z" }) }),
719
+ warning: /* @__PURE__ */ jsx13("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx13("path", { d: "M8 1.5a.75.75 0 01.65.375l6 10.5A.75.75 0 0114 13.5H2a.75.75 0 01-.65-1.125l6-10.5A.75.75 0 018 1.5zm0 4a.75.75 0 01.75.75v3a.75.75 0 01-1.5 0v-3A.75.75 0 018 5.5zm0 6.5a1 1 0 110-2 1 1 0 010 2z" }) }),
720
+ danger: /* @__PURE__ */ jsx13("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx13("path", { d: "M8 1a7 7 0 100 14A7 7 0 008 1zm0 3a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 018 4zm0 7.5a1 1 0 110-2 1 1 0 010 2z" }) }),
721
+ neutral: /* @__PURE__ */ jsx13("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx13("path", { d: "M8 1a7 7 0 100 14A7 7 0 008 1zm0 3a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 018 4zm0 7.5a1 1 0 110-2 1 1 0 010 2z" }) })
722
+ };
723
+ function Banner({
724
+ variant = "info",
725
+ layout = "inline",
726
+ title,
727
+ description,
728
+ icon,
729
+ dismissible = false,
730
+ onDismiss,
731
+ className = ""
732
+ }) {
733
+ const [dismissed, setDismissed] = useState2(false);
734
+ if (dismissed) return null;
735
+ const handleDismiss = () => {
736
+ setDismissed(true);
737
+ onDismiss?.();
738
+ };
739
+ return /* @__PURE__ */ jsxs11(
740
+ "div",
741
+ {
742
+ className: [
743
+ "gy-banner",
744
+ `gy-banner--${variant}`,
745
+ `gy-banner--${layout}`,
746
+ className
747
+ ].filter(Boolean).join(" "),
748
+ role: "alert",
749
+ children: [
750
+ /* @__PURE__ */ jsx13("span", { className: "gy-banner__icon", children: icon ?? icons[variant] }),
751
+ /* @__PURE__ */ jsxs11("div", { className: "gy-banner__content", children: [
752
+ title && /* @__PURE__ */ jsx13("div", { className: "gy-banner__title", children: title }),
753
+ description && /* @__PURE__ */ jsx13("div", { className: "gy-banner__description", children: description })
754
+ ] }),
755
+ dismissible && /* @__PURE__ */ jsx13("button", { className: "gy-banner__close", onClick: handleDismiss, "aria-label": "Dismiss", children: /* @__PURE__ */ jsxs11("svg", { width: "12", height: "12", viewBox: "0 0 12 12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: [
756
+ /* @__PURE__ */ jsx13("line", { x1: "1", y1: "1", x2: "11", y2: "11" }),
757
+ /* @__PURE__ */ jsx13("line", { x1: "11", y1: "1", x2: "1", y2: "11" })
758
+ ] }) })
759
+ ]
760
+ }
761
+ );
762
+ }
763
+
764
+ // src/breadcrumb/Breadcrumb.tsx
765
+ import { useState as useState3 } from "react";
766
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
767
+ var DefaultSeparator = () => /* @__PURE__ */ jsx14("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx14("polyline", { points: "4,2 8,6 4,10" }) });
768
+ function Breadcrumb({
769
+ items,
770
+ separator = /* @__PURE__ */ jsx14(DefaultSeparator, {}),
771
+ maxItems,
772
+ className = ""
773
+ }) {
774
+ const [expanded, setExpanded] = useState3(false);
775
+ const shouldCollapse = maxItems && items.length > maxItems + 1 && !expanded;
776
+ const displayed = [];
777
+ if (shouldCollapse) {
778
+ const first = items[0];
779
+ const last = items[items.length - 1];
780
+ displayed.push(renderItem(first, false, separator));
781
+ displayed.push(
782
+ /* @__PURE__ */ jsxs12("li", { className: "gy-breadcrumb-item", children: [
783
+ /* @__PURE__ */ jsx14("span", { className: "gy-breadcrumb-separator", children: separator }),
784
+ /* @__PURE__ */ jsx14(
785
+ "button",
786
+ {
787
+ className: "gy-breadcrumb-ellipsis",
788
+ onClick: () => setExpanded(true),
789
+ "aria-label": "Show more breadcrumbs",
790
+ children: "\u2022\u2022\u2022"
791
+ }
792
+ )
793
+ ] }, "ellipsis")
794
+ );
795
+ displayed.push(renderItem(last, true, separator));
796
+ } else {
797
+ items.forEach((item, i) => {
798
+ displayed.push(renderItem(item, i === items.length - 1, separator, i));
799
+ });
800
+ }
801
+ return /* @__PURE__ */ jsx14("nav", { "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsx14("ol", { className: `gy-breadcrumb ${className}`, children: displayed }) });
802
+ }
803
+ function renderItem(item, isCurrent, separator, key) {
804
+ return /* @__PURE__ */ jsxs12("li", { className: "gy-breadcrumb-item", children: [
805
+ key !== 0 && key !== void 0 && /* @__PURE__ */ jsx14("span", { className: "gy-breadcrumb-separator", "aria-hidden": "true", children: separator }),
806
+ isCurrent ? /* @__PURE__ */ jsx14("span", { className: "gy-breadcrumb-current", "aria-current": "page", children: item.label }) : /* @__PURE__ */ jsx14(
807
+ "a",
808
+ {
809
+ className: "gy-breadcrumb-link",
810
+ href: item.href ?? "#",
811
+ onClick: item.onClick ? (e) => {
812
+ e.preventDefault();
813
+ item.onClick?.();
814
+ } : void 0,
815
+ children: item.label
816
+ }
817
+ )
818
+ ] }, key ?? item.label);
819
+ }
820
+
821
+ // src/animatednumber/AnimatedNumber.tsx
822
+ import { useEffect as useEffect2, useRef as useRef4, useState as useState4 } from "react";
823
+ import { jsxs as jsxs13 } from "react/jsx-runtime";
824
+ function easeOut(t) {
825
+ return 1 - Math.pow(1 - t, 3);
826
+ }
827
+ function easeInOut(t) {
828
+ return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
829
+ }
830
+ function AnimatedNumber({
831
+ value,
832
+ duration = 1e3,
833
+ format,
834
+ className = "",
835
+ prefix = "",
836
+ suffix = "",
837
+ decimals = 0,
838
+ easing = "easeOut"
839
+ }) {
840
+ const [displayed, setDisplayed] = useState4(0);
841
+ const startRef = useRef4(0);
842
+ const startTimeRef = useRef4(null);
843
+ const rafRef = useRef4(0);
844
+ const prevValueRef = useRef4(0);
845
+ useEffect2(() => {
846
+ startRef.current = prevValueRef.current;
847
+ startTimeRef.current = null;
848
+ const easeFn = easing === "linear" ? (t) => t : easing === "easeOut" ? easeOut : easeInOut;
849
+ const animate = (time) => {
850
+ if (!startTimeRef.current) startTimeRef.current = time;
851
+ const elapsed = time - startTimeRef.current;
852
+ const t = Math.min(elapsed / duration, 1);
853
+ const eased = easeFn(t);
854
+ const current = startRef.current + (value - startRef.current) * eased;
855
+ setDisplayed(current);
856
+ if (t < 1) {
857
+ rafRef.current = requestAnimationFrame(animate);
858
+ } else {
859
+ prevValueRef.current = value;
860
+ }
861
+ };
862
+ cancelAnimationFrame(rafRef.current);
863
+ rafRef.current = requestAnimationFrame(animate);
864
+ return () => cancelAnimationFrame(rafRef.current);
865
+ }, [value, duration, easing]);
866
+ const formatted = format ? format(displayed) : displayed.toFixed(decimals).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
867
+ return /* @__PURE__ */ jsxs13("span", { className: `gy-animated-number ${className}`, "aria-live": "polite", "aria-atomic": "true", children: [
868
+ prefix,
869
+ formatted,
870
+ suffix
871
+ ] });
872
+ }
873
+
874
+ // src/accordion/Accordion.tsx
875
+ import { useRef as useRef5, useState as useState5 } from "react";
876
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
877
+ function AccordionPanel({ open, children }) {
878
+ const ref = useRef5(null);
879
+ const height = open ? ref.current?.scrollHeight ?? 0 : 0;
880
+ return /* @__PURE__ */ jsx15(
881
+ "div",
882
+ {
883
+ className: "gy-accordion-panel",
884
+ style: { height, transition: `height 250ms cubic-bezier(0.4, 0, 0.2, 1)`, overflow: "hidden" },
885
+ "aria-hidden": !open,
886
+ children: /* @__PURE__ */ jsx15("div", { ref, className: "gy-accordion-panel-inner", children })
887
+ }
888
+ );
889
+ }
890
+ function Accordion({ items, type = "single", defaultOpen, flush = false, className = "" }) {
891
+ const initOpen = defaultOpen ? Array.isArray(defaultOpen) ? defaultOpen : [defaultOpen] : [];
892
+ const [openIds, setOpenIds] = useState5(new Set(initOpen));
893
+ const toggle = (id) => {
894
+ setOpenIds((prev) => {
895
+ const next = new Set(prev);
896
+ if (next.has(id)) {
897
+ next.delete(id);
898
+ } else {
899
+ if (type === "single") next.clear();
900
+ next.add(id);
901
+ }
902
+ return next;
903
+ });
904
+ };
905
+ return /* @__PURE__ */ jsx15("div", { className: `gy-accordion ${className}`, children: items.map((item) => {
906
+ const isOpen = openIds.has(item.id);
907
+ return /* @__PURE__ */ jsxs14(
908
+ "div",
909
+ {
910
+ className: `gy-accordion-item ${flush ? "gy-accordion-item--flush" : ""}`,
911
+ children: [
912
+ /* @__PURE__ */ jsxs14(
913
+ "button",
914
+ {
915
+ type: "button",
916
+ className: `gy-accordion-trigger ${isOpen ? "gy-accordion-trigger--open" : ""}`,
917
+ onClick: () => !item.disabled && toggle(item.id),
918
+ "aria-expanded": isOpen,
919
+ disabled: item.disabled,
920
+ children: [
921
+ /* @__PURE__ */ jsx15("span", { className: "gy-accordion-title", children: item.title }),
922
+ /* @__PURE__ */ jsx15("span", { className: `gy-accordion-icon ${isOpen ? "gy-accordion-icon--open" : ""}`, "aria-hidden": "true", children: /* @__PURE__ */ jsx15("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx15("polyline", { points: "4,6 8,10 12,6" }) }) })
923
+ ]
924
+ }
925
+ ),
926
+ /* @__PURE__ */ jsx15(AccordionPanel, { open: isOpen, children: item.content })
927
+ ]
928
+ },
929
+ item.id
930
+ );
931
+ }) });
932
+ }
933
+
934
+ // src/tab/Tabs.tsx
935
+ import { useState as useState6 } from "react";
936
+ import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
937
+ function Tabs({ items, defaultTab, activeTab, onChange, orientation = "horizontal", className = "" }) {
938
+ const [internalActive, setInternalActive] = useState6(defaultTab ?? items[0]?.id ?? "");
939
+ const current = activeTab ?? internalActive;
940
+ const handleSelect = (id) => {
941
+ setInternalActive(id);
942
+ onChange?.(id);
943
+ };
944
+ const activeItem = items.find((i) => i.id === current);
945
+ return /* @__PURE__ */ jsxs15("div", { className: `gy-tabs ${orientation === "vertical" ? "gy-tabs--vertical" : ""} ${className}`, children: [
946
+ /* @__PURE__ */ jsx16("div", { className: "gy-tabs-list", role: "tablist", "aria-orientation": orientation, children: items.map((item) => /* @__PURE__ */ jsxs15(
947
+ "button",
948
+ {
949
+ role: "tab",
950
+ id: `gy-tab-${item.id}`,
951
+ "aria-controls": `gy-panel-${item.id}`,
952
+ "aria-selected": current === item.id,
953
+ disabled: item.disabled,
954
+ className: `gy-tabs-trigger ${current === item.id ? "gy-tabs-trigger--active" : ""}`,
955
+ onClick: () => !item.disabled && handleSelect(item.id),
956
+ children: [
957
+ item.icon && /* @__PURE__ */ jsx16("span", { "aria-hidden": "true", children: item.icon }),
958
+ item.label,
959
+ item.badge !== void 0 && /* @__PURE__ */ jsx16("span", { className: "gy-tabs-trigger-badge", children: item.badge })
960
+ ]
961
+ },
962
+ item.id
963
+ )) }),
964
+ activeItem && /* @__PURE__ */ jsx16(
965
+ "div",
966
+ {
967
+ id: `gy-panel-${current}`,
968
+ role: "tabpanel",
969
+ "aria-labelledby": `gy-tab-${current}`,
970
+ className: "gy-tabs-panel",
971
+ children: activeItem.content
972
+ },
973
+ current
974
+ )
975
+ ] });
976
+ }
977
+
978
+ // src/modal/Modal.tsx
979
+ import { useEffect as useEffect3, useRef as useRef6 } from "react";
980
+ import { createPortal } from "react-dom";
981
+ import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
982
+ function Modal({
983
+ open,
984
+ onClose,
985
+ title,
986
+ size = "md",
987
+ children,
988
+ footer,
989
+ closeOnBackdrop = true,
990
+ closeOnEscape = true,
991
+ className = ""
992
+ }) {
993
+ const dialogRef = useRef6(null);
994
+ useEffect3(() => {
995
+ if (!open) return;
996
+ const previous = document.activeElement;
997
+ dialogRef.current?.focus();
998
+ const handleKey = (e) => {
999
+ if (e.key === "Escape" && closeOnEscape) onClose();
1000
+ if (e.key === "Tab") {
1001
+ const focusable = dialogRef.current?.querySelectorAll(
1002
+ 'a, button:not(:disabled), textarea, input, select, [tabindex]:not([tabindex="-1"])'
1003
+ );
1004
+ if (!focusable?.length) return;
1005
+ const first = focusable[0];
1006
+ const last = focusable[focusable.length - 1];
1007
+ if (e.shiftKey && document.activeElement === first) {
1008
+ e.preventDefault();
1009
+ last.focus();
1010
+ } else if (!e.shiftKey && document.activeElement === last) {
1011
+ e.preventDefault();
1012
+ first.focus();
1013
+ }
1014
+ }
1015
+ };
1016
+ document.addEventListener("keydown", handleKey);
1017
+ document.body.style.overflow = "hidden";
1018
+ return () => {
1019
+ document.removeEventListener("keydown", handleKey);
1020
+ document.body.style.overflow = "";
1021
+ previous?.focus();
1022
+ };
1023
+ }, [open, onClose, closeOnEscape]);
1024
+ if (!open) return null;
1025
+ const content = /* @__PURE__ */ jsx17(
1026
+ "div",
1027
+ {
1028
+ className: "gy-modal-backdrop",
1029
+ onClick: closeOnBackdrop ? (e) => {
1030
+ if (e.target === e.currentTarget) onClose();
1031
+ } : void 0,
1032
+ "aria-modal": "true",
1033
+ children: /* @__PURE__ */ jsxs16(
1034
+ "div",
1035
+ {
1036
+ ref: dialogRef,
1037
+ role: "dialog",
1038
+ "aria-labelledby": title ? "gy-modal-title" : void 0,
1039
+ className: `gy-modal gy-modal--${size} ${className}`,
1040
+ tabIndex: -1,
1041
+ children: [
1042
+ title && /* @__PURE__ */ jsxs16("div", { className: "gy-modal-header", children: [
1043
+ /* @__PURE__ */ jsx17("h2", { id: "gy-modal-title", className: "gy-modal-title", children: title }),
1044
+ /* @__PURE__ */ jsx17("button", { className: "gy-modal-close", onClick: onClose, "aria-label": "Close dialog", children: /* @__PURE__ */ jsxs16("svg", { width: "16", height: "16", viewBox: "0 0 16 16", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: [
1045
+ /* @__PURE__ */ jsx17("line", { x1: "1", y1: "1", x2: "15", y2: "15" }),
1046
+ /* @__PURE__ */ jsx17("line", { x1: "15", y1: "1", x2: "1", y2: "15" })
1047
+ ] }) })
1048
+ ] }),
1049
+ /* @__PURE__ */ jsx17("div", { className: "gy-modal-body", children }),
1050
+ footer && /* @__PURE__ */ jsx17("div", { className: "gy-modal-footer", children: footer })
1051
+ ]
1052
+ }
1053
+ )
1054
+ }
1055
+ );
1056
+ return createPortal(content, document.body);
1057
+ }
1058
+
1059
+ // src/dropdown/Dropdown.tsx
1060
+ import { useEffect as useEffect4, useId as useId6, useRef as useRef7, useState as useState7 } from "react";
1061
+ import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
1062
+ function Dropdown({
1063
+ options,
1064
+ value,
1065
+ onChange,
1066
+ placeholder = "Select an option",
1067
+ searchable = false,
1068
+ disabled = false,
1069
+ label,
1070
+ error,
1071
+ className = "",
1072
+ id
1073
+ }) {
1074
+ const uid = useId6();
1075
+ const inputId = id ?? uid;
1076
+ const [open, setOpen] = useState7(false);
1077
+ const [search, setSearch] = useState7("");
1078
+ const [focused, setFocused] = useState7(0);
1079
+ const rootRef = useRef7(null);
1080
+ const searchRef = useRef7(null);
1081
+ const selected = options.find((o) => o.value === value);
1082
+ const filtered = searchable && search ? options.filter((o) => String(o.label).toLowerCase().includes(search.toLowerCase())) : options;
1083
+ const groups = filtered.reduce((acc, opt) => {
1084
+ const g = opt.group ?? "__default__";
1085
+ acc[g] = [...acc[g] ?? [], opt];
1086
+ return acc;
1087
+ }, {});
1088
+ useEffect4(() => {
1089
+ if (!open) {
1090
+ setSearch("");
1091
+ setFocused(0);
1092
+ return;
1093
+ }
1094
+ if (searchable) setTimeout(() => searchRef.current?.focus(), 50);
1095
+ }, [open, searchable]);
1096
+ useEffect4(() => {
1097
+ const handler = (e) => {
1098
+ if (!rootRef.current?.contains(e.target)) setOpen(false);
1099
+ };
1100
+ document.addEventListener("mousedown", handler);
1101
+ return () => document.removeEventListener("mousedown", handler);
1102
+ }, []);
1103
+ const handleSelect = (opt) => {
1104
+ if (opt.disabled) return;
1105
+ onChange?.(opt.value);
1106
+ setOpen(false);
1107
+ };
1108
+ const handleKeyDown = (e) => {
1109
+ const flat = filtered.filter((o) => !o.disabled);
1110
+ if (e.key === "ArrowDown") {
1111
+ e.preventDefault();
1112
+ setFocused((f) => Math.min(f + 1, flat.length - 1));
1113
+ }
1114
+ if (e.key === "ArrowUp") {
1115
+ e.preventDefault();
1116
+ setFocused((f) => Math.max(f - 1, 0));
1117
+ }
1118
+ if (e.key === "Enter" && open) {
1119
+ e.preventDefault();
1120
+ const opt = flat[focused];
1121
+ if (opt) handleSelect(opt);
1122
+ }
1123
+ if (e.key === "Escape") setOpen(false);
1124
+ if (!open && (e.key === "Enter" || e.key === " ")) {
1125
+ e.preventDefault();
1126
+ setOpen(true);
1127
+ }
1128
+ };
1129
+ return /* @__PURE__ */ jsxs17("div", { ref: rootRef, className: `gy-dropdown-root ${className}`, onKeyDown: handleKeyDown, children: [
1130
+ label && /* @__PURE__ */ jsx18("label", { className: "gy-input-label", htmlFor: inputId, children: label }),
1131
+ /* @__PURE__ */ jsxs17(
1132
+ "button",
1133
+ {
1134
+ id: inputId,
1135
+ type: "button",
1136
+ className: [
1137
+ "gy-dropdown-trigger",
1138
+ open ? "gy-dropdown-trigger--open" : "",
1139
+ disabled ? "gy-dropdown-trigger--disabled" : "",
1140
+ !selected ? "gy-dropdown-trigger--placeholder" : ""
1141
+ ].filter(Boolean).join(" "),
1142
+ onClick: () => !disabled && setOpen((o) => !o),
1143
+ disabled,
1144
+ "aria-expanded": open,
1145
+ "aria-haspopup": "listbox",
1146
+ children: [
1147
+ /* @__PURE__ */ jsx18("span", { children: selected ? selected.label : placeholder }),
1148
+ /* @__PURE__ */ jsx18("span", { className: `gy-dropdown-chevron ${open ? "gy-dropdown-chevron--open" : ""}`, "aria-hidden": "true", children: /* @__PURE__ */ jsx18("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx18("polyline", { points: "3,5 7,9 11,5" }) }) })
1149
+ ]
1150
+ }
1151
+ ),
1152
+ open && /* @__PURE__ */ jsxs17("div", { className: "gy-dropdown-menu", role: "listbox", children: [
1153
+ searchable && /* @__PURE__ */ jsx18("div", { className: "gy-dropdown-search", children: /* @__PURE__ */ jsx18(
1154
+ "input",
1155
+ {
1156
+ ref: searchRef,
1157
+ className: "gy-dropdown-search-input",
1158
+ value: search,
1159
+ onChange: (e) => {
1160
+ setSearch(e.target.value);
1161
+ setFocused(0);
1162
+ },
1163
+ placeholder: "Search...",
1164
+ "aria-label": "Search options"
1165
+ }
1166
+ ) }),
1167
+ /* @__PURE__ */ jsx18("div", { className: "gy-dropdown-options", children: filtered.length === 0 ? /* @__PURE__ */ jsx18("div", { className: "gy-dropdown-empty", children: "No options found" }) : Object.entries(groups).map(([group, opts]) => /* @__PURE__ */ jsxs17("div", { children: [
1168
+ group !== "__default__" && /* @__PURE__ */ jsx18("div", { className: "gy-dropdown-group-label", children: group }),
1169
+ opts.map((opt, i) => /* @__PURE__ */ jsxs17(
1170
+ "div",
1171
+ {
1172
+ className: [
1173
+ "gy-dropdown-option",
1174
+ opt.value === value ? "gy-dropdown-option--selected" : "",
1175
+ focused === i ? "gy-dropdown-option--focused" : "",
1176
+ opt.disabled ? "gy-dropdown-option--disabled" : ""
1177
+ ].filter(Boolean).join(" "),
1178
+ role: "option",
1179
+ "aria-selected": opt.value === value,
1180
+ onClick: () => handleSelect(opt),
1181
+ children: [
1182
+ opt.icon && /* @__PURE__ */ jsx18("span", { "aria-hidden": "true", children: opt.icon }),
1183
+ opt.label,
1184
+ opt.value === value && /* @__PURE__ */ jsx18("span", { className: "gy-dropdown-check", "aria-hidden": "true", children: /* @__PURE__ */ jsx18("svg", { width: "14", height: "11", viewBox: "0 0 14 11", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx18("polyline", { points: "1,5 5,9 13,1" }) }) })
1185
+ ]
1186
+ },
1187
+ opt.value
1188
+ ))
1189
+ ] }, group)) })
1190
+ ] }),
1191
+ error && /* @__PURE__ */ jsx18("span", { className: "gy-input-helper gy-input-helper--error", role: "alert", children: error })
1192
+ ] });
1193
+ }
1194
+
1195
+ // src/menu/Menu.tsx
1196
+ import React15, { useEffect as useEffect5, useRef as useRef8, useState as useState8 } from "react";
1197
+ import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
1198
+ function Tooltip({ content, children, position = "top", delay = 300, disabled = false }) {
1199
+ const [visible, setVisible] = useState8(false);
1200
+ const timerRef = useRef8(void 0);
1201
+ const show = () => {
1202
+ timerRef.current = setTimeout(() => setVisible(true), delay);
1203
+ };
1204
+ const hide = () => {
1205
+ clearTimeout(timerRef.current);
1206
+ setVisible(false);
1207
+ };
1208
+ return /* @__PURE__ */ jsxs18("span", { className: "gy-tooltip-wrapper", onMouseEnter: show, onMouseLeave: hide, onFocus: show, onBlur: hide, children: [
1209
+ children,
1210
+ visible && !disabled && content && /* @__PURE__ */ jsx19("span", { className: `gy-tooltip gy-tooltip--${position}`, role: "tooltip", children: content })
1211
+ ] });
1212
+ }
1213
+ var posStyle = {
1214
+ "bottom-left": { top: "calc(100% + 4px)", left: 0 },
1215
+ "bottom-right": { top: "calc(100% + 4px)", right: 0 },
1216
+ "top-left": { bottom: "calc(100% + 4px)", left: 0 },
1217
+ "top-right": { bottom: "calc(100% + 4px)", right: 0 }
1218
+ };
1219
+ function Menu({ items, trigger, position = "bottom-left", className = "" }) {
1220
+ const [open, setOpen] = useState8(false);
1221
+ const rootRef = useRef8(null);
1222
+ useEffect5(() => {
1223
+ const handler = (e) => {
1224
+ if (!rootRef.current?.contains(e.target)) setOpen(false);
1225
+ };
1226
+ document.addEventListener("mousedown", handler);
1227
+ return () => document.removeEventListener("mousedown", handler);
1228
+ }, []);
1229
+ return /* @__PURE__ */ jsxs18("div", { ref: rootRef, className: "gy-menu-trigger", style: { position: "relative" }, children: [
1230
+ React15.cloneElement(trigger, { onClick: () => setOpen((o) => !o) }),
1231
+ open && /* @__PURE__ */ jsx19("div", { className: `gy-menu gy-menu--absolute ${className}`, style: posStyle[position], role: "menu", children: items.map((entry) => {
1232
+ if ("separator" in entry && entry.separator) {
1233
+ return /* @__PURE__ */ jsx19("div", { className: "gy-menu-separator", role: "separator" }, entry.id);
1234
+ }
1235
+ if ("groupLabel" in entry && entry.groupLabel) {
1236
+ return /* @__PURE__ */ jsx19("div", { className: "gy-menu-group-label", children: entry.groupLabel }, entry.id);
1237
+ }
1238
+ const item = entry;
1239
+ return /* @__PURE__ */ jsxs18(
1240
+ "button",
1241
+ {
1242
+ type: "button",
1243
+ className: [
1244
+ "gy-menu-item",
1245
+ item.danger ? "gy-menu-item--danger" : "",
1246
+ item.disabled ? "gy-menu-item--disabled" : ""
1247
+ ].filter(Boolean).join(" "),
1248
+ role: "menuitem",
1249
+ disabled: item.disabled,
1250
+ onClick: () => {
1251
+ item.onClick?.();
1252
+ setOpen(false);
1253
+ },
1254
+ children: [
1255
+ item.icon && /* @__PURE__ */ jsx19("span", { className: "gy-menu-item__icon", "aria-hidden": "true", children: item.icon }),
1256
+ item.label,
1257
+ item.badge && /* @__PURE__ */ jsx19("span", { className: "gy-menu-item__badge", children: item.badge })
1258
+ ]
1259
+ },
1260
+ item.id
1261
+ );
1262
+ }) })
1263
+ ] });
1264
+ }
1265
+
1266
+ // src/toaster/Toaster.tsx
1267
+ import { createContext, useCallback as useCallback3, useContext, useState as useState9 } from "react";
1268
+ import { createPortal as createPortal2 } from "react-dom";
1269
+ import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
1270
+ var ToastContext = createContext(null);
1271
+ var icons2 = {
1272
+ success: /* @__PURE__ */ jsxs19("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "#10b981", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1273
+ /* @__PURE__ */ jsx20("circle", { cx: "8", cy: "8", r: "7" }),
1274
+ /* @__PURE__ */ jsx20("polyline", { points: "5,8 7,10 11,6" })
1275
+ ] }),
1276
+ error: /* @__PURE__ */ jsxs19("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "#ef4444", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1277
+ /* @__PURE__ */ jsx20("circle", { cx: "8", cy: "8", r: "7" }),
1278
+ /* @__PURE__ */ jsx20("line", { x1: "8", y1: "5", x2: "8", y2: "9" }),
1279
+ /* @__PURE__ */ jsx20("circle", { cx: "8", cy: "11.5", r: "0.5", fill: "#ef4444" })
1280
+ ] }),
1281
+ warning: /* @__PURE__ */ jsx20("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "#f59e0b", children: /* @__PURE__ */ jsx20("path", { d: "M8 2L1 14h14L8 2zm0 4v4m0 2v.01", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round" }) }),
1282
+ info: /* @__PURE__ */ jsxs19("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "#0ea5e9", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1283
+ /* @__PURE__ */ jsx20("circle", { cx: "8", cy: "8", r: "7" }),
1284
+ /* @__PURE__ */ jsx20("line", { x1: "8", y1: "8", x2: "8", y2: "12" }),
1285
+ /* @__PURE__ */ jsx20("circle", { cx: "8", cy: "5", r: "0.5", fill: "#0ea5e9" })
1286
+ ] }),
1287
+ loading: /* @__PURE__ */ jsx20(Spinner, { size: "xs" })
1288
+ };
1289
+ function ToasterProvider({ children, position = "top-right" }) {
1290
+ const [toasts, setToasts] = useState9([]);
1291
+ const dismiss = useCallback3((id) => {
1292
+ setToasts((prev) => prev.filter((t) => t.id !== id));
1293
+ }, []);
1294
+ const dismissAll = useCallback3(() => setToasts([]), []);
1295
+ const toast = useCallback3((data) => {
1296
+ const id = Math.random().toString(36).slice(2);
1297
+ const duration = data.duration ?? (data.variant === "loading" ? 0 : 4e3);
1298
+ const newToast = { ...data, id, duration };
1299
+ setToasts((prev) => [...prev, newToast]);
1300
+ if (duration > 0) {
1301
+ setTimeout(() => dismiss(id), duration);
1302
+ }
1303
+ return id;
1304
+ }, [dismiss]);
1305
+ const isLeft = position.includes("left");
1306
+ const toasterNode = /* @__PURE__ */ jsx20("div", { className: `gy-toaster gy-toaster--${position}`, children: toasts.map((t) => /* @__PURE__ */ jsxs19(
1307
+ "div",
1308
+ {
1309
+ className: `gy-toast gy-toast--${t.variant ?? "info"} ${isLeft ? "gy-toast--left" : ""}`,
1310
+ role: "alert",
1311
+ "aria-live": "polite",
1312
+ children: [
1313
+ /* @__PURE__ */ jsx20("div", { className: "gy-toast-accent" }),
1314
+ /* @__PURE__ */ jsx20("span", { className: "gy-toast-icon", children: icons2[t.variant ?? "info"] }),
1315
+ /* @__PURE__ */ jsxs19("div", { className: "gy-toast-content", children: [
1316
+ /* @__PURE__ */ jsx20("div", { className: "gy-toast-title", children: t.title }),
1317
+ t.description && /* @__PURE__ */ jsx20("div", { className: "gy-toast-description", children: t.description })
1318
+ ] }),
1319
+ (t.dismissible ?? true) && /* @__PURE__ */ jsx20("button", { className: "gy-toast-close", onClick: () => dismiss(t.id), "aria-label": "Dismiss", children: /* @__PURE__ */ jsxs19("svg", { width: "12", height: "12", viewBox: "0 0 12 12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: [
1320
+ /* @__PURE__ */ jsx20("line", { x1: "1", y1: "1", x2: "11", y2: "11" }),
1321
+ /* @__PURE__ */ jsx20("line", { x1: "11", y1: "1", x2: "1", y2: "11" })
1322
+ ] }) }),
1323
+ t.duration && t.duration > 0 && /* @__PURE__ */ jsx20("div", { className: "gy-toast-progress", children: /* @__PURE__ */ jsx20("div", { className: "gy-toast-progress-bar", style: { animationDuration: `${t.duration}ms` } }) })
1324
+ ]
1325
+ },
1326
+ t.id
1327
+ )) });
1328
+ return /* @__PURE__ */ jsxs19(ToastContext.Provider, { value: { toasts, toast, dismiss, dismissAll }, children: [
1329
+ children,
1330
+ typeof document !== "undefined" && createPortal2(toasterNode, document.body)
1331
+ ] });
1332
+ }
1333
+ function useToast() {
1334
+ const ctx = useContext(ToastContext);
1335
+ if (!ctx) throw new Error("useToast must be used inside ToasterProvider");
1336
+ return ctx;
1337
+ }
1338
+
1339
+ // src/stepper/Stepper.tsx
1340
+ import React17, { useState as useState10 } from "react";
1341
+ import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
1342
+ var CheckIcon = () => /* @__PURE__ */ jsx21("svg", { width: "14", height: "11", viewBox: "0 0 14 11", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx21("polyline", { points: "1,5 5,9 13,1" }) });
1343
+ var ErrorIcon = () => /* @__PURE__ */ jsxs20("svg", { width: "12", height: "12", viewBox: "0 0 12 12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: [
1344
+ /* @__PURE__ */ jsx21("line", { x1: "2", y1: "2", x2: "10", y2: "10" }),
1345
+ /* @__PURE__ */ jsx21("line", { x1: "10", y1: "2", x2: "2", y2: "10" })
1346
+ ] });
1347
+ function Stepper({
1348
+ steps,
1349
+ activeStep: controlledStep,
1350
+ defaultStep = 0,
1351
+ variant = "linear",
1352
+ orientation = "horizontal",
1353
+ onStepChange,
1354
+ onComplete,
1355
+ className = ""
1356
+ }) {
1357
+ const [internalStep, setInternalStep] = useState10(defaultStep);
1358
+ const current = controlledStep ?? internalStep;
1359
+ const goTo = (idx) => {
1360
+ if (variant === "linear" && idx > current + 1) return;
1361
+ if (idx < 0 || idx >= steps.length) return;
1362
+ setInternalStep(idx);
1363
+ onStepChange?.(idx);
1364
+ };
1365
+ const next = () => {
1366
+ if (current === steps.length - 1) {
1367
+ onComplete?.();
1368
+ } else {
1369
+ goTo(current + 1);
1370
+ }
1371
+ };
1372
+ const prev = () => goTo(current - 1);
1373
+ const getStatus = (idx) => {
1374
+ if (idx < current) return "completed";
1375
+ if (idx === current) return "active";
1376
+ return "upcoming";
1377
+ };
1378
+ return /* @__PURE__ */ jsxs20("div", { className: `gy-stepper ${orientation === "vertical" ? "gy-stepper--vertical" : ""} ${className}`, children: [
1379
+ /* @__PURE__ */ jsx21("div", { className: `gy-stepper ${orientation === "vertical" ? "gy-stepper--vertical" : ""}`, style: { width: "100%" }, children: steps.map((step, idx) => {
1380
+ const status = getStatus(idx);
1381
+ const isClickable = variant === "free" || idx <= current;
1382
+ return /* @__PURE__ */ jsxs20(React17.Fragment, { children: [
1383
+ /* @__PURE__ */ jsxs20("div", { className: "gy-stepper-item", children: [
1384
+ /* @__PURE__ */ jsx21(
1385
+ "span",
1386
+ {
1387
+ className: [
1388
+ "gy-stepper-indicator",
1389
+ `gy-stepper-indicator--${status}`,
1390
+ isClickable ? "gy-stepper-indicator--clickable" : ""
1391
+ ].filter(Boolean).join(" "),
1392
+ onClick: () => isClickable && goTo(idx),
1393
+ role: isClickable ? "button" : void 0,
1394
+ tabIndex: isClickable ? 0 : void 0,
1395
+ onKeyDown: isClickable ? (e) => {
1396
+ if (e.key === "Enter") goTo(idx);
1397
+ } : void 0,
1398
+ "aria-label": `Step ${idx + 1}: ${step.label}`,
1399
+ "aria-current": status === "active" ? "step" : void 0,
1400
+ children: status === "completed" ? /* @__PURE__ */ jsx21(CheckIcon, {}) : status === "error" ? /* @__PURE__ */ jsx21(ErrorIcon, {}) : idx + 1
1401
+ }
1402
+ ),
1403
+ /* @__PURE__ */ jsxs20("div", { children: [
1404
+ /* @__PURE__ */ jsx21("div", { className: `gy-stepper-label gy-stepper-label--${status}`, children: step.label }),
1405
+ step.optional && /* @__PURE__ */ jsx21("div", { className: "gy-stepper-description", children: "Optional" }),
1406
+ step.description && /* @__PURE__ */ jsx21("div", { className: "gy-stepper-description", children: step.description })
1407
+ ] })
1408
+ ] }),
1409
+ idx < steps.length - 1 && /* @__PURE__ */ jsx21("div", { className: `gy-stepper-connector ${idx < current ? "gy-stepper-connector--completed" : ""}` })
1410
+ ] }, step.id);
1411
+ }) }),
1412
+ steps[current]?.content && /* @__PURE__ */ jsx21("div", { className: "gy-stepper-panel", children: steps[current].content }, current)
1413
+ ] });
1414
+ }
1415
+
1416
+ // src/table/Table.tsx
1417
+ import React18, { useMemo, useState as useState11 } from "react";
1418
+ import { Fragment, jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
1419
+ function SortIcon({ dir }) {
1420
+ return /* @__PURE__ */ jsx22("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "currentColor", className: `gy-table-sort-icon ${dir ? "gy-table-sort-icon--active" : ""}`, children: dir === "asc" ? /* @__PURE__ */ jsx22("path", { d: "M6 2L10 8H2L6 2z" }) : dir === "desc" ? /* @__PURE__ */ jsx22("path", { d: "M6 10L2 4H10L6 10z" }) : /* @__PURE__ */ jsxs21(Fragment, { children: [
1421
+ /* @__PURE__ */ jsx22("path", { d: "M6 1L9 5H3L6 1z", opacity: ".5" }),
1422
+ /* @__PURE__ */ jsx22("path", { d: "M6 11L3 7H9L6 11z", opacity: ".5" })
1423
+ ] }) });
1424
+ }
1425
+ function Table({
1426
+ columns,
1427
+ data,
1428
+ rowKey,
1429
+ selectable = false,
1430
+ selectedRows = [],
1431
+ onSelectionChange,
1432
+ pageSize = 10,
1433
+ emptyMessage = "No data available",
1434
+ className = "",
1435
+ stickyHeader = false
1436
+ }) {
1437
+ const [sortKey, setSortKey] = useState11(null);
1438
+ const [sortDir, setSortDir] = useState11("asc");
1439
+ const [page, setPage] = useState11(1);
1440
+ const sortedData = useMemo(() => {
1441
+ if (!sortKey) return data;
1442
+ const col = columns.find((c) => c.key === sortKey);
1443
+ if (!col) return data;
1444
+ return [...data].sort((a, b) => {
1445
+ const av = String(col.accessor(a) ?? "");
1446
+ const bv = String(col.accessor(b) ?? "");
1447
+ const cmp = av.localeCompare(bv, void 0, { numeric: true });
1448
+ return sortDir === "asc" ? cmp : -cmp;
1449
+ });
1450
+ }, [data, sortKey, sortDir, columns]);
1451
+ const totalPages = Math.max(1, Math.ceil(sortedData.length / pageSize));
1452
+ const paged = sortedData.slice((page - 1) * pageSize, page * pageSize);
1453
+ const allSelected = paged.length > 0 && paged.every((r) => selectedRows.includes(rowKey(r)));
1454
+ const someSelected = paged.some((r) => selectedRows.includes(rowKey(r)));
1455
+ const toggleSort = (key) => {
1456
+ if (sortKey === key) {
1457
+ setSortDir((d) => d === "asc" ? "desc" : "asc");
1458
+ } else {
1459
+ setSortKey(key);
1460
+ setSortDir("asc");
1461
+ }
1462
+ setPage(1);
1463
+ };
1464
+ const toggleRow = (key) => {
1465
+ const next = selectedRows.includes(key) ? selectedRows.filter((k) => k !== key) : [...selectedRows, key];
1466
+ onSelectionChange?.(next);
1467
+ };
1468
+ const toggleAll = () => {
1469
+ const pageKeys = paged.map(rowKey);
1470
+ if (allSelected) {
1471
+ onSelectionChange?.(selectedRows.filter((k) => !pageKeys.includes(k)));
1472
+ } else {
1473
+ const combined = [.../* @__PURE__ */ new Set([...selectedRows, ...pageKeys])];
1474
+ onSelectionChange?.(combined);
1475
+ }
1476
+ };
1477
+ const pageNums = Array.from({ length: totalPages }, (_, i) => i + 1);
1478
+ const visiblePages = pageNums.filter(
1479
+ (p) => p === 1 || p === totalPages || Math.abs(p - page) <= 1
1480
+ );
1481
+ return /* @__PURE__ */ jsxs21("div", { className: `gy-table-wrapper ${className}`, children: [
1482
+ /* @__PURE__ */ jsxs21("table", { className: "gy-table", "aria-label": "Data table", children: [
1483
+ /* @__PURE__ */ jsx22("thead", { className: "gy-table-header", children: /* @__PURE__ */ jsxs21("tr", { children: [
1484
+ selectable && /* @__PURE__ */ jsx22("th", { className: "gy-table-th gy-table-th--checkbox", children: /* @__PURE__ */ jsx22(
1485
+ Checkbox,
1486
+ {
1487
+ checked: allSelected,
1488
+ indeterminate: !allSelected && someSelected,
1489
+ onChange: toggleAll,
1490
+ size: "sm"
1491
+ }
1492
+ ) }),
1493
+ columns.map((col) => /* @__PURE__ */ jsx22(
1494
+ "th",
1495
+ {
1496
+ className: `gy-table-th ${col.sortable ? "gy-table-th--sortable" : ""}`,
1497
+ style: { width: col.width, textAlign: col.align },
1498
+ onClick: col.sortable ? () => toggleSort(col.key) : void 0,
1499
+ "aria-sort": sortKey === col.key ? sortDir === "asc" ? "ascending" : "descending" : void 0,
1500
+ children: /* @__PURE__ */ jsxs21("span", { className: "gy-table-th-inner", children: [
1501
+ col.header,
1502
+ col.sortable && /* @__PURE__ */ jsx22(SortIcon, { dir: sortKey === col.key ? sortDir : void 0 })
1503
+ ] })
1504
+ },
1505
+ col.key
1506
+ ))
1507
+ ] }) }),
1508
+ /* @__PURE__ */ jsx22("tbody", { children: paged.length === 0 ? /* @__PURE__ */ jsx22("tr", { children: /* @__PURE__ */ jsx22("td", { colSpan: columns.length + (selectable ? 1 : 0), className: "gy-table-empty", children: emptyMessage }) }) : paged.map((row) => {
1509
+ const key = rowKey(row);
1510
+ const isSelected = selectedRows.includes(key);
1511
+ return /* @__PURE__ */ jsxs21(
1512
+ "tr",
1513
+ {
1514
+ className: `gy-table-tr ${isSelected ? "gy-table-tr--selected" : ""}`,
1515
+ "aria-selected": selectable ? isSelected : void 0,
1516
+ children: [
1517
+ selectable && /* @__PURE__ */ jsx22("td", { className: "gy-table-td gy-table-td--checkbox", children: /* @__PURE__ */ jsx22(Checkbox, { checked: isSelected, onChange: () => toggleRow(key), size: "sm" }) }),
1518
+ columns.map((col) => /* @__PURE__ */ jsx22("td", { className: "gy-table-td", style: { textAlign: col.align }, children: col.accessor(row) }, col.key))
1519
+ ]
1520
+ },
1521
+ key
1522
+ );
1523
+ }) })
1524
+ ] }),
1525
+ totalPages > 1 && /* @__PURE__ */ jsxs21("div", { className: "gy-table-pagination", children: [
1526
+ /* @__PURE__ */ jsxs21("span", { className: "gy-table-pagination-info", children: [
1527
+ "Showing ",
1528
+ (page - 1) * pageSize + 1,
1529
+ "\u2013",
1530
+ Math.min(page * pageSize, sortedData.length),
1531
+ " of ",
1532
+ sortedData.length
1533
+ ] }),
1534
+ /* @__PURE__ */ jsxs21("div", { className: "gy-table-pagination-controls", children: [
1535
+ /* @__PURE__ */ jsx22("button", { className: "gy-table-pagination-btn", onClick: () => setPage((p) => p - 1), disabled: page === 1, "aria-label": "Previous page", children: "\u2039" }),
1536
+ visiblePages.map((p, i, arr) => /* @__PURE__ */ jsxs21(React18.Fragment, { children: [
1537
+ i > 0 && arr[i - 1] !== p - 1 && /* @__PURE__ */ jsx22("span", { style: { padding: "0 4px", color: "var(--gy-text-subtle)" }, children: "\u2026" }),
1538
+ /* @__PURE__ */ jsx22(
1539
+ "button",
1540
+ {
1541
+ className: `gy-table-pagination-btn ${page === p ? "gy-table-pagination-btn--active" : ""}`,
1542
+ onClick: () => setPage(p),
1543
+ "aria-label": `Page ${p}`,
1544
+ "aria-current": page === p ? "page" : void 0,
1545
+ children: p
1546
+ }
1547
+ )
1548
+ ] }, p)),
1549
+ /* @__PURE__ */ jsx22("button", { className: "gy-table-pagination-btn", onClick: () => setPage((p) => p + 1), disabled: page === totalPages, "aria-label": "Next page", children: "\u203A" })
1550
+ ] })
1551
+ ] })
1552
+ ] });
1553
+ }
1554
+
1555
+ // src/dragdrop/DragDrop.tsx
1556
+ import { useState as useState12 } from "react";
1557
+ import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
1558
+ function ReorderList({ items, onReorder, keyExtractor, renderItem: renderItem2, className = "" }) {
1559
+ const [draggedIdx, setDraggedIdx] = useState12(null);
1560
+ const [dragOverIdx, setDragOverIdx] = useState12(null);
1561
+ const handleDragStart = (idx, e) => {
1562
+ setDraggedIdx(idx);
1563
+ e.dataTransfer.effectAllowed = "move";
1564
+ e.dataTransfer.setData("text/plain", idx.toString());
1565
+ };
1566
+ const handleDragOver = (idx, e) => {
1567
+ e.preventDefault();
1568
+ e.dataTransfer.dropEffect = "move";
1569
+ if (idx !== dragOverIdx) setDragOverIdx(idx);
1570
+ };
1571
+ const handleDrop = (idx, e) => {
1572
+ e.preventDefault();
1573
+ const fromIdx = Number(e.dataTransfer.getData("text/plain"));
1574
+ if (fromIdx !== idx) {
1575
+ const next = [...items];
1576
+ const [moved] = next.splice(fromIdx, 1);
1577
+ if (moved !== void 0) {
1578
+ next.splice(idx, 0, moved);
1579
+ onReorder(next);
1580
+ }
1581
+ }
1582
+ setDraggedIdx(null);
1583
+ setDragOverIdx(null);
1584
+ };
1585
+ return /* @__PURE__ */ jsx23("div", { className: `gy-dnd-list ${className}`, children: items.map((item, idx) => {
1586
+ const isDragging = draggedIdx === idx;
1587
+ const isOver = dragOverIdx === idx;
1588
+ return /* @__PURE__ */ jsxs22(
1589
+ "div",
1590
+ {
1591
+ className: [
1592
+ "gy-dnd-item",
1593
+ isDragging ? "gy-dnd-item--dragging" : "",
1594
+ isOver && !isDragging ? "gy-dnd-item--drag-over" : ""
1595
+ ].filter(Boolean).join(" "),
1596
+ draggable: true,
1597
+ onDragStart: (e) => handleDragStart(idx, e),
1598
+ onDragOver: (e) => handleDragOver(idx, e),
1599
+ onDragLeave: () => setDragOverIdx(null),
1600
+ onDrop: (e) => handleDrop(idx, e),
1601
+ onDragEnd: () => {
1602
+ setDraggedIdx(null);
1603
+ setDragOverIdx(null);
1604
+ },
1605
+ children: [
1606
+ /* @__PURE__ */ jsx23("div", { className: "gy-dnd-handle", "aria-hidden": "true", children: /* @__PURE__ */ jsxs22("svg", { width: "12", height: "16", viewBox: "0 0 12 16", fill: "currentColor", children: [
1607
+ /* @__PURE__ */ jsx23("circle", { cx: "4", cy: "4", r: "1.5" }),
1608
+ /* @__PURE__ */ jsx23("circle", { cx: "8", cy: "4", r: "1.5" }),
1609
+ /* @__PURE__ */ jsx23("circle", { cx: "4", cy: "8", r: "1.5" }),
1610
+ /* @__PURE__ */ jsx23("circle", { cx: "8", cy: "8", r: "1.5" }),
1611
+ /* @__PURE__ */ jsx23("circle", { cx: "4", cy: "12", r: "1.5" }),
1612
+ /* @__PURE__ */ jsx23("circle", { cx: "8", cy: "12", r: "1.5" })
1613
+ ] }) }),
1614
+ /* @__PURE__ */ jsx23("div", { className: "gy-dnd-item-content", children: renderItem2(item, isDragging) })
1615
+ ]
1616
+ },
1617
+ keyExtractor(item)
1618
+ );
1619
+ }) });
1620
+ }
1621
+ function KanbanBoard({ columns, onMove, keyExtractor, renderCard, className = "" }) {
1622
+ const [dragged, setDragged] = useState12(null);
1623
+ const [overCol, setOverCol] = useState12(null);
1624
+ const handleDragStart = (e, key, colId, idx) => {
1625
+ setDragged({ key, colId, idx });
1626
+ e.dataTransfer.effectAllowed = "move";
1627
+ e.dataTransfer.setData("application/json", JSON.stringify({ key, colId }));
1628
+ };
1629
+ const handleDragOver = (e, colId) => {
1630
+ e.preventDefault();
1631
+ e.dataTransfer.dropEffect = "move";
1632
+ if (overCol !== colId) setOverCol(colId);
1633
+ };
1634
+ const handleDrop = (e, toCol, toIndex) => {
1635
+ e.preventDefault();
1636
+ setOverCol(null);
1637
+ try {
1638
+ const data = JSON.parse(e.dataTransfer.getData("application/json"));
1639
+ if (data.colId === toCol && data.key === dragged?.key && toIndex === dragged?.idx) {
1640
+ return;
1641
+ }
1642
+ onMove(data.key, data.colId, toCol, toIndex);
1643
+ } catch (err) {
1644
+ }
1645
+ setDragged(null);
1646
+ };
1647
+ return /* @__PURE__ */ jsx23("div", { className: `gy-kanban ${className}`, children: columns.map((col) => /* @__PURE__ */ jsxs22("div", { className: "gy-kanban-column", children: [
1648
+ /* @__PURE__ */ jsxs22("div", { className: "gy-kanban-column-header", children: [
1649
+ /* @__PURE__ */ jsx23("span", { className: "gy-kanban-column-title", children: col.title }),
1650
+ /* @__PURE__ */ jsx23("span", { className: "gy-kanban-column-count", children: col.items.length })
1651
+ ] }),
1652
+ /* @__PURE__ */ jsx23(
1653
+ "div",
1654
+ {
1655
+ className: `gy-kanban-drop-zone ${overCol === col.id ? "gy-kanban-drop-zone--over" : ""}`,
1656
+ onDragOver: (e) => handleDragOver(e, col.id),
1657
+ onDragLeave: () => setOverCol(null),
1658
+ onDrop: (e) => handleDrop(e, col.id, col.items.length),
1659
+ children: col.items.map((item, idx) => {
1660
+ const key = keyExtractor(item);
1661
+ const isDragging = dragged?.key === key;
1662
+ return /* @__PURE__ */ jsx23(
1663
+ "div",
1664
+ {
1665
+ className: `gy-kanban-card ${isDragging ? "gy-kanban-card--dragging" : ""}`,
1666
+ draggable: true,
1667
+ onDragStart: (e) => handleDragStart(e, key, col.id, idx),
1668
+ onDragEnd: () => {
1669
+ setDragged(null);
1670
+ setOverCol(null);
1671
+ },
1672
+ onDrop: (e) => {
1673
+ e.stopPropagation();
1674
+ handleDrop(e, col.id, idx);
1675
+ },
1676
+ children: renderCard(item, isDragging)
1677
+ },
1678
+ key
1679
+ );
1680
+ })
1681
+ }
1682
+ )
1683
+ ] }, col.id)) });
1684
+ }
1685
+
1686
+ // src/fileupload/FileUpload.tsx
1687
+ import { useRef as useRef10, useState as useState13 } from "react";
1688
+ import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
1689
+ var formatSize = (bytes) => {
1690
+ if (bytes === 0) return "0 B";
1691
+ const k = 1024;
1692
+ const sizes = ["B", "KB", "MB", "GB"];
1693
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
1694
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + " " + sizes[i];
1695
+ };
1696
+ function FileUpload({
1697
+ onFilesSelected,
1698
+ multiple = false,
1699
+ accept,
1700
+ maxSize,
1701
+ maxFiles,
1702
+ disabled = false,
1703
+ label = "Click or drag files to upload",
1704
+ helperText,
1705
+ className = ""
1706
+ }) {
1707
+ const [dragActive, setDragActive] = useState13(false);
1708
+ const [selectedFiles, setSelectedFiles] = useState13([]);
1709
+ const inputRef = useRef10(null);
1710
+ const handleFiles = (files) => {
1711
+ if (!files) return;
1712
+ const valid = Array.from(files).filter((f) => !maxSize || f.size <= maxSize);
1713
+ const newFiles = multiple ? [...selectedFiles, ...valid] : valid;
1714
+ const limited = maxFiles ? newFiles.slice(0, maxFiles) : newFiles;
1715
+ if (!multiple) limited.splice(1);
1716
+ setSelectedFiles(limited);
1717
+ onFilesSelected?.(limited);
1718
+ };
1719
+ const handleDrag = (e) => {
1720
+ e.preventDefault();
1721
+ e.stopPropagation();
1722
+ if (disabled) return;
1723
+ if (e.type === "dragenter" || e.type === "dragover") setDragActive(true);
1724
+ else if (e.type === "dragleave") setDragActive(false);
1725
+ };
1726
+ const handleDrop = (e) => {
1727
+ e.preventDefault();
1728
+ e.stopPropagation();
1729
+ setDragActive(false);
1730
+ if (disabled) return;
1731
+ handleFiles(e.dataTransfer.files);
1732
+ };
1733
+ const removeFile = (idx) => {
1734
+ const updated = selectedFiles.filter((_, i) => i !== idx);
1735
+ setSelectedFiles(updated);
1736
+ onFilesSelected?.(updated);
1737
+ };
1738
+ return /* @__PURE__ */ jsxs23("div", { className: `gy-fileupload ${className}`, children: [
1739
+ /* @__PURE__ */ jsxs23(
1740
+ "div",
1741
+ {
1742
+ className: [
1743
+ "gy-fileupload-zone",
1744
+ dragActive ? "gy-fileupload-zone--drag-active" : "",
1745
+ disabled ? "gy-fileupload-zone--disabled" : ""
1746
+ ].filter(Boolean).join(" "),
1747
+ onClick: () => !disabled && inputRef.current?.click(),
1748
+ onDragEnter: handleDrag,
1749
+ onDragLeave: handleDrag,
1750
+ onDragOver: handleDrag,
1751
+ onDrop: handleDrop,
1752
+ children: [
1753
+ /* @__PURE__ */ jsx24(
1754
+ "input",
1755
+ {
1756
+ ref: inputRef,
1757
+ type: "file",
1758
+ className: "gy-fileupload-input",
1759
+ multiple,
1760
+ accept,
1761
+ disabled,
1762
+ onChange: (e) => handleFiles(e.target.files)
1763
+ }
1764
+ ),
1765
+ /* @__PURE__ */ jsxs23("svg", { className: "gy-fileupload-icon", width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1766
+ /* @__PURE__ */ jsx24("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1767
+ /* @__PURE__ */ jsx24("polyline", { points: "17 8 12 3 7 8" }),
1768
+ /* @__PURE__ */ jsx24("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
1769
+ ] }),
1770
+ /* @__PURE__ */ jsx24("div", { className: "gy-fileupload-text", children: label }),
1771
+ (helperText || maxSize) && /* @__PURE__ */ jsxs23("div", { className: "gy-fileupload-subtext", children: [
1772
+ helperText,
1773
+ " ",
1774
+ maxSize && `(Max ${formatSize(maxSize)})`
1775
+ ] })
1776
+ ]
1777
+ }
1778
+ ),
1779
+ selectedFiles.length > 0 && /* @__PURE__ */ jsx24("div", { className: "gy-fileupload-list", children: selectedFiles.map((f, i) => /* @__PURE__ */ jsxs23("div", { className: "gy-fileupload-item", children: [
1780
+ /* @__PURE__ */ jsx24("div", { className: "gy-fileupload-item-icon", children: /* @__PURE__ */ jsxs23("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1781
+ /* @__PURE__ */ jsx24("path", { d: "M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" }),
1782
+ /* @__PURE__ */ jsx24("polyline", { points: "13 2 13 9 20 9" })
1783
+ ] }) }),
1784
+ /* @__PURE__ */ jsxs23("div", { className: "gy-fileupload-item-info", children: [
1785
+ /* @__PURE__ */ jsx24("span", { className: "gy-fileupload-item-name", title: f.name, children: f.name }),
1786
+ /* @__PURE__ */ jsx24("span", { className: "gy-fileupload-item-size", children: formatSize(f.size) })
1787
+ ] }),
1788
+ /* @__PURE__ */ jsx24(
1789
+ "button",
1790
+ {
1791
+ type: "button",
1792
+ className: "gy-fileupload-item-remove",
1793
+ onClick: (e) => {
1794
+ e.stopPropagation();
1795
+ removeFile(i);
1796
+ },
1797
+ "aria-label": "Remove file",
1798
+ children: /* @__PURE__ */ jsxs23("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1799
+ /* @__PURE__ */ jsx24("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1800
+ /* @__PURE__ */ jsx24("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1801
+ ] })
1802
+ }
1803
+ )
1804
+ ] }, `${f.name}-${i}`)) })
1805
+ ] });
1806
+ }
1807
+
1808
+ // src/calendar/Calendar.tsx
1809
+ import { useState as useState14 } from "react";
1810
+ import { Fragment as Fragment2, jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
1811
+ var getDaysInMonth = (year, month) => new Date(year, month + 1, 0).getDate();
1812
+ var getFirstDay = (year, month) => new Date(year, month, 1).getDay();
1813
+ var isSameDay = (d1, d2) => {
1814
+ if (!d1 || !d2) return false;
1815
+ return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate();
1816
+ };
1817
+ var isBetween = (d, start, end) => {
1818
+ if (!start || !end) return false;
1819
+ return d > start && d < end;
1820
+ };
1821
+ function Calendar({ mode = "single", value, onChange, minDate, maxDate, className = "", style }) {
1822
+ const [view, setView] = useState14("days");
1823
+ const [current, setCurrent] = useState14(() => {
1824
+ if (Array.isArray(value)) return value[0] ?? /* @__PURE__ */ new Date();
1825
+ return value ?? /* @__PURE__ */ new Date();
1826
+ });
1827
+ const [hoverDate, setHoverDate] = useState14(null);
1828
+ const [selStart, selEnd] = Array.isArray(value) ? value : [value, void 0];
1829
+ const y = current.getFullYear();
1830
+ const m = current.getMonth();
1831
+ const prevMonth = () => setCurrent(new Date(y, m - 1, 1));
1832
+ const nextMonth = () => setCurrent(new Date(y, m + 1, 1));
1833
+ const prevYear = () => setCurrent(new Date(y - 1, m, 1));
1834
+ const nextYear = () => setCurrent(new Date(y + 1, m, 1));
1835
+ const prevDecade = () => setCurrent(new Date(y - 10, m, 1));
1836
+ const nextDecade = () => setCurrent(new Date(y + 10, m, 1));
1837
+ const daysInMonth = getDaysInMonth(y, m);
1838
+ const firstDay = getFirstDay(y, m);
1839
+ const daysInPrev = getDaysInMonth(y, m - 1);
1840
+ const handleSelectDay = (date) => {
1841
+ if (mode === "single") {
1842
+ onChange?.(date);
1843
+ } else {
1844
+ if (!selStart || selStart && selEnd) {
1845
+ onChange?.([date, date]);
1846
+ } else {
1847
+ const start = date < selStart ? date : selStart;
1848
+ const end = date < selStart ? selStart : date;
1849
+ onChange?.([start, end]);
1850
+ }
1851
+ }
1852
+ };
1853
+ const renderDays = () => {
1854
+ const days = [];
1855
+ const today = /* @__PURE__ */ new Date();
1856
+ for (let i = firstDay - 1; i >= 0; i--) {
1857
+ const d = new Date(y, m - 1, daysInPrev - i);
1858
+ days.push(/* @__PURE__ */ jsx25(Day, { date: d, outside: true }, `prev-${i}`));
1859
+ }
1860
+ for (let i = 1; i <= daysInMonth; i++) {
1861
+ const d = new Date(y, m, i);
1862
+ days.push(/* @__PURE__ */ jsx25(Day, { date: d, isToday: isSameDay(d, today) }, `curr-${i}`));
1863
+ }
1864
+ const total = days.length;
1865
+ for (let i = 1; i <= 42 - total; i++) {
1866
+ const d = new Date(y, m + 1, i);
1867
+ days.push(/* @__PURE__ */ jsx25(Day, { date: d, outside: true }, `next-${i}`));
1868
+ }
1869
+ return days;
1870
+ };
1871
+ const Day = ({ date, outside, isToday }) => {
1872
+ const disabled = minDate && date < minDate || maxDate && date > maxDate;
1873
+ const selected = isSameDay(date, selStart) || isSameDay(date, selEnd);
1874
+ const inRange = mode === "range" && isBetween(date, selStart, selEnd ?? hoverDate ?? void 0);
1875
+ const isStart = mode === "range" && isSameDay(date, selStart);
1876
+ const isEnd = mode === "range" && isSameDay(date, selEnd ?? hoverDate ?? void 0) && date > selStart;
1877
+ const cls = [
1878
+ "gy-calendar-day",
1879
+ outside ? "gy-calendar-day--outside" : "",
1880
+ isToday ? "gy-calendar-day--today" : "",
1881
+ selected ? "gy-calendar-day--selected" : "",
1882
+ inRange ? "gy-calendar-day--range-in" : "",
1883
+ isStart && (selEnd ?? hoverDate) ? "gy-calendar-day--range-start" : "",
1884
+ isEnd ? "gy-calendar-day--range-end" : "",
1885
+ disabled ? "gy-calendar-day--disabled" : ""
1886
+ ].filter(Boolean).join(" ");
1887
+ return /* @__PURE__ */ jsx25(
1888
+ "button",
1889
+ {
1890
+ type: "button",
1891
+ className: cls,
1892
+ disabled,
1893
+ onClick: () => handleSelectDay(date),
1894
+ onMouseEnter: () => mode === "range" && selStart && !selEnd ? setHoverDate(date) : null,
1895
+ children: date.getDate()
1896
+ }
1897
+ );
1898
+ };
1899
+ const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
1900
+ const monthName = current.toLocaleString("default", { month: "long" });
1901
+ return /* @__PURE__ */ jsxs24("div", { className: `gy-calendar ${className}`, style, children: [
1902
+ view === "days" && /* @__PURE__ */ jsxs24(Fragment2, { children: [
1903
+ /* @__PURE__ */ jsxs24("div", { className: "gy-calendar-header", children: [
1904
+ /* @__PURE__ */ jsx25("button", { className: "gy-calendar-nav", onClick: prevMonth, children: "\u2039" }),
1905
+ /* @__PURE__ */ jsxs24("div", { className: "gy-calendar-title", onClick: () => setView("months"), children: [
1906
+ monthName,
1907
+ " ",
1908
+ y
1909
+ ] }),
1910
+ /* @__PURE__ */ jsx25("button", { className: "gy-calendar-nav", onClick: nextMonth, children: "\u203A" })
1911
+ ] }),
1912
+ /* @__PURE__ */ jsxs24("div", { className: "gy-calendar-grid", children: [
1913
+ ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((d) => /* @__PURE__ */ jsx25("div", { className: "gy-calendar-weekday", children: d }, d)),
1914
+ renderDays()
1915
+ ] })
1916
+ ] }),
1917
+ view === "months" && /* @__PURE__ */ jsxs24(Fragment2, { children: [
1918
+ /* @__PURE__ */ jsxs24("div", { className: "gy-calendar-header", children: [
1919
+ /* @__PURE__ */ jsx25("button", { className: "gy-calendar-nav", onClick: prevYear, children: "\u2039" }),
1920
+ /* @__PURE__ */ jsx25("div", { className: "gy-calendar-title", onClick: () => setView("years"), children: y }),
1921
+ /* @__PURE__ */ jsx25("button", { className: "gy-calendar-nav", onClick: nextYear, children: "\u203A" })
1922
+ ] }),
1923
+ /* @__PURE__ */ jsx25("div", { className: "gy-calendar-picker-grid", children: months.map((mon, i) => /* @__PURE__ */ jsx25(
1924
+ "button",
1925
+ {
1926
+ className: `gy-calendar-picker-item ${m === i ? "gy-calendar-picker-item--selected" : ""}`,
1927
+ onClick: () => {
1928
+ setCurrent(new Date(y, i, 1));
1929
+ setView("days");
1930
+ },
1931
+ children: mon
1932
+ },
1933
+ mon
1934
+ )) })
1935
+ ] }),
1936
+ view === "years" && /* @__PURE__ */ jsxs24(Fragment2, { children: [
1937
+ /* @__PURE__ */ jsxs24("div", { className: "gy-calendar-header", children: [
1938
+ /* @__PURE__ */ jsx25("button", { className: "gy-calendar-nav", onClick: prevDecade, children: "\u2039" }),
1939
+ /* @__PURE__ */ jsxs24("div", { className: "gy-calendar-title", children: [
1940
+ y - y % 10,
1941
+ " - ",
1942
+ y - y % 10 + 9
1943
+ ] }),
1944
+ /* @__PURE__ */ jsx25("button", { className: "gy-calendar-nav", onClick: nextDecade, children: "\u203A" })
1945
+ ] }),
1946
+ /* @__PURE__ */ jsx25("div", { className: "gy-calendar-picker-grid", children: Array.from({ length: 12 }, (_, i) => y - y % 10 - 1 + i).map((year) => /* @__PURE__ */ jsx25(
1947
+ "button",
1948
+ {
1949
+ className: `gy-calendar-picker-item ${y === year ? "gy-calendar-picker-item--selected" : ""}`,
1950
+ onClick: () => {
1951
+ setCurrent(new Date(year, m, 1));
1952
+ setView("months");
1953
+ },
1954
+ children: year
1955
+ },
1956
+ year
1957
+ )) })
1958
+ ] })
1959
+ ] });
1960
+ }
1961
+
1962
+ // src/datepicker/DatePicker.tsx
1963
+ import { useEffect as useEffect6, useRef as useRef11, useState as useState15, useId as useId8 } from "react";
1964
+ import { jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
1965
+ var formatDate = (date) => {
1966
+ return date.toLocaleDateString(void 0, {
1967
+ year: "numeric",
1968
+ month: "short",
1969
+ day: "numeric"
1970
+ });
1971
+ };
1972
+ function DatePicker({
1973
+ mode = "single",
1974
+ value,
1975
+ onChange,
1976
+ minDate,
1977
+ maxDate,
1978
+ label,
1979
+ placeholder = "Select date",
1980
+ disabled,
1981
+ error,
1982
+ helperText,
1983
+ className = ""
1984
+ }) {
1985
+ const uid = useId8();
1986
+ const [open, setOpen] = useState15(false);
1987
+ const rootRef = useRef11(null);
1988
+ useEffect6(() => {
1989
+ const handler = (e) => {
1990
+ if (!rootRef.current?.contains(e.target)) setOpen(false);
1991
+ };
1992
+ document.addEventListener("mousedown", handler);
1993
+ return () => document.removeEventListener("mousedown", handler);
1994
+ }, []);
1995
+ let displayValue = "";
1996
+ if (Array.isArray(value)) {
1997
+ if (value[0] && value[1]) displayValue = `${formatDate(value[0])} - ${formatDate(value[1])}`;
1998
+ else if (value[0]) displayValue = formatDate(value[0]);
1999
+ } else if (value) {
2000
+ displayValue = formatDate(value);
2001
+ }
2002
+ const handleChange = (val) => {
2003
+ onChange?.(val);
2004
+ if (mode === "single" || Array.isArray(val) && val[0] && val[1]) {
2005
+ setOpen(false);
2006
+ }
2007
+ };
2008
+ return /* @__PURE__ */ jsxs25("div", { ref: rootRef, className: `gy-datepicker ${className}`, children: [
2009
+ /* @__PURE__ */ jsx26("div", { onClick: () => !disabled && setOpen((o) => !o), style: { cursor: disabled ? "not-allowed" : "pointer" }, children: /* @__PURE__ */ jsx26(
2010
+ Input,
2011
+ {
2012
+ id: `gy-datepicker-${uid}`,
2013
+ label,
2014
+ placeholder,
2015
+ value: displayValue,
2016
+ readOnly: true,
2017
+ disabled,
2018
+ error,
2019
+ helperText,
2020
+ style: { cursor: disabled ? "not-allowed" : "pointer", pointerEvents: "none" },
2021
+ rightIcon: /* @__PURE__ */ jsxs25("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2022
+ /* @__PURE__ */ jsx26("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }),
2023
+ /* @__PURE__ */ jsx26("line", { x1: "16", y1: "2", x2: "16", y2: "6" }),
2024
+ /* @__PURE__ */ jsx26("line", { x1: "8", y1: "2", x2: "8", y2: "6" }),
2025
+ /* @__PURE__ */ jsx26("line", { x1: "3", y1: "10", x2: "21", y2: "10" })
2026
+ ] })
2027
+ }
2028
+ ) }),
2029
+ open && !disabled && /* @__PURE__ */ jsx26("div", { className: "gy-datepicker-popover", children: /* @__PURE__ */ jsx26(
2030
+ Calendar,
2031
+ {
2032
+ mode,
2033
+ value,
2034
+ onChange: handleChange,
2035
+ minDate,
2036
+ maxDate,
2037
+ className: "gy-calendar--popover",
2038
+ style: { border: "none", borderRadius: 0 }
2039
+ }
2040
+ ) })
2041
+ ] });
2042
+ }
2043
+
2044
+ // src/chart/Chart.tsx
2045
+ import {
2046
+ LineChart,
2047
+ Line,
2048
+ BarChart,
2049
+ Bar,
2050
+ AreaChart,
2051
+ Area,
2052
+ PieChart,
2053
+ Pie,
2054
+ Cell,
2055
+ XAxis,
2056
+ YAxis,
2057
+ CartesianGrid,
2058
+ Tooltip as Tooltip2,
2059
+ ResponsiveContainer,
2060
+ Legend
2061
+ } from "recharts";
2062
+ import { jsx as jsx27, jsxs as jsxs26 } from "react/jsx-runtime";
2063
+ var DEFAULT_COLORS = [
2064
+ "var(--gy-primary)",
2065
+ "var(--gy-success)",
2066
+ "var(--gy-warning)",
2067
+ "var(--gy-danger)",
2068
+ "var(--gy-info)",
2069
+ "#8b5cf6",
2070
+ "#ec4899"
2071
+ ];
2072
+ function Chart({
2073
+ type,
2074
+ data,
2075
+ xAxisKey,
2076
+ series = [],
2077
+ nameKey,
2078
+ valueKey,
2079
+ height = 300,
2080
+ showGrid = true,
2081
+ showLegend = true,
2082
+ className = ""
2083
+ }) {
2084
+ const commonAxisProps = {
2085
+ stroke: "var(--gy-border-strong)",
2086
+ tick: { fill: "var(--gy-text-subtle)", fontSize: 12 },
2087
+ tickLine: { stroke: "var(--gy-border)" }
2088
+ };
2089
+ const commonTooltipProps = {
2090
+ contentStyle: {
2091
+ backgroundColor: "var(--gy-surface)",
2092
+ borderColor: "var(--gy-border)",
2093
+ borderRadius: "var(--gy-radius-lg)",
2094
+ boxShadow: "var(--gy-shadow-md)",
2095
+ color: "var(--gy-text)",
2096
+ fontSize: 13
2097
+ },
2098
+ itemStyle: { color: "var(--gy-text)" }
2099
+ };
2100
+ const renderContent = () => {
2101
+ switch (type) {
2102
+ case "line":
2103
+ return /* @__PURE__ */ jsxs26(LineChart, { data, children: [
2104
+ showGrid && /* @__PURE__ */ jsx27(CartesianGrid, { strokeDasharray: "3 3", stroke: "var(--gy-border)", vertical: false }),
2105
+ /* @__PURE__ */ jsx27(XAxis, { dataKey: xAxisKey, ...commonAxisProps }),
2106
+ /* @__PURE__ */ jsx27(YAxis, { ...commonAxisProps }),
2107
+ /* @__PURE__ */ jsx27(Tooltip2, { ...commonTooltipProps }),
2108
+ showLegend && /* @__PURE__ */ jsx27(Legend, { wrapperStyle: { fontSize: 12 } }),
2109
+ series.map((s, i) => /* @__PURE__ */ jsx27(
2110
+ Line,
2111
+ {
2112
+ type: "monotone",
2113
+ dataKey: s.key,
2114
+ name: s.name ?? s.key,
2115
+ stroke: s.color ?? DEFAULT_COLORS[i % DEFAULT_COLORS.length],
2116
+ strokeWidth: 2,
2117
+ dot: { r: 4, strokeWidth: 2, fill: "var(--gy-surface)" },
2118
+ activeDot: { r: 6, strokeWidth: 0 }
2119
+ },
2120
+ s.key
2121
+ ))
2122
+ ] });
2123
+ case "bar":
2124
+ return /* @__PURE__ */ jsxs26(BarChart, { data, children: [
2125
+ showGrid && /* @__PURE__ */ jsx27(CartesianGrid, { strokeDasharray: "3 3", stroke: "var(--gy-border)", vertical: false }),
2126
+ /* @__PURE__ */ jsx27(XAxis, { dataKey: xAxisKey, ...commonAxisProps }),
2127
+ /* @__PURE__ */ jsx27(YAxis, { ...commonAxisProps }),
2128
+ /* @__PURE__ */ jsx27(Tooltip2, { ...commonTooltipProps, cursor: { fill: "var(--gy-background-muted)" } }),
2129
+ showLegend && /* @__PURE__ */ jsx27(Legend, { wrapperStyle: { fontSize: 12 } }),
2130
+ series.map((s, i) => /* @__PURE__ */ jsx27(
2131
+ Bar,
2132
+ {
2133
+ dataKey: s.key,
2134
+ name: s.name ?? s.key,
2135
+ fill: s.color ?? DEFAULT_COLORS[i % DEFAULT_COLORS.length],
2136
+ radius: [4, 4, 0, 0]
2137
+ },
2138
+ s.key
2139
+ ))
2140
+ ] });
2141
+ case "area":
2142
+ return /* @__PURE__ */ jsxs26(AreaChart, { data, children: [
2143
+ /* @__PURE__ */ jsx27("defs", { children: series.map((s, i) => {
2144
+ const color = s.color ?? DEFAULT_COLORS[i % DEFAULT_COLORS.length];
2145
+ return /* @__PURE__ */ jsxs26("linearGradient", { id: `grad-${s.key}`, x1: "0", y1: "0", x2: "0", y2: "1", children: [
2146
+ /* @__PURE__ */ jsx27("stop", { offset: "5%", stopColor: color, stopOpacity: 0.3 }),
2147
+ /* @__PURE__ */ jsx27("stop", { offset: "95%", stopColor: color, stopOpacity: 0 })
2148
+ ] }, `grad-${s.key}`);
2149
+ }) }),
2150
+ showGrid && /* @__PURE__ */ jsx27(CartesianGrid, { strokeDasharray: "3 3", stroke: "var(--gy-border)", vertical: false }),
2151
+ /* @__PURE__ */ jsx27(XAxis, { dataKey: xAxisKey, ...commonAxisProps }),
2152
+ /* @__PURE__ */ jsx27(YAxis, { ...commonAxisProps }),
2153
+ /* @__PURE__ */ jsx27(Tooltip2, { ...commonTooltipProps }),
2154
+ showLegend && /* @__PURE__ */ jsx27(Legend, { wrapperStyle: { fontSize: 12 } }),
2155
+ series.map((s, i) => {
2156
+ const color = s.color ?? DEFAULT_COLORS[i % DEFAULT_COLORS.length];
2157
+ return /* @__PURE__ */ jsx27(
2158
+ Area,
2159
+ {
2160
+ type: "monotone",
2161
+ dataKey: s.key,
2162
+ name: s.name ?? s.key,
2163
+ stroke: color,
2164
+ strokeWidth: 2,
2165
+ fillOpacity: 1,
2166
+ fill: `url(#grad-${s.key})`
2167
+ },
2168
+ s.key
2169
+ );
2170
+ })
2171
+ ] });
2172
+ case "pie":
2173
+ case "donut":
2174
+ return /* @__PURE__ */ jsxs26(PieChart, { children: [
2175
+ /* @__PURE__ */ jsx27(Tooltip2, { ...commonTooltipProps }),
2176
+ showLegend && /* @__PURE__ */ jsx27(Legend, { wrapperStyle: { fontSize: 12 } }),
2177
+ /* @__PURE__ */ jsx27(
2178
+ Pie,
2179
+ {
2180
+ data,
2181
+ dataKey: valueKey,
2182
+ nameKey,
2183
+ cx: "50%",
2184
+ cy: "50%",
2185
+ innerRadius: type === "donut" ? "60%" : 0,
2186
+ outerRadius: "80%",
2187
+ stroke: "var(--gy-surface)",
2188
+ strokeWidth: 2,
2189
+ paddingAngle: type === "donut" ? 2 : 0,
2190
+ children: data.map((entry, index) => /* @__PURE__ */ jsx27(Cell, { fill: entry.color ?? DEFAULT_COLORS[index % DEFAULT_COLORS.length] }, `cell-${index}`))
2191
+ }
2192
+ )
2193
+ ] });
2194
+ }
2195
+ };
2196
+ return /* @__PURE__ */ jsx27("div", { className: `gy-chart ${className}`, style: { width: "100%", height }, children: /* @__PURE__ */ jsx27(ResponsiveContainer, { width: "100%", height: "100%", children: renderContent() }) });
2197
+ }
2198
+ export {
2199
+ Accordion,
2200
+ AnimatedNumber,
2201
+ Banner,
2202
+ Breadcrumb,
2203
+ Button,
2204
+ Calendar,
2205
+ Card,
2206
+ CardBody,
2207
+ CardFooter,
2208
+ CardHeader,
2209
+ CardInfo,
2210
+ Chart,
2211
+ Checkbox,
2212
+ Chip,
2213
+ ChipsInput,
2214
+ DatePicker,
2215
+ Dropdown,
2216
+ FileUpload,
2217
+ Input,
2218
+ KanbanBoard,
2219
+ Menu,
2220
+ Modal,
2221
+ ProgressBar,
2222
+ RadioGroup,
2223
+ ReorderList,
2224
+ Skeleton,
2225
+ Spinner,
2226
+ Stepper,
2227
+ Table,
2228
+ Tabs,
2229
+ Textarea,
2230
+ ToasterProvider,
2231
+ Toggle,
2232
+ Tooltip,
2233
+ Typography,
2234
+ useToast
2235
+ };