@axzydev/axzy_ui_system 1.2.1 → 1.2.2

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 (202) hide show
  1. package/dist/index.css +82 -1
  2. package/dist/index.css.map +1 -1
  3. package/package.json +2 -2
  4. package/src/App.tsx +354 -0
  5. package/src/assets/logo.png +0 -0
  6. package/src/assets/react.svg +1 -0
  7. package/src/components/alert/alert.props.ts +13 -0
  8. package/src/components/alert/alert.stories.tsx +41 -0
  9. package/src/components/alert/alert.tsx +53 -0
  10. package/src/components/avatar/avatar.props.ts +14 -0
  11. package/src/components/avatar/avatar.stories.tsx +46 -0
  12. package/src/components/avatar/avatar.tsx +53 -0
  13. package/src/components/badget/badget.props.ts +12 -0
  14. package/src/components/badget/badget.stories.tsx +76 -0
  15. package/src/components/badget/badget.tsx +61 -0
  16. package/src/components/breadcrumbs/breadcrumbs.props.ts +13 -0
  17. package/src/components/breadcrumbs/breadcrumbs.stories.tsx +21 -0
  18. package/src/components/breadcrumbs/breadcrumbs.tsx +34 -0
  19. package/src/components/button/button.props.ts +18 -0
  20. package/src/components/button/button.stories.tsx +174 -0
  21. package/src/components/button/button.tsx +117 -0
  22. package/src/components/calendar/calendar.props.ts +33 -0
  23. package/src/components/calendar/calendar.stories.tsx +91 -0
  24. package/src/components/calendar/calendar.tsx +608 -0
  25. package/src/components/calendar/index.ts +3 -0
  26. package/src/components/card/card.props.ts +13 -0
  27. package/src/components/card/card.stories.tsx +58 -0
  28. package/src/components/card/card.tsx +79 -0
  29. package/src/components/checkbox/checkbox.props.ts +11 -0
  30. package/src/components/checkbox/checkbox.stories.tsx +54 -0
  31. package/src/components/checkbox/checkbox.tsx +52 -0
  32. package/src/components/confirm-dialog/confirm-dialog.props.ts +14 -0
  33. package/src/components/confirm-dialog/confirm-dialog.stories.tsx +33 -0
  34. package/src/components/confirm-dialog/confirm-dialog.tsx +45 -0
  35. package/src/components/data-table/ITDataTable.stories.tsx +213 -0
  36. package/src/components/data-table/dataTable.props.ts +69 -0
  37. package/src/components/data-table/dataTable.tsx +313 -0
  38. package/src/components/date-picker/date-picker.props.ts +30 -0
  39. package/src/components/date-picker/date-picker.stories.tsx +90 -0
  40. package/src/components/date-picker/datePicker.tsx +307 -0
  41. package/src/components/dialog/dialog.props.ts +9 -0
  42. package/src/components/dialog/dialog.stories.tsx +80 -0
  43. package/src/components/dialog/dialog.tsx +88 -0
  44. package/src/components/divider/divider.props.ts +8 -0
  45. package/src/components/divider/divider.stories.tsx +34 -0
  46. package/src/components/divider/divider.tsx +21 -0
  47. package/src/components/drawer/drawer.props.ts +14 -0
  48. package/src/components/drawer/drawer.stories.tsx +41 -0
  49. package/src/components/drawer/drawer.tsx +53 -0
  50. package/src/components/dropfile/dropfile.stories.tsx +75 -0
  51. package/src/components/dropfile/dropfile.tsx +407 -0
  52. package/src/components/empty-state/empty-state.props.ts +9 -0
  53. package/src/components/empty-state/empty-state.stories.tsx +20 -0
  54. package/src/components/empty-state/empty-state.tsx +21 -0
  55. package/src/components/flex/flex.props.ts +22 -0
  56. package/src/components/flex/flex.stories.tsx +71 -0
  57. package/src/components/flex/flex.tsx +79 -0
  58. package/src/components/form-builder/fieldRenderer.tsx +218 -0
  59. package/src/components/form-builder/formBuilder.context.tsx +70 -0
  60. package/src/components/form-builder/formBuilder.props.ts +43 -0
  61. package/src/components/form-builder/formBuilder.stories.tsx +317 -0
  62. package/src/components/form-builder/formBuilder.tsx +186 -0
  63. package/src/components/form-builder/useFormBuilder.ts +80 -0
  64. package/src/components/form-header/form-header.props.ts +5 -0
  65. package/src/components/form-header/form-header.tsx +38 -0
  66. package/src/components/grid/grid.props.ts +17 -0
  67. package/src/components/grid/grid.stories.tsx +72 -0
  68. package/src/components/grid/grid.tsx +69 -0
  69. package/src/components/image/image.props.ts +7 -0
  70. package/src/components/image/image.tsx +38 -0
  71. package/src/components/input/input.props.ts +49 -0
  72. package/src/components/input/input.stories.tsx +115 -0
  73. package/src/components/input/input.tsx +615 -0
  74. package/src/components/layout/layout.props.ts +10 -0
  75. package/src/components/layout/layout.stories.tsx +114 -0
  76. package/src/components/layout/layout.tsx +80 -0
  77. package/src/components/loader/loader.props.ts +8 -0
  78. package/src/components/loader/loader.stories.tsx +105 -0
  79. package/src/components/loader/loader.tsx +108 -0
  80. package/src/components/navbar/navbar.props.ts +37 -0
  81. package/src/components/navbar/navbar.tsx +328 -0
  82. package/src/components/page/page.props.ts +19 -0
  83. package/src/components/page/page.stories.tsx +98 -0
  84. package/src/components/page/page.tsx +90 -0
  85. package/src/components/page-header/page-header.props.ts +11 -0
  86. package/src/components/page-header/page-header.stories.tsx +61 -0
  87. package/src/components/page-header/page-header.tsx +62 -0
  88. package/src/components/pagination/pagination.props.ts +53 -0
  89. package/src/components/pagination/pagination.stories.tsx +111 -0
  90. package/src/components/pagination/pagination.tsx +241 -0
  91. package/src/components/popover/popover.props.ts +12 -0
  92. package/src/components/popover/popover.stories.tsx +25 -0
  93. package/src/components/popover/popover.tsx +45 -0
  94. package/src/components/progress/progress.props.ts +12 -0
  95. package/src/components/progress/progress.stories.tsx +40 -0
  96. package/src/components/progress/progress.tsx +52 -0
  97. package/src/components/radio/radio.props.ts +16 -0
  98. package/src/components/radio/radio.stories.tsx +50 -0
  99. package/src/components/radio/radio.tsx +58 -0
  100. package/src/components/search-select/index.ts +2 -0
  101. package/src/components/search-select/search-select.props.ts +46 -0
  102. package/src/components/search-select/search-select.stories.tsx +129 -0
  103. package/src/components/search-select/search-select.tsx +229 -0
  104. package/src/components/searchTable/components/EditableCell.tsx +149 -0
  105. package/src/components/searchTable/components/PaginationControls.tsx +86 -0
  106. package/src/components/searchTable/components/PaginationInfo.tsx +20 -0
  107. package/src/components/searchTable/components/SearchAndSortBar.tsx +53 -0
  108. package/src/components/searchTable/components/SearchInput.tsx +33 -0
  109. package/src/components/searchTable/components/SortButton.tsx +50 -0
  110. package/src/components/searchTable/components/TableEmptyState.tsx +22 -0
  111. package/src/components/searchTable/components/TableHeader.tsx +35 -0
  112. package/src/components/searchTable/components/TableHeaderCell.tsx +43 -0
  113. package/src/components/searchTable/components/TableRow.tsx +144 -0
  114. package/src/components/searchTable/searchTable.props.ts +56 -0
  115. package/src/components/searchTable/searchTable.tsx +187 -0
  116. package/src/components/segmented-control/segmented-control.props.ts +18 -0
  117. package/src/components/segmented-control/segmented-control.stories.tsx +63 -0
  118. package/src/components/segmented-control/segmented-control.tsx +52 -0
  119. package/src/components/select/select.props.ts +25 -0
  120. package/src/components/select/select.stories.tsx +86 -0
  121. package/src/components/select/select.tsx +150 -0
  122. package/src/components/sidebar/sidebar.props.ts +28 -0
  123. package/src/components/sidebar/sidebar.stories.tsx +117 -0
  124. package/src/components/sidebar/sidebar.tsx +313 -0
  125. package/src/components/skeleton/skeleton.props.ts +12 -0
  126. package/src/components/skeleton/skeleton.stories.tsx +30 -0
  127. package/src/components/skeleton/skeleton.tsx +45 -0
  128. package/src/components/slide/slide.props.ts +45 -0
  129. package/src/components/slide/slide.stories.tsx +121 -0
  130. package/src/components/slide/slide.tsx +109 -0
  131. package/src/components/slider/slider.props.ts +10 -0
  132. package/src/components/slider/slider.stories.tsx +30 -0
  133. package/src/components/slider/slider.tsx +49 -0
  134. package/src/components/stack/stack.props.ts +19 -0
  135. package/src/components/stack/stack.stories.tsx +79 -0
  136. package/src/components/stack/stack.tsx +79 -0
  137. package/src/components/stat-card/stat-card.props.ts +13 -0
  138. package/src/components/stat-card/stat-card.stories.tsx +41 -0
  139. package/src/components/stat-card/stat-card.tsx +44 -0
  140. package/src/components/stepper/stepper.css +26 -0
  141. package/src/components/stepper/stepper.props.ts +29 -0
  142. package/src/components/stepper/stepper.stories.tsx +155 -0
  143. package/src/components/stepper/stepper.tsx +227 -0
  144. package/src/components/table/table.props.ts +43 -0
  145. package/src/components/table/table.stories.tsx +189 -0
  146. package/src/components/table/table.tsx +376 -0
  147. package/src/components/tabs/tabs.props.ts +18 -0
  148. package/src/components/tabs/tabs.stories.tsx +32 -0
  149. package/src/components/tabs/tabs.tsx +74 -0
  150. package/src/components/text/text.props.ts +9 -0
  151. package/src/components/text/text.tsx +20 -0
  152. package/src/components/textarea/textarea.props.ts +15 -0
  153. package/src/components/textarea/textarea.stories.tsx +27 -0
  154. package/src/components/textarea/textarea.tsx +55 -0
  155. package/src/components/theme-provider/themeProvider.props.ts +28 -0
  156. package/src/components/theme-provider/themeProvider.tsx +1854 -0
  157. package/src/components/time-picker/timePicker.props.ts +16 -0
  158. package/src/components/time-picker/timePicker.stories.tsx +131 -0
  159. package/src/components/time-picker/timePicker.tsx +317 -0
  160. package/src/components/toast/toast.css +32 -0
  161. package/src/components/toast/toast.props.ts +13 -0
  162. package/src/components/toast/toast.stories.tsx +138 -0
  163. package/src/components/toast/toast.tsx +87 -0
  164. package/src/components/tooltip/tooltip.props.ts +11 -0
  165. package/src/components/tooltip/tooltip.stories.tsx +20 -0
  166. package/src/components/tooltip/tooltip.tsx +55 -0
  167. package/src/components/topbar/topbar.props.ts +21 -0
  168. package/src/components/topbar/topbar.stories.tsx +80 -0
  169. package/src/components/topbar/topbar.tsx +205 -0
  170. package/src/components/triple-filter/tripleFilter.props.ts +15 -0
  171. package/src/components/triple-filter/tripleFilter.stories.tsx +32 -0
  172. package/src/components/triple-filter/tripleFilter.tsx +50 -0
  173. package/src/hooks/useClickOutside.ts +21 -0
  174. package/src/hooks/useDebouncedSearch.ts +55 -0
  175. package/src/hooks/useEditableRow.ts +157 -0
  176. package/src/hooks/useTableState.ts +122 -0
  177. package/src/index.css +168 -0
  178. package/src/index.ts +165 -0
  179. package/src/main.tsx +9 -0
  180. package/src/showcases/DataShowcases.tsx +260 -0
  181. package/src/showcases/FeedbackShowcases.tsx +268 -0
  182. package/src/showcases/FormShowcases.tsx +1159 -0
  183. package/src/showcases/HomeShowcase.tsx +324 -0
  184. package/src/showcases/LayoutPrimitivesShowcases.tsx +569 -0
  185. package/src/showcases/NavigationShowcases.tsx +193 -0
  186. package/src/showcases/PageShowcases.tsx +207 -0
  187. package/src/showcases/ShowcaseLayout.tsx +139 -0
  188. package/src/showcases/StructureShowcases.tsx +152 -0
  189. package/src/types/badget.types.ts +37 -0
  190. package/src/types/button.types.ts +16 -0
  191. package/src/types/colors.types.ts +3 -0
  192. package/src/types/field.types.ts +103 -0
  193. package/src/types/formik.types.ts +15 -0
  194. package/src/types/input.types.ts +14 -0
  195. package/src/types/loader.types.ts +9 -0
  196. package/src/types/sizes.types.ts +1 -0
  197. package/src/types/table.types.ts +15 -0
  198. package/src/types/toast.types.ts +8 -0
  199. package/src/types/yup.types.ts +11 -0
  200. package/src/utils/color.utils.ts +99 -0
  201. package/src/utils/styles.ts +120 -0
  202. package/src/utils/table.utils.ts +10 -0
