neogestify-ui-components 2.2.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +803 -349
  3. package/dist/components/ElementLibraryBuilder/index.js +299 -120
  4. package/dist/components/ElementLibraryBuilder/index.js.map +1 -1
  5. package/dist/components/ElementLibraryBuilder/index.mjs +300 -121
  6. package/dist/components/ElementLibraryBuilder/index.mjs.map +1 -1
  7. package/dist/components/VenueMapEditor/index.js.map +1 -1
  8. package/dist/components/VenueMapEditor/index.mjs.map +1 -1
  9. package/dist/components/alerts/index.js +108 -51
  10. package/dist/components/alerts/index.js.map +1 -1
  11. package/dist/components/alerts/index.mjs +109 -52
  12. package/dist/components/alerts/index.mjs.map +1 -1
  13. package/dist/components/html/index.d.mts +123 -11
  14. package/dist/components/html/index.d.ts +123 -11
  15. package/dist/components/html/index.js +607 -144
  16. package/dist/components/html/index.js.map +1 -1
  17. package/dist/components/html/index.mjs +608 -145
  18. package/dist/components/html/index.mjs.map +1 -1
  19. package/dist/components/icons/index.d.mts +5 -1
  20. package/dist/components/icons/index.d.ts +5 -1
  21. package/dist/components/icons/index.js +16 -0
  22. package/dist/components/icons/index.js.map +1 -1
  23. package/dist/components/icons/index.mjs +13 -1
  24. package/dist/components/icons/index.mjs.map +1 -1
  25. package/dist/context/theme/index.js +59 -37
  26. package/dist/context/theme/index.js.map +1 -1
  27. package/dist/context/theme/index.mjs +59 -37
  28. package/dist/context/theme/index.mjs.map +1 -1
  29. package/dist/index.d.mts +1 -1
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.js +611 -144
  32. package/dist/index.js.map +1 -1
  33. package/dist/index.mjs +609 -146
  34. package/dist/index.mjs.map +1 -1
  35. package/package.json +1 -1
  36. package/src/components/html/Button.tsx +84 -38
  37. package/src/components/html/Form.tsx +33 -13
  38. package/src/components/html/Input.tsx +110 -31
  39. package/src/components/html/Loading.tsx +58 -33
  40. package/src/components/html/Modal.tsx +67 -20
  41. package/src/components/html/Select.tsx +92 -39
  42. package/src/components/html/Table.tsx +429 -38
  43. package/src/components/html/TextArea.tsx +81 -31
  44. package/src/components/icons/icons.tsx +32 -0
@@ -1,4 +1,4 @@
1
- import { forwardRef, useState, useEffect, useImperativeHandle, useMemo } from 'react';
1
+ import { forwardRef, useState, useRef, useEffect, useImperativeHandle, useMemo } from 'react';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
 
4
4
  // src/components/ElementLibraryBuilder/builder.tsx
@@ -36,56 +36,92 @@ function CloseIcon({ className }) {
36
36
  }
37
37
  ) });
38
38
  }
