@marcoschwartz/lite-ui 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -8,7 +8,7 @@ var themes = {
8
8
  default: {
9
9
  name: "default",
10
10
  button: {
11
- base: "font-semibold rounded-lg transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 active:scale-95",
11
+ base: "font-semibold rounded-lg transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 active:scale-95 gap-2",
12
12
  variants: {
13
13
  primary: "bg-blue-600 hover:bg-blue-700 active:bg-blue-800 text-white shadow-sm hover:shadow-md dark:bg-blue-500 dark:hover:bg-blue-600 dark:active:bg-blue-700",
14
14
  secondary: "bg-gray-600 hover:bg-gray-700 active:bg-gray-800 text-white shadow-sm hover:shadow-md dark:bg-gray-500 dark:hover:bg-gray-600 dark:active:bg-gray-700",
@@ -18,15 +18,15 @@ var themes = {
18
18
  info: "bg-cyan-600 hover:bg-cyan-700 active:bg-cyan-800 text-white shadow-sm hover:shadow-md dark:bg-cyan-500 dark:hover:bg-cyan-600 dark:active:bg-cyan-700"
19
19
  },
20
20
  sizes: {
21
- sm: "px-3 py-1.5 text-sm",
22
- md: "px-4 py-2 text-base",
23
- lg: "px-6 py-3 text-lg",
24
- xl: "px-8 py-4 text-xl"
21
+ sm: "px-3 py-1.5 text-sm min-h-[30px]",
22
+ md: "px-4 py-2 text-base min-h-[38px]",
23
+ lg: "px-6 py-3 text-lg min-h-[48px]",
24
+ xl: "px-8 py-4 text-xl min-h-[60px]"
25
25
  },
26
26
  disabled: "opacity-50 cursor-not-allowed hover:shadow-sm active:scale-100"
27
27
  },
28
28
  select: {
29
- base: "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 pr-10 cursor-pointer dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500",
29
+ base: "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 text-left transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 pr-10 cursor-pointer dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500",
30
30
  sizes: {
31
31
  sm: "px-3 py-1.5 text-sm",
32
32
  md: "px-4 py-2.5 text-base",
@@ -39,7 +39,7 @@ var themes = {
39
39
  minimalistic: {
40
40
  name: "minimalistic",
41
41
  button: {
42
- base: "font-normal rounded-none transition-colors duration-200 focus:outline-none border-2",
42
+ base: "font-normal rounded-none transition-colors duration-200 focus:outline-none border-2 gap-2",
43
43
  variants: {
44
44
  primary: "bg-transparent border-white text-white hover:bg-white hover:text-black",
45
45
  secondary: "bg-transparent border-gray-400 text-gray-400 hover:bg-gray-400 hover:text-black",
@@ -49,15 +49,15 @@ var themes = {
49
49
  info: "bg-transparent border-blue-400 text-blue-400 hover:bg-blue-400 hover:text-black"
50
50
  },
51
51
  sizes: {
52
- sm: "px-4 py-2 text-sm uppercase tracking-wide",
53
- md: "px-6 py-3 text-base uppercase tracking-wide",
54
- lg: "px-8 py-4 text-lg uppercase tracking-wider",
55
- xl: "px-10 py-5 text-xl uppercase tracking-wider"
52
+ sm: "px-4 py-2 text-sm uppercase tracking-wide min-h-[36px]",
53
+ md: "px-6 py-3 text-base uppercase tracking-wide min-h-[48px]",
54
+ lg: "px-8 py-4 text-lg uppercase tracking-wider min-h-[60px]",
55
+ xl: "px-10 py-5 text-xl uppercase tracking-wider min-h-[72px]"
56
56
  },
57
57
  disabled: "opacity-30 cursor-not-allowed hover:bg-transparent"
58
58
  },
59
59
  select: {
60
- base: "w-full appearance-none rounded-none border-2 border-white bg-transparent text-white transition-colors duration-200 focus:outline-none pr-10 cursor-pointer placeholder:text-gray-500",
60
+ base: "w-full appearance-none rounded-none border-2 border-white bg-transparent text-white text-left transition-colors duration-200 focus:outline-none pr-10 cursor-pointer placeholder:text-gray-500",
61
61
  sizes: {
62
62
  sm: "px-4 py-2 text-sm uppercase tracking-wide",
63
63
  md: "px-4 py-3 text-base uppercase tracking-wide",
@@ -75,7 +75,20 @@ var ThemeContext = createContext(void 0);
75
75
  function useTheme() {
76
76
  const context = useContext(ThemeContext);
77
77
  if (!context) {
78
- throw new Error("useTheme must be used within a ThemeProvider");
78
+ const warnOnce = () => {
79
+ if (process.env.NODE_ENV === "development") {
80
+ console.warn("useTheme: Component used outside ThemeProvider. Using default theme. Wrap your app with <ThemeProvider> for full functionality.");
81
+ }
82
+ };
83
+ return {
84
+ theme: themes.default,
85
+ themeName: "default",
86
+ setTheme: () => warnOnce(),
87
+ colorMode: "light",
88
+ setColorMode: () => warnOnce(),
89
+ toggleColorMode: () => warnOnce(),
90
+ resolvedColorMode: "light"
91
+ };
79
92
  }
80
93
  return context;
81
94
  }
@@ -123,6 +136,13 @@ function ThemeProvider({
123
136
  document.documentElement.classList.remove("dark");
124
137
  }
125
138
  };
139
+ const toggleColorMode = () => {
140
+ if (colorMode === "system") {
141
+ setColorMode(resolvedColorMode === "dark" ? "light" : "dark");
142
+ } else {
143
+ setColorMode(colorMode === "dark" ? "light" : "dark");
144
+ }
145
+ };
126
146
  useEffect(() => {
127
147
  if (!mounted) return;
128
148
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
@@ -147,40 +167,49 @@ function ThemeProvider({
147
167
  setTheme,
148
168
  colorMode,
149
169
  setColorMode,
170
+ toggleColorMode,
150
171
  resolvedColorMode
151
172
  }, children });
152
173
  }
153
174
 
154
175
  // src/components/Button.tsx
155
- import { jsx as jsx2 } from "react/jsx-runtime";
176
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
156
177
  var Button = ({
157
178
  variant = "primary",
158
179
  size = "md",
159
180
  className = "",
160
181
  children,
161
182
  disabled,
183
+ leftIcon,
184
+ rightIcon,
185
+ iconOnly = false,
162
186
  ...props
163
187
  }) => {
164
188
  const { theme } = useTheme();
165
189
  const baseStyles = theme.button.base;
166
- const variantStyles = theme.button.variants[variant];
167
- const sizeStyles = theme.button.sizes[size];
190
+ const variantStyles3 = theme.button.variants[variant];
191
+ const sizeStyles2 = theme.button.sizes[size];
168
192
  const disabledStyles = disabled ? theme.button.disabled : "";
169
- const classes = `${baseStyles} ${variantStyles} ${sizeStyles} ${disabledStyles} ${className}`.trim();
193
+ const iconOnlyStyles = iconOnly ? "!p-0 aspect-square" : "";
194
+ const classes = `inline-flex items-center justify-center ${baseStyles} ${variantStyles3} ${sizeStyles2} ${disabledStyles} ${iconOnlyStyles} ${className}`.trim();
170
195
  return /* @__PURE__ */ jsx2(
171
196
  "button",
172
197
  {
173
198
  className: classes,
174
199
  disabled,
175
200
  ...props,
176
- children
201
+ children: iconOnly ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
202
+ leftIcon && /* @__PURE__ */ jsx2("span", { className: "inline-flex shrink-0", children: leftIcon }),
203
+ children && /* @__PURE__ */ jsx2("span", { className: "inline-flex items-center", children }),
204
+ rightIcon && /* @__PURE__ */ jsx2("span", { className: "inline-flex shrink-0", children: rightIcon })
205
+ ] })
177
206
  }
178
207
  );
179
208
  };
180
209
 
181
210
  // src/components/Select.tsx
182
211
  import { useState as useState2, useRef, useEffect as useEffect2 } from "react";
183
- import { jsx as jsx3, jsxs } from "react/jsx-runtime";
212
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
184
213
  var Select = ({
185
214
  options,
186
215
  size = "md",
@@ -190,19 +219,30 @@ var Select = ({
190
219
  value: controlledValue,
191
220
  defaultValue,
192
221
  onChange,
222
+ label,
223
+ error,
224
+ helperText,
225
+ searchable = false,
226
+ searchPlaceholder = "Search...",
193
227
  ...props
194
228
  }) => {
195
229
  const { theme, themeName } = useTheme();
196
230
  const [isOpen, setIsOpen] = useState2(false);
197
231
  const [internalValue, setInternalValue] = useState2(defaultValue || "");
232
+ const [searchQuery, setSearchQuery] = useState2("");
198
233
  const dropdownRef = useRef(null);
234
+ const searchInputRef = useRef(null);
199
235
  const value = controlledValue !== void 0 ? controlledValue : internalValue;
200
236
  const selectedOption = options.find((opt) => opt.value === value);
201
237
  const displayText = selectedOption ? selectedOption.label : placeholder || "Select...";
238
+ const filteredOptions = searchable && searchQuery ? options.filter(
239
+ (option) => option.label.toLowerCase().includes(searchQuery.toLowerCase())
240
+ ) : options;
202
241
  useEffect2(() => {
203
242
  const handleClickOutside = (event) => {
204
243
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
205
244
  setIsOpen(false);
245
+ setSearchQuery("");
206
246
  }
207
247
  };
208
248
  if (isOpen) {
@@ -210,11 +250,17 @@ var Select = ({
210
250
  return () => document.removeEventListener("mousedown", handleClickOutside);
211
251
  }
212
252
  }, [isOpen]);
253
+ useEffect2(() => {
254
+ if (isOpen && searchable && searchInputRef.current) {
255
+ searchInputRef.current.focus();
256
+ }
257
+ }, [isOpen, searchable]);
213
258
  const handleSelect = (optionValue) => {
214
259
  if (disabled) return;
215
260
  setInternalValue(optionValue);
216
261
  onChange?.(optionValue);
217
262
  setIsOpen(false);
263
+ setSearchQuery("");
218
264
  };
219
265
  const handleToggle = () => {
220
266
  if (!disabled) {
@@ -222,9 +268,10 @@ var Select = ({
222
268
  }
223
269
  };
224
270
  const baseStyles = theme.select.base;
225
- const sizeStyles = theme.select.sizes[size];
271
+ const sizeStyles2 = theme.select.sizes[size];
226
272
  const disabledStyles = disabled ? theme.select.disabled : "";
227
- const buttonClasses = `${baseStyles} ${sizeStyles} ${disabledStyles} ${className}`.trim();
273
+ const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
274
+ const buttonClasses = `${baseStyles} ${sizeStyles2} ${disabledStyles} ${errorStyles}`.trim();
228
275
  const iconColor = themeName === "minimalistic" ? disabled ? "text-gray-600" : "text-white" : disabled ? "text-gray-400" : "text-gray-500";
229
276
  const dropdownBaseStyles = themeName === "minimalistic" ? "bg-black border-2 border-white" : "bg-white border border-gray-300 shadow-lg dark:bg-gray-800 dark:border-gray-600";
230
277
  const optionBaseStyles = themeName === "minimalistic" ? "text-white hover:bg-white hover:text-black transition-colors duration-200" : "text-gray-900 hover:bg-blue-50 transition-colors duration-150 dark:text-gray-100 dark:hover:bg-gray-700";
@@ -234,51 +281,3407 @@ var Select = ({
234
281
  lg: "px-4 py-3 text-lg",
235
282
  xl: "px-5 py-4 text-xl"
236
283
  }[size];
237
- return /* @__PURE__ */ jsxs("div", { className: "relative inline-block w-full", ref: dropdownRef, ...props, children: [
238
- /* @__PURE__ */ jsx3(
239
- "button",
240
- {
241
- type: "button",
242
- className: buttonClasses,
243
- onClick: handleToggle,
244
- disabled,
245
- children: /* @__PURE__ */ jsx3("span", { className: !selectedOption && placeholder ? "opacity-50" : "", children: displayText })
284
+ return /* @__PURE__ */ jsxs2("div", { className: `w-full ${className}`, children: [
285
+ label && /* @__PURE__ */ jsx3("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
286
+ /* @__PURE__ */ jsxs2("div", { className: "relative inline-block w-full", ref: dropdownRef, ...props, children: [
287
+ /* @__PURE__ */ jsx3(
288
+ "button",
289
+ {
290
+ type: "button",
291
+ className: buttonClasses,
292
+ onClick: handleToggle,
293
+ disabled,
294
+ children: /* @__PURE__ */ jsx3("span", { className: !selectedOption && placeholder ? "opacity-50" : "", children: displayText })
295
+ }
296
+ ),
297
+ /* @__PURE__ */ jsx3("div", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-4", children: /* @__PURE__ */ jsx3(
298
+ "svg",
299
+ {
300
+ className: `h-5 w-5 transition-transform duration-200 ${iconColor} ${isOpen ? "rotate-180" : ""}`,
301
+ xmlns: "http://www.w3.org/2000/svg",
302
+ viewBox: "0 0 20 20",
303
+ fill: "currentColor",
304
+ "aria-hidden": "true",
305
+ children: /* @__PURE__ */ jsx3(
306
+ "path",
307
+ {
308
+ fillRule: "evenodd",
309
+ d: "M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z",
310
+ clipRule: "evenodd"
311
+ }
312
+ )
313
+ }
314
+ ) }),
315
+ isOpen && !disabled && /* @__PURE__ */ jsxs2(
316
+ "div",
317
+ {
318
+ className: `absolute z-50 w-full mt-1 ${dropdownBaseStyles} rounded-lg overflow-hidden`,
319
+ children: [
320
+ searchable && /* @__PURE__ */ jsx3("div", { className: `sticky top-0 ${themeName === "minimalistic" ? "bg-black border-b-2 border-white" : "bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700"}`, children: /* @__PURE__ */ jsx3(
321
+ "input",
322
+ {
323
+ ref: searchInputRef,
324
+ type: "text",
325
+ className: `w-full ${optionSizeStyles} ${themeName === "minimalistic" ? "bg-black text-white placeholder-gray-600 focus:outline-none" : "bg-transparent text-gray-900 dark:text-gray-100 placeholder-gray-400 focus:outline-none"}`,
326
+ placeholder: searchPlaceholder,
327
+ value: searchQuery,
328
+ onChange: (e) => setSearchQuery(e.target.value),
329
+ onClick: (e) => e.stopPropagation()
330
+ }
331
+ ) }),
332
+ /* @__PURE__ */ jsx3("style", { children: `
333
+ .select-dropdown-scroll {
334
+ scrollbar-width: thin;
335
+ scrollbar-color: rgba(156, 163, 175, 0.5) transparent;
336
+ }
337
+ .select-dropdown-scroll::-webkit-scrollbar {
338
+ width: 8px;
339
+ }
340
+ .select-dropdown-scroll::-webkit-scrollbar-track {
341
+ background: transparent;
342
+ }
343
+ .select-dropdown-scroll::-webkit-scrollbar-thumb {
344
+ background-color: rgba(156, 163, 175, 0.5);
345
+ border-radius: 4px;
346
+ border: 2px solid transparent;
347
+ background-clip: padding-box;
348
+ }
349
+ .select-dropdown-scroll::-webkit-scrollbar-thumb:hover {
350
+ background-color: rgba(156, 163, 175, 0.7);
351
+ }
352
+ .dark .select-dropdown-scroll {
353
+ scrollbar-color: rgba(75, 85, 99, 0.6) transparent;
354
+ }
355
+ .dark .select-dropdown-scroll::-webkit-scrollbar-thumb {
356
+ background-color: rgba(75, 85, 99, 0.6);
357
+ }
358
+ .dark .select-dropdown-scroll::-webkit-scrollbar-thumb:hover {
359
+ background-color: rgba(75, 85, 99, 0.8);
360
+ }
361
+ ` }),
362
+ /* @__PURE__ */ jsx3(
363
+ "div",
364
+ {
365
+ className: "select-dropdown-scroll",
366
+ style: { maxHeight: "300px", overflowY: "auto" },
367
+ children: filteredOptions.length > 0 ? filteredOptions.map((option) => /* @__PURE__ */ jsx3(
368
+ "div",
369
+ {
370
+ className: `${optionBaseStyles} ${optionSizeStyles} cursor-pointer ${value === option.value ? themeName === "minimalistic" ? "bg-white text-black" : "bg-blue-50 dark:bg-gray-700" : ""}`,
371
+ onClick: () => handleSelect(option.value),
372
+ children: option.label
373
+ },
374
+ option.value
375
+ )) : /* @__PURE__ */ jsx3("div", { className: `${optionSizeStyles} ${themeName === "minimalistic" ? "text-gray-500" : "text-gray-500 dark:text-gray-400"} text-center`, children: "No results found" })
376
+ }
377
+ )
378
+ ]
379
+ }
380
+ )
381
+ ] }),
382
+ error && /* @__PURE__ */ jsx3("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
383
+ helperText && !error && /* @__PURE__ */ jsx3("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
384
+ ] });
385
+ };
386
+
387
+ // src/components/Modal.tsx
388
+ import { useEffect as useEffect3 } from "react";
389
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
390
+ var sizeClasses = {
391
+ sm: "max-w-md",
392
+ md: "max-w-lg",
393
+ lg: "max-w-2xl",
394
+ xl: "max-w-4xl"
395
+ };
396
+ var Modal = ({
397
+ isOpen,
398
+ onClose,
399
+ title,
400
+ children,
401
+ size = "md",
402
+ showCloseButton = true
403
+ }) => {
404
+ const { theme } = useTheme();
405
+ useEffect3(() => {
406
+ const handleEscape = (e) => {
407
+ if (e.key === "Escape" && isOpen) {
408
+ onClose();
246
409
  }
247
- ),
248
- /* @__PURE__ */ jsx3("div", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-4", children: /* @__PURE__ */ jsx3(
410
+ };
411
+ if (isOpen) {
412
+ document.addEventListener("keydown", handleEscape);
413
+ document.body.style.overflow = "hidden";
414
+ }
415
+ return () => {
416
+ document.removeEventListener("keydown", handleEscape);
417
+ document.body.style.overflow = "unset";
418
+ };
419
+ }, [isOpen, onClose]);
420
+ if (!isOpen) return null;
421
+ const sizeClass = sizeClasses[size];
422
+ return /* @__PURE__ */ jsx4(
423
+ "div",
424
+ {
425
+ className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm transition-all duration-200",
426
+ onClick: onClose,
427
+ role: "dialog",
428
+ "aria-modal": "true",
429
+ "aria-labelledby": title ? "modal-title" : void 0,
430
+ children: /* @__PURE__ */ jsxs3(
431
+ "div",
432
+ {
433
+ className: `relative w-full ${sizeClass} bg-white dark:bg-gray-800 rounded-lg shadow-2xl transform transition-all duration-200 scale-100 animate-in`,
434
+ onClick: (e) => e.stopPropagation(),
435
+ children: [
436
+ (title || showCloseButton) && /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700", children: [
437
+ title && /* @__PURE__ */ jsx4("h3", { id: "modal-title", className: "text-xl font-semibold text-gray-900 dark:text-gray-100", children: title }),
438
+ showCloseButton && /* @__PURE__ */ jsx4(
439
+ "button",
440
+ {
441
+ onClick: onClose,
442
+ className: "ml-auto text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors",
443
+ "aria-label": "Close modal",
444
+ children: /* @__PURE__ */ jsx4("svg", { className: "w-6 h-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
445
+ }
446
+ )
447
+ ] }),
448
+ /* @__PURE__ */ jsx4("div", { className: "p-6", children })
449
+ ]
450
+ }
451
+ )
452
+ }
453
+ );
454
+ };
455
+
456
+ // src/components/Navbar.tsx
457
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
458
+ var Navbar = ({
459
+ logo,
460
+ children,
461
+ className = "",
462
+ sticky = false
463
+ }) => {
464
+ const { theme } = useTheme();
465
+ const baseClasses = sticky ? "sticky top-0 z-40" : "";
466
+ return /* @__PURE__ */ jsx5("nav", { className: `bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 ${baseClasses} ${className}`, children: /* @__PURE__ */ jsx5("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxs4("div", { className: "flex justify-between items-center h-16", children: [
467
+ logo && /* @__PURE__ */ jsx5("div", { className: "flex items-center", children: logo }),
468
+ children && /* @__PURE__ */ jsx5("div", { className: "flex items-center gap-6", children })
469
+ ] }) }) });
470
+ };
471
+
472
+ // src/components/Sidebar.tsx
473
+ import { jsx as jsx6 } from "react/jsx-runtime";
474
+ var widthClasses = {
475
+ sm: "w-48",
476
+ md: "w-64",
477
+ lg: "w-80"
478
+ };
479
+ var Sidebar = ({
480
+ children,
481
+ className = "",
482
+ width = "md",
483
+ position = "left"
484
+ }) => {
485
+ const { theme } = useTheme();
486
+ const widthClass = widthClasses[width];
487
+ const borderClass = position === "left" ? "border-r" : "border-l";
488
+ return /* @__PURE__ */ jsx6(
489
+ "aside",
490
+ {
491
+ className: `${widthClass} bg-white dark:bg-gray-800 ${borderClass} border-gray-200 dark:border-gray-700 h-full overflow-y-auto ${className}`,
492
+ children
493
+ }
494
+ );
495
+ };
496
+
497
+ // src/components/SidebarProvider.tsx
498
+ import { createContext as createContext2, useContext as useContext2, useState as useState3 } from "react";
499
+ import { jsx as jsx7 } from "react/jsx-runtime";
500
+ var SidebarContext = createContext2(void 0);
501
+ var SidebarProvider = ({
502
+ children,
503
+ defaultOpen = false
504
+ }) => {
505
+ const [isOpen, setIsOpen] = useState3(defaultOpen);
506
+ const [isMobile, setIsMobile] = useState3(false);
507
+ const open = () => setIsOpen(true);
508
+ const close = () => setIsOpen(false);
509
+ const toggle = () => setIsOpen((prev) => !prev);
510
+ const value = {
511
+ isOpen,
512
+ isMobile,
513
+ open,
514
+ close,
515
+ toggle,
516
+ setIsMobile
517
+ };
518
+ return /* @__PURE__ */ jsx7(SidebarContext.Provider, { value, children });
519
+ };
520
+ var useSidebar = () => {
521
+ const context = useContext2(SidebarContext);
522
+ if (!context) {
523
+ throw new Error("useSidebar must be used within a SidebarProvider");
524
+ }
525
+ return context;
526
+ };
527
+
528
+ // src/components/AppShell.tsx
529
+ import { useState as useState4 } from "react";
530
+
531
+ // src/icons/icon-utils.tsx
532
+ import { jsx as jsx8 } from "react/jsx-runtime";
533
+ var sizeClasses2 = {
534
+ xs: "w-3 h-3",
535
+ sm: "w-4 h-4",
536
+ md: "w-5 h-5",
537
+ lg: "w-6 h-6",
538
+ xl: "w-8 h-8"
539
+ };
540
+ var createIcon = (displayName, path, filled = false) => {
541
+ const Icon = ({ size = "md", className = "", color = "currentColor" }) => {
542
+ const sizeClass = sizeClasses2[size];
543
+ return /* @__PURE__ */ jsx8(
249
544
  "svg",
250
545
  {
251
- className: `h-5 w-5 transition-transform duration-200 ${iconColor} ${isOpen ? "rotate-180" : ""}`,
252
- xmlns: "http://www.w3.org/2000/svg",
253
- viewBox: "0 0 20 20",
254
- fill: "currentColor",
546
+ className: `${sizeClass} ${className}`,
547
+ fill: filled ? color : "none",
548
+ viewBox: "0 0 24 24",
549
+ stroke: filled ? "none" : color,
255
550
  "aria-hidden": "true",
256
- children: /* @__PURE__ */ jsx3(
257
- "path",
551
+ children: path
552
+ }
553
+ );
554
+ };
555
+ Icon.displayName = displayName;
556
+ return Icon;
557
+ };
558
+
559
+ // src/icons/HomeIcon.tsx
560
+ import { jsx as jsx9 } from "react/jsx-runtime";
561
+ var HomeIcon = createIcon(
562
+ "HomeIcon",
563
+ /* @__PURE__ */ jsx9("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" })
564
+ );
565
+
566
+ // src/icons/UserIcon.tsx
567
+ import { jsx as jsx10 } from "react/jsx-runtime";
568
+ var UserIcon = createIcon(
569
+ "UserIcon",
570
+ /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" })
571
+ );
572
+
573
+ // src/icons/SearchIcon.tsx
574
+ import { jsx as jsx11 } from "react/jsx-runtime";
575
+ var SearchIcon = createIcon(
576
+ "SearchIcon",
577
+ /* @__PURE__ */ jsx11("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" })
578
+ );
579
+
580
+ // src/icons/BellIcon.tsx
581
+ import { jsx as jsx12 } from "react/jsx-runtime";
582
+ var BellIcon = createIcon(
583
+ "BellIcon",
584
+ /* @__PURE__ */ jsx12("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" })
585
+ );
586
+
587
+ // src/icons/SettingsIcon.tsx
588
+ import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs5 } from "react/jsx-runtime";
589
+ var SettingsIcon = createIcon(
590
+ "SettingsIcon",
591
+ /* @__PURE__ */ jsxs5(Fragment2, { children: [
592
+ /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }),
593
+ /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" })
594
+ ] })
595
+ );
596
+
597
+ // src/icons/MenuIcon.tsx
598
+ import { jsx as jsx14 } from "react/jsx-runtime";
599
+ var MenuIcon = createIcon(
600
+ "MenuIcon",
601
+ /* @__PURE__ */ jsx14("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h16M4 18h16" })
602
+ );
603
+
604
+ // src/icons/CloseIcon.tsx
605
+ import { jsx as jsx15 } from "react/jsx-runtime";
606
+ var CloseIcon = createIcon(
607
+ "CloseIcon",
608
+ /* @__PURE__ */ jsx15("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" })
609
+ );
610
+
611
+ // src/icons/ChevronDownIcon.tsx
612
+ import { jsx as jsx16 } from "react/jsx-runtime";
613
+ var ChevronDownIcon = createIcon(
614
+ "ChevronDownIcon",
615
+ /* @__PURE__ */ jsx16("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" })
616
+ );
617
+
618
+ // src/icons/ChevronRightIcon.tsx
619
+ import { jsx as jsx17 } from "react/jsx-runtime";
620
+ var ChevronRightIcon = createIcon(
621
+ "ChevronRightIcon",
622
+ /* @__PURE__ */ jsx17("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" })
623
+ );
624
+
625
+ // src/icons/CheckIcon.tsx
626
+ import { jsx as jsx18 } from "react/jsx-runtime";
627
+ var CheckIcon = createIcon(
628
+ "CheckIcon",
629
+ /* @__PURE__ */ jsx18("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" })
630
+ );
631
+
632
+ // src/icons/PlusIcon.tsx
633
+ import { jsx as jsx19 } from "react/jsx-runtime";
634
+ var PlusIcon = createIcon(
635
+ "PlusIcon",
636
+ /* @__PURE__ */ jsx19("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 4v16m8-8H4" })
637
+ );
638
+
639
+ // src/icons/TrashIcon.tsx
640
+ import { jsx as jsx20 } from "react/jsx-runtime";
641
+ var TrashIcon = createIcon(
642
+ "TrashIcon",
643
+ /* @__PURE__ */ jsx20("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" })
644
+ );
645
+
646
+ // src/icons/EditIcon.tsx
647
+ import { jsx as jsx21 } from "react/jsx-runtime";
648
+ var EditIcon = createIcon(
649
+ "EditIcon",
650
+ /* @__PURE__ */ jsx21("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" })
651
+ );
652
+
653
+ // src/icons/MailIcon.tsx
654
+ import { jsx as jsx22 } from "react/jsx-runtime";
655
+ var MailIcon = createIcon(
656
+ "MailIcon",
657
+ /* @__PURE__ */ jsx22("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" })
658
+ );
659
+
660
+ // src/icons/StarIcon.tsx
661
+ import { jsx as jsx23 } from "react/jsx-runtime";
662
+ var StarIcon = createIcon(
663
+ "StarIcon",
664
+ /* @__PURE__ */ jsx23("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" })
665
+ );
666
+
667
+ // src/icons/HeartIcon.tsx
668
+ import { jsx as jsx24 } from "react/jsx-runtime";
669
+ var HeartIcon = createIcon(
670
+ "HeartIcon",
671
+ /* @__PURE__ */ jsx24("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" })
672
+ );
673
+
674
+ // src/icons/DownloadIcon.tsx
675
+ import { jsx as jsx25 } from "react/jsx-runtime";
676
+ var DownloadIcon = createIcon(
677
+ "DownloadIcon",
678
+ /* @__PURE__ */ jsx25("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" })
679
+ );
680
+
681
+ // src/icons/UploadIcon.tsx
682
+ import { jsx as jsx26 } from "react/jsx-runtime";
683
+ var UploadIcon = createIcon(
684
+ "UploadIcon",
685
+ /* @__PURE__ */ jsx26("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" })
686
+ );
687
+
688
+ // src/icons/CameraIcon.tsx
689
+ import { Fragment as Fragment3, jsx as jsx27, jsxs as jsxs6 } from "react/jsx-runtime";
690
+ var CameraIcon = createIcon(
691
+ "CameraIcon",
692
+ /* @__PURE__ */ jsxs6(Fragment3, { children: [
693
+ /* @__PURE__ */ jsx27("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z" }),
694
+ /* @__PURE__ */ jsx27("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 13a3 3 0 11-6 0 3 3 0 016 0z" })
695
+ ] })
696
+ );
697
+
698
+ // src/icons/LockIcon.tsx
699
+ import { jsx as jsx28 } from "react/jsx-runtime";
700
+ var LockIcon = createIcon(
701
+ "LockIcon",
702
+ /* @__PURE__ */ jsx28("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" })
703
+ );
704
+
705
+ // src/icons/CalendarIcon.tsx
706
+ import { jsx as jsx29 } from "react/jsx-runtime";
707
+ var CalendarIcon = createIcon(
708
+ "CalendarIcon",
709
+ /* @__PURE__ */ jsx29("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" })
710
+ );
711
+
712
+ // src/icons/GoogleIcon.tsx
713
+ import { jsx as jsx30 } from "react/jsx-runtime";
714
+ var GoogleIcon = createIcon(
715
+ "GoogleIcon",
716
+ /* @__PURE__ */ jsx30("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" }),
717
+ true
718
+ );
719
+
720
+ // src/icons/GitHubIcon.tsx
721
+ import { jsx as jsx31 } from "react/jsx-runtime";
722
+ var GitHubIcon = createIcon(
723
+ "GitHubIcon",
724
+ /* @__PURE__ */ jsx31("path", { d: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" }),
725
+ true
726
+ );
727
+
728
+ // src/icons/TwitterIcon.tsx
729
+ import { jsx as jsx32 } from "react/jsx-runtime";
730
+ var TwitterIcon = createIcon(
731
+ "TwitterIcon",
732
+ /* @__PURE__ */ jsx32("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }),
733
+ true
734
+ );
735
+
736
+ // src/icons/FacebookIcon.tsx
737
+ import { jsx as jsx33 } from "react/jsx-runtime";
738
+ var FacebookIcon = createIcon(
739
+ "FacebookIcon",
740
+ /* @__PURE__ */ jsx33("path", { d: "M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z" }),
741
+ true
742
+ );
743
+
744
+ // src/icons/AppleIcon.tsx
745
+ import { jsx as jsx34 } from "react/jsx-runtime";
746
+ var AppleIcon = createIcon(
747
+ "AppleIcon",
748
+ /* @__PURE__ */ jsx34("path", { d: "M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09l.01-.01zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z" }),
749
+ true
750
+ );
751
+
752
+ // src/icons/LinkedInIcon.tsx
753
+ import { jsx as jsx35 } from "react/jsx-runtime";
754
+ var LinkedInIcon = createIcon(
755
+ "LinkedInIcon",
756
+ /* @__PURE__ */ jsx35("path", { d: "M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" }),
757
+ true
758
+ );
759
+
760
+ // src/icons/YouTubeIcon.tsx
761
+ import { jsx as jsx36 } from "react/jsx-runtime";
762
+ var YouTubeIcon = createIcon(
763
+ "YouTubeIcon",
764
+ /* @__PURE__ */ jsx36("path", { d: "M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" }),
765
+ true
766
+ );
767
+
768
+ // src/icons/SlackIcon.tsx
769
+ import { jsx as jsx37 } from "react/jsx-runtime";
770
+ var SlackIcon = createIcon(
771
+ "SlackIcon",
772
+ /* @__PURE__ */ jsx37("path", { d: "M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zm1.271 0a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zm0 1.271a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zm10.122 2.521a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zm-1.268 0a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zm-2.523 10.122a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zm0-1.268a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z" }),
773
+ true
774
+ );
775
+
776
+ // src/components/AppShell.tsx
777
+ import { Fragment as Fragment4, jsx as jsx38, jsxs as jsxs7 } from "react/jsx-runtime";
778
+ var widthClasses2 = {
779
+ sm: "w-48",
780
+ md: "w-64",
781
+ lg: "w-80"
782
+ };
783
+ var breakpointClasses = {
784
+ sm: "sm",
785
+ md: "md",
786
+ lg: "lg",
787
+ xl: "xl"
788
+ };
789
+ var AppShell = ({
790
+ children,
791
+ navbar,
792
+ header,
793
+ navbarTitle,
794
+ navbarLogo,
795
+ defaultNavbarOpen = false,
796
+ responsive = true,
797
+ className = ""
798
+ }) => {
799
+ const { theme } = useTheme();
800
+ const [isMobileNavbarOpen, setIsMobileNavbarOpen] = useState4(defaultNavbarOpen);
801
+ const navbarWidth = navbar?.width || "md";
802
+ const navbarBreakpoint = navbar?.breakpoint || "md";
803
+ const navbarPosition = navbar?.position || "side";
804
+ const widthClass = widthClasses2[navbarWidth];
805
+ const breakpoint = breakpointClasses[navbarBreakpoint];
806
+ if (!responsive && navbar) {
807
+ return /* @__PURE__ */ jsxs7("div", { className: `min-h-screen flex flex-col ${className}`, children: [
808
+ header && /* @__PURE__ */ jsx38("div", { className: "w-full", children: header }),
809
+ /* @__PURE__ */ jsxs7("div", { className: "flex flex-1", children: [
810
+ /* @__PURE__ */ jsx38("aside", { className: `${widthClass} bg-white dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 h-full overflow-y-auto`, children: navbar.content }),
811
+ /* @__PURE__ */ jsx38("main", { className: "flex-1 overflow-y-auto", children })
812
+ ] })
813
+ ] });
814
+ }
815
+ if (!responsive) {
816
+ return /* @__PURE__ */ jsxs7("div", { className: `min-h-screen flex flex-col ${className}`, children: [
817
+ header && /* @__PURE__ */ jsx38("div", { className: "w-full", children: header }),
818
+ /* @__PURE__ */ jsx38("main", { className: "flex-1 overflow-y-auto", children })
819
+ ] });
820
+ }
821
+ if (navbar && navbarPosition === "top") {
822
+ const mobileMenuClass = navbarBreakpoint === "sm" ? "sm:hidden" : navbarBreakpoint === "md" ? "md:hidden" : navbarBreakpoint === "lg" ? "lg:hidden" : "xl:hidden";
823
+ const desktopNavClass = navbarBreakpoint === "sm" ? "sm:flex" : navbarBreakpoint === "md" ? "md:flex" : navbarBreakpoint === "lg" ? "lg:flex" : "xl:flex";
824
+ return /* @__PURE__ */ jsxs7("div", { className: `min-h-screen flex flex-col bg-gray-50 dark:bg-gray-900 ${className}`, children: [
825
+ /* @__PURE__ */ jsx38("nav", { className: "sticky top-0 z-30 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsx38("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxs7("div", { className: "flex justify-between items-center h-16", children: [
826
+ /* @__PURE__ */ jsx38("div", { className: "flex items-center", children: navbarLogo ? /* @__PURE__ */ jsx38("div", { children: navbarLogo }) : navbarTitle ? /* @__PURE__ */ jsx38("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: navbarTitle }) : null }),
827
+ /* @__PURE__ */ jsx38("div", { className: `hidden ${desktopNavClass} items-center gap-6`, children: navbar.content }),
828
+ /* @__PURE__ */ jsx38(
829
+ "button",
258
830
  {
259
- fillRule: "evenodd",
260
- d: "M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z",
261
- clipRule: "evenodd"
831
+ className: `${mobileMenuClass} p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors`,
832
+ onClick: () => setIsMobileNavbarOpen(!isMobileNavbarOpen),
833
+ "aria-label": "Toggle menu",
834
+ children: /* @__PURE__ */ jsx38(MenuIcon, { size: "md" })
262
835
  }
263
836
  )
837
+ ] }) }) }),
838
+ header && /* @__PURE__ */ jsx38("div", { className: "w-full", children: header }),
839
+ isMobileNavbarOpen && /* @__PURE__ */ jsxs7(Fragment4, { children: [
840
+ /* @__PURE__ */ jsx38(
841
+ "div",
842
+ {
843
+ className: `${mobileMenuClass} fixed inset-0 z-40 bg-black/60 backdrop-blur-sm animate-in fade-in duration-200`,
844
+ onClick: () => setIsMobileNavbarOpen(false)
845
+ }
846
+ ),
847
+ /* @__PURE__ */ jsxs7("div", { className: `${mobileMenuClass} fixed left-0 top-0 bottom-0 z-50 w-64 bg-white dark:bg-gray-800 shadow-2xl animate-in slide-in-from-left duration-300`, children: [
848
+ /* @__PURE__ */ jsxs7("div", { className: "p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between", children: [
849
+ navbarLogo ? /* @__PURE__ */ jsx38("div", { children: navbarLogo }) : navbarTitle ? /* @__PURE__ */ jsx38("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: navbarTitle }) : null,
850
+ /* @__PURE__ */ jsx38(
851
+ "button",
852
+ {
853
+ className: "p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",
854
+ onClick: () => setIsMobileNavbarOpen(false),
855
+ "aria-label": "Close menu",
856
+ children: /* @__PURE__ */ jsx38("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx38("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
857
+ }
858
+ )
859
+ ] }),
860
+ /* @__PURE__ */ jsx38(
861
+ "div",
862
+ {
863
+ className: "p-4 flex flex-col gap-4",
864
+ onClick: () => setIsMobileNavbarOpen(false),
865
+ children: navbar.content
866
+ }
867
+ )
868
+ ] })
869
+ ] }),
870
+ /* @__PURE__ */ jsx38("main", { className: "flex-1 overflow-y-auto", children })
871
+ ] });
872
+ }
873
+ if (navbar) {
874
+ const mobileHeaderClass = navbarBreakpoint === "sm" ? "sm:hidden" : navbarBreakpoint === "md" ? "md:hidden" : navbarBreakpoint === "lg" ? "lg:hidden" : "xl:hidden";
875
+ const desktopNavbarClass = navbarBreakpoint === "sm" ? "sm:block" : navbarBreakpoint === "md" ? "md:block" : navbarBreakpoint === "lg" ? "lg:block" : "xl:block";
876
+ const mobileDrawerClass = navbarBreakpoint === "sm" ? "sm:hidden" : navbarBreakpoint === "md" ? "md:hidden" : navbarBreakpoint === "lg" ? "lg:hidden" : "xl:hidden";
877
+ const sidebarWidthClass = navbarWidth === "sm" ? "w-48" : navbarWidth === "lg" ? "w-80" : "w-64";
878
+ return /* @__PURE__ */ jsxs7("div", { className: `min-h-screen flex flex-col bg-gray-50 dark:bg-gray-900 ${className}`, children: [
879
+ /* @__PURE__ */ jsxs7("div", { className: `${mobileHeaderClass} sticky top-0 z-30 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 px-4 py-3 flex items-center justify-between`, children: [
880
+ navbarLogo ? /* @__PURE__ */ jsx38("div", { children: navbarLogo }) : navbarTitle ? /* @__PURE__ */ jsx38("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: navbarTitle }) : null,
881
+ /* @__PURE__ */ jsx38(
882
+ "button",
883
+ {
884
+ className: "p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",
885
+ onClick: () => setIsMobileNavbarOpen(!isMobileNavbarOpen),
886
+ "aria-label": "Toggle menu",
887
+ children: /* @__PURE__ */ jsx38(MenuIcon, { size: "md" })
888
+ }
889
+ )
890
+ ] }),
891
+ header && /* @__PURE__ */ jsx38("div", { className: "w-full", children: header }),
892
+ /* @__PURE__ */ jsxs7("div", { className: "flex flex-1 min-h-0", children: [
893
+ /* @__PURE__ */ jsx38("aside", { className: `hidden ${desktopNavbarClass} ${sidebarWidthClass} bg-white dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 overflow-y-auto shrink-0`, children: navbar.content }),
894
+ isMobileNavbarOpen && /* @__PURE__ */ jsxs7(Fragment4, { children: [
895
+ /* @__PURE__ */ jsx38(
896
+ "div",
897
+ {
898
+ className: `${mobileDrawerClass} fixed inset-0 z-40 bg-black/60 backdrop-blur-sm animate-in fade-in duration-200`,
899
+ onClick: () => setIsMobileNavbarOpen(false)
900
+ }
901
+ ),
902
+ /* @__PURE__ */ jsxs7("div", { className: `${mobileDrawerClass} fixed left-0 top-0 bottom-0 z-50 w-64 bg-white dark:bg-gray-800 shadow-2xl animate-in slide-in-from-left duration-300`, children: [
903
+ /* @__PURE__ */ jsxs7("div", { className: "p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between", children: [
904
+ navbarLogo ? /* @__PURE__ */ jsx38("div", { children: navbarLogo }) : navbarTitle ? /* @__PURE__ */ jsx38("span", { className: "text-xl font-bold text-gray-900 dark:text-gray-100", children: navbarTitle }) : null,
905
+ /* @__PURE__ */ jsx38(
906
+ "button",
907
+ {
908
+ className: "p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",
909
+ onClick: () => setIsMobileNavbarOpen(false),
910
+ "aria-label": "Close menu",
911
+ children: /* @__PURE__ */ jsx38("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx38("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
912
+ }
913
+ )
914
+ ] }),
915
+ /* @__PURE__ */ jsx38(
916
+ "div",
917
+ {
918
+ className: "overflow-y-auto h-[calc(100vh-73px)]",
919
+ onClick: () => setIsMobileNavbarOpen(false),
920
+ children: navbar.content
921
+ }
922
+ )
923
+ ] })
924
+ ] }),
925
+ /* @__PURE__ */ jsx38("main", { className: "flex-1 overflow-y-auto min-h-screen", children })
926
+ ] })
927
+ ] });
928
+ }
929
+ return /* @__PURE__ */ jsxs7("div", { className: `min-h-screen flex flex-col ${className}`, children: [
930
+ header && /* @__PURE__ */ jsx38("div", { className: "w-full", children: header }),
931
+ /* @__PURE__ */ jsx38("main", { className: "flex-1 overflow-y-auto", children })
932
+ ] });
933
+ };
934
+
935
+ // src/components/Drawer.tsx
936
+ import { useEffect as useEffect4 } from "react";
937
+ import { Fragment as Fragment5, jsx as jsx39, jsxs as jsxs8 } from "react/jsx-runtime";
938
+ var sizeClasses3 = {
939
+ left: {
940
+ sm: "w-64",
941
+ md: "w-80",
942
+ lg: "w-96"
943
+ },
944
+ right: {
945
+ sm: "w-64",
946
+ md: "w-80",
947
+ lg: "w-96"
948
+ },
949
+ top: {
950
+ sm: "h-48",
951
+ md: "h-64",
952
+ lg: "h-80"
953
+ },
954
+ bottom: {
955
+ sm: "h-48",
956
+ md: "h-64",
957
+ lg: "h-80"
958
+ }
959
+ };
960
+ var positionClasses = {
961
+ left: "left-0 top-0 h-full",
962
+ right: "right-0 top-0 h-full",
963
+ top: "top-0 left-0 w-full",
964
+ bottom: "bottom-0 left-0 w-full"
965
+ };
966
+ var slideClasses = {
967
+ left: "transform transition-transform duration-300",
968
+ right: "transform transition-transform duration-300",
969
+ top: "transform transition-transform duration-300",
970
+ bottom: "transform transition-transform duration-300"
971
+ };
972
+ var Drawer = ({
973
+ isOpen,
974
+ onClose,
975
+ title,
976
+ children,
977
+ position = "right",
978
+ size = "md",
979
+ showCloseButton = true
980
+ }) => {
981
+ const { theme } = useTheme();
982
+ useEffect4(() => {
983
+ const handleEscape = (e) => {
984
+ if (e.key === "Escape" && isOpen) {
985
+ onClose();
986
+ }
987
+ };
988
+ if (isOpen) {
989
+ document.addEventListener("keydown", handleEscape);
990
+ document.body.style.overflow = "hidden";
991
+ }
992
+ return () => {
993
+ document.removeEventListener("keydown", handleEscape);
994
+ document.body.style.overflow = "unset";
995
+ };
996
+ }, [isOpen, onClose]);
997
+ if (!isOpen) return null;
998
+ const sizeClass = sizeClasses3[position][size];
999
+ const positionClass = positionClasses[position];
1000
+ return /* @__PURE__ */ jsxs8(Fragment5, { children: [
1001
+ /* @__PURE__ */ jsx39(
1002
+ "div",
1003
+ {
1004
+ className: "fixed inset-0 z-40 bg-black/60 backdrop-blur-sm transition-all duration-200",
1005
+ onClick: onClose
264
1006
  }
265
- ) }),
266
- isOpen && !disabled && /* @__PURE__ */ jsx3(
1007
+ ),
1008
+ /* @__PURE__ */ jsxs8(
267
1009
  "div",
268
1010
  {
269
- className: `absolute z-50 w-full mt-1 ${dropdownBaseStyles} rounded-lg overflow-hidden`,
270
- style: { maxHeight: "300px", overflowY: "auto" },
271
- children: options.map((option) => /* @__PURE__ */ jsx3(
272
- "div",
1011
+ className: `fixed z-50 ${positionClass} ${sizeClass} bg-white dark:bg-gray-800 shadow-2xl overflow-hidden flex flex-col ${slideClasses[position]}`,
1012
+ children: [
1013
+ (title || showCloseButton) && /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700", children: [
1014
+ title && /* @__PURE__ */ jsx39("h3", { className: "text-xl font-semibold text-gray-900 dark:text-gray-100", children: title }),
1015
+ showCloseButton && /* @__PURE__ */ jsx39(
1016
+ "button",
1017
+ {
1018
+ onClick: onClose,
1019
+ className: "ml-auto text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors",
1020
+ "aria-label": "Close drawer",
1021
+ children: /* @__PURE__ */ jsx39("svg", { className: "w-6 h-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx39("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
1022
+ }
1023
+ )
1024
+ ] }),
1025
+ /* @__PURE__ */ jsx39("div", { className: "flex-1 p-6 overflow-y-auto", children })
1026
+ ]
1027
+ }
1028
+ )
1029
+ ] });
1030
+ };
1031
+
1032
+ // src/components/TextInput.tsx
1033
+ import { forwardRef } from "react";
1034
+ import { jsx as jsx40, jsxs as jsxs9 } from "react/jsx-runtime";
1035
+ var sizeClasses4 = {
1036
+ sm: "px-3 py-1.5 text-sm",
1037
+ md: "px-4 py-2.5 text-base",
1038
+ lg: "px-4 py-3 text-lg"
1039
+ };
1040
+ var TextInput = forwardRef(
1041
+ ({
1042
+ label,
1043
+ error,
1044
+ helperText,
1045
+ size = "md",
1046
+ fullWidth = false,
1047
+ leftIcon,
1048
+ rightIcon,
1049
+ className = "",
1050
+ disabled,
1051
+ ...props
1052
+ }, ref) => {
1053
+ const { theme, themeName } = useTheme();
1054
+ const baseStyles = theme.select?.base || "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500";
1055
+ const sizeStyle = sizeClasses4[size];
1056
+ const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
1057
+ const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
1058
+ const widthStyle = fullWidth ? "w-full" : "";
1059
+ const paddingWithIcon = leftIcon ? "pl-10" : rightIcon ? "pr-10" : "";
1060
+ return /* @__PURE__ */ jsxs9("div", { className: `${widthStyle} ${className}`, children: [
1061
+ label && /* @__PURE__ */ jsx40("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
1062
+ /* @__PURE__ */ jsxs9("div", { className: "relative", children: [
1063
+ leftIcon && /* @__PURE__ */ jsx40("div", { className: "absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 dark:text-gray-500", children: leftIcon }),
1064
+ /* @__PURE__ */ jsx40(
1065
+ "input",
1066
+ {
1067
+ ref,
1068
+ className: `${baseStyles} ${sizeStyle} ${errorStyles} ${disabledStyles} ${paddingWithIcon}`.trim(),
1069
+ disabled,
1070
+ ...props
1071
+ }
1072
+ ),
1073
+ rightIcon && /* @__PURE__ */ jsx40("div", { className: "absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 dark:text-gray-500", children: rightIcon })
1074
+ ] }),
1075
+ error && /* @__PURE__ */ jsx40("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
1076
+ helperText && !error && /* @__PURE__ */ jsx40("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
1077
+ ] });
1078
+ }
1079
+ );
1080
+ TextInput.displayName = "TextInput";
1081
+
1082
+ // src/components/NumberInput.tsx
1083
+ import { useState as useState5, useRef as useRef2 } from "react";
1084
+ import { jsx as jsx41, jsxs as jsxs10 } from "react/jsx-runtime";
1085
+ var sizeClasses5 = {
1086
+ sm: "px-3 py-1.5 text-sm",
1087
+ md: "px-4 py-2.5 text-base",
1088
+ lg: "px-4 py-3 text-lg"
1089
+ };
1090
+ var NumberInput = ({
1091
+ label,
1092
+ error,
1093
+ helperText,
1094
+ value,
1095
+ onChange,
1096
+ min,
1097
+ max,
1098
+ step = 1,
1099
+ precision,
1100
+ disabled = false,
1101
+ hideControls = false,
1102
+ size = "md",
1103
+ fullWidth = false,
1104
+ placeholder,
1105
+ className = ""
1106
+ }) => {
1107
+ const { theme } = useTheme();
1108
+ const inputRef = useRef2(null);
1109
+ const [isFocused, setIsFocused] = useState5(false);
1110
+ const clampValue = (val) => {
1111
+ let clamped = val;
1112
+ if (min !== void 0 && clamped < min) clamped = min;
1113
+ if (max !== void 0 && clamped > max) clamped = max;
1114
+ if (precision !== void 0) {
1115
+ clamped = parseFloat(clamped.toFixed(precision));
1116
+ }
1117
+ return clamped;
1118
+ };
1119
+ const handleIncrement = () => {
1120
+ if (disabled) return;
1121
+ const currentValue = value ?? 0;
1122
+ const newValue = clampValue(currentValue + step);
1123
+ onChange?.(newValue);
1124
+ };
1125
+ const handleDecrement = () => {
1126
+ if (disabled) return;
1127
+ const currentValue = value ?? 0;
1128
+ const newValue = clampValue(currentValue - step);
1129
+ onChange?.(newValue);
1130
+ };
1131
+ const handleInputChange = (e) => {
1132
+ const inputValue = e.target.value;
1133
+ if (inputValue === "" || inputValue === "-") {
1134
+ onChange?.(void 0);
1135
+ return;
1136
+ }
1137
+ const numValue = parseFloat(inputValue);
1138
+ if (!isNaN(numValue)) {
1139
+ const clamped = clampValue(numValue);
1140
+ onChange?.(clamped);
1141
+ }
1142
+ };
1143
+ const handleKeyDown = (e) => {
1144
+ if (e.key === "ArrowUp") {
1145
+ e.preventDefault();
1146
+ handleIncrement();
1147
+ } else if (e.key === "ArrowDown") {
1148
+ e.preventDefault();
1149
+ handleDecrement();
1150
+ }
1151
+ };
1152
+ const baseStyles = "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500";
1153
+ const sizeStyle = sizeClasses5[size];
1154
+ const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
1155
+ const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
1156
+ const widthStyle = fullWidth ? "w-full" : "";
1157
+ const paddingWithControls = !hideControls ? "pr-8" : "";
1158
+ const displayValue = value !== void 0 ? value.toString() : "";
1159
+ return /* @__PURE__ */ jsxs10("div", { className: `${widthStyle} ${className}`, children: [
1160
+ label && /* @__PURE__ */ jsx41("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
1161
+ /* @__PURE__ */ jsxs10("div", { className: "relative", children: [
1162
+ /* @__PURE__ */ jsx41(
1163
+ "input",
1164
+ {
1165
+ ref: inputRef,
1166
+ type: "number",
1167
+ value: displayValue,
1168
+ onChange: handleInputChange,
1169
+ onKeyDown: handleKeyDown,
1170
+ onFocus: () => setIsFocused(true),
1171
+ onBlur: () => setIsFocused(false),
1172
+ disabled,
1173
+ placeholder,
1174
+ min,
1175
+ max,
1176
+ step,
1177
+ className: `${baseStyles} ${sizeStyle} ${errorStyles} ${disabledStyles} ${paddingWithControls} [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`.trim()
1178
+ }
1179
+ ),
1180
+ !hideControls && /* @__PURE__ */ jsxs10("div", { className: "absolute right-1 top-1/2 -translate-y-1/2 flex flex-col", children: [
1181
+ /* @__PURE__ */ jsx41(
1182
+ "button",
1183
+ {
1184
+ type: "button",
1185
+ onClick: handleIncrement,
1186
+ disabled: disabled || max !== void 0 && value !== void 0 && value >= max,
1187
+ className: "px-2 py-0.5 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
1188
+ tabIndex: -1,
1189
+ children: /* @__PURE__ */ jsx41("svg", { className: "w-3 h-3 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx41("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M5 15l7-7 7 7" }) })
1190
+ }
1191
+ ),
1192
+ /* @__PURE__ */ jsx41(
1193
+ "button",
1194
+ {
1195
+ type: "button",
1196
+ onClick: handleDecrement,
1197
+ disabled: disabled || min !== void 0 && value !== void 0 && value <= min,
1198
+ className: "px-2 py-0.5 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
1199
+ tabIndex: -1,
1200
+ children: /* @__PURE__ */ jsx41("svg", { className: "w-3 h-3 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx41("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M19 9l-7 7-7-7" }) })
1201
+ }
1202
+ )
1203
+ ] })
1204
+ ] }),
1205
+ error && /* @__PURE__ */ jsx41("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
1206
+ helperText && !error && /* @__PURE__ */ jsx41("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
1207
+ ] });
1208
+ };
1209
+ NumberInput.displayName = "NumberInput";
1210
+
1211
+ // src/components/ActionMenu.tsx
1212
+ import { useState as useState6, useRef as useRef3, useEffect as useEffect5 } from "react";
1213
+ import { createPortal } from "react-dom";
1214
+ import { Fragment as Fragment6, jsx as jsx42, jsxs as jsxs11 } from "react/jsx-runtime";
1215
+ var ActionMenu = ({
1216
+ items,
1217
+ trigger,
1218
+ position = "right",
1219
+ placement = "bottom"
1220
+ }) => {
1221
+ const { themeName } = useTheme();
1222
+ const [isOpen, setIsOpen] = useState6(false);
1223
+ const [menuPosition, setMenuPosition] = useState6(null);
1224
+ const [mounted, setMounted] = useState6(false);
1225
+ const menuRef = useRef3(null);
1226
+ const triggerRef = useRef3(null);
1227
+ useEffect5(() => {
1228
+ setMounted(true);
1229
+ }, []);
1230
+ useEffect5(() => {
1231
+ const handleClickOutside = (event) => {
1232
+ if (menuRef.current && !menuRef.current.contains(event.target) && triggerRef.current && !triggerRef.current.contains(event.target)) {
1233
+ setIsOpen(false);
1234
+ }
1235
+ };
1236
+ if (isOpen) {
1237
+ document.addEventListener("mousedown", handleClickOutside);
1238
+ return () => document.removeEventListener("mousedown", handleClickOutside);
1239
+ }
1240
+ }, [isOpen]);
1241
+ useEffect5(() => {
1242
+ if (isOpen && triggerRef.current) {
1243
+ const rect = triggerRef.current.getBoundingClientRect();
1244
+ const menuWidth = 224;
1245
+ const menuHeight = 300;
1246
+ const spacing = 8;
1247
+ let top = 0;
1248
+ let left = 0;
1249
+ switch (placement) {
1250
+ case "top":
1251
+ top = rect.top - menuHeight - spacing;
1252
+ left = position === "left" ? rect.left : rect.right - menuWidth;
1253
+ break;
1254
+ case "bottom":
1255
+ top = rect.bottom + spacing;
1256
+ left = position === "left" ? rect.left : rect.right - menuWidth;
1257
+ break;
1258
+ case "left":
1259
+ top = rect.top;
1260
+ left = rect.left - menuWidth - spacing;
1261
+ break;
1262
+ case "right":
1263
+ top = rect.top;
1264
+ left = rect.right + spacing;
1265
+ break;
1266
+ }
1267
+ setMenuPosition({ top, left });
1268
+ } else {
1269
+ setMenuPosition(null);
1270
+ }
1271
+ }, [isOpen, position, placement]);
1272
+ const handleItemClick = (item) => {
1273
+ if (item.type === "divider") return;
1274
+ if (!item.disabled) {
1275
+ item.onClick();
1276
+ setIsOpen(false);
1277
+ }
1278
+ };
1279
+ const defaultTrigger = /* @__PURE__ */ jsx42(
1280
+ "button",
1281
+ {
1282
+ className: "p-2 rounded-md hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",
1283
+ "aria-label": "Open menu",
1284
+ children: /* @__PURE__ */ jsx42("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx42("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z" }) })
1285
+ }
1286
+ );
1287
+ const menuBaseStyles = themeName === "minimalistic" ? "bg-black border-2 border-white" : "bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 shadow-lg";
1288
+ const itemBaseStyles = themeName === "minimalistic" ? "text-white hover:bg-white hover:text-black transition-colors duration-200" : "text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors";
1289
+ const menu = isOpen && mounted && menuPosition ? /* @__PURE__ */ jsx42(
1290
+ "div",
1291
+ {
1292
+ ref: menuRef,
1293
+ className: `fixed w-56 rounded-lg ${menuBaseStyles} z-[9999] max-h-[80vh] overflow-auto`,
1294
+ style: {
1295
+ minWidth: "14rem",
1296
+ top: `${menuPosition.top}px`,
1297
+ left: `${menuPosition.left}px`
1298
+ },
1299
+ children: items.map((item, index) => {
1300
+ if (item.type === "divider") {
1301
+ return /* @__PURE__ */ jsx42(
1302
+ "div",
1303
+ {
1304
+ className: "my-1 border-t border-gray-200 dark:border-gray-700"
1305
+ },
1306
+ index
1307
+ );
1308
+ }
1309
+ return /* @__PURE__ */ jsxs11(
1310
+ "button",
273
1311
  {
274
- className: `${optionBaseStyles} ${optionSizeStyles} cursor-pointer ${value === option.value ? themeName === "minimalistic" ? "bg-white text-black" : "bg-blue-100 dark:bg-blue-900" : ""}`,
275
- onClick: () => handleSelect(option.value),
276
- children: option.label
1312
+ onClick: () => handleItemClick(item),
1313
+ disabled: item.disabled,
1314
+ className: `w-full text-left px-4 py-3 flex items-center gap-3 ${itemBaseStyles} ${item.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"} ${item.variant === "danger" ? "text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20" : ""}`,
1315
+ children: [
1316
+ item.icon && /* @__PURE__ */ jsx42("span", { className: "flex-shrink-0", children: item.icon }),
1317
+ /* @__PURE__ */ jsx42("span", { className: "flex-1", children: item.label })
1318
+ ]
277
1319
  },
278
- option.value
279
- ))
1320
+ index
1321
+ );
1322
+ })
1323
+ }
1324
+ ) : null;
1325
+ return /* @__PURE__ */ jsxs11(Fragment6, { children: [
1326
+ /* @__PURE__ */ jsx42("div", { className: "relative inline-block", ref: triggerRef, children: /* @__PURE__ */ jsx42("div", { onClick: () => setIsOpen(!isOpen), children: trigger || defaultTrigger }) }),
1327
+ mounted && createPortal(menu, document.body)
1328
+ ] });
1329
+ };
1330
+
1331
+ // src/components/Card.tsx
1332
+ import { jsx as jsx43 } from "react/jsx-runtime";
1333
+ var paddingClasses = {
1334
+ none: "",
1335
+ sm: "p-4",
1336
+ md: "p-6",
1337
+ lg: "p-8"
1338
+ };
1339
+ var Card = ({
1340
+ children,
1341
+ className = "",
1342
+ padding = "md",
1343
+ hover = false,
1344
+ ...props
1345
+ }) => {
1346
+ const { theme } = useTheme();
1347
+ const paddingClass = paddingClasses[padding];
1348
+ const hoverClass = hover ? "hover:shadow-xl hover:scale-[1.02] hover:border-blue-400 dark:hover:border-blue-500 cursor-pointer transition-all duration-200 ease-in-out" : "";
1349
+ return /* @__PURE__ */ jsx43(
1350
+ "div",
1351
+ {
1352
+ className: `bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 ${paddingClass} ${hoverClass} ${className}`,
1353
+ ...props,
1354
+ children
1355
+ }
1356
+ );
1357
+ };
1358
+
1359
+ // src/components/Alert.tsx
1360
+ import { jsx as jsx44, jsxs as jsxs12 } from "react/jsx-runtime";
1361
+ var variantStyles = {
1362
+ info: "bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800 text-blue-900 dark:text-blue-100",
1363
+ success: "bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800 text-green-900 dark:text-green-100",
1364
+ warning: "bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 dark:border-yellow-800 text-yellow-900 dark:text-yellow-100",
1365
+ error: "bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800 text-red-900 dark:text-red-100"
1366
+ };
1367
+ var iconStyles = {
1368
+ info: "text-blue-600 dark:text-blue-400",
1369
+ success: "text-green-600 dark:text-green-400",
1370
+ warning: "text-yellow-600 dark:text-yellow-400",
1371
+ error: "text-red-600 dark:text-red-400"
1372
+ };
1373
+ var Alert = ({
1374
+ variant = "info",
1375
+ title,
1376
+ children,
1377
+ onClose,
1378
+ className = ""
1379
+ }) => {
1380
+ const { theme } = useTheme();
1381
+ const variantClass = variantStyles[variant];
1382
+ const iconClass = iconStyles[variant];
1383
+ return /* @__PURE__ */ jsx44("div", { className: `rounded-lg border p-4 ${variantClass} ${className}`, role: "alert", children: /* @__PURE__ */ jsxs12("div", { className: "flex items-start gap-3", children: [
1384
+ /* @__PURE__ */ jsxs12("div", { className: `flex-shrink-0 ${iconClass}`, children: [
1385
+ variant === "info" && /* @__PURE__ */ jsx44("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx44("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }) }),
1386
+ variant === "success" && /* @__PURE__ */ jsx44("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx44("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z", clipRule: "evenodd" }) }),
1387
+ variant === "warning" && /* @__PURE__ */ jsx44("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx44("path", { fillRule: "evenodd", d: "M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z", clipRule: "evenodd" }) }),
1388
+ variant === "error" && /* @__PURE__ */ jsx44("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx44("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z", clipRule: "evenodd" }) })
1389
+ ] }),
1390
+ /* @__PURE__ */ jsxs12("div", { className: "flex-1", children: [
1391
+ title && /* @__PURE__ */ jsx44("h3", { className: "font-semibold mb-1", children: title }),
1392
+ /* @__PURE__ */ jsx44("div", { className: "text-sm", children })
1393
+ ] }),
1394
+ onClose && /* @__PURE__ */ jsx44(
1395
+ "button",
1396
+ {
1397
+ onClick: onClose,
1398
+ className: `flex-shrink-0 ${iconClass} hover:opacity-70 transition-opacity`,
1399
+ "aria-label": "Close alert",
1400
+ children: /* @__PURE__ */ jsx44("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx44("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
280
1401
  }
281
1402
  )
1403
+ ] }) });
1404
+ };
1405
+
1406
+ // src/components/Checkbox.tsx
1407
+ import { forwardRef as forwardRef2 } from "react";
1408
+ import { jsx as jsx45, jsxs as jsxs13 } from "react/jsx-runtime";
1409
+ var Checkbox = forwardRef2(
1410
+ ({ label, error, className = "", disabled, checked, ...props }, ref) => {
1411
+ const { theme } = useTheme();
1412
+ return /* @__PURE__ */ jsxs13("div", { className, children: [
1413
+ /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-2 cursor-pointer group", children: [
1414
+ /* @__PURE__ */ jsxs13("div", { className: "relative inline-flex items-center", children: [
1415
+ /* @__PURE__ */ jsx45(
1416
+ "input",
1417
+ {
1418
+ ref,
1419
+ type: "checkbox",
1420
+ disabled,
1421
+ checked,
1422
+ className: "sr-only peer",
1423
+ ...props
1424
+ }
1425
+ ),
1426
+ /* @__PURE__ */ jsx45("div", { className: `w-4 h-4 border-2 rounded transition-all duration-200 flex items-center justify-center
1427
+ ${error ? "border-red-500 dark:border-red-500" : "border-gray-300 dark:border-gray-600"}
1428
+ ${disabled ? "opacity-50 cursor-not-allowed bg-gray-100 dark:bg-gray-800" : "peer-hover:border-gray-400 dark:peer-hover:border-gray-500"}
1429
+ peer-checked:bg-blue-600 peer-checked:border-blue-600
1430
+ peer-focus:ring-2 peer-focus:ring-blue-500 peer-focus:ring-offset-2
1431
+ `, children: /* @__PURE__ */ jsx45(
1432
+ "svg",
1433
+ {
1434
+ className: `w-3 h-3 text-white transition-opacity duration-200 ${checked ? "opacity-100" : "opacity-0"}`,
1435
+ viewBox: "0 0 12 12",
1436
+ fill: "none",
1437
+ xmlns: "http://www.w3.org/2000/svg",
1438
+ children: /* @__PURE__ */ jsx45(
1439
+ "path",
1440
+ {
1441
+ d: "M10 3L4.5 8.5L2 6",
1442
+ stroke: "currentColor",
1443
+ strokeWidth: "2",
1444
+ strokeLinecap: "round",
1445
+ strokeLinejoin: "round"
1446
+ }
1447
+ )
1448
+ }
1449
+ ) })
1450
+ ] }),
1451
+ label && /* @__PURE__ */ jsx45("span", { className: `text-sm text-gray-700 dark:text-gray-300 ${disabled ? "opacity-50 cursor-not-allowed" : "group-hover:text-gray-900 dark:group-hover:text-gray-100"}`, children: label })
1452
+ ] }),
1453
+ error && /* @__PURE__ */ jsx45("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error })
1454
+ ] });
1455
+ }
1456
+ );
1457
+ Checkbox.displayName = "Checkbox";
1458
+
1459
+ // src/components/Toggle.tsx
1460
+ import { forwardRef as forwardRef3 } from "react";
1461
+ import { jsx as jsx46, jsxs as jsxs14 } from "react/jsx-runtime";
1462
+ var Toggle = forwardRef3(
1463
+ ({ label, size = "md", className = "", disabled, checked, ...props }, ref) => {
1464
+ const { theme } = useTheme();
1465
+ const toggleClasses = {
1466
+ sm: {
1467
+ switch: "w-9 h-5",
1468
+ thumb: "w-4 h-4 peer-checked:translate-x-4"
1469
+ },
1470
+ md: {
1471
+ switch: "w-11 h-6",
1472
+ thumb: "w-5 h-5 peer-checked:translate-x-5"
1473
+ },
1474
+ lg: {
1475
+ switch: "w-14 h-7",
1476
+ thumb: "w-6 h-6 peer-checked:translate-x-7"
1477
+ }
1478
+ };
1479
+ const currentSize = toggleClasses[size];
1480
+ return /* @__PURE__ */ jsxs14("label", { className: `inline-flex items-center gap-3 cursor-pointer ${disabled ? "opacity-50 cursor-not-allowed" : ""} ${className}`, children: [
1481
+ /* @__PURE__ */ jsxs14("div", { className: "relative", children: [
1482
+ /* @__PURE__ */ jsx46(
1483
+ "input",
1484
+ {
1485
+ ref,
1486
+ type: "checkbox",
1487
+ className: "sr-only peer",
1488
+ disabled,
1489
+ checked,
1490
+ ...props
1491
+ }
1492
+ ),
1493
+ /* @__PURE__ */ jsx46(
1494
+ "div",
1495
+ {
1496
+ className: `${currentSize.switch} bg-gray-300 dark:bg-gray-700 peer-focus:ring-2 peer-focus:ring-blue-500 rounded-full peer peer-checked:bg-blue-600 dark:peer-checked:bg-blue-500 transition-colors`
1497
+ }
1498
+ ),
1499
+ /* @__PURE__ */ jsx46(
1500
+ "div",
1501
+ {
1502
+ className: `${currentSize.thumb} bg-white rounded-full shadow-md absolute top-0.5 left-0.5 transition-transform`
1503
+ }
1504
+ )
1505
+ ] }),
1506
+ label && /* @__PURE__ */ jsx46("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: label })
1507
+ ] });
1508
+ }
1509
+ );
1510
+ Toggle.displayName = "Toggle";
1511
+
1512
+ // src/components/Badge.tsx
1513
+ import { jsx as jsx47 } from "react/jsx-runtime";
1514
+ var variantStyles2 = {
1515
+ default: "bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200",
1516
+ primary: "bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-200",
1517
+ success: "bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-200",
1518
+ warning: "bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-200",
1519
+ error: "bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-200",
1520
+ info: "bg-cyan-100 dark:bg-cyan-900/30 text-cyan-800 dark:text-cyan-200"
1521
+ };
1522
+ var sizeStyles = {
1523
+ sm: "px-2 py-0.5 text-xs",
1524
+ md: "px-2.5 py-1 text-sm",
1525
+ lg: "px-3 py-1.5 text-base"
1526
+ };
1527
+ var Badge = ({
1528
+ children,
1529
+ variant = "default",
1530
+ size = "md",
1531
+ className = ""
1532
+ }) => {
1533
+ const { theme } = useTheme();
1534
+ const variantClass = variantStyles2[variant];
1535
+ const sizeClass = sizeStyles[size];
1536
+ return /* @__PURE__ */ jsx47("span", { className: `inline-flex items-center font-medium rounded-full ${variantClass} ${sizeClass} ${className}`, children });
1537
+ };
1538
+
1539
+ // src/components/Spinner.tsx
1540
+ import { jsx as jsx48 } from "react/jsx-runtime";
1541
+ var sizeClasses6 = {
1542
+ sm: "w-4 h-4 border-2",
1543
+ md: "w-8 h-8 border-2",
1544
+ lg: "w-12 h-12 border-3",
1545
+ xl: "w-16 h-16 border-4"
1546
+ };
1547
+ var colorClasses = {
1548
+ primary: "border-blue-600 border-t-transparent",
1549
+ secondary: "border-gray-600 border-t-transparent",
1550
+ white: "border-white border-t-transparent"
1551
+ };
1552
+ var Spinner = ({
1553
+ size = "md",
1554
+ color = "primary",
1555
+ className = ""
1556
+ }) => {
1557
+ const { theme } = useTheme();
1558
+ const sizeClass = sizeClasses6[size];
1559
+ const colorClass = colorClasses[color];
1560
+ return /* @__PURE__ */ jsx48(
1561
+ "div",
1562
+ {
1563
+ className: `inline-block rounded-full animate-spin ${sizeClass} ${colorClass} ${className}`,
1564
+ role: "status",
1565
+ "aria-label": "Loading",
1566
+ children: /* @__PURE__ */ jsx48("span", { className: "sr-only", children: "Loading..." })
1567
+ }
1568
+ );
1569
+ };
1570
+
1571
+ // src/components/Tabs.tsx
1572
+ import { useState as useState7 } from "react";
1573
+ import { jsx as jsx49, jsxs as jsxs15 } from "react/jsx-runtime";
1574
+ var Tabs = ({
1575
+ tabs,
1576
+ defaultIndex = 0,
1577
+ onChange,
1578
+ className = ""
1579
+ }) => {
1580
+ const { theme } = useTheme();
1581
+ const [activeIndex, setActiveIndex] = useState7(defaultIndex);
1582
+ const handleTabClick = (index) => {
1583
+ if (tabs[index].disabled) return;
1584
+ setActiveIndex(index);
1585
+ onChange?.(index);
1586
+ };
1587
+ return /* @__PURE__ */ jsxs15("div", { className, children: [
1588
+ /* @__PURE__ */ jsx49("div", { className: "border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsx49("nav", { className: "flex gap-8 px-6", "aria-label": "Tabs", children: tabs.map((tab, index) => /* @__PURE__ */ jsx49(
1589
+ "button",
1590
+ {
1591
+ onClick: () => handleTabClick(index),
1592
+ disabled: tab.disabled,
1593
+ className: `py-4 px-1 border-b-2 font-medium text-sm transition-colors ${activeIndex === index ? "border-blue-600 text-blue-600 dark:text-blue-400" : "border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 hover:border-gray-300 dark:hover:border-gray-600"} ${tab.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}`,
1594
+ "aria-current": activeIndex === index ? "page" : void 0,
1595
+ children: tab.label
1596
+ },
1597
+ index
1598
+ )) }) }),
1599
+ /* @__PURE__ */ jsx49("div", { children: tabs[activeIndex]?.content })
1600
+ ] });
1601
+ };
1602
+
1603
+ // src/components/Table.tsx
1604
+ import { jsx as jsx50, jsxs as jsxs16 } from "react/jsx-runtime";
1605
+ function Table({
1606
+ columns,
1607
+ data,
1608
+ keyField = "id",
1609
+ striped = false,
1610
+ hoverable = true,
1611
+ className = ""
1612
+ }) {
1613
+ const { theme } = useTheme();
1614
+ return /* @__PURE__ */ jsxs16("div", { className: `overflow-x-auto ${className}`, children: [
1615
+ /* @__PURE__ */ jsxs16("table", { className: "w-full text-left", children: [
1616
+ /* @__PURE__ */ jsx50("thead", { className: "bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsx50("tr", { children: columns.map((column, colIndex) => {
1617
+ const isLast = colIndex === columns.length - 1;
1618
+ return /* @__PURE__ */ jsx50(
1619
+ "th",
1620
+ {
1621
+ className: isLast ? "px-6 py-3 text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider relative" : "px-6 py-3 text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider",
1622
+ style: { width: column.width },
1623
+ children: column.title
1624
+ },
1625
+ column.key
1626
+ );
1627
+ }) }) }),
1628
+ /* @__PURE__ */ jsx50("tbody", { className: "bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700", children: data.map((row, rowIndex) => {
1629
+ const rowClasses = [
1630
+ striped && rowIndex % 2 === 1 ? "bg-gray-50 dark:bg-gray-800/50" : "",
1631
+ hoverable ? "hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors" : ""
1632
+ ].filter(Boolean).join(" ");
1633
+ return /* @__PURE__ */ jsx50(
1634
+ "tr",
1635
+ {
1636
+ className: rowClasses,
1637
+ children: columns.map((column, colIndex) => {
1638
+ const isLast = colIndex === columns.length - 1;
1639
+ return /* @__PURE__ */ jsx50(
1640
+ "td",
1641
+ {
1642
+ className: isLast ? "px-6 py-4 text-sm text-gray-900 dark:text-gray-100 overflow-visible" : "px-6 py-4 text-sm text-gray-900 dark:text-gray-100",
1643
+ children: column.render ? column.render(row[column.key], row, rowIndex) : row[column.key]
1644
+ },
1645
+ column.key
1646
+ );
1647
+ })
1648
+ },
1649
+ row[keyField] || rowIndex
1650
+ );
1651
+ }) })
1652
+ ] }),
1653
+ data.length === 0 && /* @__PURE__ */ jsx50("div", { className: "text-center py-8 text-gray-500 dark:text-gray-400", children: "No data available" })
1654
+ ] });
1655
+ }
1656
+
1657
+ // src/components/Pagination.tsx
1658
+ import { jsx as jsx51, jsxs as jsxs17 } from "react/jsx-runtime";
1659
+ var Pagination = ({
1660
+ currentPage,
1661
+ totalPages,
1662
+ onPageChange,
1663
+ siblingCount = 1,
1664
+ className = ""
1665
+ }) => {
1666
+ const { theme } = useTheme();
1667
+ const range = (start, end) => {
1668
+ const length = end - start + 1;
1669
+ return Array.from({ length }, (_, idx) => idx + start);
1670
+ };
1671
+ const paginationRange = () => {
1672
+ const totalPageNumbers = siblingCount + 5;
1673
+ if (totalPageNumbers >= totalPages) {
1674
+ return range(1, totalPages);
1675
+ }
1676
+ const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);
1677
+ const rightSiblingIndex = Math.min(currentPage + siblingCount, totalPages);
1678
+ const shouldShowLeftDots = leftSiblingIndex > 2;
1679
+ const shouldShowRightDots = rightSiblingIndex < totalPages - 2;
1680
+ const firstPageIndex = 1;
1681
+ const lastPageIndex = totalPages;
1682
+ if (!shouldShowLeftDots && shouldShowRightDots) {
1683
+ const leftItemCount = 3 + 2 * siblingCount;
1684
+ const leftRange = range(1, leftItemCount);
1685
+ return [...leftRange, "...", totalPages];
1686
+ }
1687
+ if (shouldShowLeftDots && !shouldShowRightDots) {
1688
+ const rightItemCount = 3 + 2 * siblingCount;
1689
+ const rightRange = range(totalPages - rightItemCount + 1, totalPages);
1690
+ return [firstPageIndex, "...", ...rightRange];
1691
+ }
1692
+ if (shouldShowLeftDots && shouldShowRightDots) {
1693
+ const middleRange = range(leftSiblingIndex, rightSiblingIndex);
1694
+ return [firstPageIndex, "...", ...middleRange, "...", lastPageIndex];
1695
+ }
1696
+ return range(1, totalPages);
1697
+ };
1698
+ const pages = paginationRange();
1699
+ return /* @__PURE__ */ jsxs17("nav", { className: `flex items-center gap-1 ${className}`, "aria-label": "Pagination", children: [
1700
+ /* @__PURE__ */ jsx51(
1701
+ "button",
1702
+ {
1703
+ onClick: () => onPageChange(currentPage - 1),
1704
+ disabled: currentPage === 1,
1705
+ className: "px-3 py-2 rounded-md text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
1706
+ "aria-label": "Previous page",
1707
+ children: "Previous"
1708
+ }
1709
+ ),
1710
+ pages.map((page, index) => {
1711
+ if (page === "...") {
1712
+ return /* @__PURE__ */ jsx51(
1713
+ "span",
1714
+ {
1715
+ className: "px-3 py-2 text-gray-700 dark:text-gray-300",
1716
+ children: "..."
1717
+ },
1718
+ `dots-${index}`
1719
+ );
1720
+ }
1721
+ return /* @__PURE__ */ jsx51(
1722
+ "button",
1723
+ {
1724
+ onClick: () => onPageChange(page),
1725
+ className: `px-3 py-2 rounded-md text-sm font-medium transition-colors ${currentPage === page ? "bg-blue-600 text-white" : "text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800"}`,
1726
+ "aria-label": `Page ${page}`,
1727
+ "aria-current": currentPage === page ? "page" : void 0,
1728
+ children: page
1729
+ },
1730
+ page
1731
+ );
1732
+ }),
1733
+ /* @__PURE__ */ jsx51(
1734
+ "button",
1735
+ {
1736
+ onClick: () => onPageChange(currentPage + 1),
1737
+ disabled: currentPage === totalPages,
1738
+ className: "px-3 py-2 rounded-md text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
1739
+ "aria-label": "Next page",
1740
+ children: "Next"
1741
+ }
1742
+ )
1743
+ ] });
1744
+ };
1745
+
1746
+ // src/components/DatePicker.tsx
1747
+ import { useState as useState8, useRef as useRef4, useEffect as useEffect6 } from "react";
1748
+ import { createPortal as createPortal2 } from "react-dom";
1749
+ import { jsx as jsx52, jsxs as jsxs18 } from "react/jsx-runtime";
1750
+ var DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
1751
+ var MONTHS = [
1752
+ "January",
1753
+ "February",
1754
+ "March",
1755
+ "April",
1756
+ "May",
1757
+ "June",
1758
+ "July",
1759
+ "August",
1760
+ "September",
1761
+ "October",
1762
+ "November",
1763
+ "December"
1764
+ ];
1765
+ var DatePicker = ({
1766
+ label,
1767
+ error,
1768
+ helperText,
1769
+ value,
1770
+ onChange,
1771
+ minDate,
1772
+ maxDate,
1773
+ disabled,
1774
+ className = "",
1775
+ placeholder = "Select date..."
1776
+ }) => {
1777
+ const { theme } = useTheme();
1778
+ const [isOpen, setIsOpen] = useState8(false);
1779
+ const [viewDate, setViewDate] = useState8(value || /* @__PURE__ */ new Date());
1780
+ const [mounted, setMounted] = useState8(false);
1781
+ const [calendarPosition, setCalendarPosition] = useState8(null);
1782
+ const inputRef = useRef4(null);
1783
+ const calendarRef = useRef4(null);
1784
+ useEffect6(() => {
1785
+ setMounted(true);
1786
+ }, []);
1787
+ useEffect6(() => {
1788
+ const handleClickOutside = (event) => {
1789
+ if (calendarRef.current && !calendarRef.current.contains(event.target) && inputRef.current && !inputRef.current.contains(event.target)) {
1790
+ setIsOpen(false);
1791
+ }
1792
+ };
1793
+ if (isOpen) {
1794
+ document.addEventListener("mousedown", handleClickOutside);
1795
+ return () => document.removeEventListener("mousedown", handleClickOutside);
1796
+ }
1797
+ }, [isOpen]);
1798
+ useEffect6(() => {
1799
+ if (isOpen && inputRef.current) {
1800
+ const rect = inputRef.current.getBoundingClientRect();
1801
+ setCalendarPosition({
1802
+ top: rect.bottom + 8,
1803
+ left: rect.left
1804
+ });
1805
+ } else {
1806
+ setCalendarPosition(null);
1807
+ }
1808
+ }, [isOpen]);
1809
+ const year = viewDate.getFullYear();
1810
+ const month = viewDate.getMonth();
1811
+ const firstDayOfMonth = new Date(year, month, 1).getDay();
1812
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
1813
+ const daysInPrevMonth = new Date(year, month, 0).getDate();
1814
+ const calendarDays = [];
1815
+ for (let i = firstDayOfMonth - 1; i >= 0; i--) {
1816
+ calendarDays.push(new Date(year, month - 1, daysInPrevMonth - i));
1817
+ }
1818
+ for (let i = 1; i <= daysInMonth; i++) {
1819
+ calendarDays.push(new Date(year, month, i));
1820
+ }
1821
+ const remainingDays = 42 - calendarDays.length;
1822
+ for (let i = 1; i <= remainingDays; i++) {
1823
+ calendarDays.push(new Date(year, month + 1, i));
1824
+ }
1825
+ const isSameDay = (date1, date2) => {
1826
+ return date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear();
1827
+ };
1828
+ const isToday = (date) => {
1829
+ return isSameDay(date, /* @__PURE__ */ new Date());
1830
+ };
1831
+ const isSelected = (date) => {
1832
+ return value && isSameDay(date, value);
1833
+ };
1834
+ const isCurrentMonth = (date) => {
1835
+ return date.getMonth() === month;
1836
+ };
1837
+ const isDisabled = (date) => {
1838
+ if (minDate && date < minDate) return true;
1839
+ if (maxDate && date > maxDate) return true;
1840
+ return false;
1841
+ };
1842
+ const handleDateClick = (date) => {
1843
+ if (isDisabled(date)) return;
1844
+ onChange?.(date);
1845
+ setIsOpen(false);
1846
+ };
1847
+ const handlePrevMonth = () => {
1848
+ setViewDate(new Date(year, month - 1, 1));
1849
+ };
1850
+ const handleNextMonth = () => {
1851
+ setViewDate(new Date(year, month + 1, 1));
1852
+ };
1853
+ const handleToday = () => {
1854
+ const today = /* @__PURE__ */ new Date();
1855
+ setViewDate(today);
1856
+ onChange?.(today);
1857
+ setIsOpen(false);
1858
+ };
1859
+ const formatDate = (date) => {
1860
+ if (!date) return "";
1861
+ return date.toLocaleDateString("en-US", {
1862
+ month: "short",
1863
+ day: "numeric",
1864
+ year: "numeric"
1865
+ });
1866
+ };
1867
+ const baseStyles = "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 px-4 py-2.5 text-base transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500 cursor-pointer";
1868
+ const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
1869
+ const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
1870
+ const calendar = isOpen && mounted && calendarPosition ? /* @__PURE__ */ jsxs18(
1871
+ "div",
1872
+ {
1873
+ ref: calendarRef,
1874
+ className: "fixed z-[9999] bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 shadow-xl p-4",
1875
+ style: {
1876
+ top: `${calendarPosition.top}px`,
1877
+ left: `${calendarPosition.left}px`,
1878
+ minWidth: "320px"
1879
+ },
1880
+ children: [
1881
+ /* @__PURE__ */ jsxs18("div", { className: "flex items-center justify-between mb-4", children: [
1882
+ /* @__PURE__ */ jsx52(
1883
+ "button",
1884
+ {
1885
+ onClick: handlePrevMonth,
1886
+ className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
1887
+ "aria-label": "Previous month",
1888
+ children: /* @__PURE__ */ jsx52("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx52("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
1889
+ }
1890
+ ),
1891
+ /* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-2", children: [
1892
+ /* @__PURE__ */ jsxs18("h2", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: [
1893
+ MONTHS[month],
1894
+ " ",
1895
+ year
1896
+ ] }),
1897
+ /* @__PURE__ */ jsx52(
1898
+ "button",
1899
+ {
1900
+ onClick: handleToday,
1901
+ className: "px-2 py-1 text-xs bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors",
1902
+ children: "Today"
1903
+ }
1904
+ )
1905
+ ] }),
1906
+ /* @__PURE__ */ jsx52(
1907
+ "button",
1908
+ {
1909
+ onClick: handleNextMonth,
1910
+ className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
1911
+ "aria-label": "Next month",
1912
+ children: /* @__PURE__ */ jsx52("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx52("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
1913
+ }
1914
+ )
1915
+ ] }),
1916
+ /* @__PURE__ */ jsx52("div", { className: "grid grid-cols-7 gap-1 mb-2", children: DAYS.map((day) => /* @__PURE__ */ jsx52("div", { className: "text-center text-xs font-semibold text-gray-600 dark:text-gray-400 py-1", children: day }, day)) }),
1917
+ /* @__PURE__ */ jsx52("div", { className: "grid grid-cols-7 gap-1", children: calendarDays.map((date, index) => {
1918
+ const isCurrentMonthDay = isCurrentMonth(date);
1919
+ const isTodayDay = isToday(date);
1920
+ const isSelectedDay = isSelected(date);
1921
+ const isDisabledDay = isDisabled(date);
1922
+ return /* @__PURE__ */ jsx52(
1923
+ "button",
1924
+ {
1925
+ onClick: () => handleDateClick(date),
1926
+ disabled: isDisabledDay,
1927
+ className: `
1928
+ aspect-square p-1 rounded-lg text-sm font-medium transition-all
1929
+ ${!isCurrentMonthDay ? "text-gray-400 dark:text-gray-600" : "text-gray-900 dark:text-gray-100"}
1930
+ ${isTodayDay && !isSelectedDay ? "bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 font-bold" : ""}
1931
+ ${isSelectedDay ? "bg-blue-600 text-white hover:bg-blue-700" : ""}
1932
+ ${!isSelectedDay && !isDisabledDay ? "hover:bg-gray-100 dark:hover:bg-gray-700" : ""}
1933
+ ${isDisabledDay ? "opacity-30 cursor-not-allowed" : "cursor-pointer"}
1934
+ `,
1935
+ children: date.getDate()
1936
+ },
1937
+ index
1938
+ );
1939
+ }) })
1940
+ ]
1941
+ }
1942
+ ) : null;
1943
+ return /* @__PURE__ */ jsxs18("div", { className, children: [
1944
+ label && /* @__PURE__ */ jsx52("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
1945
+ /* @__PURE__ */ jsxs18(
1946
+ "div",
1947
+ {
1948
+ ref: inputRef,
1949
+ onClick: () => !disabled && setIsOpen(!isOpen),
1950
+ className: `${baseStyles} ${errorStyles} ${disabledStyles} flex items-center justify-between`.trim(),
1951
+ children: [
1952
+ /* @__PURE__ */ jsx52("span", { className: !value ? "text-gray-500 dark:text-gray-400" : "", children: value ? formatDate(value) : placeholder }),
1953
+ /* @__PURE__ */ jsx52("svg", { className: "w-5 h-5 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx52("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) })
1954
+ ]
1955
+ }
1956
+ ),
1957
+ error && /* @__PURE__ */ jsx52("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
1958
+ helperText && !error && /* @__PURE__ */ jsx52("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText }),
1959
+ mounted && createPortal2(calendar, document.body)
1960
+ ] });
1961
+ };
1962
+ DatePicker.displayName = "DatePicker";
1963
+
1964
+ // src/components/TimePicker.tsx
1965
+ import { forwardRef as forwardRef4 } from "react";
1966
+ import { jsx as jsx53, jsxs as jsxs19 } from "react/jsx-runtime";
1967
+ var TimePicker = forwardRef4(
1968
+ ({ label, error, helperText, className = "", disabled, ...props }, ref) => {
1969
+ const { theme } = useTheme();
1970
+ const baseStyles = "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 px-4 py-2.5 text-base transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500";
1971
+ const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
1972
+ const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
1973
+ return /* @__PURE__ */ jsxs19("div", { className, children: [
1974
+ label && /* @__PURE__ */ jsx53("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
1975
+ /* @__PURE__ */ jsx53(
1976
+ "input",
1977
+ {
1978
+ ref,
1979
+ type: "time",
1980
+ disabled,
1981
+ className: `${baseStyles} ${errorStyles} ${disabledStyles}`.trim(),
1982
+ ...props
1983
+ }
1984
+ ),
1985
+ error && /* @__PURE__ */ jsx53("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
1986
+ helperText && !error && /* @__PURE__ */ jsx53("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
1987
+ ] });
1988
+ }
1989
+ );
1990
+ TimePicker.displayName = "TimePicker";
1991
+
1992
+ // src/components/DateTimePicker.tsx
1993
+ import { useState as useState9, useRef as useRef5, useEffect as useEffect7 } from "react";
1994
+ import { createPortal as createPortal3 } from "react-dom";
1995
+ import { jsx as jsx54, jsxs as jsxs20 } from "react/jsx-runtime";
1996
+ var DAYS2 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
1997
+ var MONTHS2 = [
1998
+ "January",
1999
+ "February",
2000
+ "March",
2001
+ "April",
2002
+ "May",
2003
+ "June",
2004
+ "July",
2005
+ "August",
2006
+ "September",
2007
+ "October",
2008
+ "November",
2009
+ "December"
2010
+ ];
2011
+ var DateTimePicker = ({
2012
+ label,
2013
+ error,
2014
+ helperText,
2015
+ value,
2016
+ onChange,
2017
+ minDate,
2018
+ maxDate,
2019
+ disabled,
2020
+ className = "",
2021
+ placeholder = "Select date and time..."
2022
+ }) => {
2023
+ const { theme } = useTheme();
2024
+ const [isOpen, setIsOpen] = useState9(false);
2025
+ const [viewDate, setViewDate] = useState9(value || /* @__PURE__ */ new Date());
2026
+ const [selectedTime, setSelectedTime] = useState9(
2027
+ value ? { hours: value.getHours(), minutes: value.getMinutes() } : { hours: 12, minutes: 0 }
2028
+ );
2029
+ const [mounted, setMounted] = useState9(false);
2030
+ const [pickerPosition, setPickerPosition] = useState9(null);
2031
+ const inputRef = useRef5(null);
2032
+ const pickerRef = useRef5(null);
2033
+ useEffect7(() => {
2034
+ setMounted(true);
2035
+ }, []);
2036
+ useEffect7(() => {
2037
+ const handleClickOutside = (event) => {
2038
+ if (pickerRef.current && !pickerRef.current.contains(event.target) && inputRef.current && !inputRef.current.contains(event.target)) {
2039
+ setIsOpen(false);
2040
+ }
2041
+ };
2042
+ if (isOpen) {
2043
+ document.addEventListener("mousedown", handleClickOutside);
2044
+ return () => document.removeEventListener("mousedown", handleClickOutside);
2045
+ }
2046
+ }, [isOpen]);
2047
+ useEffect7(() => {
2048
+ if (isOpen && inputRef.current) {
2049
+ const rect = inputRef.current.getBoundingClientRect();
2050
+ setPickerPosition({
2051
+ top: rect.bottom + 8,
2052
+ left: rect.left
2053
+ });
2054
+ } else {
2055
+ setPickerPosition(null);
2056
+ }
2057
+ }, [isOpen]);
2058
+ const year = viewDate.getFullYear();
2059
+ const month = viewDate.getMonth();
2060
+ const firstDayOfMonth = new Date(year, month, 1).getDay();
2061
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
2062
+ const daysInPrevMonth = new Date(year, month, 0).getDate();
2063
+ const calendarDays = [];
2064
+ for (let i = firstDayOfMonth - 1; i >= 0; i--) {
2065
+ calendarDays.push(new Date(year, month - 1, daysInPrevMonth - i));
2066
+ }
2067
+ for (let i = 1; i <= daysInMonth; i++) {
2068
+ calendarDays.push(new Date(year, month, i));
2069
+ }
2070
+ const remainingDays = 42 - calendarDays.length;
2071
+ for (let i = 1; i <= remainingDays; i++) {
2072
+ calendarDays.push(new Date(year, month + 1, i));
2073
+ }
2074
+ const isSameDay = (date1, date2) => {
2075
+ return date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear();
2076
+ };
2077
+ const isToday = (date) => {
2078
+ return isSameDay(date, /* @__PURE__ */ new Date());
2079
+ };
2080
+ const isSelected = (date) => {
2081
+ return value && isSameDay(date, value);
2082
+ };
2083
+ const isCurrentMonth = (date) => {
2084
+ return date.getMonth() === month;
2085
+ };
2086
+ const isDisabled = (date) => {
2087
+ if (minDate && date < minDate) return true;
2088
+ if (maxDate && date > maxDate) return true;
2089
+ return false;
2090
+ };
2091
+ const handleDateClick = (date) => {
2092
+ if (isDisabled(date)) return;
2093
+ const newDateTime = new Date(
2094
+ date.getFullYear(),
2095
+ date.getMonth(),
2096
+ date.getDate(),
2097
+ selectedTime.hours,
2098
+ selectedTime.minutes
2099
+ );
2100
+ onChange?.(newDateTime);
2101
+ };
2102
+ const handleTimeChange = (hours, minutes) => {
2103
+ setSelectedTime({ hours, minutes });
2104
+ if (value) {
2105
+ const newDateTime = new Date(
2106
+ value.getFullYear(),
2107
+ value.getMonth(),
2108
+ value.getDate(),
2109
+ hours,
2110
+ minutes
2111
+ );
2112
+ onChange?.(newDateTime);
2113
+ }
2114
+ };
2115
+ const handleDone = () => {
2116
+ if (value) {
2117
+ setIsOpen(false);
2118
+ }
2119
+ };
2120
+ const handlePrevMonth = () => {
2121
+ setViewDate(new Date(year, month - 1, 1));
2122
+ };
2123
+ const handleNextMonth = () => {
2124
+ setViewDate(new Date(year, month + 1, 1));
2125
+ };
2126
+ const handleToday = () => {
2127
+ const now = /* @__PURE__ */ new Date();
2128
+ setViewDate(now);
2129
+ setSelectedTime({ hours: now.getHours(), minutes: now.getMinutes() });
2130
+ onChange?.(now);
2131
+ };
2132
+ const formatDateTime = (date) => {
2133
+ if (!date) return "";
2134
+ return date.toLocaleString("en-US", {
2135
+ month: "short",
2136
+ day: "numeric",
2137
+ year: "numeric",
2138
+ hour: "numeric",
2139
+ minute: "2-digit",
2140
+ hour12: true
2141
+ });
2142
+ };
2143
+ const formatTime = (hours, minutes) => {
2144
+ const period = hours >= 12 ? "PM" : "AM";
2145
+ const displayHours = hours % 12 || 12;
2146
+ const displayMinutes = minutes.toString().padStart(2, "0");
2147
+ return `${displayHours}:${displayMinutes} ${period}`;
2148
+ };
2149
+ const baseStyles = "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 px-4 py-2.5 text-base transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500 cursor-pointer";
2150
+ const errorStyles = error ? "border-red-500 focus:ring-red-500 dark:border-red-500" : "";
2151
+ const disabledStyles = disabled ? "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900" : "";
2152
+ const picker = isOpen && mounted && pickerPosition ? /* @__PURE__ */ jsxs20(
2153
+ "div",
2154
+ {
2155
+ ref: pickerRef,
2156
+ className: "fixed z-[9999] bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 shadow-xl p-4",
2157
+ style: {
2158
+ top: `${pickerPosition.top}px`,
2159
+ left: `${pickerPosition.left}px`,
2160
+ minWidth: "360px"
2161
+ },
2162
+ children: [
2163
+ /* @__PURE__ */ jsxs20("div", { className: "flex items-center justify-between mb-4", children: [
2164
+ /* @__PURE__ */ jsx54(
2165
+ "button",
2166
+ {
2167
+ onClick: handlePrevMonth,
2168
+ className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
2169
+ "aria-label": "Previous month",
2170
+ children: /* @__PURE__ */ jsx54("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx54("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
2171
+ }
2172
+ ),
2173
+ /* @__PURE__ */ jsxs20("div", { className: "flex items-center gap-2", children: [
2174
+ /* @__PURE__ */ jsxs20("h2", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: [
2175
+ MONTHS2[month],
2176
+ " ",
2177
+ year
2178
+ ] }),
2179
+ /* @__PURE__ */ jsx54(
2180
+ "button",
2181
+ {
2182
+ onClick: handleToday,
2183
+ className: "px-2 py-1 text-xs bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors",
2184
+ children: "Now"
2185
+ }
2186
+ )
2187
+ ] }),
2188
+ /* @__PURE__ */ jsx54(
2189
+ "button",
2190
+ {
2191
+ onClick: handleNextMonth,
2192
+ className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
2193
+ "aria-label": "Next month",
2194
+ children: /* @__PURE__ */ jsx54("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx54("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
2195
+ }
2196
+ )
2197
+ ] }),
2198
+ /* @__PURE__ */ jsx54("div", { className: "grid grid-cols-7 gap-1 mb-2", children: DAYS2.map((day) => /* @__PURE__ */ jsx54("div", { className: "text-center text-xs font-semibold text-gray-600 dark:text-gray-400 py-1", children: day }, day)) }),
2199
+ /* @__PURE__ */ jsx54("div", { className: "grid grid-cols-7 gap-1 mb-4", children: calendarDays.map((date, index) => {
2200
+ const isCurrentMonthDay = isCurrentMonth(date);
2201
+ const isTodayDay = isToday(date);
2202
+ const isSelectedDay = isSelected(date);
2203
+ const isDisabledDay = isDisabled(date);
2204
+ return /* @__PURE__ */ jsx54(
2205
+ "button",
2206
+ {
2207
+ onClick: () => handleDateClick(date),
2208
+ disabled: isDisabledDay,
2209
+ className: `
2210
+ aspect-square p-1 rounded-lg text-sm font-medium transition-all
2211
+ ${!isCurrentMonthDay ? "text-gray-400 dark:text-gray-600" : "text-gray-900 dark:text-gray-100"}
2212
+ ${isTodayDay && !isSelectedDay ? "bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 font-bold" : ""}
2213
+ ${isSelectedDay ? "bg-blue-600 text-white hover:bg-blue-700" : ""}
2214
+ ${!isSelectedDay && !isDisabledDay ? "hover:bg-gray-100 dark:hover:bg-gray-700" : ""}
2215
+ ${isDisabledDay ? "opacity-30 cursor-not-allowed" : "cursor-pointer"}
2216
+ `,
2217
+ children: date.getDate()
2218
+ },
2219
+ index
2220
+ );
2221
+ }) }),
2222
+ /* @__PURE__ */ jsxs20("div", { className: "border-t border-gray-200 dark:border-gray-700 pt-4", children: [
2223
+ /* @__PURE__ */ jsxs20("div", { className: "flex items-center justify-center gap-4 mb-4", children: [
2224
+ /* @__PURE__ */ jsxs20("div", { className: "flex flex-col items-center", children: [
2225
+ /* @__PURE__ */ jsx54("label", { className: "text-xs font-semibold text-gray-600 dark:text-gray-400 mb-2", children: "Hour" }),
2226
+ /* @__PURE__ */ jsxs20("div", { className: "flex flex-col items-center gap-1", children: [
2227
+ /* @__PURE__ */ jsx54(
2228
+ "button",
2229
+ {
2230
+ type: "button",
2231
+ onClick: () => handleTimeChange((selectedTime.hours + 1) % 24, selectedTime.minutes),
2232
+ className: "p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors",
2233
+ children: /* @__PURE__ */ jsx54("svg", { className: "w-4 h-4 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx54("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 15l7-7 7 7" }) })
2234
+ }
2235
+ ),
2236
+ /* @__PURE__ */ jsx54(
2237
+ "input",
2238
+ {
2239
+ type: "number",
2240
+ min: "0",
2241
+ max: "23",
2242
+ value: selectedTime.hours,
2243
+ onChange: (e) => {
2244
+ const val = parseInt(e.target.value);
2245
+ if (!isNaN(val) && val >= 0 && val <= 23) {
2246
+ handleTimeChange(val, selectedTime.minutes);
2247
+ }
2248
+ },
2249
+ className: "w-16 px-2 py-2 text-center border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 text-lg font-semibold [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
2250
+ }
2251
+ ),
2252
+ /* @__PURE__ */ jsx54(
2253
+ "button",
2254
+ {
2255
+ type: "button",
2256
+ onClick: () => handleTimeChange((selectedTime.hours - 1 + 24) % 24, selectedTime.minutes),
2257
+ className: "p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors",
2258
+ children: /* @__PURE__ */ jsx54("svg", { className: "w-4 h-4 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx54("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
2259
+ }
2260
+ )
2261
+ ] })
2262
+ ] }),
2263
+ /* @__PURE__ */ jsx54("span", { className: "text-2xl font-bold text-gray-600 dark:text-gray-400 mt-8", children: ":" }),
2264
+ /* @__PURE__ */ jsxs20("div", { className: "flex flex-col items-center", children: [
2265
+ /* @__PURE__ */ jsx54("label", { className: "text-xs font-semibold text-gray-600 dark:text-gray-400 mb-2", children: "Minute" }),
2266
+ /* @__PURE__ */ jsxs20("div", { className: "flex flex-col items-center gap-1", children: [
2267
+ /* @__PURE__ */ jsx54(
2268
+ "button",
2269
+ {
2270
+ type: "button",
2271
+ onClick: () => handleTimeChange(selectedTime.hours, (selectedTime.minutes + 1) % 60),
2272
+ className: "p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors",
2273
+ children: /* @__PURE__ */ jsx54("svg", { className: "w-4 h-4 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx54("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 15l7-7 7 7" }) })
2274
+ }
2275
+ ),
2276
+ /* @__PURE__ */ jsx54(
2277
+ "input",
2278
+ {
2279
+ type: "number",
2280
+ min: "0",
2281
+ max: "59",
2282
+ value: selectedTime.minutes,
2283
+ onChange: (e) => {
2284
+ const val = parseInt(e.target.value);
2285
+ if (!isNaN(val) && val >= 0 && val <= 59) {
2286
+ handleTimeChange(selectedTime.hours, val);
2287
+ }
2288
+ },
2289
+ className: "w-16 px-2 py-2 text-center border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 text-lg font-semibold [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
2290
+ }
2291
+ ),
2292
+ /* @__PURE__ */ jsx54(
2293
+ "button",
2294
+ {
2295
+ type: "button",
2296
+ onClick: () => handleTimeChange(selectedTime.hours, (selectedTime.minutes - 1 + 60) % 60),
2297
+ className: "p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors",
2298
+ children: /* @__PURE__ */ jsx54("svg", { className: "w-4 h-4 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx54("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
2299
+ }
2300
+ )
2301
+ ] })
2302
+ ] })
2303
+ ] }),
2304
+ /* @__PURE__ */ jsx54("div", { className: "text-center text-sm text-gray-600 dark:text-gray-400 mb-4", children: formatTime(selectedTime.hours, selectedTime.minutes) }),
2305
+ /* @__PURE__ */ jsx54(
2306
+ "button",
2307
+ {
2308
+ onClick: handleDone,
2309
+ className: "w-full px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium",
2310
+ children: "Done"
2311
+ }
2312
+ )
2313
+ ] })
2314
+ ]
2315
+ }
2316
+ ) : null;
2317
+ return /* @__PURE__ */ jsxs20("div", { className, children: [
2318
+ label && /* @__PURE__ */ jsx54("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
2319
+ /* @__PURE__ */ jsxs20(
2320
+ "div",
2321
+ {
2322
+ ref: inputRef,
2323
+ onClick: () => !disabled && setIsOpen(!isOpen),
2324
+ className: `${baseStyles} ${errorStyles} ${disabledStyles} flex items-center justify-between`.trim(),
2325
+ children: [
2326
+ /* @__PURE__ */ jsx54("span", { className: !value ? "text-gray-500 dark:text-gray-400" : "", children: value ? formatDateTime(value) : placeholder }),
2327
+ /* @__PURE__ */ jsx54("svg", { className: "w-5 h-5 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx54("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) })
2328
+ ]
2329
+ }
2330
+ ),
2331
+ error && /* @__PURE__ */ jsx54("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
2332
+ helperText && !error && /* @__PURE__ */ jsx54("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText }),
2333
+ mounted && createPortal3(picker, document.body)
2334
+ ] });
2335
+ };
2336
+ DateTimePicker.displayName = "DateTimePicker";
2337
+
2338
+ // src/components/Calendar.tsx
2339
+ import { useState as useState10 } from "react";
2340
+ import { jsx as jsx55, jsxs as jsxs21 } from "react/jsx-runtime";
2341
+ var DAYS3 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
2342
+ var MONTHS3 = [
2343
+ "January",
2344
+ "February",
2345
+ "March",
2346
+ "April",
2347
+ "May",
2348
+ "June",
2349
+ "July",
2350
+ "August",
2351
+ "September",
2352
+ "October",
2353
+ "November",
2354
+ "December"
2355
+ ];
2356
+ var Calendar = ({
2357
+ value,
2358
+ onChange,
2359
+ minDate,
2360
+ maxDate,
2361
+ className = ""
2362
+ }) => {
2363
+ const { theme } = useTheme();
2364
+ const [currentDate, setCurrentDate] = useState10(value || /* @__PURE__ */ new Date());
2365
+ const [viewDate, setViewDate] = useState10(value || /* @__PURE__ */ new Date());
2366
+ const year = viewDate.getFullYear();
2367
+ const month = viewDate.getMonth();
2368
+ const firstDayOfMonth = new Date(year, month, 1).getDay();
2369
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
2370
+ const daysInPrevMonth = new Date(year, month, 0).getDate();
2371
+ const calendarDays = [];
2372
+ for (let i = firstDayOfMonth - 1; i >= 0; i--) {
2373
+ calendarDays.push(new Date(year, month - 1, daysInPrevMonth - i));
2374
+ }
2375
+ for (let i = 1; i <= daysInMonth; i++) {
2376
+ calendarDays.push(new Date(year, month, i));
2377
+ }
2378
+ const remainingDays = 42 - calendarDays.length;
2379
+ for (let i = 1; i <= remainingDays; i++) {
2380
+ calendarDays.push(new Date(year, month + 1, i));
2381
+ }
2382
+ const isSameDay = (date1, date2) => {
2383
+ return date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear();
2384
+ };
2385
+ const isToday = (date) => {
2386
+ return isSameDay(date, /* @__PURE__ */ new Date());
2387
+ };
2388
+ const isSelected = (date) => {
2389
+ return value && isSameDay(date, value);
2390
+ };
2391
+ const isCurrentMonth = (date) => {
2392
+ return date.getMonth() === month;
2393
+ };
2394
+ const isDisabled = (date) => {
2395
+ if (minDate && date < minDate) return true;
2396
+ if (maxDate && date > maxDate) return true;
2397
+ return false;
2398
+ };
2399
+ const handleDateClick = (date) => {
2400
+ if (isDisabled(date)) return;
2401
+ setCurrentDate(date);
2402
+ onChange?.(date);
2403
+ };
2404
+ const handlePrevMonth = () => {
2405
+ setViewDate(new Date(year, month - 1, 1));
2406
+ };
2407
+ const handleNextMonth = () => {
2408
+ setViewDate(new Date(year, month + 1, 1));
2409
+ };
2410
+ const handleToday = () => {
2411
+ const today = /* @__PURE__ */ new Date();
2412
+ setViewDate(today);
2413
+ setCurrentDate(today);
2414
+ onChange?.(today);
2415
+ };
2416
+ return /* @__PURE__ */ jsxs21("div", { className: `bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-4 ${className}`, children: [
2417
+ /* @__PURE__ */ jsxs21("div", { className: "flex items-center justify-between mb-4", children: [
2418
+ /* @__PURE__ */ jsx55(
2419
+ "button",
2420
+ {
2421
+ onClick: handlePrevMonth,
2422
+ className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
2423
+ "aria-label": "Previous month",
2424
+ children: /* @__PURE__ */ jsx55("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx55("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
2425
+ }
2426
+ ),
2427
+ /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-2", children: [
2428
+ /* @__PURE__ */ jsxs21("h2", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100", children: [
2429
+ MONTHS3[month],
2430
+ " ",
2431
+ year
2432
+ ] }),
2433
+ /* @__PURE__ */ jsx55(
2434
+ "button",
2435
+ {
2436
+ onClick: handleToday,
2437
+ className: "px-3 py-1 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors",
2438
+ children: "Today"
2439
+ }
2440
+ )
2441
+ ] }),
2442
+ /* @__PURE__ */ jsx55(
2443
+ "button",
2444
+ {
2445
+ onClick: handleNextMonth,
2446
+ className: "p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
2447
+ "aria-label": "Next month",
2448
+ children: /* @__PURE__ */ jsx55("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx55("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
2449
+ }
2450
+ )
2451
+ ] }),
2452
+ /* @__PURE__ */ jsx55("div", { className: "grid grid-cols-7 gap-1 mb-2", children: DAYS3.map((day) => /* @__PURE__ */ jsx55(
2453
+ "div",
2454
+ {
2455
+ className: "text-center text-xs font-semibold text-gray-600 dark:text-gray-400 py-2",
2456
+ children: day
2457
+ },
2458
+ day
2459
+ )) }),
2460
+ /* @__PURE__ */ jsx55("div", { className: "grid grid-cols-7 gap-1", children: calendarDays.map((date, index) => {
2461
+ if (!date) return /* @__PURE__ */ jsx55("div", {}, index);
2462
+ const isCurrentMonthDay = isCurrentMonth(date);
2463
+ const isTodayDay = isToday(date);
2464
+ const isSelectedDay = isSelected(date);
2465
+ const isDisabledDay = isDisabled(date);
2466
+ return /* @__PURE__ */ jsx55(
2467
+ "button",
2468
+ {
2469
+ onClick: () => handleDateClick(date),
2470
+ disabled: isDisabledDay,
2471
+ className: `
2472
+ aspect-square p-2 rounded-lg text-sm font-medium transition-all
2473
+ ${!isCurrentMonthDay ? "text-gray-400 dark:text-gray-600" : "text-gray-900 dark:text-gray-100"}
2474
+ ${isTodayDay && !isSelectedDay ? "bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 font-bold" : ""}
2475
+ ${isSelectedDay ? "bg-blue-600 text-white hover:bg-blue-700" : ""}
2476
+ ${!isSelectedDay && !isDisabledDay ? "hover:bg-gray-100 dark:hover:bg-gray-700" : ""}
2477
+ ${isDisabledDay ? "opacity-30 cursor-not-allowed" : "cursor-pointer"}
2478
+ `,
2479
+ children: date.getDate()
2480
+ },
2481
+ index
2482
+ );
2483
+ }) })
2484
+ ] });
2485
+ };
2486
+
2487
+ // src/components/Radio.tsx
2488
+ import React17 from "react";
2489
+ import { jsx as jsx56, jsxs as jsxs22 } from "react/jsx-runtime";
2490
+ var Radio = ({
2491
+ name,
2492
+ options,
2493
+ value: controlledValue,
2494
+ defaultValue,
2495
+ onChange,
2496
+ disabled = false,
2497
+ orientation = "vertical",
2498
+ className = ""
2499
+ }) => {
2500
+ const [internalValue, setInternalValue] = React17.useState(defaultValue || "");
2501
+ const value = controlledValue !== void 0 ? controlledValue : internalValue;
2502
+ const handleChange = (optionValue) => {
2503
+ if (disabled) return;
2504
+ setInternalValue(optionValue);
2505
+ onChange?.(optionValue);
2506
+ };
2507
+ const containerClass = orientation === "horizontal" ? "flex flex-wrap gap-4" : "flex flex-col gap-2";
2508
+ return /* @__PURE__ */ jsx56("div", { className: `${containerClass} ${className}`, role: "radiogroup", children: options.map((option) => {
2509
+ const isDisabled = disabled || option.disabled;
2510
+ const isChecked = value === option.value;
2511
+ const id = `${name}-${option.value}`;
2512
+ return /* @__PURE__ */ jsxs22(
2513
+ "label",
2514
+ {
2515
+ htmlFor: id,
2516
+ className: `flex items-center gap-2 cursor-pointer group ${isDisabled ? "opacity-50 cursor-not-allowed" : ""}`,
2517
+ children: [
2518
+ /* @__PURE__ */ jsxs22("div", { className: "relative inline-flex items-center", children: [
2519
+ /* @__PURE__ */ jsx56(
2520
+ "input",
2521
+ {
2522
+ type: "radio",
2523
+ id,
2524
+ name,
2525
+ value: option.value,
2526
+ checked: isChecked,
2527
+ onChange: () => handleChange(option.value),
2528
+ disabled: isDisabled,
2529
+ className: "sr-only peer"
2530
+ }
2531
+ ),
2532
+ /* @__PURE__ */ jsx56("div", { className: `w-4 h-4 rounded-full border-2 transition-all duration-200 flex items-center justify-center
2533
+ border-gray-300 dark:border-gray-600
2534
+ ${isDisabled ? "bg-gray-100 dark:bg-gray-800" : "peer-hover:border-gray-400 dark:peer-hover:border-gray-500"}
2535
+ ${isChecked ? "border-blue-600 bg-white dark:bg-gray-900" : ""}
2536
+ peer-focus:ring-2 peer-focus:ring-blue-500 peer-focus:ring-offset-2
2537
+ `, children: /* @__PURE__ */ jsx56("div", { className: `w-2 h-2 rounded-full bg-blue-600 transition-all duration-200 ${isChecked ? "scale-100" : "scale-0"}` }) })
2538
+ ] }),
2539
+ /* @__PURE__ */ jsx56("span", { className: `text-sm font-medium text-gray-900 dark:text-gray-300 ${!isDisabled && "group-hover:text-gray-700 dark:group-hover:text-gray-100"}`, children: option.label })
2540
+ ]
2541
+ },
2542
+ option.value
2543
+ );
2544
+ }) });
2545
+ };
2546
+
2547
+ // src/components/ProgressBar.tsx
2548
+ import { jsx as jsx57, jsxs as jsxs23 } from "react/jsx-runtime";
2549
+ var ProgressBar = ({
2550
+ value,
2551
+ max = 100,
2552
+ size = "md",
2553
+ variant = "default",
2554
+ showLabel = false,
2555
+ label,
2556
+ className = ""
2557
+ }) => {
2558
+ const percentage = Math.min(Math.max(value / max * 100, 0), 100);
2559
+ const sizeClasses7 = {
2560
+ sm: "h-1",
2561
+ md: "h-2",
2562
+ lg: "h-3"
2563
+ };
2564
+ const variantClasses = {
2565
+ default: "bg-blue-600 dark:bg-blue-500",
2566
+ success: "bg-green-600 dark:bg-green-500",
2567
+ warning: "bg-yellow-500 dark:bg-yellow-400",
2568
+ danger: "bg-red-600 dark:bg-red-500"
2569
+ };
2570
+ return /* @__PURE__ */ jsxs23("div", { className: `w-full ${className}`, children: [
2571
+ (showLabel || label) && /* @__PURE__ */ jsxs23("div", { className: "flex justify-between items-center mb-1", children: [
2572
+ label && /* @__PURE__ */ jsx57("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: label }),
2573
+ showLabel && /* @__PURE__ */ jsxs23("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: [
2574
+ Math.round(percentage),
2575
+ "%"
2576
+ ] })
2577
+ ] }),
2578
+ /* @__PURE__ */ jsx57(
2579
+ "div",
2580
+ {
2581
+ className: `w-full bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden ${sizeClasses7[size]}`,
2582
+ role: "progressbar",
2583
+ "aria-valuenow": value,
2584
+ "aria-valuemin": 0,
2585
+ "aria-valuemax": max,
2586
+ children: /* @__PURE__ */ jsx57(
2587
+ "div",
2588
+ {
2589
+ className: `${sizeClasses7[size]} ${variantClasses[variant]} rounded-full transition-all duration-300 ease-out`,
2590
+ style: { width: `${percentage}%` }
2591
+ }
2592
+ )
2593
+ }
2594
+ )
2595
+ ] });
2596
+ };
2597
+
2598
+ // src/components/Slider.tsx
2599
+ import React18, { useRef as useRef6 } from "react";
2600
+ import { jsx as jsx58, jsxs as jsxs24 } from "react/jsx-runtime";
2601
+ var Slider = ({
2602
+ value: controlledValue,
2603
+ defaultValue = 50,
2604
+ min = 0,
2605
+ max = 100,
2606
+ step = 1,
2607
+ onChange,
2608
+ disabled = false,
2609
+ showValue = false,
2610
+ label,
2611
+ className = "",
2612
+ range = false,
2613
+ rangeValue: controlledRangeValue,
2614
+ defaultRangeValue = [25, 75],
2615
+ onRangeChange
2616
+ }) => {
2617
+ const [internalValue, setInternalValue] = React18.useState(defaultValue);
2618
+ const [internalRangeValue, setInternalRangeValue] = React18.useState(defaultRangeValue);
2619
+ const trackRef = useRef6(null);
2620
+ const [isDragging, setIsDragging] = React18.useState(null);
2621
+ const value = controlledValue !== void 0 ? controlledValue : internalValue;
2622
+ const rangeValue = controlledRangeValue !== void 0 ? controlledRangeValue : internalRangeValue;
2623
+ const handleChange = (e) => {
2624
+ const newValue = Number(e.target.value);
2625
+ setInternalValue(newValue);
2626
+ onChange?.(newValue);
2627
+ };
2628
+ const handleRangeMouseDown = (e, handle) => {
2629
+ if (disabled) return;
2630
+ e.preventDefault();
2631
+ setIsDragging(handle);
2632
+ };
2633
+ const handleRangeMouseMove = (e) => {
2634
+ if (!isDragging || !trackRef.current || disabled) return;
2635
+ const rect = trackRef.current.getBoundingClientRect();
2636
+ const percentage2 = Math.max(0, Math.min(100, (e.clientX - rect.left) / rect.width * 100));
2637
+ const newValue = Math.round(percentage2 / 100 * (max - min) / step) * step + min;
2638
+ if (isDragging === "min") {
2639
+ const newMin = Math.min(newValue, rangeValue[1] - step);
2640
+ const newRange = [newMin, rangeValue[1]];
2641
+ setInternalRangeValue(newRange);
2642
+ onRangeChange?.(newRange);
2643
+ } else {
2644
+ const newMax = Math.max(newValue, rangeValue[0] + step);
2645
+ const newRange = [rangeValue[0], newMax];
2646
+ setInternalRangeValue(newRange);
2647
+ onRangeChange?.(newRange);
2648
+ }
2649
+ };
2650
+ const handleRangeMouseUp = () => {
2651
+ setIsDragging(null);
2652
+ };
2653
+ React18.useEffect(() => {
2654
+ if (isDragging) {
2655
+ document.addEventListener("mousemove", handleRangeMouseMove);
2656
+ document.addEventListener("mouseup", handleRangeMouseUp);
2657
+ return () => {
2658
+ document.removeEventListener("mousemove", handleRangeMouseMove);
2659
+ document.removeEventListener("mouseup", handleRangeMouseUp);
2660
+ };
2661
+ }
2662
+ }, [isDragging, rangeValue]);
2663
+ const percentage = (value - min) / (max - min) * 100;
2664
+ const minPercentage = (rangeValue[0] - min) / (max - min) * 100;
2665
+ const maxPercentage = (rangeValue[1] - min) / (max - min) * 100;
2666
+ if (range) {
2667
+ return /* @__PURE__ */ jsxs24("div", { className: `w-full ${className}`, children: [
2668
+ (label || showValue) && /* @__PURE__ */ jsxs24("div", { className: "flex justify-between items-center mb-2", children: [
2669
+ label && /* @__PURE__ */ jsx58("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: label }),
2670
+ showValue && /* @__PURE__ */ jsxs24("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: [
2671
+ rangeValue[0],
2672
+ " - ",
2673
+ rangeValue[1]
2674
+ ] })
2675
+ ] }),
2676
+ /* @__PURE__ */ jsxs24("div", { className: "relative h-10 flex items-center", ref: trackRef, children: [
2677
+ /* @__PURE__ */ jsx58("div", { className: "absolute w-full h-2 bg-gray-200 dark:bg-gray-700 rounded-full" }),
2678
+ /* @__PURE__ */ jsx58(
2679
+ "div",
2680
+ {
2681
+ className: "absolute h-2 bg-blue-600 dark:bg-blue-500 rounded-full pointer-events-none",
2682
+ style: {
2683
+ left: `${minPercentage}%`,
2684
+ width: `${maxPercentage - minPercentage}%`
2685
+ }
2686
+ }
2687
+ ),
2688
+ /* @__PURE__ */ jsx58(
2689
+ "div",
2690
+ {
2691
+ className: `absolute w-4 h-4 -ml-2 rounded-sm bg-white dark:bg-gray-800 border-2 border-blue-600 shadow-md cursor-pointer z-10
2692
+ ${disabled ? "opacity-50 cursor-not-allowed" : ""}
2693
+ `,
2694
+ style: { left: `${minPercentage}%` },
2695
+ onMouseDown: (e) => handleRangeMouseDown(e, "min"),
2696
+ role: "slider",
2697
+ "aria-label": `${label ? label + " " : ""}minimum value`,
2698
+ "aria-valuemin": min,
2699
+ "aria-valuemax": rangeValue[1],
2700
+ "aria-valuenow": rangeValue[0],
2701
+ tabIndex: disabled ? -1 : 0
2702
+ }
2703
+ ),
2704
+ /* @__PURE__ */ jsx58(
2705
+ "div",
2706
+ {
2707
+ className: `absolute w-4 h-4 -ml-2 rounded-sm bg-white dark:bg-gray-800 border-2 border-blue-600 shadow-md cursor-pointer z-10
2708
+ ${disabled ? "opacity-50 cursor-not-allowed" : ""}
2709
+ `,
2710
+ style: { left: `${maxPercentage}%` },
2711
+ onMouseDown: (e) => handleRangeMouseDown(e, "max"),
2712
+ role: "slider",
2713
+ "aria-label": `${label ? label + " " : ""}maximum value`,
2714
+ "aria-valuemin": rangeValue[0],
2715
+ "aria-valuemax": max,
2716
+ "aria-valuenow": rangeValue[1],
2717
+ tabIndex: disabled ? -1 : 0
2718
+ }
2719
+ )
2720
+ ] })
2721
+ ] });
2722
+ }
2723
+ return /* @__PURE__ */ jsxs24("div", { className: `w-full ${className}`, children: [
2724
+ (label || showValue) && /* @__PURE__ */ jsxs24("div", { className: "flex justify-between items-center mb-2", children: [
2725
+ label && /* @__PURE__ */ jsx58("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: label }),
2726
+ showValue && /* @__PURE__ */ jsx58("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: value })
2727
+ ] }),
2728
+ /* @__PURE__ */ jsxs24("div", { className: "relative h-10 flex items-center", children: [
2729
+ /* @__PURE__ */ jsx58("div", { className: "absolute w-full h-2 bg-gray-200 dark:bg-gray-700 rounded-full" }),
2730
+ /* @__PURE__ */ jsx58(
2731
+ "div",
2732
+ {
2733
+ className: "absolute h-2 bg-blue-600 dark:bg-blue-500 rounded-full pointer-events-none",
2734
+ style: { width: `${percentage}%` }
2735
+ }
2736
+ ),
2737
+ /* @__PURE__ */ jsx58(
2738
+ "div",
2739
+ {
2740
+ className: `absolute w-4 h-4 -ml-2 rounded-sm bg-white dark:bg-gray-800 border-2 border-blue-600 shadow-md pointer-events-none z-10
2741
+ ${disabled ? "opacity-50" : ""}
2742
+ `,
2743
+ style: { left: `${percentage}%` }
2744
+ }
2745
+ ),
2746
+ /* @__PURE__ */ jsx58(
2747
+ "input",
2748
+ {
2749
+ type: "range",
2750
+ min,
2751
+ max,
2752
+ step,
2753
+ value,
2754
+ onChange: handleChange,
2755
+ disabled,
2756
+ className: "relative w-full h-10 bg-transparent appearance-none cursor-pointer disabled:cursor-not-allowed z-20\n [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:h-4\n [&::-webkit-slider-thumb]:rounded-sm [&::-webkit-slider-thumb]:bg-transparent [&::-webkit-slider-thumb]:cursor-pointer\n [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:rounded-sm\n [&::-moz-range-thumb]:bg-transparent [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:border-none",
2757
+ "aria-label": label,
2758
+ "aria-valuemin": min,
2759
+ "aria-valuemax": max,
2760
+ "aria-valuenow": value
2761
+ }
2762
+ )
2763
+ ] })
2764
+ ] });
2765
+ };
2766
+
2767
+ // src/components/Avatar.tsx
2768
+ import React19 from "react";
2769
+ import { jsx as jsx59 } from "react/jsx-runtime";
2770
+ var Avatar = ({
2771
+ src,
2772
+ alt,
2773
+ name,
2774
+ size = "md",
2775
+ shape = "circle",
2776
+ className = "",
2777
+ fallbackColor = "bg-blue-600"
2778
+ }) => {
2779
+ const [imageError, setImageError] = React19.useState(false);
2780
+ const sizeClasses7 = {
2781
+ xs: "w-6 h-6 text-xs",
2782
+ sm: "w-8 h-8 text-sm",
2783
+ md: "w-10 h-10 text-base",
2784
+ lg: "w-12 h-12 text-lg",
2785
+ xl: "w-16 h-16 text-2xl"
2786
+ };
2787
+ const shapeClass = shape === "circle" ? "rounded-full" : "rounded-md";
2788
+ const getInitials = (name2) => {
2789
+ const parts = name2.trim().split(" ");
2790
+ if (parts.length >= 2) {
2791
+ return `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase();
2792
+ }
2793
+ return name2.slice(0, 2).toUpperCase();
2794
+ };
2795
+ const showImage = src && !imageError;
2796
+ const showInitials = !showImage && name;
2797
+ return /* @__PURE__ */ jsx59(
2798
+ "div",
2799
+ {
2800
+ className: `${sizeClasses7[size]} ${shapeClass} flex items-center justify-center overflow-hidden ${showImage ? "bg-gray-200 dark:bg-gray-700" : `${fallbackColor} text-white`} ${className}`,
2801
+ children: showImage ? /* @__PURE__ */ jsx59(
2802
+ "img",
2803
+ {
2804
+ src,
2805
+ alt: alt || name || "Avatar",
2806
+ className: "w-full h-full object-cover",
2807
+ onError: () => setImageError(true)
2808
+ }
2809
+ ) : showInitials ? /* @__PURE__ */ jsx59("span", { className: "font-semibold select-none", children: getInitials(name) }) : /* @__PURE__ */ jsx59(
2810
+ "svg",
2811
+ {
2812
+ className: "w-full h-full text-gray-400 dark:text-gray-600",
2813
+ fill: "currentColor",
2814
+ viewBox: "0 0 24 24",
2815
+ children: /* @__PURE__ */ jsx59("path", { d: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" })
2816
+ }
2817
+ )
2818
+ }
2819
+ );
2820
+ };
2821
+
2822
+ // src/components/Textarea.tsx
2823
+ import { jsx as jsx60, jsxs as jsxs25 } from "react/jsx-runtime";
2824
+ var Textarea = ({
2825
+ label,
2826
+ error,
2827
+ helperText,
2828
+ size = "md",
2829
+ resize = "vertical",
2830
+ className = "",
2831
+ disabled,
2832
+ ...props
2833
+ }) => {
2834
+ const sizeClasses7 = {
2835
+ sm: "px-3 py-1.5 text-sm min-h-[80px]",
2836
+ md: "px-4 py-2 text-base min-h-[100px]",
2837
+ lg: "px-4 py-3 text-lg min-h-[120px]"
2838
+ };
2839
+ const resizeClasses = {
2840
+ none: "resize-none",
2841
+ vertical: "resize-y",
2842
+ horizontal: "resize-x",
2843
+ both: "resize"
2844
+ };
2845
+ const baseClasses = `w-full rounded-lg border transition-colors duration-150 focus:outline-none focus:ring-2
2846
+ ${error ? "border-red-500 focus:ring-red-500 focus:border-red-500 dark:border-red-400 dark:focus:ring-red-400" : "border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:border-gray-600 dark:focus:ring-blue-400"}
2847
+ bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100
2848
+ placeholder:text-gray-500 dark:placeholder:text-gray-400
2849
+ disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-gray-50 dark:disabled:bg-gray-900`;
2850
+ return /* @__PURE__ */ jsxs25("div", { className: `w-full ${className}`, children: [
2851
+ label && /* @__PURE__ */ jsx60("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }),
2852
+ /* @__PURE__ */ jsx60(
2853
+ "textarea",
2854
+ {
2855
+ className: `${baseClasses} ${sizeClasses7[size]} ${resizeClasses[resize]}`,
2856
+ disabled,
2857
+ ...props
2858
+ }
2859
+ ),
2860
+ error && /* @__PURE__ */ jsx60("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
2861
+ helperText && !error && /* @__PURE__ */ jsx60("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText })
2862
+ ] });
2863
+ };
2864
+
2865
+ // src/components/RichTextEditor.tsx
2866
+ import { useRef as useRef7, useCallback, useState as useState12, useEffect as useEffect8, useLayoutEffect } from "react";
2867
+ import { jsx as jsx61, jsxs as jsxs26 } from "react/jsx-runtime";
2868
+ var RichTextEditor = ({
2869
+ value = "",
2870
+ onChange,
2871
+ placeholder = "Start typing...",
2872
+ className = "",
2873
+ minHeight = "200px",
2874
+ maxHeight = "500px",
2875
+ disabled = false,
2876
+ label,
2877
+ error,
2878
+ helperText
2879
+ }) => {
2880
+ const { themeName } = useTheme();
2881
+ const editorRef = useRef7(null);
2882
+ const [isFocused, setIsFocused] = useState12(false);
2883
+ const [activeFormats, setActiveFormats] = useState12(/* @__PURE__ */ new Set());
2884
+ const [showLinkModal, setShowLinkModal] = useState12(false);
2885
+ const [linkUrl, setLinkUrl] = useState12("");
2886
+ const [showImageModal, setShowImageModal] = useState12(false);
2887
+ const [imageUrl, setImageUrl] = useState12("");
2888
+ const [imageAlt, setImageAlt] = useState12("");
2889
+ useLayoutEffect(() => {
2890
+ const styleId = "rich-text-editor-styles";
2891
+ if (!document.getElementById(styleId)) {
2892
+ const style = document.createElement("style");
2893
+ style.id = styleId;
2894
+ style.textContent = `
2895
+ [contenteditable]:empty:before {
2896
+ content: attr(data-placeholder);
2897
+ color: #9ca3af;
2898
+ pointer-events: none;
2899
+ }
2900
+ [contenteditable] h1 {
2901
+ font-size: 2em;
2902
+ font-weight: bold;
2903
+ margin: 0.67em 0;
2904
+ }
2905
+ [contenteditable] h2 {
2906
+ font-size: 1.5em;
2907
+ font-weight: bold;
2908
+ margin: 0.75em 0;
2909
+ }
2910
+ [contenteditable] h3 {
2911
+ font-size: 1.17em;
2912
+ font-weight: bold;
2913
+ margin: 0.83em 0;
2914
+ }
2915
+ [contenteditable] ul, [contenteditable] ol {
2916
+ margin: 1em 0;
2917
+ padding-left: 2em;
2918
+ }
2919
+ [contenteditable] a {
2920
+ color: #3b82f6;
2921
+ text-decoration: underline;
2922
+ }
2923
+ .dark [contenteditable] a {
2924
+ color: #60a5fa;
2925
+ }
2926
+ [contenteditable] img {
2927
+ max-width: 100%;
2928
+ height: auto;
2929
+ border-radius: 0.5rem;
2930
+ margin: 1em 0;
2931
+ }
2932
+ [contenteditable] video {
2933
+ max-width: 100%;
2934
+ height: auto;
2935
+ border-radius: 0.5rem;
2936
+ margin: 1em 0;
2937
+ }
2938
+ `;
2939
+ document.head.appendChild(style);
2940
+ }
2941
+ }, []);
2942
+ const isInitialRender = useRef7(true);
2943
+ useEffect8(() => {
2944
+ if (!isInitialRender.current && editorRef.current && editorRef.current.innerHTML !== value) {
2945
+ editorRef.current.innerHTML = value;
2946
+ }
2947
+ isInitialRender.current = false;
2948
+ }, [value]);
2949
+ const updateActiveFormats = useCallback(() => {
2950
+ const formats = /* @__PURE__ */ new Set();
2951
+ if (document.queryCommandState("bold")) formats.add("bold");
2952
+ if (document.queryCommandState("italic")) formats.add("italic");
2953
+ if (document.queryCommandState("underline")) formats.add("underline");
2954
+ if (document.queryCommandState("strikeThrough")) formats.add("strikeThrough");
2955
+ if (document.queryCommandState("insertUnorderedList")) formats.add("ul");
2956
+ if (document.queryCommandState("insertOrderedList")) formats.add("ol");
2957
+ const parentNode = window.getSelection()?.anchorNode?.parentElement;
2958
+ if (parentNode) {
2959
+ const tagName = parentNode.tagName.toLowerCase();
2960
+ if (["h1", "h2", "h3"].includes(tagName)) {
2961
+ formats.add(tagName);
2962
+ }
2963
+ }
2964
+ setActiveFormats(formats);
2965
+ }, []);
2966
+ const handleInput = useCallback(() => {
2967
+ if (editorRef.current && onChange) {
2968
+ onChange(editorRef.current.innerHTML);
2969
+ }
2970
+ updateActiveFormats();
2971
+ }, [onChange, updateActiveFormats]);
2972
+ const handleFormat = useCallback((command) => {
2973
+ if (disabled) return;
2974
+ document.execCommand(command, false);
2975
+ editorRef.current?.focus();
2976
+ updateActiveFormats();
2977
+ handleInput();
2978
+ }, [disabled, updateActiveFormats, handleInput]);
2979
+ const handleList = useCallback((command) => {
2980
+ if (disabled) return;
2981
+ document.execCommand(command, false);
2982
+ editorRef.current?.focus();
2983
+ updateActiveFormats();
2984
+ handleInput();
2985
+ }, [disabled, updateActiveFormats, handleInput]);
2986
+ const handleHeading = useCallback((level) => {
2987
+ if (disabled) return;
2988
+ document.execCommand("formatBlock", false, level);
2989
+ editorRef.current?.focus();
2990
+ updateActiveFormats();
2991
+ handleInput();
2992
+ }, [disabled, updateActiveFormats, handleInput]);
2993
+ const handleLink = useCallback(() => {
2994
+ if (disabled) return;
2995
+ setShowLinkModal(true);
2996
+ }, [disabled]);
2997
+ const insertLink = useCallback(() => {
2998
+ if (linkUrl) {
2999
+ document.execCommand("createLink", false, linkUrl);
3000
+ setShowLinkModal(false);
3001
+ setLinkUrl("");
3002
+ editorRef.current?.focus();
3003
+ handleInput();
3004
+ }
3005
+ }, [linkUrl, handleInput]);
3006
+ const handleCode = useCallback(() => {
3007
+ if (disabled) return;
3008
+ const selection = window.getSelection();
3009
+ if (selection && selection.rangeCount > 0) {
3010
+ const range = selection.getRangeAt(0);
3011
+ const code = document.createElement("code");
3012
+ code.className = "bg-gray-100 dark:bg-gray-700 px-1.5 py-0.5 rounded text-sm font-mono";
3013
+ try {
3014
+ range.surroundContents(code);
3015
+ handleInput();
3016
+ } catch (e) {
3017
+ console.warn("Could not apply code formatting");
3018
+ }
3019
+ }
3020
+ editorRef.current?.focus();
3021
+ }, [disabled, handleInput]);
3022
+ const handleImage = useCallback(() => {
3023
+ if (disabled) return;
3024
+ setShowImageModal(true);
3025
+ }, [disabled]);
3026
+ const insertImage = useCallback(() => {
3027
+ if (!imageUrl) return;
3028
+ const img = document.createElement("img");
3029
+ img.src = imageUrl;
3030
+ img.alt = imageAlt || "";
3031
+ img.style.maxWidth = "100%";
3032
+ img.style.height = "auto";
3033
+ const selection = window.getSelection();
3034
+ if (selection && selection.rangeCount > 0) {
3035
+ const range = selection.getRangeAt(0);
3036
+ range.deleteContents();
3037
+ range.insertNode(img);
3038
+ range.setStartAfter(img);
3039
+ range.setEndAfter(img);
3040
+ selection.removeAllRanges();
3041
+ selection.addRange(range);
3042
+ } else if (editorRef.current) {
3043
+ editorRef.current.appendChild(img);
3044
+ }
3045
+ setShowImageModal(false);
3046
+ setImageUrl("");
3047
+ setImageAlt("");
3048
+ editorRef.current?.focus();
3049
+ handleInput();
3050
+ }, [imageUrl, imageAlt, handleInput, disabled]);
3051
+ const getButtonClass = (isActive) => {
3052
+ const baseClass = themeName === "minimalistic" ? "border border-white text-white transition-colors" : "border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 transition-colors";
3053
+ const activeClass = themeName === "minimalistic" ? "bg-white text-black" : "bg-blue-100 dark:bg-blue-900 border-blue-500 dark:border-blue-400";
3054
+ const hoverClass = themeName === "minimalistic" ? "hover:bg-white hover:text-black" : "hover:bg-gray-100 dark:hover:bg-gray-700";
3055
+ const disabledClass = disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer";
3056
+ return `px-2.5 py-1.5 rounded text-sm font-medium ${baseClass} ${isActive ? activeClass : hoverClass} ${disabledClass}`;
3057
+ };
3058
+ const editorBaseClass = themeName === "minimalistic" ? "bg-transparent border-2 border-white text-white placeholder:text-gray-500" : "bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 text-gray-900 dark:text-gray-100";
3059
+ const focusClass = isFocused && !disabled ? themeName === "minimalistic" ? "border-white" : "border-blue-500 dark:border-blue-400 ring-2 ring-blue-500/20" : "";
3060
+ const errorClass = error ? "border-red-500 dark:border-red-400" : "";
3061
+ return /* @__PURE__ */ jsxs26("div", { className: `w-full ${className}`, children: [
3062
+ label && /* @__PURE__ */ jsx61("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2", children: label }),
3063
+ /* @__PURE__ */ jsxs26("div", { className: `rounded-t-lg border-b ${editorBaseClass} p-2 flex flex-wrap gap-1`, children: [
3064
+ /* @__PURE__ */ jsxs26("div", { className: "flex gap-1", children: [
3065
+ /* @__PURE__ */ jsx61(
3066
+ "button",
3067
+ {
3068
+ type: "button",
3069
+ onClick: () => handleFormat("bold"),
3070
+ className: getButtonClass(activeFormats.has("bold")),
3071
+ disabled,
3072
+ title: "Bold (Ctrl+B)",
3073
+ children: /* @__PURE__ */ jsx61("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx61("path", { d: "M12.78 4c1.09 0 2.04.38 2.84 1.14.8.76 1.2 1.74 1.2 2.94 0 .9-.25 1.68-.76 2.36-.51.68-1.2 1.14-2.04 1.38v.08c1.06.22 1.89.7 2.48 1.44.59.74.88 1.64.88 2.7 0 1.34-.47 2.43-1.41 3.27C14.96 19.77 13.74 20 12.24 20H4V4h8.78zm-.66 7.14c.62 0 1.12-.18 1.5-.54.38-.36.57-.84.57-1.44 0-.6-.19-1.08-.57-1.44-.38-.36-.88-.54-1.5-.54H7.5v3.96h4.62zm.24 6.86c.68 0 1.24-.19 1.68-.57.44-.38.66-.9.66-1.56 0-.66-.22-1.18-.66-1.56-.44-.38-1-.57-1.68-.57H7.5v4.26h4.86z" }) })
3074
+ }
3075
+ ),
3076
+ /* @__PURE__ */ jsx61(
3077
+ "button",
3078
+ {
3079
+ type: "button",
3080
+ onClick: () => handleFormat("italic"),
3081
+ className: getButtonClass(activeFormats.has("italic")),
3082
+ disabled,
3083
+ title: "Italic (Ctrl+I)",
3084
+ children: /* @__PURE__ */ jsx61("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx61("path", { d: "M11.59 4H16v2h-1.71l-3.58 8H13v2H8v-2h1.71l3.58-8H11.59V4z" }) })
3085
+ }
3086
+ ),
3087
+ /* @__PURE__ */ jsx61(
3088
+ "button",
3089
+ {
3090
+ type: "button",
3091
+ onClick: () => handleFormat("underline"),
3092
+ className: getButtonClass(activeFormats.has("underline")),
3093
+ disabled,
3094
+ title: "Underline (Ctrl+U)",
3095
+ children: /* @__PURE__ */ jsx61("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx61("path", { d: "M10 16c-2.21 0-4-1.79-4-4V4h2v8c0 1.1.9 2 2 2s2-.9 2-2V4h2v8c0 2.21-1.79 4-4 4zM4 18h12v2H4v-2z" }) })
3096
+ }
3097
+ ),
3098
+ /* @__PURE__ */ jsx61(
3099
+ "button",
3100
+ {
3101
+ type: "button",
3102
+ onClick: () => handleFormat("strikeThrough"),
3103
+ className: getButtonClass(activeFormats.has("strikeThrough")),
3104
+ disabled,
3105
+ title: "Strikethrough",
3106
+ children: /* @__PURE__ */ jsx61("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx61("path", { d: "M10 4c-2 0-3.5.5-4.5 1.5S4 7.5 4 9h2c0-.7.2-1.2.6-1.6.4-.4 1-.6 1.9-.6.8 0 1.4.2 1.8.5.4.3.7.8.7 1.4 0 .5-.2.9-.5 1.2-.3.3-.9.6-1.8.9l-.7.2c-1.2.3-2.1.7-2.7 1.2C4.2 12.7 4 13.5 4 14.5c0 1.1.4 2 1.1 2.6.7.6 1.7.9 3 .9 2.1 0 3.6-.5 4.6-1.5.9-1 1.3-2.3 1.3-3.8h-2c0 .9-.2 1.6-.7 2.1-.5.5-1.2.7-2.2.7-.8 0-1.4-.2-1.8-.5-.4-.3-.6-.8-.6-1.4 0-.5.2-.9.5-1.2.3-.3.9-.6 1.8-.9l.7-.2c1.2-.3 2.1-.7 2.7-1.2.6-.5.9-1.3.9-2.3 0-1.2-.4-2.1-1.2-2.8-.8-.7-1.9-1-3.3-1zM2 10h16v1H2v-1z" }) })
3107
+ }
3108
+ )
3109
+ ] }),
3110
+ /* @__PURE__ */ jsx61("div", { className: "w-px bg-gray-300 dark:bg-gray-600 mx-1" }),
3111
+ /* @__PURE__ */ jsxs26("div", { className: "flex gap-1", children: [
3112
+ /* @__PURE__ */ jsx61(
3113
+ "button",
3114
+ {
3115
+ type: "button",
3116
+ onClick: () => handleHeading("h1"),
3117
+ className: getButtonClass(activeFormats.has("h1")),
3118
+ disabled,
3119
+ title: "Heading 1",
3120
+ children: /* @__PURE__ */ jsx61("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx61("text", { x: "2", y: "16", fontSize: "14", fontWeight: "bold", children: "H1" }) })
3121
+ }
3122
+ ),
3123
+ /* @__PURE__ */ jsx61(
3124
+ "button",
3125
+ {
3126
+ type: "button",
3127
+ onClick: () => handleHeading("h2"),
3128
+ className: getButtonClass(activeFormats.has("h2")),
3129
+ disabled,
3130
+ title: "Heading 2",
3131
+ children: /* @__PURE__ */ jsx61("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx61("text", { x: "2", y: "16", fontSize: "14", fontWeight: "bold", children: "H2" }) })
3132
+ }
3133
+ ),
3134
+ /* @__PURE__ */ jsx61(
3135
+ "button",
3136
+ {
3137
+ type: "button",
3138
+ onClick: () => handleHeading("h3"),
3139
+ className: getButtonClass(activeFormats.has("h3")),
3140
+ disabled,
3141
+ title: "Heading 3",
3142
+ children: /* @__PURE__ */ jsx61("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx61("text", { x: "2", y: "16", fontSize: "14", fontWeight: "bold", children: "H3" }) })
3143
+ }
3144
+ )
3145
+ ] }),
3146
+ /* @__PURE__ */ jsx61("div", { className: "w-px bg-gray-300 dark:bg-gray-600 mx-1" }),
3147
+ /* @__PURE__ */ jsxs26("div", { className: "flex gap-1", children: [
3148
+ /* @__PURE__ */ jsx61(
3149
+ "button",
3150
+ {
3151
+ type: "button",
3152
+ onClick: () => handleList("insertUnorderedList"),
3153
+ className: getButtonClass(activeFormats.has("ul")),
3154
+ disabled,
3155
+ title: "Bullet List",
3156
+ children: /* @__PURE__ */ jsx61("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx61("path", { d: "M4 4h2v2H4V4zm4 0h8v2H8V4zM4 8h2v2H4V8zm4 0h8v2H8V8zm-4 4h2v2H4v-2zm4 0h8v2H8v-2zm-4 4h2v2H4v-2zm4 0h8v2H8v-2z" }) })
3157
+ }
3158
+ ),
3159
+ /* @__PURE__ */ jsx61(
3160
+ "button",
3161
+ {
3162
+ type: "button",
3163
+ onClick: () => handleList("insertOrderedList"),
3164
+ className: getButtonClass(activeFormats.has("ol")),
3165
+ disabled,
3166
+ title: "Numbered List",
3167
+ children: /* @__PURE__ */ jsx61("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx61("path", { d: "M4 4h1v3H4V4zm0 4h1v1H3V8h2v1H4zm1 2H3v1h2v1H3v1h2v-3zM8 4h8v2H8V4zm0 4h8v2H8V8zm0 4h8v2H8v-2zm0 4h8v2H8v-2z" }) })
3168
+ }
3169
+ )
3170
+ ] }),
3171
+ /* @__PURE__ */ jsx61("div", { className: "w-px bg-gray-300 dark:bg-gray-600 mx-1" }),
3172
+ /* @__PURE__ */ jsxs26("div", { className: "flex gap-1", children: [
3173
+ /* @__PURE__ */ jsx61(
3174
+ "button",
3175
+ {
3176
+ type: "button",
3177
+ onClick: handleLink,
3178
+ className: getButtonClass(false),
3179
+ disabled,
3180
+ title: "Insert Link",
3181
+ children: /* @__PURE__ */ jsx61("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx61("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" }) })
3182
+ }
3183
+ ),
3184
+ /* @__PURE__ */ jsx61(
3185
+ "button",
3186
+ {
3187
+ type: "button",
3188
+ onClick: handleImage,
3189
+ className: getButtonClass(false),
3190
+ disabled,
3191
+ title: "Insert Image/Video",
3192
+ children: /* @__PURE__ */ jsx61("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx61("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) })
3193
+ }
3194
+ ),
3195
+ /* @__PURE__ */ jsx61(
3196
+ "button",
3197
+ {
3198
+ type: "button",
3199
+ onClick: handleCode,
3200
+ className: getButtonClass(false),
3201
+ disabled,
3202
+ title: "Code",
3203
+ children: /* @__PURE__ */ jsx61("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx61("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" }) })
3204
+ }
3205
+ )
3206
+ ] })
3207
+ ] }),
3208
+ /* @__PURE__ */ jsx61(
3209
+ "div",
3210
+ {
3211
+ ref: editorRef,
3212
+ contentEditable: !disabled,
3213
+ onInput: handleInput,
3214
+ onFocus: () => setIsFocused(true),
3215
+ onBlur: () => setIsFocused(false),
3216
+ onMouseUp: updateActiveFormats,
3217
+ onKeyUp: updateActiveFormats,
3218
+ dangerouslySetInnerHTML: { __html: value },
3219
+ className: `
3220
+ w-full px-4 py-3 rounded-b-lg outline-none overflow-y-auto
3221
+ ${editorBaseClass} ${focusClass} ${errorClass}
3222
+ ${disabled ? "opacity-50 cursor-not-allowed" : ""}
3223
+ prose prose-sm dark:prose-invert max-w-none
3224
+ `,
3225
+ style: {
3226
+ minHeight,
3227
+ maxHeight
3228
+ },
3229
+ "data-placeholder": placeholder,
3230
+ suppressContentEditableWarning: true
3231
+ }
3232
+ ),
3233
+ error && /* @__PURE__ */ jsx61("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error }),
3234
+ helperText && !error && /* @__PURE__ */ jsx61("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: helperText }),
3235
+ /* @__PURE__ */ jsx61(
3236
+ Modal,
3237
+ {
3238
+ isOpen: showLinkModal,
3239
+ onClose: () => {
3240
+ setShowLinkModal(false);
3241
+ setLinkUrl("");
3242
+ },
3243
+ title: "Insert Link",
3244
+ size: "sm",
3245
+ children: /* @__PURE__ */ jsxs26("div", { className: "space-y-4", children: [
3246
+ /* @__PURE__ */ jsx61(
3247
+ TextInput,
3248
+ {
3249
+ label: "URL",
3250
+ value: linkUrl,
3251
+ onChange: (e) => setLinkUrl(e.target.value),
3252
+ placeholder: "https://example.com",
3253
+ autoFocus: true,
3254
+ onKeyDown: (e) => {
3255
+ if (e.key === "Enter") {
3256
+ e.preventDefault();
3257
+ insertLink();
3258
+ }
3259
+ }
3260
+ }
3261
+ ),
3262
+ /* @__PURE__ */ jsxs26("div", { className: "flex gap-2 justify-end", children: [
3263
+ /* @__PURE__ */ jsx61(
3264
+ Button,
3265
+ {
3266
+ variant: "secondary",
3267
+ onClick: () => {
3268
+ setShowLinkModal(false);
3269
+ setLinkUrl("");
3270
+ },
3271
+ children: "Cancel"
3272
+ }
3273
+ ),
3274
+ /* @__PURE__ */ jsx61(
3275
+ Button,
3276
+ {
3277
+ variant: "primary",
3278
+ onClick: insertLink,
3279
+ disabled: !linkUrl,
3280
+ children: "Insert"
3281
+ }
3282
+ )
3283
+ ] })
3284
+ ] })
3285
+ }
3286
+ ),
3287
+ /* @__PURE__ */ jsx61(
3288
+ Modal,
3289
+ {
3290
+ isOpen: showImageModal,
3291
+ onClose: () => {
3292
+ setShowImageModal(false);
3293
+ setImageUrl("");
3294
+ setImageAlt("");
3295
+ },
3296
+ title: "Insert Image",
3297
+ size: "sm",
3298
+ children: /* @__PURE__ */ jsxs26("div", { className: "space-y-4", children: [
3299
+ /* @__PURE__ */ jsx61(
3300
+ TextInput,
3301
+ {
3302
+ label: "Image URL",
3303
+ value: imageUrl,
3304
+ onChange: (e) => setImageUrl(e.target.value),
3305
+ placeholder: "https://example.com/image.jpg",
3306
+ autoFocus: true,
3307
+ onKeyDown: (e) => {
3308
+ if (e.key === "Enter") {
3309
+ e.preventDefault();
3310
+ insertImage();
3311
+ }
3312
+ }
3313
+ }
3314
+ ),
3315
+ /* @__PURE__ */ jsx61(
3316
+ TextInput,
3317
+ {
3318
+ label: "Alt Text (optional)",
3319
+ value: imageAlt,
3320
+ onChange: (e) => setImageAlt(e.target.value),
3321
+ placeholder: "Describe the image"
3322
+ }
3323
+ ),
3324
+ /* @__PURE__ */ jsxs26("div", { className: "flex gap-2 justify-end", children: [
3325
+ /* @__PURE__ */ jsx61(
3326
+ Button,
3327
+ {
3328
+ variant: "secondary",
3329
+ onClick: () => {
3330
+ setShowImageModal(false);
3331
+ setImageUrl("");
3332
+ setImageAlt("");
3333
+ },
3334
+ children: "Cancel"
3335
+ }
3336
+ ),
3337
+ /* @__PURE__ */ jsx61(
3338
+ Button,
3339
+ {
3340
+ variant: "primary",
3341
+ onClick: insertImage,
3342
+ disabled: !imageUrl,
3343
+ children: "Insert"
3344
+ }
3345
+ )
3346
+ ] })
3347
+ ] })
3348
+ }
3349
+ )
3350
+ ] });
3351
+ };
3352
+
3353
+ // src/components/Toast.tsx
3354
+ import { createContext as createContext3, useContext as useContext3, useState as useState13, useCallback as useCallback2 } from "react";
3355
+ import { jsx as jsx62, jsxs as jsxs27 } from "react/jsx-runtime";
3356
+ var ToastContext = createContext3(void 0);
3357
+ var useToast = () => {
3358
+ const context = useContext3(ToastContext);
3359
+ if (!context) {
3360
+ throw new Error("useToast must be used within a ToastProvider");
3361
+ }
3362
+ return context;
3363
+ };
3364
+ var ToastProvider = ({ children, position = "top-right" }) => {
3365
+ const [toasts, setToasts] = useState13([]);
3366
+ const addToast = useCallback2((toast2) => {
3367
+ const id = Math.random().toString(36).substring(7);
3368
+ const newToast = { ...toast2, id };
3369
+ setToasts((prev) => [...prev, newToast]);
3370
+ const duration = toast2.duration || 5e3;
3371
+ setTimeout(() => {
3372
+ removeToast(id);
3373
+ }, duration);
3374
+ }, []);
3375
+ const removeToast = useCallback2((id) => {
3376
+ setToasts((prev) => prev.filter((toast2) => toast2.id !== id));
3377
+ }, []);
3378
+ const positionClasses2 = {
3379
+ "top-right": "top-4 right-4",
3380
+ "top-left": "top-4 left-4",
3381
+ "bottom-right": "bottom-4 right-4",
3382
+ "bottom-left": "bottom-4 left-4",
3383
+ "top-center": "top-4 left-1/2 -translate-x-1/2",
3384
+ "bottom-center": "bottom-4 left-1/2 -translate-x-1/2"
3385
+ };
3386
+ return /* @__PURE__ */ jsxs27(ToastContext.Provider, { value: { toasts, addToast, removeToast }, children: [
3387
+ children,
3388
+ /* @__PURE__ */ jsx62("div", { className: `fixed ${positionClasses2[position]} z-50 flex flex-col gap-2 max-w-md`, children: toasts.map((toast2) => /* @__PURE__ */ jsx62(ToastItem, { toast: toast2, onClose: () => removeToast(toast2.id) }, toast2.id)) })
3389
+ ] });
3390
+ };
3391
+ var ToastItem = ({ toast: toast2, onClose }) => {
3392
+ const typeStyles = {
3393
+ success: "bg-green-50 dark:bg-green-900/30 border-green-500 text-green-800 dark:text-green-200",
3394
+ error: "bg-red-50 dark:bg-red-900/30 border-red-500 text-red-800 dark:text-red-200",
3395
+ warning: "bg-yellow-50 dark:bg-yellow-900/30 border-yellow-500 text-yellow-800 dark:text-yellow-200",
3396
+ info: "bg-blue-50 dark:bg-blue-900/30 border-blue-500 text-blue-800 dark:text-blue-200"
3397
+ };
3398
+ const typeIcons = {
3399
+ success: /* @__PURE__ */ jsx62(CheckIcon, { size: "sm", className: "text-green-600 dark:text-green-400" }),
3400
+ error: /* @__PURE__ */ jsx62(CloseIcon, { size: "sm", className: "text-red-600 dark:text-red-400" }),
3401
+ warning: /* @__PURE__ */ jsx62("svg", { className: "w-4 h-4 text-yellow-600 dark:text-yellow-400", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx62("path", { fillRule: "evenodd", d: "M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z", clipRule: "evenodd" }) }),
3402
+ info: /* @__PURE__ */ jsx62("svg", { className: "w-4 h-4 text-blue-600 dark:text-blue-400", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx62("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }) })
3403
+ };
3404
+ const type = toast2.type || "info";
3405
+ return /* @__PURE__ */ jsxs27(
3406
+ "div",
3407
+ {
3408
+ className: `flex items-start gap-3 p-4 rounded-lg border-l-4 shadow-lg backdrop-blur-sm ${typeStyles[type]} animate-slide-in`,
3409
+ role: "alert",
3410
+ children: [
3411
+ /* @__PURE__ */ jsx62("div", { className: "flex-shrink-0 mt-0.5", children: typeIcons[type] }),
3412
+ /* @__PURE__ */ jsx62("p", { className: "flex-1 text-sm font-medium", children: toast2.message }),
3413
+ /* @__PURE__ */ jsx62(
3414
+ "button",
3415
+ {
3416
+ onClick: onClose,
3417
+ className: "flex-shrink-0 text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 transition-colors",
3418
+ "aria-label": "Close",
3419
+ children: /* @__PURE__ */ jsx62(CloseIcon, { size: "sm" })
3420
+ }
3421
+ )
3422
+ ]
3423
+ }
3424
+ );
3425
+ };
3426
+ var toast = {
3427
+ success: (message, duration) => ({
3428
+ message,
3429
+ type: "success",
3430
+ duration
3431
+ }),
3432
+ error: (message, duration) => ({
3433
+ message,
3434
+ type: "error",
3435
+ duration
3436
+ }),
3437
+ warning: (message, duration) => ({
3438
+ message,
3439
+ type: "warning",
3440
+ duration
3441
+ }),
3442
+ info: (message, duration) => ({
3443
+ message,
3444
+ type: "info",
3445
+ duration
3446
+ })
3447
+ };
3448
+
3449
+ // src/components/Stepper.tsx
3450
+ import React22 from "react";
3451
+ import { jsx as jsx63, jsxs as jsxs28 } from "react/jsx-runtime";
3452
+ var Stepper = ({
3453
+ steps,
3454
+ currentStep,
3455
+ orientation = "horizontal",
3456
+ className = ""
3457
+ }) => {
3458
+ const isHorizontal = orientation === "horizontal";
3459
+ return /* @__PURE__ */ jsx63("div", { className: `${isHorizontal ? "flex items-center" : "flex flex-col"} ${className}`, children: steps.map((step, index) => {
3460
+ const stepNumber = index + 1;
3461
+ const isActive = stepNumber === currentStep;
3462
+ const isCompleted = stepNumber < currentStep;
3463
+ const isLast = index === steps.length - 1;
3464
+ return /* @__PURE__ */ jsxs28(React22.Fragment, { children: [
3465
+ /* @__PURE__ */ jsxs28("div", { className: `flex ${isHorizontal ? "flex-col items-center" : "flex-row items-start"} ${isHorizontal ? "" : "flex-1"}`, children: [
3466
+ /* @__PURE__ */ jsx63("div", { className: "flex items-center", children: /* @__PURE__ */ jsx63(
3467
+ "div",
3468
+ {
3469
+ className: `flex items-center justify-center w-10 h-10 rounded-full border-2 transition-all ${isCompleted ? "bg-blue-600 border-blue-600 dark:bg-blue-500 dark:border-blue-500" : isActive ? "border-blue-600 bg-white dark:border-blue-500 dark:bg-gray-800" : "border-gray-300 bg-white dark:border-gray-600 dark:bg-gray-800"}`,
3470
+ children: isCompleted ? /* @__PURE__ */ jsx63(CheckIcon, { size: "sm", className: "text-white" }) : /* @__PURE__ */ jsx63(
3471
+ "span",
3472
+ {
3473
+ className: `text-sm font-semibold ${isActive ? "text-blue-600 dark:text-blue-400" : "text-gray-500 dark:text-gray-400"}`,
3474
+ children: stepNumber
3475
+ }
3476
+ )
3477
+ }
3478
+ ) }),
3479
+ /* @__PURE__ */ jsxs28("div", { className: `${isHorizontal ? "mt-2 text-center" : "ml-4 pb-8"} ${isLast && !isHorizontal ? "pb-0" : ""}`, children: [
3480
+ /* @__PURE__ */ jsx63(
3481
+ "p",
3482
+ {
3483
+ className: `text-sm font-medium ${isActive || isCompleted ? "text-gray-900 dark:text-gray-100" : "text-gray-500 dark:text-gray-400"}`,
3484
+ children: step.label
3485
+ }
3486
+ ),
3487
+ step.description && /* @__PURE__ */ jsx63("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: step.description })
3488
+ ] })
3489
+ ] }),
3490
+ !isLast && /* @__PURE__ */ jsx63(
3491
+ "div",
3492
+ {
3493
+ className: `${isHorizontal ? "flex-1 h-0.5 mx-4" : "w-0.5 h-full ml-5 -mt-8"} ${isCompleted || isActive && stepNumber < currentStep ? "bg-blue-600 dark:bg-blue-500" : "bg-gray-300 dark:bg-gray-600"}`
3494
+ }
3495
+ )
3496
+ ] }, index);
3497
+ }) });
3498
+ };
3499
+
3500
+ // src/components/Divider.tsx
3501
+ import { jsx as jsx64, jsxs as jsxs29 } from "react/jsx-runtime";
3502
+ var Divider = ({
3503
+ orientation = "horizontal",
3504
+ variant = "solid",
3505
+ className = "",
3506
+ label,
3507
+ labelPosition = "center"
3508
+ }) => {
3509
+ const variantClasses = {
3510
+ solid: "border-solid",
3511
+ dashed: "border-dashed",
3512
+ dotted: "border-dotted"
3513
+ };
3514
+ if (label && orientation === "horizontal") {
3515
+ const alignmentClasses = {
3516
+ left: "justify-start",
3517
+ center: "justify-center",
3518
+ right: "justify-end"
3519
+ };
3520
+ return /* @__PURE__ */ jsxs29("div", { className: `flex items-center ${alignmentClasses[labelPosition]} ${className}`, role: "separator", children: [
3521
+ labelPosition !== "left" && /* @__PURE__ */ jsx64("div", { className: `flex-1 border-t ${variantClasses[variant]} border-gray-300 dark:border-gray-600` }),
3522
+ /* @__PURE__ */ jsx64("span", { className: "px-4 text-sm text-gray-500 dark:text-gray-400", children: label }),
3523
+ labelPosition !== "right" && /* @__PURE__ */ jsx64("div", { className: `flex-1 border-t ${variantClasses[variant]} border-gray-300 dark:border-gray-600` })
3524
+ ] });
3525
+ }
3526
+ if (orientation === "vertical") {
3527
+ return /* @__PURE__ */ jsx64(
3528
+ "div",
3529
+ {
3530
+ className: `inline-block h-full border-l ${variantClasses[variant]} border-gray-300 dark:border-gray-600 ${className}`,
3531
+ role: "separator",
3532
+ "aria-orientation": "vertical"
3533
+ }
3534
+ );
3535
+ }
3536
+ return /* @__PURE__ */ jsx64(
3537
+ "hr",
3538
+ {
3539
+ className: `border-t ${variantClasses[variant]} border-gray-300 dark:border-gray-600 ${className}`,
3540
+ role: "separator"
3541
+ }
3542
+ );
3543
+ };
3544
+
3545
+ // src/components/FileUpload.tsx
3546
+ import { useRef as useRef8, useState as useState14 } from "react";
3547
+ import { jsx as jsx65, jsxs as jsxs30 } from "react/jsx-runtime";
3548
+ var FileUpload = ({
3549
+ accept,
3550
+ multiple = false,
3551
+ maxSize,
3552
+ maxFiles = 10,
3553
+ disabled = false,
3554
+ onChange,
3555
+ onError,
3556
+ className = "",
3557
+ label,
3558
+ helperText
3559
+ }) => {
3560
+ const [files, setFiles] = useState14([]);
3561
+ const [isDragging, setIsDragging] = useState14(false);
3562
+ const fileInputRef = useRef8(null);
3563
+ const formatFileSize = (bytes) => {
3564
+ if (bytes === 0) return "0 Bytes";
3565
+ const k = 1024;
3566
+ const sizes = ["Bytes", "KB", "MB", "GB"];
3567
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
3568
+ return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i];
3569
+ };
3570
+ const validateFiles = (fileList) => {
3571
+ const validFiles = [];
3572
+ const filesArray = Array.from(fileList);
3573
+ if (filesArray.length + files.length > maxFiles) {
3574
+ onError?.(`Maximum ${maxFiles} files allowed`);
3575
+ return validFiles;
3576
+ }
3577
+ for (const file of filesArray) {
3578
+ if (maxSize && file.size > maxSize) {
3579
+ onError?.(`File ${file.name} exceeds maximum size of ${formatFileSize(maxSize)}`);
3580
+ continue;
3581
+ }
3582
+ validFiles.push(file);
3583
+ }
3584
+ return validFiles;
3585
+ };
3586
+ const handleFiles = (fileList) => {
3587
+ if (!fileList || disabled) return;
3588
+ const validFiles = validateFiles(fileList);
3589
+ if (validFiles.length > 0) {
3590
+ const newFiles = multiple ? [...files, ...validFiles] : validFiles;
3591
+ setFiles(newFiles);
3592
+ onChange?.(newFiles);
3593
+ }
3594
+ };
3595
+ const handleDrop = (e) => {
3596
+ e.preventDefault();
3597
+ setIsDragging(false);
3598
+ handleFiles(e.dataTransfer.files);
3599
+ };
3600
+ const handleDragOver = (e) => {
3601
+ e.preventDefault();
3602
+ if (!disabled) {
3603
+ setIsDragging(true);
3604
+ }
3605
+ };
3606
+ const handleDragLeave = (e) => {
3607
+ e.preventDefault();
3608
+ setIsDragging(false);
3609
+ };
3610
+ const handleClick = () => {
3611
+ if (!disabled) {
3612
+ fileInputRef.current?.click();
3613
+ }
3614
+ };
3615
+ const handleRemoveFile = (index) => {
3616
+ const newFiles = files.filter((_, i) => i !== index);
3617
+ setFiles(newFiles);
3618
+ onChange?.(newFiles);
3619
+ };
3620
+ return /* @__PURE__ */ jsxs30("div", { className: `w-full ${className}`, children: [
3621
+ label && /* @__PURE__ */ jsx65("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2", children: label }),
3622
+ /* @__PURE__ */ jsxs30(
3623
+ "div",
3624
+ {
3625
+ onDrop: handleDrop,
3626
+ onDragOver: handleDragOver,
3627
+ onDragLeave: handleDragLeave,
3628
+ onClick: handleClick,
3629
+ className: `relative border-2 border-dashed rounded-lg p-8 text-center cursor-pointer transition-all ${isDragging ? "border-blue-500 bg-blue-50 dark:bg-blue-900/20" : "border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500"} ${disabled ? "opacity-50 cursor-not-allowed" : ""}`,
3630
+ children: [
3631
+ /* @__PURE__ */ jsx65(
3632
+ "input",
3633
+ {
3634
+ ref: fileInputRef,
3635
+ type: "file",
3636
+ accept,
3637
+ multiple,
3638
+ onChange: (e) => handleFiles(e.target.files),
3639
+ disabled,
3640
+ className: "hidden"
3641
+ }
3642
+ ),
3643
+ /* @__PURE__ */ jsxs30("div", { className: "flex flex-col items-center gap-2", children: [
3644
+ /* @__PURE__ */ jsx65("div", { className: "w-12 h-12 rounded-full bg-gray-100 dark:bg-gray-800 flex items-center justify-center", children: /* @__PURE__ */ jsx65(UploadIcon, { size: "lg", className: "text-gray-400 dark:text-gray-500" }) }),
3645
+ /* @__PURE__ */ jsxs30("div", { children: [
3646
+ /* @__PURE__ */ jsxs30("p", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: [
3647
+ /* @__PURE__ */ jsx65("span", { className: "text-blue-600 dark:text-blue-400", children: "Click to upload" }),
3648
+ " or drag and drop"
3649
+ ] }),
3650
+ /* @__PURE__ */ jsxs30("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: [
3651
+ accept ? `Accepted: ${accept}` : "Any file type",
3652
+ maxSize && ` \u2022 Max size: ${formatFileSize(maxSize)}`
3653
+ ] })
3654
+ ] })
3655
+ ] })
3656
+ ]
3657
+ }
3658
+ ),
3659
+ helperText && /* @__PURE__ */ jsx65("p", { className: "mt-2 text-sm text-gray-500 dark:text-gray-400", children: helperText }),
3660
+ files.length > 0 && /* @__PURE__ */ jsx65("div", { className: "mt-4 space-y-2", children: files.map((file, index) => /* @__PURE__ */ jsxs30(
3661
+ "div",
3662
+ {
3663
+ className: "flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700",
3664
+ children: [
3665
+ /* @__PURE__ */ jsxs30("div", { className: "flex-1 min-w-0", children: [
3666
+ /* @__PURE__ */ jsx65("p", { className: "text-sm font-medium text-gray-900 dark:text-gray-100 truncate", children: file.name }),
3667
+ /* @__PURE__ */ jsx65("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: formatFileSize(file.size) })
3668
+ ] }),
3669
+ /* @__PURE__ */ jsx65(
3670
+ "button",
3671
+ {
3672
+ onClick: (e) => {
3673
+ e.stopPropagation();
3674
+ handleRemoveFile(index);
3675
+ },
3676
+ className: "ml-4 text-gray-400 hover:text-red-600 dark:hover:text-red-400 transition-colors",
3677
+ "aria-label": "Remove file",
3678
+ children: /* @__PURE__ */ jsx65(CloseIcon, { size: "sm" })
3679
+ }
3680
+ )
3681
+ ]
3682
+ },
3683
+ index
3684
+ )) })
282
3685
  ] });
283
3686
  };
284
3687
 
@@ -315,12 +3718,76 @@ function getThemeScript() {
315
3718
  return themeScript;
316
3719
  }
317
3720
  export {
3721
+ ActionMenu,
3722
+ Alert,
3723
+ AppShell,
3724
+ AppleIcon,
3725
+ Avatar,
3726
+ Badge,
3727
+ BellIcon,
318
3728
  Button,
3729
+ Calendar,
3730
+ CalendarIcon,
3731
+ CameraIcon,
3732
+ Card,
3733
+ CheckIcon,
3734
+ Checkbox,
3735
+ ChevronDownIcon,
3736
+ ChevronRightIcon,
3737
+ CloseIcon,
3738
+ DatePicker,
3739
+ DateTimePicker,
3740
+ Divider,
3741
+ DownloadIcon,
3742
+ Drawer,
3743
+ EditIcon,
3744
+ FacebookIcon,
3745
+ FileUpload,
3746
+ GitHubIcon,
3747
+ GoogleIcon,
3748
+ HeartIcon,
3749
+ HomeIcon,
3750
+ LinkedInIcon,
3751
+ LockIcon,
3752
+ MailIcon,
3753
+ MenuIcon,
3754
+ Modal,
3755
+ Navbar,
3756
+ NumberInput,
3757
+ Pagination,
3758
+ PlusIcon,
3759
+ ProgressBar,
3760
+ Radio,
3761
+ RichTextEditor,
3762
+ SearchIcon,
319
3763
  Select,
3764
+ SettingsIcon,
3765
+ Sidebar,
3766
+ SidebarProvider,
3767
+ SlackIcon,
3768
+ Slider,
3769
+ Spinner,
3770
+ StarIcon,
3771
+ Stepper,
3772
+ Table,
3773
+ Tabs,
3774
+ TextInput,
3775
+ Textarea,
320
3776
  ThemeProvider,
3777
+ TimePicker,
3778
+ ToastProvider,
3779
+ Toggle,
3780
+ TrashIcon,
3781
+ TwitterIcon,
3782
+ UploadIcon,
3783
+ UserIcon,
3784
+ YouTubeIcon,
321
3785
  getThemeScript,
322
3786
  themeScript,
323
3787
  themes,
324
- useTheme
3788
+ toast,
3789
+ useSidebar,
3790
+ useTheme,
3791
+ useToast
325
3792
  };
326
3793
  //# sourceMappingURL=index.mjs.map