@@ -0,0 +1,1159 @@
1
+ import React, { useState, useEffect, useMemo } from "react";
2
+ import { FaSync, FaSave, FaTrash, FaEdit } from "react-icons/fa";
3
+ import {
4
+ ITButton,
5
+ ITInput,
6
+ ITSelect,
7
+ ITSearchSelect,
8
+ ITDatePicker,
9
+ ITTimePicker,
10
+ ITCalendar,
11
+ ITSlideToggle,
12
+ ITDropfile,
13
+ ITFormBuilder,
14
+ UploadStatus
15
+ } from "../index";
16
+ import { ShowcaseLayout } from "./ShowcaseLayout";
17
+
18
+ // 1. ITButton Showcase
19
+ export const ButtonShowcase = () => {
20
+ const [color, setColor] = useState<any>("primary");
21
+ const [size, setSize] = useState<any>("medium");
22
+ const [variant, setVariant] = useState<any>("filled");
23
+ const [disabled, setDisabled] = useState(false);
24
+ const [withIcon, setWithIcon] = useState(false);
25
+ const [clickCount, setClickCount] = useState(0);
26
+
27
+ const code = `<ITButton\n label="Hacer Click"\n color="${color}"\n size="${size}"\n variant="${variant}"${withIcon ? '\n icon={<FaSync />}' : ""}\n disabled={${disabled}}\n onClick={() => console.log('Click!')}\n/>`;
28
+
29
+ return (
30
+ <ShowcaseLayout
31
+ title="ITButton"
32
+ description="Botón premium con soporte completo de variantes, colores del tema, icono y estados."
33
+ code={code}
34
+ demo={
35
+ <div className="flex flex-col items-center gap-3">
36
+ <ITButton
37
+ label="Hacer Click"
38
+ color={color}
39
+ size={size}
40
+ variant={variant}
41
+ disabled={disabled}
42
+ icon={withIcon ? <FaSync /> : undefined}
43
+ onClick={() => setClickCount(c => c + 1)}
44
+ />
45
+ {clickCount > 0 && (
46
+ <span className="text-xs font-mono text-slate-500 animate-pulse">
47
+ Clicks registrados: {clickCount}
48
+ </span>
49
+ )}
50
+ </div>
51
+ }
52
+ controls={
53
+ <>
54
+ <ITSelect
55
+ name="color"
56
+ label="Color"
57
+ value={color}
58
+ onChange={(e: any) => setColor(e.target.value)}
59
+ options={[
60
+ { label: "Primary", value: "primary" },
61
+ { label: "Secondary", value: "secondary" },
62
+ { label: "Success", value: "success" },
63
+ { label: "Danger", value: "danger" },
64
+ { label: "Warning", value: "warning" },
65
+ { label: "Info", value: "info" },
66
+ { label: "Purple", value: "purple" },
67
+ { label: "Gray", value: "gray" }
68
+ ]}
69
+ />
70
+ <ITSelect
71
+ name="size"
72
+ label="Tamaño"
73
+ value={size}
74
+ onChange={(e: any) => setSize(e.target.value)}
75
+ options={[
76
+ { label: "Small", value: "small" },
77
+ { label: "Medium", value: "medium" },
78
+ { label: "Large", value: "large" }
79
+ ]}
80
+ />
81
+ <ITSelect
82
+ name="variant"
83
+ label="Variante"
84
+ value={variant}
85
+ onChange={(e: any) => setVariant(e.target.value)}
86
+ options={[
87
+ { label: "Filled", value: "filled" },
88
+ { label: "Outlined", value: "outlined" },
89
+ { label: "Raised", value: "raised" },
90
+ { label: "Rounded", value: "rounded" },
91
+ { label: "Text", value: "text" },
92
+ { label: "Raised Text", value: "raised-text" },
93
+ { label: "Link", value: "link" }
94
+ ]}
95
+ />
96
+ <div className="flex items-center justify-between pt-2">
97
+ <span className="text-sm font-semibold text-gray-700">Con Icono</span>
98
+ <ITSlideToggle isOn={withIcon} onToggle={setWithIcon} size="sm" />
99
+ </div>
100
+ <div className="flex items-center justify-between">
101
+ <span className="text-sm font-semibold text-gray-700">Deshabilitado</span>
102
+ <ITSlideToggle isOn={disabled} onToggle={setDisabled} activeColor="danger" size="sm" />
103
+ </div>
104
+ </>
105
+ }
106
+ gallery={
107
+ <div className="space-y-6">
108
+ <div>
109
+ <h4 className="text-sm font-bold text-slate-700 mb-3">Con Icono</h4>
110
+ <div className="flex flex-wrap gap-3">
111
+ <ITButton label="Guardar" icon={<FaSave />} color="success" />
112
+ <ITButton label="Editar" icon={<FaEdit />} color="info" />
113
+ <ITButton label="Eliminar" icon={<FaTrash />} color="danger" variant="outlined" />
114
+ <ITButton label="Sincronizar" icon={<FaSync />} variant="text" />
115
+ </div>
116
+ </div>
117
+ <div>
118
+ <h4 className="text-sm font-bold text-slate-700 mb-3">Variantes</h4>
119
+ <div className="flex flex-wrap gap-3">
120
+ <ITButton label="Filled" variant="filled" />
121
+ <ITButton label="Outlined" variant="outlined" />
122
+ <ITButton label="Raised" variant="raised" />
123
+ <ITButton label="Rounded" variant="rounded" />
124
+ <ITButton label="Text" variant="text" />
125
+ <ITButton label="Link" variant="link" />
126
+ </div>
127
+ </div>
128
+ <div>
129
+ <h4 className="text-sm font-bold text-slate-700 mb-3">Colores Semánticos</h4>
130
+ <div className="flex flex-wrap gap-3">
131
+ <ITButton label="Primary" color="primary" />
132
+ <ITButton label="Secondary" color="secondary" />
133
+ <ITButton label="Success" color="success" />
134
+ <ITButton label="Danger" color="danger" />
135
+ <ITButton label="Warning" color="warning" />
136
+ <ITButton label="Info" color="info" />
137
+ <ITButton label="Purple" color="purple" />
138
+ </div>
139
+ </div>
140
+ </div>
141
+ }
142
+ />
143
+ );
144
+ };
145
+
146
+ // 2. ITInput Showcase
147
+ export const InputShowcase = () => {
148
+ const [selectedInput, setSelectedInput] = useState<
149
+ "text" | "password" | "select" | "searchselect" | "datepicker" | "timepicker" | "toggle" | "dropfile" | "form"
150
+ >("text");
151
+
152
+ const [textVal, setTextVal] = useState("usuario_admin");
153
+ const [passVal, setPassVal] = useState("secreto123");
154
+ const [selectVal, setSelectVal] = useState("admin");
155
+ const [searchSelectVal, setSearchSelectVal] = useState("MX");
156
+ const [dateVal, setDateVal] = useState<any>(new Date());
157
+ const [timeVal, setTimeVal] = useState("08:00");
158
+ const [toggleVal, setToggleVal] = useState(true);
159
+ const [fileVal, setFileVal] = useState<File | null>(null);
160
+
161
+ const [formData, setFormData] = useState({
162
+ name: "",
163
+ email: "",
164
+ password: "",
165
+ role: "",
166
+ country: "",
167
+ birthday: new Date(),
168
+ meetingTime: "09:30",
169
+ newsletter: false,
170
+ file: null as File | null
171
+ });
172
+ const [submittedData, setSubmittedData] = useState<any>(null);
173
+
174
+ const [label, setLabel] = useState("Nombre de Usuario");
175
+ const [placeholder, setPlaceholder] = useState("Escribe tu apodo...");
176
+ const [variant, setVariant] = useState<any>("primary");
177
+ const [disabled, setDisabled] = useState(false);
178
+ const [required, setRequired] = useState(false);
179
+ const [errorInput, setErrorInput] = useState("");
180
+
181
+ const [formVariant, setFormVariant] = useState<any>("primary");
182
+ const [formDisabled, setFormDisabled] = useState(false);
183
+ const [showFormErrors, setShowFormErrors] = useState(false);
184
+
185
+ const formErrors = showFormErrors ? {
186
+ name: "El nombre es obligatorio",
187
+ email: "Formato de correo no válido",
188
+ password: "La contraseña es muy corta",
189
+ role: "Debes elegir un rol administrativo",
190
+ country: "Debes elegir tu país de residencia",
191
+ birthday: "Fecha incorrecta",
192
+ meetingTime: "Hora no permitida",
193
+ file: "Debes adjuntar un archivo"
194
+ } : {} as any;
195
+
196
+ useEffect(() => {
197
+ if (selectedInput !== "form") {
198
+ const DEFAULT_PROPS: Record<string, { label: string; placeholder: string }> = {
199
+ text: { label: "Nombre de Usuario", placeholder: "Escribe tu apodo..." },
200
+ password: { label: "Contraseña", placeholder: "Introduce tu clave..." },
201
+ select: { label: "Rol Administrativo", placeholder: "Selecciona un rol" },
202
+ searchselect: { label: "País de Origen", placeholder: "Buscar país..." },
203
+ datepicker: { label: "Fecha de Registro", placeholder: "Elige una fecha" },
204
+ timepicker: { label: "Hora de Turno", placeholder: "Elige una hora" },
205
+ toggle: { label: "Habilitar Notificaciones", placeholder: "" },
206
+ dropfile: { label: "Subir Documento", placeholder: "" }
207
+ };
208
+ const defaults = DEFAULT_PROPS[selectedInput];
209
+ if (defaults) {
210
+ setLabel(defaults.label);
211
+ setPlaceholder(defaults.placeholder);
212
+ }
213
+ }
214
+ }, [selectedInput]);
215
+
216
+ const code = useMemo(() => {
217
+ if (selectedInput === "text") {
218
+ return `<ITInput\n name="username"\n label="${label}"\n placeholder="${placeholder}"\n value="${textVal}"\n onChange={(e) => setVal(e.target.value)}\n variant="${variant}"\n disabled={${disabled}}\n required={${required}}\n error=${errorInput === "true" ? "{true}" : (errorInput ? `"${errorInput}"` : "undefined")}\n/>`;
219
+ }
220
+ if (selectedInput === "password") {
221
+ return `<ITInput\n name="password"\n type="password"\n label="${label}"\n placeholder="${placeholder}"\n value="${passVal}"\n onChange={(e) => setVal(e.target.value)}\n variant="${variant}"\n disabled={${disabled}}\n required={${required}}\n error=${errorInput === "true" ? "{true}" : (errorInput ? `"${errorInput}"` : "undefined")}\n/>`;
222
+ }
223
+ if (selectedInput === "select") {
224
+ return `<ITSelect\n name="user_role"\n label="${label}"\n value="${selectVal}"\n onChange={(e) => setVal(e.target.value)}\n options={[\n { label: "Administrador", value: "admin" },\n { label: "Colaborador", value: "staff" },\n { label: "Auditor Externo", value: "auditor" }\n ]}\n disabled={${disabled}}\n required={${required}}\n error=${errorInput === "true" ? "{true}" : (errorInput ? `"${errorInput}"` : "undefined")}\n/>`;
225
+ }
226
+ if (selectedInput === "searchselect") {
227
+ return `<ITSearchSelect\n name="user_country"\n label="${label}"\n placeholder="${placeholder}"\n value="${searchSelectVal}"\n onChange={(val) => setVal(val)}\n options={[\n { label: "México", value: "MX" },\n { label: "España", value: "ES" },\n { label: "Colombia", value: "CO" },\n { label: "Argentina", value: "AR" },\n { label: "Perú", value: "PE" }\n ]}\n disabled={${disabled}}\n required={${required}}\n error=${errorInput === "true" ? "{true}" : (errorInput ? `"${errorInput}"` : "undefined")}\n/>`;
228
+ }
229
+ if (selectedInput === "datepicker") {
230
+ return `<ITDatePicker\n name="birthday"\n label="${label}"\n placeholder="${placeholder}"\n value={dateVal}\n onChange={(e) => setVal(e.target.value)}\n variant="${variant}"\n disabled={${disabled}}\n required={${required}}\n error=${errorInput === "true" ? "{true}" : (errorInput ? `"${errorInput}"` : "undefined")}\n/>`;
231
+ }
232
+ if (selectedInput === "timepicker") {
233
+ return `<ITTimePicker\n name="meeting_time"\n label="${label}"\n placeholder="${placeholder}"\n value="${timeVal}"\n onChange={(e) => setVal(e.target.value)}\n variant="${variant}"\n disabled={${disabled}}\n required={${required}}\n error=${errorInput === "true" ? "{true}" : (errorInput ? `"${errorInput}"` : "undefined")}\n/>`;
234
+ }
235
+ if (selectedInput === "toggle") {
236
+ return `<ITSlideToggle\n label="${label}"\n isOn={${toggleVal}}\n onToggle={(val) => setVal(val)}\n disabled={${disabled}}\n/>`;
237
+ }
238
+ if (selectedInput === "dropfile") {
239
+ return `<ITDropfile\n onFileSelect={(file) => setFile(file)}\n uploadStatus={${fileVal ? "UploadStatus.UPLOADED" : "UploadStatus.PENDING"}}\n/>`;
240
+ }
241
+ return `// Formulario Completo AXZY con todos los tipos de Input:\n<form onSubmit={handleSubmit} className="space-y-4">\n <ITInput label="Nombre Completo" name="name" value={name} onChange={...} />\n <ITInput label="Correo" name="email" value={email} onChange={...} />\n <ITInput label="Contraseña" type="password" name="password" value={password} onChange={...} />\n \n <ITSelect label="Rol de Usuario" value={role} options={roles} onChange={...} />\n <ITSearchSelect label="País" value={country} options={countries} onChange={...} />\n \n <ITDatePicker label="Nacimiento" value={birthday} onChange={...} />\n <ITTimePicker label="Hora de Entrada" value={time} onChange={...} />\n \n <ITSlideToggle label="Boletín" isOn={newsletter} onToggle={...} />\n <ITDropfile label="Documento" onFileSelect={...} />\n \n <ITButton type="submit" label="Enviar Formulario" />\n</form>`;
242
+ }, [selectedInput, label, placeholder, variant, disabled, required, errorInput, textVal, passVal, selectVal, searchSelectVal, dateVal, timeVal, toggleVal, fileVal]);
243
+
244
+ const tabs = [
245
+ { id: "text", label: "Texto" },
246
+ { id: "password", label: "Contraseña" },
247
+ { id: "select", label: "Select" },
248
+ { id: "searchselect", label: "SearchSelect" },
249
+ { id: "datepicker", label: "DatePicker" },
250
+ { id: "timepicker", label: "TimePicker" },
251
+ { id: "toggle", label: "SlideToggle" },
252
+ { id: "dropfile", label: "Dropfile" },
253
+ { id: "form", label: "Formulario" }
254
+ ];
255
+
256
+ const renderActiveInput = () => {
257
+ switch (selectedInput) {
258
+ case "text":
259
+ return (
260
+ <div className="w-full max-w-sm">
261
+ <ITInput
262
+ name="sandbox_username"
263
+ label={label}
264
+ placeholder={placeholder}
265
+ value={textVal}
266
+ onChange={(e: any) => setTextVal(e.target.value)}
267
+ onBlur={() => { }}
268
+ variant={variant}
269
+ disabled={disabled}
270
+ required={required}
271
+ error={errorInput === "true" ? true : (errorInput || undefined)}
272
+ />
273
+ </div>
274
+ );
275
+ case "password":
276
+ return (
277
+ <div className="w-full max-w-sm">
278
+ <ITInput
279
+ name="sandbox_password"
280
+ type="password"
281
+ label={label}
282
+ placeholder={placeholder}
283
+ value={passVal}
284
+ onChange={(e: any) => setPassVal(e.target.value)}
285
+ onBlur={() => { }}
286
+ variant={variant}
287
+ disabled={disabled}
288
+ required={required}
289
+ error={errorInput === "true" ? true : (errorInput || undefined)}
290
+ />
291
+ </div>
292
+ );
293
+ case "select":
294
+ return (
295
+ <div className="w-full max-w-sm">
296
+ <ITSelect
297
+ name="sandbox_select"
298
+ label={label}
299
+ value={selectVal}
300
+ onChange={(e: any) => setSelectVal(e.target.value)}
301
+ options={[
302
+ { label: "Administrador", value: "admin" },
303
+ { label: "Colaborador", value: "staff" },
304
+ { label: "Auditor Externo", value: "auditor" }
305
+ ]}
306
+ disabled={disabled}
307
+ required={required}
308
+ error={errorInput === "true" ? true : (errorInput || undefined)}
309
+ />
310
+ </div>
311
+ );
312
+ case "searchselect":
313
+ return (
314
+ <div className="w-full max-w-sm">
315
+ <ITSearchSelect
316
+ name="sandbox_searchselect"
317
+ label={label}
318
+ placeholder={placeholder}
319
+ value={searchSelectVal}
320
+ onChange={(val: string) => setSearchSelectVal(val)}
321
+ options={[
322
+ { label: "México", value: "MX" },
323
+ { label: "España", value: "ES" },
324
+ { label: "Colombia", value: "CO" },
325
+ { label: "Argentina", value: "AR" },
326
+ { label: "Perú", value: "PE" }
327
+ ]}
328
+ disabled={disabled}
329
+ required={required}
330
+ error={errorInput === "true" ? true : (errorInput || undefined)}
331
+ />
332
+ </div>
333
+ );
334
+ case "datepicker":
335
+ return (
336
+ <div className="w-full max-w-sm">
337
+ <ITDatePicker
338
+ name="sandbox_datepicker"
339
+ label={label}
340
+ value={dateVal}
341
+ onChange={(e: any) => setDateVal(e.target.value)}
342
+ variant={variant}
343
+ disabled={disabled}
344
+ required={required}
345
+ error={errorInput === "true" ? true : (errorInput || undefined)}
346
+ />
347
+ </div>
348
+ );
349
+ case "timepicker":
350
+ return (
351
+ <div className="w-full max-w-sm">
352
+ <ITTimePicker
353
+ name="sandbox_timepicker"
354
+ label={label}
355
+ placeholder={placeholder}
356
+ value={timeVal}
357
+ onChange={(e: any) => setTimeVal(e.target.value)}
358
+ onBlur={() => { }}
359
+ variant={variant}
360
+ disabled={disabled}
361
+ required={required}
362
+ error={errorInput === "true" ? true : (errorInput || undefined)}
363
+ />
364
+ </div>
365
+ );
366
+ case "toggle":
367
+ return (
368
+ <div className="w-full max-w-sm flex items-center justify-between p-4 bg-slate-50 dark:bg-slate-800/40 border border-slate-100 dark:border-slate-800 rounded-xl">
369
+ <span className="text-sm font-semibold text-slate-700 dark:text-slate-300">{label || "Toggle Switch"}</span>
370
+ <ITSlideToggle
371
+ isOn={toggleVal}
372
+ onToggle={setToggleVal}
373
+ disabled={disabled}
374
+ activeColor={variant === "primary" ? "success" : variant}
375
+ />
376
+ </div>
377
+ );
378
+ case "dropfile":
379
+ return (
380
+ <div className="w-full max-w-sm">
381
+ {label && <label className="text-sm font-medium text-gray-700 dark:text-slate-300 mb-1.5 block">{label}</label>}
382
+ <ITDropfile
383
+ onFileSelect={setFileVal}
384
+ uploadStatus={fileVal ? UploadStatus.UPLOADED : UploadStatus.PENDING}
385
+ />
386
+ </div>
387
+ );
388
+ case "form":
389
+ return (
390
+ <form
391
+ onSubmit={(e) => {
392
+ e.preventDefault();
393
+ setSubmittedData(formData);
394
+ }}
395
+ className="w-full max-w-lg space-y-5 bg-white dark:bg-slate-900 border border-slate-100 dark:border-slate-800 p-6 rounded-2xl shadow-sm"
396
+ >
397
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
398
+ <ITInput
399
+ name="form_name"
400
+ label="Nombre Completo"
401
+ placeholder="Juan Pérez"
402
+ value={formData.name}
403
+ onChange={(e: any) => setFormData(prev => ({ ...prev, name: e.target.value }))}
404
+ variant={formVariant}
405
+ disabled={formDisabled}
406
+ required={true}
407
+ error={formErrors.name}
408
+ touched={showFormErrors ? true : undefined}
409
+ />
410
+ <ITInput
411
+ name="form_email"
412
+ label="Correo Electrónico"
413
+ placeholder="juan@ejemplo.com"
414
+ value={formData.email}
415
+ onChange={(e: any) => setFormData(prev => ({ ...prev, email: e.target.value }))}
416
+ variant={formVariant}
417
+ disabled={formDisabled}
418
+ required={true}
419
+ error={formErrors.email}
420
+ touched={showFormErrors ? true : undefined}
421
+ />
422
+ </div>
423
+
424
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
425
+ <ITInput
426
+ name="form_password"
427
+ label="Contraseña"
428
+ type="password"
429
+ placeholder="••••••••"
430
+ value={formData.password}
431
+ onChange={(e: any) => setFormData(prev => ({ ...prev, password: e.target.value }))}
432
+ variant={formVariant}
433
+ disabled={formDisabled}
434
+ required={true}
435
+ error={formErrors.password}
436
+ touched={showFormErrors ? true : undefined}
437
+ />
438
+ <ITSelect
439
+ name="form_role"
440
+ label="Rol de Usuario"
441
+ value={formData.role}
442
+ onChange={(e: any) => setFormData(prev => ({ ...prev, role: e.target.value }))}
443
+ options={[
444
+ { label: "Administrador", value: "admin" },
445
+ { label: "Colaborador", value: "staff" },
446
+ { label: "Auditor Externo", value: "auditor" }
447
+ ]}
448
+ disabled={formDisabled}
449
+ required={true}
450
+ error={formErrors.role}
451
+ touched={showFormErrors ? true : undefined}
452
+ />
453
+ </div>
454
+
455
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
456
+ <ITSearchSelect
457
+ name="form_country"
458
+ label="País de Residencia"
459
+ value={formData.country}
460
+ onChange={(val: string) => setFormData(prev => ({ ...prev, country: val }))}
461
+ options={[
462
+ { label: "México", value: "MX" },
463
+ { label: "España", value: "ES" },
464
+ { label: "Colombia", value: "CO" },
465
+ { label: "Argentina", value: "AR" },
466
+ { label: "Perú", value: "PE" }
467
+ ]}
468
+ disabled={formDisabled}
469
+ required={true}
470
+ error={formErrors.country}
471
+ touched={showFormErrors ? true : undefined}
472
+ />
473
+ <ITDatePicker
474
+ name="form_birthday"
475
+ label="Fecha de Nacimiento"
476
+ value={formData.birthday}
477
+ onChange={(e: any) => setFormData(prev => ({ ...prev, birthday: e.target.value }))}
478
+ variant={formVariant}
479
+ disabled={formDisabled}
480
+ required={true}
481
+ error={formErrors.birthday}
482
+ touched={showFormErrors ? true : undefined}
483
+ />
484
+ </div>
485
+
486
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-4 items-center">
487
+ <ITTimePicker
488
+ name="form_time"
489
+ label="Hora de Entrada"
490
+ value={formData.meetingTime}
491
+ onChange={(e: any) => setFormData(prev => ({ ...prev, meetingTime: e.target.value }))}
492
+ variant={formVariant}
493
+ disabled={formDisabled}
494
+ required={true}
495
+ error={formErrors.meetingTime}
496
+ touched={showFormErrors ? true : undefined}
497
+ />
498
+ <div className="flex items-center justify-between p-3 bg-slate-50 dark:bg-slate-800/40 border border-slate-100 dark:border-slate-800 rounded-xl h-[64px]">
499
+ <span className="text-xs font-semibold text-slate-700 dark:text-slate-300">Recibir Boletín</span>
500
+ <ITSlideToggle
501
+ isOn={formData.newsletter}
502
+ onToggle={(val) => setFormData(prev => ({ ...prev, newsletter: val }))}
503
+ disabled={formDisabled}
504
+ size="sm"
505
+ />
506
+ </div>
507
+ </div>
508
+
509
+ <ITDropfile
510
+ onFileSelect={(file) => setFormData(prev => ({ ...prev, file }))}
511
+ uploadStatus={formData.file ? UploadStatus.UPLOADED : UploadStatus.PENDING}
512
+ />
513
+ {formErrors.file && <p className="text-xs text-red-500 mt-1">{formErrors.file}</p>}
514
+
515
+ <div className="flex justify-end pt-2">
516
+ <ITButton label="Enviar Formulario" color={formVariant} type="submit" disabled={formDisabled} />
517
+ </div>
518
+
519
+ {submittedData && (
520
+ <div className="mt-4 p-4 bg-slate-950 text-emerald-400 font-mono text-[10px] sm:text-xs rounded-xl border border-slate-800">
521
+ <p className="font-bold mb-2">✓ Submit Data (JSON):</p>
522
+ <pre className="whitespace-pre-wrap">
523
+ {JSON.stringify(
524
+ {
525
+ ...submittedData,
526
+ birthday: submittedData.birthday instanceof Date ? submittedData.birthday.toLocaleDateString() : submittedData.birthday,
527
+ file: submittedData.file ? submittedData.file.name : null
528
+ },
529
+ null,
530
+ 2
531
+ )}
532
+ </pre>
533
+ </div>
534
+ )}
535
+ </form>
536
+ );
537
+ default:
538
+ return null;
539
+ }
540
+ };
541
+
542
+ return (
543
+ <div className="w-full space-y-6">
544
+ <div className="flex flex-wrap gap-1 bg-slate-100 dark:bg-slate-800 p-1 rounded-xl border border-slate-200 dark:border-slate-700">
545
+ {tabs.map((tab) => (
546
+ <button
547
+ key={tab.id}
548
+ onClick={() => {
549
+ setSelectedInput(tab.id as any);
550
+ setSubmittedData(null);
551
+ }}
552
+ className={`px-3 py-1.5 text-xs font-medium rounded-lg transition-all ${selectedInput === tab.id
553
+ ? "bg-white dark:bg-slate-700 text-slate-800 dark:text-white shadow-sm border border-slate-200 dark:border-slate-600"
554
+ : "text-slate-500 hover:text-slate-800 dark:hover:text-slate-200 border border-transparent"
555
+ }`}
556
+ >
557
+ {tab.label}
558
+ </button>
559
+ ))}
560
+ </div>
561
+
562
+ <ShowcaseLayout
563
+ title="ITInput Suite"
564
+ description={
565
+ selectedInput === "form"
566
+ ? "Formulario unificado con todos los tipos de campos de entrada (Texto, Menú, Búsqueda, Fechas, Horas, Toggles y Archivos) para validar su correcto comportamiento visual."
567
+ : `Sandbox interactivo para experimentar con el componente individual de tipo ${selectedInput.toUpperCase()}.`
568
+ }
569
+ code={code}
570
+ demo={renderActiveInput()}
571
+ controls={
572
+ selectedInput === "form" ? (
573
+ <>
574
+ <ITSelect
575
+ name="form_variant_ctrl"
576
+ label="Variante de Color de Botón"
577
+ value={formVariant}
578
+ onChange={(e: any) => setFormVariant(e.target.value)}
579
+ options={[
580
+ { label: "Primary", value: "primary" },
581
+ { label: "Secondary", value: "secondary" },
582
+ { label: "Success", value: "success" },
583
+ { label: "Danger", value: "danger" },
584
+ { label: "Warning", value: "warning" },
585
+ { label: "Info", value: "info" }
586
+ ]}
587
+ />
588
+ <div className="flex items-center justify-between pt-2">
589
+ <span className="text-sm font-semibold text-gray-700 dark:text-slate-300">Simular Errores</span>
590
+ <ITSlideToggle isOn={showFormErrors} onToggle={setShowFormErrors} size="sm" />
591
+ </div>
592
+ <div className="flex items-center justify-between">
593
+ <span className="text-sm font-semibold text-gray-700 dark:text-slate-300">Deshabilitar Todo</span>
594
+ <ITSlideToggle isOn={formDisabled} onToggle={setFormDisabled} activeColor="danger" size="sm" />
595
+ </div>
596
+ </>
597
+ ) : (
598
+ <>
599
+ <ITInput
600
+ name="label_ctrl"
601
+ label="Etiqueta (Label)"
602
+ value={label}
603
+ onChange={(e: any) => setLabel(e.target.value)}
604
+ onBlur={() => { }}
605
+ />
606
+ {["text", "password", "searchselect", "datepicker", "timepicker"].includes(selectedInput) && (
607
+ <ITInput
608
+ name="placeholder_ctrl"
609
+ label="Placeholder"
610
+ value={placeholder}
611
+ onChange={(e: any) => setPlaceholder(e.target.value)}
612
+ onBlur={() => { }}
613
+ />
614
+ )}
615
+ {["text", "password", "datepicker", "timepicker", "toggle"].includes(selectedInput) && (
616
+ <ITSelect
617
+ name="variant_ctrl"
618
+ label="Variante de Color"
619
+ value={variant}
620
+ onChange={(e: any) => setVariant(e.target.value)}
621
+ options={[
622
+ { label: "Primary", value: "primary" },
623
+ { label: "Secondary", value: "secondary" },
624
+ { label: "Success", value: "success" },
625
+ { label: "Danger", value: "danger" },
626
+ { label: "Warning", value: "warning" },
627
+ { label: "Info", value: "info" }
628
+ ]}
629
+ />
630
+ )}
631
+ <ITInput
632
+ name="error_ctrl"
633
+ label="Mensaje de Error"
634
+ value={errorInput}
635
+ onChange={(e: any) => setErrorInput(e.target.value)}
636
+ onBlur={() => { }}
637
+ placeholder="Ej. Formato inválido"
638
+ />
639
+ <div className="flex items-center justify-between pt-2">
640
+ <span className="text-sm font-semibold text-gray-700 dark:text-slate-300">Requerido</span>
641
+ <ITSlideToggle isOn={required} onToggle={setRequired} size="sm" />
642
+ </div>
643
+ <div className="flex items-center justify-between">
644
+ <span className="text-sm font-semibold text-gray-700 dark:text-slate-300">Deshabilitado</span>
645
+ <ITSlideToggle isOn={disabled} onToggle={setDisabled} activeColor="danger" size="sm" />
646
+ </div>
647
+ </>
648
+ )
649
+ }
650
+ gallery={
651
+ selectedInput === "form" ? (
652
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
653
+ <ITInput name="g1" label="Input Estándar" placeholder="Ingresa datos..." onChange={() => { }} onBlur={() => { }} />
654
+ <ITInput name="g2" label="Input Con Error" value="Email no válido" error="El formato del correo es incorrecto" onChange={() => { }} onBlur={() => { }} touched />
655
+ <ITInput name="g3" label="Input Deshabilitado" placeholder="Solo lectura" disabled onChange={() => { }} onBlur={() => { }} />
656
+ <ITInput name="g4" label="Input Contraseña" type="password" value="secreto123" onChange={() => { }} onBlur={() => { }} />
657
+ </div>
658
+ ) : undefined
659
+ }
660
+ />
661
+ </div>
662
+ );
663
+ };
664
+
665
+ // 3. ITSelect Showcase
666
+ export const SelectShowcase = () => {
667
+ const [val, setVal] = useState("");
668
+ const [label, setLabel] = useState("Rol Administrativo");
669
+ const [disabled, setDisabled] = useState(false);
670
+ const [error, setError] = useState("");
671
+
672
+ const options = [
673
+ { label: "Administrador Supremo", value: "SUPERADMIN" },
674
+ { label: "Operador de Planta", value: "OPERATOR" },
675
+ { label: "Auditor Externo", value: "AUDITOR" }
676
+ ];
677
+
678
+ const code = `<ITSelect\n name="role"\n label="${label}"\n value="${val}"\n options={[\n { label: 'Administrador Supremo', value: 'SUPERADMIN' },\n { label: 'Operador de Planta', value: 'OPERATOR' },\n { label: 'Auditor Externo', value: 'AUDITOR' }\n ]}\n disabled={${disabled}}\n error=${error ? `"${error}"` : "undefined"}\n onChange={(e) => setVal(e.target.value)}\n/>`;
679
+
680
+ return (
681
+ <ShowcaseLayout
682
+ title="ITSelect"
683
+ description="Menú desplegable de selección simple optimizado con los estilos visuales AXZY."
684
+ code={code}
685
+ demo={
686
+ <div className="w-full max-w-sm">
687
+ <ITSelect
688
+ name="showcase_select"
689
+ label={label}
690
+ value={val}
691
+ options={options}
692
+ disabled={disabled}
693
+ error={error || undefined}
694
+ onChange={(e: any) => setVal(e.target.value)}
695
+ />
696
+ {val && (
697
+ <p className="mt-2 text-xs text-slate-500 font-mono">Selección: "{val}"</p>
698
+ )}
699
+ </div>
700
+ }
701
+ controls={
702
+ <>
703
+ <ITInput name="label_ctrl" label="Label" value={label} onChange={(e: any) => setLabel(e.target.value)} onBlur={() => { }} />
704
+ <ITInput name="err_ctrl" label="Mensaje de Error" value={error} onChange={(e: any) => setError(e.target.value)} onBlur={() => { }} />
705
+ <div className="flex items-center justify-between pt-2">
706
+ <span className="text-sm font-semibold text-gray-700">Deshabilitado</span>
707
+ <ITSlideToggle isOn={disabled} onToggle={setDisabled} activeColor="danger" size="sm" />
708
+ </div>
709
+ </>
710
+ }
711
+ gallery={
712
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
713
+ <ITSelect name="s1" label="Opción Simple" options={[{ label: "Chile", value: "cl" }]} onChange={() => { }} />
714
+ <ITSelect name="s2" label="Select Con Error" options={[]} error="Este campo es obligatorio" touched onChange={() => { }} />
715
+ </div>
716
+ }
717
+ />
718
+ );
719
+ };
720
+
721
+ // 4. ITSearchSelect Showcase
722
+ export const SearchSelectShowcase = () => {
723
+ const [val, setVal] = useState<any>("");
724
+ const [isLoading, setIsLoading] = useState(false);
725
+ const [disabled, setDisabled] = useState(false);
726
+
727
+ const options = [
728
+ { label: "Argentina", value: "AR" },
729
+ { label: "Brasil", value: "BR" },
730
+ { label: "Colombia", value: "CO" },
731
+ { label: "México", value: "MX" },
732
+ { label: "Perú", value: "PE" },
733
+ { label: "España", value: "ES" }
734
+ ];
735
+
736
+ const code = `<ITSearchSelect\n name="country"\n label="Seleccionar País"\n value="${val}"\n options={[\n { label: 'Argentina', value: 'AR' },\n { label: 'Brasil', value: 'BR' },...\n ]}\n isLoading={${isLoading}}\n disabled={${disabled}}\n onChange={(value) => setVal(value)}\n/>`;
737
+
738
+ return (
739
+ <ShowcaseLayout
740
+ title="ITSearchSelect"
741
+ description="Selector avanzado con barra de búsqueda para filtrar colecciones grandes o cargar opciones remotas."
742
+ code={code}
743
+ demo={
744
+ <div className="w-full max-w-sm">
745
+ <ITSearchSelect
746
+ name="country"
747
+ label="Seleccionar País"
748
+ value={val}
749
+ options={options}
750
+ isLoading={isLoading}
751
+ disabled={disabled}
752
+ onChange={(value) => setVal(value)}
753
+ />
754
+ {val && (
755
+ <p className="mt-2 text-xs text-slate-500 font-mono">País seleccionado: "{val}"</p>
756
+ )}
757
+ </div>
758
+ }
759
+ controls={
760
+ <>
761
+ <div className="flex items-center justify-between">
762
+ <span className="text-sm font-semibold text-gray-700">Estado de Carga (Loading)</span>
763
+ <ITSlideToggle isOn={isLoading} onToggle={setIsLoading} size="sm" />
764
+ </div>
765
+ <div className="flex items-center justify-between">
766
+ <span className="text-sm font-semibold text-gray-700">Deshabilitado</span>
767
+ <ITSlideToggle isOn={disabled} onToggle={setDisabled} activeColor="danger" size="sm" />
768
+ </div>
769
+ </>
770
+ }
771
+ />
772
+ );
773
+ };
774
+
775
+ // 5. ITDatePicker Showcase
776
+ export const DatePickerShowcase = () => {
777
+ const [val, setVal] = useState<any>(new Date());
778
+ const [range, setRange] = useState(false);
779
+ const [disabled, setDisabled] = useState(false);
780
+ const [variant, setVariant] = useState<any>("primary");
781
+
782
+ const handleDateChange = (e: any) => {
783
+ setVal(e.target.value);
784
+ };
785
+
786
+ const code = `<ITDatePicker\n name="date"\n label="Fecha de Auditoría"\n value={${range ? "dateRange" : "singleDate"}}\n range={${range}}\n variant="${variant}"\n disabled={${disabled}}\n onChange={(e) => setVal(e.target.value)}\n/>`;
787
+
788
+ return (
789
+ <ShowcaseLayout
790
+ title="ITDatePicker"
791
+ description="Calendario de entrada de fechas estático y flotante con soporte para selección de rangos."
792
+ code={code}
793
+ demo={
794
+ <div className="w-full max-w-sm">
795
+ <ITDatePicker
796
+ name="showcase_datepicker"
797
+ label="Fecha del Evento"
798
+ value={val}
799
+ range={range}
800
+ variant={variant}
801
+ disabled={disabled}
802
+ onChange={handleDateChange}
803
+ />
804
+ {val && (
805
+ <p className="mt-2 text-xs text-slate-500 font-mono">
806
+ Valor actual: {range && Array.isArray(val)
807
+ ? `Rango: ${val[0]?.toLocaleDateString() || "?"} - ${val[1]?.toLocaleDateString() || "?"}`
808
+ : val instanceof Date
809
+ ? val.toLocaleDateString()
810
+ : String(val)
811
+ }
812
+ </p>
813
+ )}
814
+ </div>
815
+ }
816
+ controls={
817
+ <>
818
+ <ITSelect
819
+ name="variant_ctrl"
820
+ label="Tema de Color"
821
+ value={variant}
822
+ onChange={(e: any) => setVariant(e.target.value)}
823
+ options={[
824
+ { label: "Primary", value: "primary" },
825
+ { label: "Secondary", value: "secondary" },
826
+ { label: "Success", value: "success" },
827
+ { label: "Danger", value: "danger" },
828
+ { label: "Warning", value: "warning" },
829
+ { label: "Info", value: "info" }
830
+ ]}
831
+ />
832
+ <div className="flex items-center justify-between pt-2">
833
+ <span className="text-sm font-semibold text-gray-700">Selección de Rango</span>
834
+ <ITSlideToggle isOn={range} onToggle={(r) => { setRange(r); setVal(r ? [new Date(), new Date()] : new Date()); }} size="sm" />
835
+ </div>
836
+ <div className="flex items-center justify-between">
837
+ <span className="text-sm font-semibold text-gray-700">Deshabilitado</span>
838
+ <ITSlideToggle isOn={disabled} onToggle={setDisabled} activeColor="danger" size="sm" />
839
+ </div>
840
+ </>
841
+ }
842
+ />
843
+ );
844
+ };
845
+
846
+ // 6. ITTimePicker Showcase
847
+ export const TimePickerShowcase = () => {
848
+ const [val, setVal] = useState("09:30");
849
+ const [variant, setVariant] = useState<any>("primary");
850
+ const [disabled, setDisabled] = useState(false);
851
+
852
+ const code = `<ITTimePicker\n name="time"\n label="Hora de Inicio"\n value="${val}"\n variant="${variant}"\n disabled={${disabled}}\n onChange={(e) => setVal(e.target.value)}\n/>`;
853
+
854
+ return (
855
+ <ShowcaseLayout
856
+ title="ITTimePicker"
857
+ description="Selector de horas y minutos con panel interactivo de scroll suave."
858
+ code={code}
859
+ demo={
860
+ <div className="w-full max-w-sm">
861
+ <ITTimePicker
862
+ name="showcase_time"
863
+ label="Hora de Inicio"
864
+ value={val}
865
+ variant={variant}
866
+ disabled={disabled}
867
+ onChange={(e: any) => setVal(e.target.value)}
868
+ onBlur={() => { }}
869
+ />
870
+ {val && (
871
+ <p className="mt-2 text-xs text-slate-500 font-mono">Hora elegida: "{val}"</p>
872
+ )}
873
+ </div>
874
+ }
875
+ controls={
876
+ <>
877
+ <ITSelect
878
+ name="variant_ctrl"
879
+ label="Variante"
880
+ value={variant}
881
+ onChange={(e: any) => setVariant(e.target.value)}
882
+ options={[
883
+ { label: "Primary", value: "primary" },
884
+ { label: "Secondary", value: "secondary" },
885
+ { label: "Success", value: "success" },
886
+ { label: "Danger", value: "danger" },
887
+ { label: "Warning", value: "warning" },
888
+ { label: "Info", value: "info" },
889
+ { label: "Purple", value: "purple" }
890
+ ]}
891
+ />
892
+ <div className="flex items-center justify-between pt-2">
893
+ <span className="text-sm font-semibold text-gray-700">Deshabilitado</span>
894
+ <ITSlideToggle isOn={disabled} onToggle={setDisabled} activeColor="danger" size="sm" />
895
+ </div>
896
+ </>
897
+ }
898
+ />
899
+ );
900
+ };
901
+
902
+ // 7. ITCalendar Showcase
903
+ export const CalendarShowcase = () => {
904
+ const [mode, setMode] = useState<'month' | 'week' | 'day'>('month');
905
+ const [selectionMode, setSelectionMode] = useState<'single' | 'range'>('single');
906
+ const [calendarVariant, setCalendarVariant] = useState<any>("primary");
907
+ const [events] = useState<any[]>([
908
+ { id: "1", title: "Planificación de Sprint", start: new Date(), end: new Date(new Date().getTime() + 60 * 60 * 1000), color: "#3b82f6" },
909
+ { id: "2", title: "Revisión Técnica", start: new Date(new Date().setDate(new Date().getDate() + 2)), end: new Date(new Date().setDate(new Date().getDate() + 2)), color: "#10b981" }
910
+ ]);
911
+
912
+ const code = `<ITCalendar\n mode="${mode}"\n selectionMode="${selectionMode}"\n variant="${calendarVariant}"\n events={[\n { id: '1', title: 'Sprint Planning', start: new Date(), end: new Date() }\n ]}\n onSlotClick={(date) => alert(date)}\n/>`;
913
+
914
+ return (
915
+ <ShowcaseLayout
916
+ title="ITCalendar"
917
+ description="Calendario completo con soporte para eventos y agendamiento diario/semanal."
918
+ code={code}
919
+ demo={
920
+ <div className="w-full h-[450px]">
921
+ <ITCalendar
922
+ mode={mode}
923
+ selectionMode={selectionMode}
924
+ variant={calendarVariant}
925
+ events={events}
926
+ onSlotClick={(date) => alert(`Click en horario: ${date.toLocaleString()}`)}
927
+ onEventClick={(evt) => alert(`Detalle del Evento: ${evt.title}`)}
928
+ />
929
+ </div>
930
+ }
931
+ controls={
932
+ <>
933
+ <ITSelect
934
+ name="mode_ctrl"
935
+ label="Modo de Vista"
936
+ value={mode}
937
+ onChange={(e: any) => setMode(e.target.value)}
938
+ options={[
939
+ { label: "Mes (Month)", value: "month" },
940
+ { label: "Semana (Week)", value: "week" },
941
+ { label: "Día (Day)", value: "day" }
942
+ ]}
943
+ />
944
+ <ITSelect
945
+ name="sel_ctrl"
946
+ label="Modo de Selección"
947
+ value={selectionMode}
948
+ onChange={(e: any) => setSelectionMode(e.target.value)}
949
+ options={[
950
+ { label: "Single", value: "single" },
951
+ { label: "Range", value: "range" }
952
+ ]}
953
+ />
954
+ <ITSelect
955
+ name="var_ctrl"
956
+ label="Variante de Color"
957
+ value={calendarVariant}
958
+ onChange={(e: any) => setCalendarVariant(e.target.value)}
959
+ options={[
960
+ { label: "Primary", value: "primary" },
961
+ { label: "Secondary", value: "secondary" },
962
+ { label: "Success", value: "success" },
963
+ { label: "Danger", value: "danger" },
964
+ { label: "Warning", value: "warning" },
965
+ { label: "Info", value: "info" }
966
+ ]}
967
+ />
968
+ </>
969
+ }
970
+ />
971
+ );
972
+ };
973
+
974
+ // 8. ITSlideToggle Showcase
975
+ export const SlideToggleShowcase = () => {
976
+ const [isOn, setIsOn] = useState(false);
977
+ const [activeColor, setActiveColor] = useState<any>("success");
978
+ const [size, setSize] = useState<any>("md");
979
+ const [disabled, setDisabled] = useState(false);
980
+
981
+ const code = `<ITSlideToggle\n isOn={${isOn}}\n onToggle={(state) => setIsOn(state)}\n activeColor="${activeColor}"\n size="${size}"\n disabled={${disabled}}\n/>`;
982
+
983
+ return (
984
+ <ShowcaseLayout
985
+ title="ITSlideToggle"
986
+ description="Interruptor de alternancia (Switch) estilizado para cambiar estados binarios."
987
+ code={code}
988
+ demo={
989
+ <div className="flex flex-col items-center gap-3">
990
+ <ITSlideToggle
991
+ isOn={isOn}
992
+ onToggle={setIsOn}
993
+ activeColor={activeColor}
994
+ size={size}
995
+ disabled={disabled}
996
+ />
997
+ <span className="text-xs font-mono text-slate-500">
998
+ Estado: {isOn ? "ENCENDIDO" : "APAGADO"}
999
+ </span>
1000
+ </div>
1001
+ }
1002
+ controls={
1003
+ <>
1004
+ <ITSelect
1005
+ name="col_ctrl"
1006
+ label="Color Activo"
1007
+ value={activeColor}
1008
+ onChange={(e: any) => setActiveColor(e.target.value)}
1009
+ options={[
1010
+ { label: "Success (Verde)", value: "success" },
1011
+ { label: "Primary (Azul)", value: "primary" },
1012
+ { label: "Danger (Rojo)", value: "danger" },
1013
+ { label: "Warning (Naranja)", value: "warning" },
1014
+ { label: "Purple (Morado)", value: "purple" }
1015
+ ]}
1016
+ />
1017
+ <ITSelect
1018
+ name="sz_ctrl"
1019
+ label="Tamaño"
1020
+ value={size}
1021
+ onChange={(e: any) => setSize(e.target.value)}
1022
+ options={[
1023
+ { label: "Small", value: "sm" },
1024
+ { label: "Medium", value: "md" },
1025
+ { label: "Large", value: "lg" }
1026
+ ]}
1027
+ />
1028
+ <div className="flex items-center justify-between pt-2">
1029
+ <span className="text-sm font-semibold text-gray-700">Deshabilitar Switch</span>
1030
+ <ITSlideToggle isOn={disabled} onToggle={setDisabled} activeColor="danger" size="sm" />
1031
+ </div>
1032
+ </>
1033
+ }
1034
+ gallery={
1035
+ <div className="flex flex-wrap items-center gap-6">
1036
+ <ITSlideToggle initialState={false} size="sm" />
1037
+ <ITSlideToggle initialState={true} activeColor="primary" size="md" />
1038
+ <ITSlideToggle initialState={true} activeColor="purple" size="lg" />
1039
+ <ITSlideToggle initialState={true} disabled size="md" />
1040
+ </div>
1041
+ }
1042
+ />
1043
+ );
1044
+ };
1045
+
1046
+ // 9. ITDropfile Showcase
1047
+ export const DropfileShowcase = () => {
1048
+ const [selectedFile, setSelectedFile] = useState<File | null>(null);
1049
+ const [status, setStatus] = useState<any>("pendiente");
1050
+
1051
+ const code = `<ITDropfile\n onFileSelect={(file) => setSelectedFile(file)}\n uploadStatus="${status}"\n showStatusBadge={true}\n/>`;
1052
+
1053
+ return (
1054
+ <ShowcaseLayout
1055
+ title="ITDropfile"
1056
+ description="Área interactiva para arrastrar y soltar archivos, con previsualización de imágenes y barra de progreso."
1057
+ code={code}
1058
+ demo={
1059
+ <div className="w-full max-w-md">
1060
+ <ITDropfile
1061
+ onFileSelect={(file) => setSelectedFile(file)}
1062
+ uploadStatus={status}
1063
+ onStatusChange={(st) => setStatus(st)}
1064
+ />
1065
+ {selectedFile && (
1066
+ <div className="mt-4 p-3 bg-slate-50 dark:bg-slate-900 border rounded-lg text-xs font-mono">
1067
+ <p>Nombre: {selectedFile.name}</p>
1068
+ <p>Tamaño: {(selectedFile.size / 1024).toFixed(1)} KB</p>
1069
+ <p>Tipo: {selectedFile.type}</p>
1070
+ </div>
1071
+ )}
1072
+ </div>
1073
+ }
1074
+ controls={
1075
+ <>
1076
+ <ITSelect
1077
+ name="status_ctrl"
1078
+ label="Forzar Estado de Subida"
1079
+ value={status}
1080
+ onChange={(e: any) => setStatus(e.target.value)}
1081
+ options={[
1082
+ { label: "Pendiente", value: "pendiente" },
1083
+ { label: "Subiendo (Uploading)", value: "subiendo" },
1084
+ { label: "Subido (Uploaded)", value: "subido" },
1085
+ { label: "Error", value: "error" }
1086
+ ]}
1087
+ />
1088
+ </>
1089
+ }
1090
+ />
1091
+ );
1092
+ };
1093
+
1094
+ // 10. ITFormBuilder Showcase
1095
+ export const FormBuilderShowcase = () => {
1096
+ const [values, setValues] = useState({
1097
+ name: "",
1098
+ email: "",
1099
+ country: "MX",
1100
+ accept: false
1101
+ });
1102
+
1103
+ const handleChange = (e: any) => {
1104
+ const { name, value, type, checked } = e.target;
1105
+ setValues(prev => ({
1106
+ ...prev,
1107
+ [name]: type === "checkbox" ? checked : value
1108
+ }));
1109
+ };
1110
+
1111
+ const config: any = [
1112
+ { name: "name", label: "Nombre Completo", type: "text", required: true },
1113
+ { name: "email", label: "Correo de Contacto", type: "email", required: true },
1114
+ {
1115
+ name: "country",
1116
+ label: "País Operación",
1117
+ type: "select",
1118
+ options: [
1119
+ { label: "México", value: "MX" },
1120
+ { label: "Chile", value: "CL" },
1121
+ { label: "Perú", value: "PE" }
1122
+ ]
1123
+ },
1124
+ { name: "accept", label: "Acepto términos y condiciones", type: "checkbox" }
1125
+ ];
1126
+
1127
+ const code = `<ITFormBuilder\n config={[\n { name: 'name', label: 'Nombre', type: 'text', required: true },\n { name: 'email', label: 'Email', type: 'email' },\n ...\n ]}\n values={formValues}\n handleChange={handleFormChange}\n/>`;
1128
+
1129
+ return (
1130
+ <ShowcaseLayout
1131
+ title="ITFormBuilder"
1132
+ description="Generador dinámico de formularios basado en un esquema estructurado JSON."
1133
+ code={code}
1134
+ demo={
1135
+ <div className="w-full max-w-md bg-white dark:bg-slate-900 p-6 rounded-2xl border shadow-sm space-y-6">
1136
+ <ITFormBuilder
1137
+ config={config}
1138
+ values={values}
1139
+ handleChange={handleChange}
1140
+ handleBlur={() => { }}
1141
+ touched={{}}
1142
+ errors={{}}
1143
+ />
1144
+ <div className="pt-4 border-t border-slate-100 dark:border-slate-800">
1145
+ <h5 className="text-xs font-bold uppercase text-slate-400 mb-2">Valores del Formulario (JSON):</h5>
1146
+ <pre className="p-3 bg-slate-950 text-emerald-400 text-xs rounded-lg overflow-x-auto font-mono">
1147
+ {JSON.stringify(values, null, 2)}
1148
+ </pre>
1149
+ </div>
1150
+ </div>
1151
+ }
1152
+ controls={
1153
+ <div className="p-2 bg-slate-50 dark:bg-slate-900 rounded-lg text-xs">
1154
+ <p className="text-slate-500">El formulario se genera dinámicamente inyectando un array de campos configurados.</p>
1155
+ </div>
1156
+ }
1157
+ />
1158
+ );
1159
+ };