39
+ function ChevronDownIcon({ className }) {
40
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 16 16", className, fill: "currentColor", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M4.516 7.548c.436-.446 1.043-.481 1.576 0L8 9.747l1.908-2.199c.533-.481 1.14-.446 1.576 0 .436.445.408 1.197 0 1.615-.408.418-2.695 2.977-2.695 2.977-.27.282-.64.423-1.01.423s-.74-.14-1.01-.423c0 0-2.287-2.559-2.695-2.977-.408-.418-.436-1.17 0-1.615z" }) });
41
+ }
42
+ var BASE = "transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer inline-flex items-center gap-2";
43
+ var SIZE_PAD = {
44
+ sm: "px-2.5 py-1.5 text-xs",
45
+ md: "px-3 py-2 text-sm",
46
+ lg: "px-4 py-2.5 text-base"
47
+ };
48
+ var SIZE_ICON_PAD = {
49
+ sm: "p-1.5",
50
+ md: "p-2",
51
+ lg: "p-2.5"
52
+ };
53
+ var SHAPE_CLASS = {
54
+ rounded: "rounded-md",
55
+ pill: "rounded-full",
56
+ square: "rounded-none"
57
+ };
58
+ var VARIANT_STYLE = {
59
+ primary: "border border-indigo-600/20 dark:border-indigo-500/20 font-medium text-white bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-500 dark:hover:bg-indigo-600 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
60
+ secondary: "font-medium text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-200 dark:hover:bg-gray-800 border border-gray-300 dark:border-gray-600 shadow-sm hover:shadow-md focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
61
+ icon: "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-200 dark:hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
62
+ danger: "border border-red-600/20 dark:border-red-500/20 font-medium text-white bg-red-600 hover:bg-red-700 dark:bg-red-500 dark:hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500 dark:focus:ring-red-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
63
+ success: "border border-green-600/20 dark:border-green-500/20 font-medium text-white bg-green-600 hover:bg-green-700 dark:bg-green-500 dark:hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-500 dark:focus:ring-green-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
64
+ outline: "border border-gray-300 dark:border-gray-600 font-medium text-gray-700 dark:text-gray-300 bg-transparent hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
65
+ nav: "w-full px-4 py-2 text-sm font-medium hover:scale-105 text-gray-700 dark:text-gray-300 dark:hover:text-white hover:shadow-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
66
+ custom: "",
67
+ link: "text-sm text-indigo-600 dark:text-indigo-400 hover:text-indigo-700 dark:hover:text-indigo-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900 rounded-lg px-2",
68
+ warning: "border border-yellow-600/20 dark:border-yellow-500/20 font-medium text-white bg-yellow-600 hover:bg-yellow-700 dark:bg-yellow-500 dark:hover:bg-yellow-600 focus:outline-none focus:ring-2 focus:ring-yellow-500 dark:focus:ring-yellow-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
69
+ toggle: "font-medium border-2 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
70
+ ghost: "font-medium text-indigo-600 dark:text-indigo-400 bg-transparent border border-indigo-200 dark:border-indigo-800 hover:bg-indigo-50 dark:hover:bg-indigo-900/30 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900"
71
+ };
39
72
  var Button = ({
40
73
  variant = "primary",
41
74
  children,
42
75
  isLoading = false,
43
76
  loadingText,
44
77
  isActive = false,
78
+ size = "md",
79
+ leftIcon,
80
+ rightIcon,
81
+ fullWidth = false,
82
+ shape,
45
83
  className = "",
46
84
  disabled,
47
85
  ...props
48
86
  }) => {
49
- const baseClasses = "transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer";
50
- const variantClasses = {
51
- primary: "py-2 px-2 border border-indigo-600/20 dark:border-indigo-500/20 text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-500 dark:hover:bg-indigo-600 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
52
- secondary: "p-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-200 dark:hover:bg-gray-800 rounded-md border border-gray-300 dark:border-gray-600 shadow-sm hover:shadow-md focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
53
- icon: "p-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-200 dark:hover:bg-gray-800 rounded-full focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
54
- danger: "py-2 px-2 border border-red-600/20 dark:border-red-500/20 text-sm font-medium rounded-md text-white bg-red-600 hover:bg-red-700 dark:bg-red-500 dark:hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500 dark:focus:ring-red-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
55
- success: "py-2 px-2 border border-green-600/20 dark:border-green-500/20 text-sm font-medium rounded-md text-white bg-green-600 hover:bg-green-700 dark:bg-green-500 dark:hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-500 dark:focus:ring-green-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
56
- outline: "py-2 px-2 border border-gray-300 dark:border-gray-600 text-sm font-medium rounded-md text-gray-700 dark:text-gray-300 bg-transparent hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
57
- nav: "w-full flex items-center px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 hover:scale-105 text-gray-700 dark:text-gray-300 dark:hover:text-white hover:shadow-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
58
- custom: "",
59
- link: "text-sm text-indigo-600 dark:text-indigo-400 hover:text-indigo-700 dark:hover:text-indigo-300 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900 rounded-lg px-2",
60
- warning: "py-2 px-2 border border-yellow-600/20 dark:border-yellow-500/20 text-sm font-medium rounded-md text-white bg-yellow-600 hover:bg-yellow-700 dark:bg-yellow-500 dark:hover:bg-yellow-600 focus:outline-none focus:ring-2 focus:ring-yellow-500 dark:focus:ring-yellow-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900",
61
- toggle: "px-2 py-2 rounded-lg font-medium transition-all duration-200 disabled:cursor-not-allowed border-2 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900"
62
- };
63
- let classes = `${baseClasses} ${variantClasses[variant]} ${className}`;
64
- if (variant === "nav" && isActive) {
65
- classes += " bg-indigo-600 dark:bg-indigo-500 hover:bg-indigo-700 dark:hover:bg-indigo-600 text-white shadow-lg scale-105";
66
- }
67
- if (variant === "nav" && !isActive) {
68
- classes += " hover:bg-white dark:hover:bg-gray-700 hover:shadow-lg";
87
+ const sizeCls = variant === "icon" ? SIZE_ICON_PAD[size] : variant === "nav" || variant === "link" || variant === "custom" ? "" : SIZE_PAD[size];
88
+ const defaultShape = variant === "icon" ? "pill" : "rounded";
89
+ const shapeCls = variant === "link" || variant === "custom" ? "" : SHAPE_CLASS[shape ?? defaultShape];
90
+ let stateCls = "";
91
+ if (variant === "nav") {
92
+ stateCls = isActive ? "bg-indigo-600 dark:bg-indigo-500 hover:bg-indigo-700 dark:hover:bg-indigo-600 text-white shadow-lg scale-105" : "hover:bg-white dark:hover:bg-gray-700";
69
93
  }
70
94
  if (variant === "toggle") {
71
- if (isActive) {
72
- classes += " bg-indigo-600 text-white border-indigo-600/30 dark:border-indigo-500/30 hover:bg-indigo-700";
73
- } else {
74
- classes += " bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 border-gray-300 dark:border-gray-600 hover:bg-gray-300 dark:hover:bg-gray-600 hover:border-gray-400 dark:hover:border-gray-500";
75
- }
95
+ stateCls = isActive ? "bg-indigo-600 text-white border-indigo-600/30 dark:border-indigo-500/30 hover:bg-indigo-700" : "bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 border-gray-300 dark:border-gray-600 hover:bg-gray-300 dark:hover:bg-gray-600";
76
96
  }
77
- return /* @__PURE__ */ jsx(
78
- "button",
79
- {
80
- className: classes,
81
- disabled: disabled || isLoading,
82
- ...props,
83
- children: isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
84
- /* @__PURE__ */ jsx(AnimateSpin, { className: "h-5 w-5 mr-2 inline-block text-current" }),
85
- loadingText || "Cargando..."
86
- ] }) : children
87
- }
88
- );
97
+ const classes = [
98
+ BASE,
99
+ VARIANT_STYLE[variant],
100
+ sizeCls,
101
+ shapeCls,
102
+ stateCls,
103
+ fullWidth ? "w-full justify-center" : "",
104
+ className
105
+ ].filter(Boolean).join(" ");
106
+ return /* @__PURE__ */ jsx("button", { className: classes, disabled: disabled || isLoading, ...props, children: isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
107
+ /* @__PURE__ */ jsx(AnimateSpin, { className: "h-4 w-4 shrink-0 text-current" }),
108
+ loadingText ?? "Cargando..."
109
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
110
+ leftIcon && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: leftIcon }),
111
+ children,
112
+ rightIcon && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: rightIcon })
113
+ ] }) });
114
+ };
115
+ var SIZE_CLASSES = {
116
+ sm: "px-2.5 py-1.5 text-xs",
117
+ md: "px-3 py-2 text-sm",
118
+ lg: "px-4 py-2.5 text-base"
119
+ };
120
+ var VARIANT_CLASSES = {
121
+ default: "border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800",
122
+ outline: "border-2 border-indigo-300 dark:border-indigo-600 bg-transparent",
123
+ filled: "border border-gray-300 dark:border-gray-600 bg-gray-100 dark:bg-gray-700",
124
+ minimal: "border-0 border-b border-gray-300 dark:border-gray-600 bg-transparent rounded-none focus:ring-0"
89
125
  };
90
126
  var Input = ({
91
127
  label,
@@ -93,34 +129,63 @@ var Input = ({
93
129
  helperText,
94
130
  icon,
95
131
  iconSide = "left",
132
+ variant = "default",
133
+ size = "md",
134
+ prefix,
135
+ suffix,
136
+ clearable = false,
137
+ onClear,
96
138
  className = "",
97
139
  id,
98
140
  type,
99
141
  ...props
100
142
  }) => {
101
143
  const inputId = id || `input-${Math.random().toString(36).substring(2, 9)}`;
102
- const baseClasses = "appearance-none relative block w-full px-3 py-2 border placeholder-gray-500 dark:placeholder-gray-400 text-gray-900 dark:text-white bg-white dark:bg-gray-800 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:border-indigo-500 focus:z-10 sm:text-sm disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200";
103
- const errorClasses = error ? "border-red-300 dark:border-red-600 focus:ring-red-500 dark:focus:ring-red-400 focus:border-red-500" : "border-gray-300 dark:border-gray-600";
104
- const iconPaddingLeft = icon && iconSide === "left" ? "pl-9" : "";
105
- const iconPaddingRight = icon && iconSide === "right" ? "pr-9" : "";
106
- const classes = `${baseClasses} ${errorClasses} ${iconPaddingLeft} ${iconPaddingRight} ${className}`.trim();
107
- const toggleShape = type === "radio" ? "rounded-full" : "rounded";
108
- const toggleBaseClasses = `h-4 w-4 ${toggleShape} border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-indigo-600 dark:text-indigo-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-white dark:focus:ring-offset-gray-900 disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200 cursor-pointer`;
109
- const toggleErrorClasses = error ? "border-red-300 dark:border-red-600 focus:ring-red-500 dark:focus:ring-red-400" : "";
110
- const toggleClasses = `${toggleBaseClasses} ${toggleErrorClasses}`.trim();
111
- const fileBaseClasses = "block w-full sm:text-sm text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-800 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:border-indigo-500 disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200 file:mr-4 file:py-2 file:px-4 file:rounded-l-md file:border-0 file:text-sm file:font-medium file:bg-indigo-50 file:text-indigo-700 dark:file:bg-indigo-900/50 dark:file:text-indigo-300 hover:file:bg-indigo-100 dark:hover:file:bg-indigo-800/50 file:transition-colors file:duration-200 file:cursor-pointer";
112
- const fileErrorClasses = error ? "border-red-300 dark:border-red-600 focus:ring-red-500 dark:focus:ring-red-400" : "border-gray-300 dark:border-gray-600";
113
- const fileClasses = `${fileBaseClasses} ${fileErrorClasses} ${className}`.trim();
144
+ const errorCls = error ? "border-red-300 dark:border-red-600 focus:ring-red-500 dark:focus:ring-red-400 focus:border-red-500" : "";
145
+ const showClear = clearable && !props.disabled && props.value !== void 0 && props.value !== "";
146
+ const hasRightSlot = icon && iconSide === "right" || showClear;
147
+ const baseCls = "appearance-none relative block w-full placeholder-gray-500 dark:placeholder-gray-400 text-gray-900 dark:text-white rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:border-indigo-500 focus:z-10 disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200";
148
+ const inputCls = [
149
+ baseCls,
150
+ SIZE_CLASSES[size],
151
+ VARIANT_CLASSES[variant],
152
+ errorCls,
153
+ icon && iconSide === "left" ? "pl-9" : "",
154
+ hasRightSlot ? "pr-9" : "",
155
+ prefix ? "rounded-l-none" : "",
156
+ suffix ? "rounded-r-none" : "",
157
+ className
158
+ ].filter(Boolean).join(" ");
159
+ const toggleCls = [
160
+ `h-4 w-4 ${type === "radio" ? "rounded-full" : "rounded"} border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800`,
161
+ "text-indigo-600 dark:text-indigo-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400",
162
+ "focus:ring-offset-2 focus:ring-offset-white dark:focus:ring-offset-gray-900",
163
+ "disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200 cursor-pointer",
164
+ error ? "border-red-300 dark:border-red-600 focus:ring-red-500 dark:focus:ring-red-400" : ""
165
+ ].filter(Boolean).join(" ");
166
+ const fileCls = [
167
+ "block w-full text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-800 border rounded-md",
168
+ "focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:border-indigo-500",
169
+ "disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200",
170
+ "file:mr-4 file:py-2 file:px-4 file:rounded-l-md file:border-0 file:text-sm file:font-medium",
171
+ "file:bg-indigo-50 file:text-indigo-700 dark:file:bg-indigo-900/50 dark:file:text-indigo-300",
172
+ "hover:file:bg-indigo-100 dark:hover:file:bg-indigo-800/50 file:transition-colors file:duration-200 file:cursor-pointer",
173
+ SIZE_CLASSES[size],
174
+ error ? "border-red-300 dark:border-red-600 focus:ring-red-500 dark:focus:ring-red-400" : "border-gray-300 dark:border-gray-600",
175
+ className
176
+ ].filter(Boolean).join(" ");
114
177
  const hasHidden = Boolean(className && /\bhidden\b/.test(className));
115
- const wrapperBase = "space-y-1 w-full";
116
- const wrapperClasses = hasHidden ? `${wrapperBase} hidden` : wrapperBase;
117
- const labelNode = label && (typeof label === "string" ? /* @__PURE__ */ jsx("label", { htmlFor: inputId, className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: label }) : label);
178
+ const wrapperCls = `space-y-1 w-full${hasHidden ? " hidden" : ""}`;
179
+ const labelNode = label && (typeof label === "string" ? /* @__PURE__ */ jsxs("label", { htmlFor: inputId, className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: [
180
+ label,
181
+ props.required && /* @__PURE__ */ jsx("span", { className: "ml-1 text-red-500", "aria-hidden": "true", children: "*" })
182
+ ] }) : label);
118
183
  const errorNode = error && /* @__PURE__ */ jsx("p", { className: "text-sm text-red-600 dark:text-red-400", role: "alert", children: error });
119
184
  const helperNode = helperText && !error && /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: helperText });
120
185
  if (type === "checkbox" || type === "radio") {
121
- return /* @__PURE__ */ jsxs("div", { className: wrapperClasses, children: [
186
+ return /* @__PURE__ */ jsxs("div", { className: wrapperCls, children: [
122
187
  /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
123
- /* @__PURE__ */ jsx("input", { id: inputId, type, className: toggleClasses, ...props }),
188
+ /* @__PURE__ */ jsx("input", { id: inputId, type, className: toggleCls, ...props }),
124
189
  labelNode
125
190
  ] }),
126
191
  errorNode,
@@ -128,63 +193,108 @@ var Input = ({
128
193
  ] });
129
194
  }
130
195
  if (type === "file") {
131
- return /* @__PURE__ */ jsxs("div", { className: wrapperClasses, children: [
196
+ return /* @__PURE__ */ jsxs("div", { className: wrapperCls, children: [
132
197
  labelNode,
133
- /* @__PURE__ */ jsx("input", { id: inputId, type: "file", className: fileClasses, ...props }),
198
+ /* @__PURE__ */ jsx("input", { id: inputId, type: "file", className: fileCls, ...props }),
134
199
  errorNode,
135
200
  helperNode
136
201
  ] });
137
202
  }
138
- return /* @__PURE__ */ jsxs("div", { className: wrapperClasses, children: [
203
+ const prefixBorderCls = error ? "border-red-300 dark:border-red-600" : "border-gray-300 dark:border-gray-600";
204
+ return /* @__PURE__ */ jsxs("div", { className: wrapperCls, children: [
139
205
  labelNode,
140
- /* @__PURE__ */ jsxs("div", { className: "relative", children: [
141
- icon && iconSide === "left" && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-y-0 left-0 z-10 flex items-center pl-3 text-gray-400 dark:text-gray-500", children: icon }),
142
- /* @__PURE__ */ jsx("input", { id: inputId, className: classes, type, ...props }),
143
- icon && iconSide === "right" && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-y-0 right-0 z-10 flex items-center pr-3 text-gray-400 dark:text-gray-500", children: icon })
206
+ /* @__PURE__ */ jsxs("div", { className: "flex", children: [
207
+ prefix && /* @__PURE__ */ jsx("span", { className: `inline-flex shrink-0 items-center px-3 border border-r-0 ${prefixBorderCls} bg-gray-50 dark:bg-gray-700 text-gray-500 dark:text-gray-400 rounded-l-md text-sm`, children: prefix }),
208
+ /* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
209
+ icon && iconSide === "left" && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-y-0 left-0 z-10 flex items-center pl-3 text-gray-400 dark:text-gray-500", children: icon }),
210
+ /* @__PURE__ */ jsx("input", { id: inputId, className: inputCls, type, ...props }),
211
+ icon && iconSide === "right" && !showClear && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-y-0 right-0 z-10 flex items-center pr-3 text-gray-400 dark:text-gray-500", children: icon }),
212
+ showClear && /* @__PURE__ */ jsx(
213
+ "button",
214
+ {
215
+ type: "button",
216
+ onClick: onClear,
217
+ tabIndex: -1,
218
+ "aria-label": "Limpiar",
219
+ className: "absolute inset-y-0 right-0 z-10 flex items-center pr-3 text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300",
220
+ children: /* @__PURE__ */ jsx(CloseIcon, { className: "w-4 h-4" })
221
+ }
222
+ )
223
+ ] }),
224
+ suffix && /* @__PURE__ */ jsx("span", { className: `inline-flex shrink-0 items-center px-3 border border-l-0 ${prefixBorderCls} bg-gray-50 dark:bg-gray-700 text-gray-500 dark:text-gray-400 rounded-r-md text-sm`, children: suffix })
144
225
  ] }),
145
226
  errorNode,
146
227
  helperNode
147
228
  ] });
148
229
  };
230
+ var SIZE_CLASSES2 = {
231
+ small: "px-2 py-1 text-xs",
232
+ medium: "px-3 py-2 text-sm",
233
+ large: "px-4 py-3 text-base"
234
+ };
235
+ var VARIANT_CLASSES2 = {
236
+ default: "border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800",
237
+ outline: "border-2 border-indigo-300 dark:border-indigo-600 bg-transparent",
238
+ filled: "border border-gray-300 dark:border-gray-600 bg-gray-100 dark:bg-gray-700",
239
+ minimal: "border-0 border-b border-gray-300 dark:border-gray-600 bg-transparent rounded-none focus:ring-0"
240
+ };
241
+ var RESIZE_CLASSES = {
242
+ vertical: "resize-y",
243
+ horizontal: "resize-x",
244
+ both: "resize",
245
+ none: "resize-none"
246
+ };
149
247
  var TextArea = ({
150
248
  label,
151
249
  error,
152
250
  helperText,
153
251
  variant = "default",
154
252
  size = "medium",
253
+ autoResize = false,
254
+ showCount = false,
255
+ resize = "vertical",
155
256
  className = "",
156
257
  id,
258
+ onInput: propsOnInput,
157
259
  ...props
158
260
  }) => {
159
261
  const textAreaId = id || `textarea-${Math.random().toString(36).substring(2, 9)}`;
160
- const sizeClasses = {
161
- small: "px-2 py-1 text-xs",
162
- medium: "px-3 py-2 text-sm",
163
- large: "px-4 py-3 text-base"
262
+ const textareaRef = useRef(null);
263
+ const adjustHeight = () => {
264
+ const el = textareaRef.current;
265
+ if (!el) return;
266
+ el.style.height = "auto";
267
+ el.style.height = `${el.scrollHeight}px`;
164
268
  };
165
- const variantClasses = {
166
- default: "border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800",
167
- outline: "border-2 border-indigo-300 dark:border-indigo-600 bg-transparent",
168
- filled: "border-gray-300 dark:border-gray-600 bg-gray-100 dark:bg-gray-700",
169
- minimal: "border-0 bg-transparent focus:ring-0 focus:border-0"
269
+ useEffect(() => {
270
+ if (autoResize) adjustHeight();
271
+ }, [autoResize, props.value]);
272
+ const handleInput = (e) => {
273
+ if (autoResize) adjustHeight();
274
+ propsOnInput?.(e);
170
275
  };
171
- const baseClasses = "appearance-none relative block w-full placeholder-gray-500 dark:placeholder-gray-400 text-gray-900 dark:text-white rounded-md border focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:border-indigo-500 focus:z-10 disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200 resize-y";
172
- const errorClasses = error ? "border-red-300 dark:border-red-600 focus:ring-red-500 dark:focus:ring-red-400 focus:border-red-500" : "";
173
- const classes = `${baseClasses} ${sizeClasses[size]} ${variantClasses[variant]} ${errorClasses} ${className}`;
276
+ const baseCls = "appearance-none relative block w-full placeholder-gray-500 dark:placeholder-gray-400 text-gray-900 dark:text-white rounded-md border focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:border-indigo-500 focus:z-10 disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200";
277
+ const errorCls = error ? "border-red-300 dark:border-red-600 focus:ring-red-500 dark:focus:ring-red-400 focus:border-red-500" : "";
278
+ const resizeCls = autoResize ? "resize-none overflow-hidden" : RESIZE_CLASSES[resize];
279
+ const classes = [baseCls, SIZE_CLASSES2[size], VARIANT_CLASSES2[variant], errorCls, resizeCls, className].filter(Boolean).join(" ");
280
+ const maxLength = typeof props.maxLength === "number" ? props.maxLength : void 0;
281
+ const currentLength = typeof props.value === "string" ? props.value.length : typeof props.value === "number" ? String(props.value).length : 0;
282
+ const overLimit = maxLength !== void 0 && currentLength > maxLength;
174
283
  return /* @__PURE__ */ jsxs("div", { className: "space-y-1 w-full", children: [
175
- label && typeof label === "string" ? /* @__PURE__ */ jsx(
176
- "label",
177
- {
178
- htmlFor: textAreaId,
179
- className: "block text-sm font-medium text-gray-700 dark:text-gray-300",
180
- children: label
181
- }
182
- ) : label,
284
+ (label || showCount) && /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2", children: [
285
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: label && (typeof label === "string" ? /* @__PURE__ */ jsxs("label", { htmlFor: textAreaId, className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: [
286
+ label,
287
+ props.required && /* @__PURE__ */ jsx("span", { className: "ml-1 text-red-500", "aria-hidden": "true", children: "*" })
288
+ ] }) : label) }),
289
+ showCount && /* @__PURE__ */ jsx("span", { className: `text-xs shrink-0 tabular-nums ${overLimit ? "text-red-500" : "text-gray-400 dark:text-gray-500"}`, children: maxLength ? `${currentLength} / ${maxLength}` : currentLength })
290
+ ] }),
183
291
  /* @__PURE__ */ jsx(
184
292
  "textarea",
185
293
  {
294
+ ref: textareaRef,
186
295
  id: textAreaId,
187
296
  className: classes,
297
+ onInput: handleInput,
188
298
  ...props
189
299
  }
190
300
  ),
@@ -192,84 +302,153 @@ var TextArea = ({
192
302
  helperText && !error && /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: helperText })
193
303
  ] });
194
304
  };
305
+ var SIZE_CLASSES3 = {
306
+ sm: "py-1.5 text-xs",
307
+ md: "py-2 text-sm",
308
+ lg: "py-2.5 text-base"
309
+ };
310
+ var VARIANT_CLASSES3 = {
311
+ default: "border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800",
312
+ outline: "border-2 border-indigo-300 dark:border-indigo-600 bg-transparent",
313
+ filled: "border border-gray-300 dark:border-gray-600 bg-gray-100 dark:bg-gray-700",
314
+ minimal: "border-0 border-b border-gray-300 dark:border-gray-600 bg-transparent rounded-none focus:ring-0",
315
+ custom: ""
316
+ };
195
317
  var Select = ({
196
318
  options,
197
319
  placeholder,
198
320
  variant = "default",
321
+ size = "md",
199
322
  error = false,
200
323
  helperText,
201
324
  label,
325
+ icon,
202
326
  className = "",
203
327
  id,
204
328
  ...props
205
329
  }) => {
206
330
  const selectId = id || `select-${Math.random().toString(36).substring(2, 9)}`;
207
- const getVariantClasses = () => {
208
- const baseClasses = "appearance-none relative block w-full px-3 py-2 border placeholder-gray-500 dark:placeholder-gray-400 text-gray-900 dark:text-white bg-white dark:bg-gray-800 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:border-indigo-500 focus:z-10 sm:text-sm disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200";
209
- if (variant === "small") {
210
- return `${baseClasses.replace("px-3 py-2", "px-2.5 py-1.5 text-sm")} border-gray-300 dark:border-gray-600`;
211
- }
212
- return `${baseClasses} border-gray-300 dark:border-gray-600 ${error ? "border-red-300 dark:border-red-600 focus:ring-red-500 dark:focus:ring-red-400 focus:border-red-500" : ""}`;
213
- };
214
- const getOptionClasses = (option) => {
215
- return `bg-white dark:bg-gray-800 text-gray-900 dark:text-white py-2 ${option.disabled ? "opacity-50 cursor-not-allowed" : ""}`;
216
- };
217
- const combinedClassName = `${getVariantClasses()} ${className}`.trim();
331
+ const effectiveSize = variant === "small" ? "sm" : size;
332
+ const effectiveVariant = variant === "small" ? "default" : variant;
333
+ const hasError = Boolean(error);
334
+ const errorMsg = typeof error === "string" ? error : "";
335
+ const computedDefaultValue = props.value === void 0 && props.defaultValue === void 0 ? options.find((o) => o.selected)?.value?.toString() : void 0;
336
+ const baseCls = "appearance-none relative block w-full pl-3 pr-9 placeholder-gray-500 dark:placeholder-gray-400 text-gray-900 dark:text-white rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:border-indigo-500 focus:z-10 disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200";
337
+ const errorCls = hasError ? "border-red-300 dark:border-red-600 focus:ring-red-500 dark:focus:ring-red-400 focus:border-red-500" : "";
338
+ const selectCls = [
339
+ baseCls,
340
+ SIZE_CLASSES3[effectiveSize],
341
+ VARIANT_CLASSES3[effectiveVariant],
342
+ errorCls,
343
+ icon ? "pl-9" : "",
344
+ className
345
+ ].filter(Boolean).join(" ");
218
346
  return /* @__PURE__ */ jsxs("div", { className: "space-y-1 w-full", children: [
219
- label && typeof label === "string" ? /* @__PURE__ */ jsx("label", { htmlFor: selectId, className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: label }) : label,
220
- /* @__PURE__ */ jsxs("select", { id: selectId, className: combinedClassName, ...props, children: [
221
- placeholder && placeholder.trim() && /* @__PURE__ */ jsx("option", { value: "", disabled: true, selected: true, className: "bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400 py-2", children: placeholder }),
222
- options.map((option) => /* @__PURE__ */ jsx(
223
- "option",
347
+ label && (typeof label === "string" ? /* @__PURE__ */ jsxs("label", { htmlFor: selectId, className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: [
348
+ label,
349
+ props.required && /* @__PURE__ */ jsx("span", { className: "ml-1 text-red-500", "aria-hidden": "true", children: "*" })
350
+ ] }) : label),
351
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
352
+ icon && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-y-0 left-0 z-10 flex items-center pl-3 text-gray-400 dark:text-gray-500", children: icon }),
353
+ /* @__PURE__ */ jsxs(
354
+ "select",
224
355
  {
225
- value: option.value,
226
- disabled: option.disabled,
227
- selected: option.selected,
228
- className: getOptionClasses(option),
229
- children: option.label
230
- },
231
- option.value
232
- ))
356
+ id: selectId,
357
+ className: selectCls,
358
+ defaultValue: computedDefaultValue,
359
+ ...props,
360
+ children: [
361
+ placeholder && /* @__PURE__ */ jsx("option", { value: "", disabled: true, className: "bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400", children: placeholder }),
362
+ options.map((option) => /* @__PURE__ */ jsx(
363
+ "option",
364
+ {
365
+ value: option.value,
366
+ disabled: option.disabled,
367
+ className: `bg-white dark:bg-gray-800 text-gray-900 dark:text-white${option.disabled ? " opacity-50" : ""}`,
368
+ children: option.label
369
+ },
370
+ option.value
371
+ ))
372
+ ]
373
+ }
374
+ ),
375
+ /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2.5 text-gray-400 dark:text-gray-500", children: /* @__PURE__ */ jsx(ChevronDownIcon, { className: "w-4 h-4" }) })
233
376
  ] }),
234
- helperText && /* @__PURE__ */ jsx("p", { className: `text-sm ${error ? "text-red-600 dark:text-red-400" : "text-gray-500 dark:text-gray-400"}`, children: helperText })
377
+ errorMsg && /* @__PURE__ */ jsx("p", { className: "text-sm text-red-600 dark:text-red-400", role: "alert", children: errorMsg }),
378
+ helperText && !errorMsg && /* @__PURE__ */ jsx("p", { className: `text-sm ${hasError ? "text-red-600 dark:text-red-400" : "text-gray-500 dark:text-gray-400"}`, children: helperText })
235
379
  ] });
236
380
  };
381
+ var SIZE_CLASS = {
382
+ sm: "max-w-sm",
383
+ md: "max-w-md",
384
+ lg: "max-w-2xl",
385
+ xl: "max-w-4xl",
386
+ full: "max-w-[95vw] w-[95vw]"
387
+ };
388
+ var VARIANT_HEADER = {
389
+ default: "bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700",
390
+ danger: "bg-red-50 dark:bg-red-900/30 border-b border-red-200 dark:border-red-800",
391
+ success: "bg-green-50 dark:bg-green-900/30 border-b border-green-200 dark:border-green-800",
392
+ warning: "bg-yellow-50 dark:bg-yellow-900/30 border-b border-yellow-200 dark:border-yellow-800"
393
+ };
394
+ var VARIANT_TITLE = {
395
+ default: "text-gray-900 dark:text-white",
396
+ danger: "text-red-700 dark:text-red-300",
397
+ success: "text-green-700 dark:text-green-300",
398
+ warning: "text-yellow-700 dark:text-yellow-300"
399
+ };
237
400
  var Modal = forwardRef(({
238
401
  onClose,
239
402
  title,
240
403
  children,
241
404
  footer,
242
- maxWidth = "max-w-2xl",
405
+ maxWidth,
406
+ size,
243
407
  showCloseButton = true,
244
- zIndex = 50
408
+ zIndex = 50,
409
+ closeOnBackdrop = false,
410
+ closeOnEsc = false,
411
+ variant = "default"
245
412
  }, ref) => {
246
413
  const [show, setShow] = useState(false);
414
+ const handleCloseRef = useRef(() => {
415
+ });
416
+ const handleClose = () => {
417
+ setShow(false);
418
+ setTimeout(() => onClose(), 300);
419
+ };
420
+ handleCloseRef.current = handleClose;
247
421
  useEffect(() => {
248
422
  setShow(true);
249
423
  }, []);
250
- const handleClose = () => {
251
- setShow(false);
252
- setTimeout(() => {
253
- onClose();
254
- }, 300);
424
+ useEffect(() => {
425
+ if (!closeOnEsc) return;
426
+ const handler = (e) => {
427
+ if (e.key === "Escape") handleCloseRef.current();
428
+ };
429
+ document.addEventListener("keydown", handler);
430
+ return () => document.removeEventListener("keydown", handler);
431
+ }, [closeOnEsc]);
432
+ useImperativeHandle(ref, () => ({ handleClose }));
433
+ const widthCls = size ? SIZE_CLASS[size] : maxWidth ?? "max-w-2xl";
434
+ const handleBackdropClick = (e) => {
435
+ if (closeOnBackdrop && e.target === e.currentTarget) handleClose();
255
436
  };
256
- useImperativeHandle(ref, () => ({
257
- handleClose
258
- }));
259
437
  return /* @__PURE__ */ jsx(
260
438
  "dialog",
261
439
  {
262
440
  open: show,
263
- className: `fixed inset-0 w-full h-full flex items-center justify-center p-4 ${show && "opacity-100"} transition-opacity opacity-0 duration-300 bg-gray-900/60 backdrop-blur-sm`,
441
+ className: `fixed inset-0 w-full h-full flex items-center justify-center p-4 transition-opacity duration-300 bg-gray-900/60 backdrop-blur-sm ${show ? "opacity-100" : "opacity-0"}`,
264
442
  style: { zIndex: zIndex - 10 },
443
+ onClick: handleBackdropClick,
265
444
  children: /* @__PURE__ */ jsxs(
266
445
  "article",
267
446
  {
268
- className: `relative bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-2xl w-full ${maxWidth} max-h-[90vh] flex flex-col overflow-hidden`,
447
+ className: `relative bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-2xl w-full ${widthCls} max-h-[90vh] flex flex-col overflow-hidden`,
269
448
  style: { zIndex },
270
449
  children: [
271
- /* @__PURE__ */ jsxs("header", { className: "shrink-0 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 px-6 py-4 flex items-center justify-between", children: [
272
- /* @__PURE__ */ jsx("h2", { className: "text-2xl font-bold text-gray-900 dark:text-white", children: title }),
450
+ /* @__PURE__ */ jsxs("header", { className: `shrink-0 px-6 py-4 flex items-center justify-between ${VARIANT_HEADER[variant]}`, children: [
451
+ /* @__PURE__ */ jsx("h2", { className: `text-2xl font-bold ${VARIANT_TITLE[variant]}`, children: title }),
273
452
  showCloseButton && /* @__PURE__ */ jsx(
274
453
  Button,
275
454
  {