@axzydev/axzy_ui_system 1.2.1 → 1.2.3

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 (207) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +82 -1
  4. package/dist/index.css.map +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/index.js.map +1 -1
  7. package/package.json +2 -2
  8. package/src/App.tsx +354 -0
  9. package/src/assets/logo.png +0 -0
  10. package/src/assets/react.svg +1 -0
  11. package/src/components/alert/alert.props.ts +13 -0
  12. package/src/components/alert/alert.stories.tsx +41 -0
  13. package/src/components/alert/alert.tsx +53 -0
  14. package/src/components/avatar/avatar.props.ts +14 -0
  15. package/src/components/avatar/avatar.stories.tsx +46 -0
  16. package/src/components/avatar/avatar.tsx +53 -0
  17. package/src/components/badget/badget.props.ts +12 -0
  18. package/src/components/badget/badget.stories.tsx +76 -0
  19. package/src/components/badget/badget.tsx +61 -0
  20. package/src/components/breadcrumbs/breadcrumbs.props.ts +13 -0
  21. package/src/components/breadcrumbs/breadcrumbs.stories.tsx +21 -0
  22. package/src/components/breadcrumbs/breadcrumbs.tsx +34 -0
  23. package/src/components/button/button.props.ts +18 -0
  24. package/src/components/button/button.stories.tsx +174 -0
  25. package/src/components/button/button.tsx +117 -0
  26. package/src/components/calendar/calendar.props.ts +33 -0
  27. package/src/components/calendar/calendar.stories.tsx +91 -0
  28. package/src/components/calendar/calendar.tsx +608 -0
  29. package/src/components/calendar/index.ts +3 -0
  30. package/src/components/card/card.props.ts +13 -0
  31. package/src/components/card/card.stories.tsx +58 -0
  32. package/src/components/card/card.tsx +79 -0
  33. package/src/components/checkbox/checkbox.props.ts +11 -0
  34. package/src/components/checkbox/checkbox.stories.tsx +54 -0
  35. package/src/components/checkbox/checkbox.tsx +52 -0
  36. package/src/components/confirm-dialog/confirm-dialog.props.ts +14 -0
  37. package/src/components/confirm-dialog/confirm-dialog.stories.tsx +33 -0
  38. package/src/components/confirm-dialog/confirm-dialog.tsx +45 -0
  39. package/src/components/data-table/ITDataTable.stories.tsx +213 -0
  40. package/src/components/data-table/dataTable.props.ts +69 -0
  41. package/src/components/data-table/dataTable.tsx +313 -0
  42. package/src/components/date-picker/date-picker.props.ts +30 -0
  43. package/src/components/date-picker/date-picker.stories.tsx +90 -0
  44. package/src/components/date-picker/datePicker.tsx +307 -0
  45. package/src/components/dialog/dialog.props.ts +9 -0
  46. package/src/components/dialog/dialog.stories.tsx +80 -0
  47. package/src/components/dialog/dialog.tsx +88 -0
  48. package/src/components/divider/divider.props.ts +8 -0
  49. package/src/components/divider/divider.stories.tsx +34 -0
  50. package/src/components/divider/divider.tsx +21 -0
  51. package/src/components/drawer/drawer.props.ts +14 -0
  52. package/src/components/drawer/drawer.stories.tsx +41 -0
  53. package/src/components/drawer/drawer.tsx +53 -0
  54. package/src/components/dropfile/dropfile.stories.tsx +75 -0
  55. package/src/components/dropfile/dropfile.tsx +407 -0
  56. package/src/components/empty-state/empty-state.props.ts +9 -0
  57. package/src/components/empty-state/empty-state.stories.tsx +20 -0
  58. package/src/components/empty-state/empty-state.tsx +21 -0
  59. package/src/components/flex/flex.props.ts +22 -0
  60. package/src/components/flex/flex.stories.tsx +71 -0
  61. package/src/components/flex/flex.tsx +79 -0
  62. package/src/components/form-builder/fieldRenderer.tsx +218 -0
  63. package/src/components/form-builder/formBuilder.context.tsx +70 -0
  64. package/src/components/form-builder/formBuilder.props.ts +43 -0
  65. package/src/components/form-builder/formBuilder.stories.tsx +317 -0
  66. package/src/components/form-builder/formBuilder.tsx +186 -0
  67. package/src/components/form-builder/useFormBuilder.ts +80 -0
  68. package/src/components/form-header/form-header.props.ts +5 -0
  69. package/src/components/form-header/form-header.tsx +38 -0
  70. package/src/components/grid/grid.props.ts +17 -0
  71. package/src/components/grid/grid.stories.tsx +72 -0
  72. package/src/components/grid/grid.tsx +69 -0
  73. package/src/components/image/image.props.ts +7 -0
  74. package/src/components/image/image.tsx +38 -0
  75. package/src/components/input/input.props.ts +49 -0
  76. package/src/components/input/input.stories.tsx +115 -0
  77. package/src/components/input/input.tsx +615 -0
  78. package/src/components/layout/layout.props.ts +10 -0
  79. package/src/components/layout/layout.stories.tsx +114 -0
  80. package/src/components/layout/layout.tsx +80 -0
  81. package/src/components/loader/loader.props.ts +8 -0
  82. package/src/components/loader/loader.stories.tsx +105 -0
  83. package/src/components/loader/loader.tsx +108 -0
  84. package/src/components/navbar/navbar.props.ts +37 -0
  85. package/src/components/navbar/navbar.tsx +328 -0
  86. package/src/components/page/page.props.ts +19 -0
  87. package/src/components/page/page.stories.tsx +98 -0
  88. package/src/components/page/page.tsx +90 -0
  89. package/src/components/page-header/page-header.props.ts +11 -0
  90. package/src/components/page-header/page-header.stories.tsx +61 -0
  91. package/src/components/page-header/page-header.tsx +62 -0
  92. package/src/components/pagination/pagination.props.ts +53 -0
  93. package/src/components/pagination/pagination.stories.tsx +111 -0
  94. package/src/components/pagination/pagination.tsx +241 -0
  95. package/src/components/popover/popover.props.ts +12 -0
  96. package/src/components/popover/popover.stories.tsx +25 -0
  97. package/src/components/popover/popover.tsx +45 -0
  98. package/src/components/progress/progress.props.ts +12 -0
  99. package/src/components/progress/progress.stories.tsx +40 -0
  100. package/src/components/progress/progress.tsx +52 -0
  101. package/src/components/radio/radio.props.ts +16 -0
  102. package/src/components/radio/radio.stories.tsx +50 -0
  103. package/src/components/radio/radio.tsx +58 -0
  104. package/src/components/search-select/index.ts +2 -0
  105. package/src/components/search-select/search-select.props.ts +46 -0
  106. package/src/components/search-select/search-select.stories.tsx +129 -0
  107. package/src/components/search-select/search-select.tsx +229 -0
  108. package/src/components/searchTable/components/EditableCell.tsx +149 -0
  109. package/src/components/searchTable/components/PaginationControls.tsx +86 -0
  110. package/src/components/searchTable/components/PaginationInfo.tsx +20 -0
  111. package/src/components/searchTable/components/SearchAndSortBar.tsx +53 -0
  112. package/src/components/searchTable/components/SearchInput.tsx +33 -0
  113. package/src/components/searchTable/components/SortButton.tsx +50 -0
  114. package/src/components/searchTable/components/TableEmptyState.tsx +22 -0
  115. package/src/components/searchTable/components/TableHeader.tsx +35 -0
  116. package/src/components/searchTable/components/TableHeaderCell.tsx +43 -0
  117. package/src/components/searchTable/components/TableRow.tsx +144 -0
  118. package/src/components/searchTable/searchTable.props.ts +56 -0
  119. package/src/components/searchTable/searchTable.tsx +187 -0
  120. package/src/components/segmented-control/segmented-control.props.ts +18 -0
  121. package/src/components/segmented-control/segmented-control.stories.tsx +63 -0
  122. package/src/components/segmented-control/segmented-control.tsx +52 -0
  123. package/src/components/select/select.props.ts +25 -0
  124. package/src/components/select/select.stories.tsx +86 -0
  125. package/src/components/select/select.tsx +150 -0
  126. package/src/components/sidebar/sidebar.props.ts +28 -0
  127. package/src/components/sidebar/sidebar.stories.tsx +117 -0
  128. package/src/components/sidebar/sidebar.tsx +313 -0
  129. package/src/components/skeleton/skeleton.props.ts +12 -0
  130. package/src/components/skeleton/skeleton.stories.tsx +30 -0
  131. package/src/components/skeleton/skeleton.tsx +45 -0
  132. package/src/components/slide/slide.props.ts +45 -0
  133. package/src/components/slide/slide.stories.tsx +121 -0
  134. package/src/components/slide/slide.tsx +109 -0
  135. package/src/components/slider/slider.props.ts +10 -0
  136. package/src/components/slider/slider.stories.tsx +30 -0
  137. package/src/components/slider/slider.tsx +49 -0
  138. package/src/components/stack/stack.props.ts +19 -0
  139. package/src/components/stack/stack.stories.tsx +79 -0
  140. package/src/components/stack/stack.tsx +79 -0
  141. package/src/components/stat-card/stat-card.props.ts +13 -0
  142. package/src/components/stat-card/stat-card.stories.tsx +41 -0
  143. package/src/components/stat-card/stat-card.tsx +44 -0
  144. package/src/components/stepper/stepper.css +26 -0
  145. package/src/components/stepper/stepper.props.ts +29 -0
  146. package/src/components/stepper/stepper.stories.tsx +155 -0
  147. package/src/components/stepper/stepper.tsx +227 -0
  148. package/src/components/table/table.props.ts +43 -0
  149. package/src/components/table/table.stories.tsx +189 -0
  150. package/src/components/table/table.tsx +376 -0
  151. package/src/components/tabs/tabs.props.ts +18 -0
  152. package/src/components/tabs/tabs.stories.tsx +32 -0
  153. package/src/components/tabs/tabs.tsx +74 -0
  154. package/src/components/text/text.props.ts +9 -0
  155. package/src/components/text/text.tsx +20 -0
  156. package/src/components/textarea/textarea.props.ts +15 -0
  157. package/src/components/textarea/textarea.stories.tsx +27 -0
  158. package/src/components/textarea/textarea.tsx +55 -0
  159. package/src/components/theme-provider/themeProvider.props.ts +28 -0
  160. package/src/components/theme-provider/themeProvider.tsx +1854 -0
  161. package/src/components/time-picker/timePicker.props.ts +16 -0
  162. package/src/components/time-picker/timePicker.stories.tsx +131 -0
  163. package/src/components/time-picker/timePicker.tsx +317 -0
  164. package/src/components/toast/toast.css +32 -0
  165. package/src/components/toast/toast.props.ts +13 -0
  166. package/src/components/toast/toast.stories.tsx +138 -0
  167. package/src/components/toast/toast.tsx +87 -0
  168. package/src/components/tooltip/tooltip.props.ts +11 -0
  169. package/src/components/tooltip/tooltip.stories.tsx +20 -0
  170. package/src/components/tooltip/tooltip.tsx +55 -0
  171. package/src/components/topbar/topbar.props.ts +21 -0
  172. package/src/components/topbar/topbar.stories.tsx +80 -0
  173. package/src/components/topbar/topbar.tsx +205 -0
  174. package/src/components/triple-filter/tripleFilter.props.ts +15 -0
  175. package/src/components/triple-filter/tripleFilter.stories.tsx +32 -0
  176. package/src/components/triple-filter/tripleFilter.tsx +50 -0
  177. package/src/dev.css +2 -0
  178. package/src/hooks/useClickOutside.ts +21 -0
  179. package/src/hooks/useDebouncedSearch.ts +55 -0
  180. package/src/hooks/useEditableRow.ts +157 -0
  181. package/src/hooks/useTableState.ts +122 -0
  182. package/src/index.css +168 -0
  183. package/src/index.ts +165 -0
  184. package/src/main.tsx +9 -0
  185. package/src/showcases/DataShowcases.tsx +260 -0
  186. package/src/showcases/FeedbackShowcases.tsx +268 -0
  187. package/src/showcases/FormShowcases.tsx +1159 -0
  188. package/src/showcases/HomeShowcase.tsx +324 -0
  189. package/src/showcases/LayoutPrimitivesShowcases.tsx +569 -0
  190. package/src/showcases/NavigationShowcases.tsx +193 -0
  191. package/src/showcases/PageShowcases.tsx +207 -0
  192. package/src/showcases/ShowcaseLayout.tsx +139 -0
  193. package/src/showcases/StructureShowcases.tsx +152 -0
  194. package/src/types/badget.types.ts +37 -0
  195. package/src/types/button.types.ts +16 -0
  196. package/src/types/colors.types.ts +3 -0
  197. package/src/types/field.types.ts +103 -0
  198. package/src/types/formik.types.ts +15 -0
  199. package/src/types/input.types.ts +14 -0
  200. package/src/types/loader.types.ts +9 -0
  201. package/src/types/sizes.types.ts +1 -0
  202. package/src/types/table.types.ts +15 -0
  203. package/src/types/toast.types.ts +8 -0
  204. package/src/types/yup.types.ts +11 -0
  205. package/src/utils/color.utils.ts +99 -0
  206. package/src/utils/styles.ts +120 -0
  207. package/src/utils/table.utils.ts +10 -0
@@ -0,0 +1,313 @@
1
+ import { useTableState } from "@/hooks/useTableState";
2
+ import { sizeStyles, variantStyles } from "@/types/table.types";
3
+ import clsx from "clsx";
4
+ import React, { useState, useEffect, useCallback, useRef } from "react";
5
+ import { FaCheck, FaSpinner, FaTimes } from "react-icons/fa";
6
+ import { MdOutlineSwapVert } from "react-icons/md";
7
+ import ITInput from "../input/input";
8
+ import ITPagination from "../pagination/pagination";
9
+ import ITSelect from "../select/select";
10
+ import { Column } from "../table/table.props";
11
+ import { formatCurrencyMX } from "../table/table";
12
+ import { ITDataTableProps } from "./dataTable.props";
13
+ import ITText from "@/components/text/text";
14
+
15
+ const getNestedValue = (obj: unknown, path: string) => {
16
+ return path.split(".").reduce((acc, part) => acc && acc[part], obj);
17
+ };
18
+
19
+ const EMPTY_OBJECT = {};
20
+
21
+ export default function ITDataTable<T extends Record<string, unknown>>({
22
+ columns,
23
+ fetchData,
24
+ debounceMs = 500,
25
+ externalFilters = EMPTY_OBJECT,
26
+ loadingIndicator,
27
+ fetchOnMount = true,
28
+ reloadTrigger,
29
+ containerClassName,
30
+ className,
31
+ variant = "default",
32
+ size = "md",
33
+ itemsPerPageOptions = [5, 10, 20],
34
+ defaultItemsPerPage = 10,
35
+ title,
36
+ }: ITDataTableProps<T>) {
37
+ const [data, setData] = useState<T[]>([]);
38
+ const [totalItems, setTotalItems] = useState(0);
39
+ const [isLoading, setIsLoading] = useState(fetchOnMount);
40
+
41
+ const {
42
+ currentPage,
43
+ itemsPerPage,
44
+ filters,
45
+ sortConfig,
46
+ totalPages,
47
+ goToPage,
48
+ handleFilterChange,
49
+ handleSort,
50
+ handleItemsPerPageChange,
51
+ } = useTableState({ defaultItemsPerPage });
52
+
53
+ const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
54
+
55
+ const computedTotalPages = Math.ceil(totalItems / itemsPerPage) || 1;
56
+
57
+ const performFetch = useCallback(async () => {
58
+ setIsLoading(true);
59
+ try {
60
+ const response = await fetchData({
61
+ page: currentPage,
62
+ limit: itemsPerPage,
63
+ filters: { ...filters, ...externalFilters },
64
+ sort: sortConfig || undefined,
65
+ });
66
+ setData(response.data || []);
67
+ setTotalItems(response.total || 0);
68
+ } catch (error) {
69
+ console.error("ITDataTable: Error fetching data", error);
70
+ setData([]);
71
+ setTotalItems(0);
72
+ } finally {
73
+ setIsLoading(false);
74
+ }
75
+ }, [currentPage, itemsPerPage, filters, sortConfig, fetchData, externalFilters]);
76
+
77
+ useEffect(() => {
78
+ if (!fetchOnMount && data.length === 0 && !isLoading) return;
79
+
80
+ if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
81
+
82
+ debounceTimerRef.current = setTimeout(() => {
83
+ performFetch();
84
+ }, debounceMs);
85
+
86
+ return () => {
87
+ if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
88
+ };
89
+ }, [currentPage, itemsPerPage, sortConfig, filters, externalFilters, reloadTrigger, fetchOnMount, performFetch]);
90
+
91
+ const renderFilterInput = (col: Column<T>) => {
92
+ if (!col.filter) return null;
93
+
94
+ if (col.type === "boolean") {
95
+ const currentValue = filters[col.key];
96
+ const nextValue =
97
+ currentValue === undefined ? true : currentValue === true ? false : undefined;
98
+
99
+ const getToggleLabel = () => {
100
+ if (currentValue === undefined) return "Mostrar todos";
101
+ if (currentValue === true) return "Filtrar solo verdaderos";
102
+ return "Filtrar solo falsos";
103
+ };
104
+
105
+ return (
106
+ <button
107
+ className="flex items-center justify-center cursor-pointer focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 rounded-full p-1 transition-all duration-200"
108
+ onClick={() => handleFilterChange(col.key, nextValue)}
109
+ aria-label={`${getToggleLabel()} para ${col.label}`}
110
+ title={`${getToggleLabel()} para ${col.label}`}
111
+ disabled={isLoading}
112
+ >
113
+ <div className="relative w-10 h-5 bg-gray-300 rounded-full">
114
+ <div
115
+ className={clsx(
116
+ "absolute top-0.5 w-4 h-4 rounded-full transition-all duration-300 shadow-sm",
117
+ {
118
+ "left-0.5 bg-gray-400": currentValue === undefined,
119
+ "left-5 bg-slate-500": currentValue === true,
120
+ "left-0.5 bg-gray-500": currentValue === false,
121
+ }
122
+ )}
123
+ />
124
+ </div>
125
+ </button>
126
+ );
127
+ }
128
+
129
+ if (col.filter === "catalog" && col.catalogOptions) {
130
+ if (col.catalogOptions.loading) {
131
+ return <FaSpinner className="animate-spin" aria-label="Cargando opciones" title="Cargando opciones" />;
132
+ }
133
+ if (col.catalogOptions.error) {
134
+ return <ITText as="span" className="text-red-500 text-xs">Error cargando</ITText>;
135
+ }
136
+ return (
137
+ <ITSelect
138
+ name={`filter-${col.key}`}
139
+ options={[
140
+ { value: "", label: "Todos" },
141
+ ...col.catalogOptions.data.map((item) => ({
142
+ value: String(item.id),
143
+ label: item.name,
144
+ })),
145
+ ]}
146
+ value={String(filters[col.key] || "")}
147
+ onChange={(e) => {
148
+ const value = e.target.value === "" ? undefined : e.target.value;
149
+ handleFilterChange(col.key, value);
150
+ }}
151
+ onBlur={() => {}}
152
+ className="w-full text-xs"
153
+ disabled={isLoading}
154
+ />
155
+ );
156
+ }
157
+
158
+ return (
159
+ <ITInput
160
+ name={`filter-${col.key}`}
161
+ className="w-full text-xs"
162
+ placeholder="Buscar..."
163
+ value={String(filters[col.key] || "")}
164
+ onChange={(e) => handleFilterChange(col.key, e.target.value)}
165
+ onBlur={() => {}}
166
+ disabled={isLoading}
167
+ />
168
+ );
169
+ };
170
+
171
+ const renderCellContent = (col: Column<T>, row: T) => {
172
+ const value = getNestedValue(row, col.key);
173
+ if (col.render) return col.render(row);
174
+
175
+ switch (col.type) {
176
+ case "number":
177
+ return typeof value === "number" && col.currencyMX ? formatCurrencyMX(value) : value;
178
+ case "boolean":
179
+ return value ? (
180
+ <FaCheck className="text-green-500" aria-label="Verdadero" title="Verdadero" />
181
+ ) : (
182
+ <FaTimes className="text-red-500" aria-label="Falso" title="Falso" />
183
+ );
184
+ case "actions":
185
+ return col.actions ? col.actions(row) : null;
186
+ case "catalog":
187
+ if (col.catalogOptions) {
188
+ const catalogItem = col.catalogOptions.data.find((item) => item.id === value);
189
+ return catalogItem?.name || value;
190
+ }
191
+ return value as React.ReactNode;
192
+ default:
193
+ return value as React.ReactNode;
194
+ }
195
+ };
196
+
197
+ return (
198
+ <div className={clsx("space-y-4 w-full relative", containerClassName)}>
199
+ <div className="rounded-xl shadow-sm border border-secondary-200 overflow-hidden" style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)' }}>
200
+ {title && (
201
+ <div className="px-6 py-5 border-b border-secondary-100 flex justify-between items-center" style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)' }}>
202
+ <ITText as="h2" className="text-xl font-bold text-secondary-900 leading-tight">{title}</ITText>
203
+ {isLoading && (
204
+ <div className="text-secondary-400">
205
+ {loadingIndicator || <FaSpinner className="animate-spin text-primary-500 text-xl" />}
206
+ </div>
207
+ )}
208
+ </div>
209
+ )}
210
+
211
+ <div className="overflow-x-auto relative min-h-[200px]">
212
+ {isLoading && (
213
+ <div className="absolute inset-0 z-20 flex items-center justify-center bg-white/40 backdrop-blur-[2px] transition-all duration-300">
214
+ <div className="flex flex-col items-center gap-3 p-6 rounded-2xl shadow-xl border border-secondary-100 animate-in fade-in zoom-in duration-300" style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)' }}>
215
+ {loadingIndicator || (
216
+ <>
217
+ <FaSpinner className="animate-spin text-primary-500 text-4xl" />
218
+ <ITText as="span" className="text-sm font-semibold text-secondary-600 animate-pulse">Cargando datos...</ITText>
219
+ </>
220
+ )}
221
+ </div>
222
+ </div>
223
+ )}
224
+
225
+ <table
226
+ className={clsx(
227
+ "min-w-max w-full text-sm text-left text-secondary-600 transition-opacity duration-300",
228
+ isLoading ? "opacity-50" : "opacity-100",
229
+ variantStyles[variant],
230
+ sizeStyles[size],
231
+ className
232
+ )}
233
+ >
234
+ <thead>
235
+ <tr className="bg-secondary-50 border-b border-secondary-200 text-xs uppercase tracking-wider font-semibold text-secondary-500">
236
+ {columns.map((col) => (
237
+ <th key={col.key} scope="col" className={clsx("px-4 py-4 align-top", col.className)}>
238
+ <div className="flex flex-col gap-3 min-w-[150px]">
239
+ <div className="flex items-center justify-between gap-2">
240
+ <ITText as="span" className="text-secondary-700 font-bold">{col.label}</ITText>
241
+ {col.sortable && col.type !== "actions" && (
242
+ <button
243
+ onClick={() => handleSort(col.key)}
244
+ disabled={isLoading}
245
+ className={`p-1 rounded-md transition-colors ${
246
+ sortConfig?.key === col.key
247
+ ? "bg-secondary-200 text-secondary-900"
248
+ : "hover:bg-secondary-200 text-secondary-400 hover:text-secondary-700"
249
+ } disabled:opacity-50`}
250
+ title={`Ordenar por ${col.label}`}
251
+ >
252
+ <MdOutlineSwapVert className="w-4 h-4" aria-hidden="true" />
253
+ </button>
254
+ )}
255
+ </div>
256
+
257
+ <div className="w-full">{col.filter ? renderFilterInput(col) : null}</div>
258
+ </div>
259
+ </th>
260
+ ))}
261
+ </tr>
262
+ </thead>
263
+ <tbody className="divide-y divide-secondary-100">
264
+ {data.length > 0 ? (
265
+ data.map((row, rowIndex) => (
266
+ <tr key={rowIndex} className="hover:bg-secondary-50/50 transition-colors duration-150 group">
267
+ {columns.map((col) => (
268
+ <td key={`${rowIndex}-${col.key}`} className={clsx("px-4 py-3 align-middle", col.className)}>
269
+ {col.type === "actions" ? (
270
+ <div className="flex items-center justify-center gap-2">
271
+ {renderCellContent(col, row) as React.ReactNode}
272
+ </div>
273
+ ) : (
274
+ <div className="text-secondary-700 font-medium">
275
+ {renderCellContent(col, row) as React.ReactNode}
276
+ </div>
277
+ )}
278
+ </td>
279
+ ))}
280
+ </tr>
281
+ ))
282
+ ) : (
283
+ <tr>
284
+ <td colSpan={columns.length} className="px-6 py-20 text-center">
285
+ {!isLoading && (
286
+ <div className="flex flex-col items-center justify-center text-secondary-400">
287
+ <ITText as="span" className="text-lg">No se encontraron resultados</ITText>
288
+ <ITText as="span" className="text-sm mt-1">Intenta ajustar los filtros</ITText>
289
+ </div>
290
+ )}
291
+ </td>
292
+ </tr>
293
+ )}
294
+ </tbody>
295
+ </table>
296
+ </div>
297
+ </div>
298
+
299
+ <div className="rounded-b-xl border-t border-secondary-200 px-6 py-4" style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)' }}>
300
+ <ITPagination
301
+ currentPage={currentPage}
302
+ totalPages={computedTotalPages}
303
+ onPageChange={goToPage}
304
+ color="primary"
305
+ itemsPerPageOptions={itemsPerPageOptions}
306
+ itemsPerPage={itemsPerPage}
307
+ onItemsPerPageChange={handleItemsPerPageChange}
308
+ totalItems={totalItems}
309
+ />
310
+ </div>
311
+ </div>
312
+ );
313
+ }
@@ -0,0 +1,30 @@
1
+ import { ColorsTypes } from "@/types/colors.types";
2
+ import { SizesTypes } from "@/types/sizes.types";
3
+
4
+ export interface ITDatePickerProps {
5
+ name: string;
6
+ value?: Date | [Date | null, Date | null];
7
+ onChange: (
8
+ event:
9
+ | React.ChangeEvent<HTMLInputElement>
10
+ | { target: { name: string; value: Date | [Date | null, Date | null] } }
11
+ ) => void;
12
+ onBlur?: (
13
+ event:
14
+ | React.FocusEvent<HTMLInputElement>
15
+ | { target: { name: string; value: Date | [Date | null, Date | null] } }
16
+ ) => void;
17
+ range?: boolean;
18
+ variant?: ColorsTypes;
19
+ size?: SizesTypes;
20
+ className?: string;
21
+ calendarClassName?: string;
22
+ disabled?: boolean;
23
+ placeholder?: string;
24
+ label?: string;
25
+ required?: boolean;
26
+ touched?: boolean;
27
+ error?: string | boolean;
28
+ minDate?: Date;
29
+ maxDate?: Date;
30
+ }
@@ -0,0 +1,90 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import ITDatePicker from './datePicker';
3
+ import { useState } from 'react';
4
+
5
+ const meta = {
6
+ title: 'Components/Form Elements/ITDatePicker',
7
+ component: ITDatePicker,
8
+ parameters: {
9
+ layout: 'padded',
10
+ },
11
+ tags: ['autodocs'],
12
+ argTypes: {
13
+ value: { control: 'date' },
14
+ minDate: { control: 'date' },
15
+ maxDate: { control: 'date' },
16
+ onChange: { action: 'changed' },
17
+ onBlur: { action: 'blurred' },
18
+ disabled: { control: 'boolean' },
19
+ error: { control: 'text' },
20
+ },
21
+ } satisfies Meta<typeof ITDatePicker>;
22
+
23
+ export default meta;
24
+ type Story = StoryObj<typeof meta>;
25
+
26
+ // Wrapper for controlled component state
27
+ const DatePickerWrapper = (args: any) => {
28
+ const [date, setDate] = useState<Date>(args.value || new Date());
29
+
30
+ const handleChange = (e: any) => {
31
+ // Handle both event types the component might emit
32
+ if (e.target && e.target.value) {
33
+ setDate(e.target.value instanceof Date ? e.target.value : new Date(e.target.value));
34
+ }
35
+ args.onChange(e);
36
+ };
37
+
38
+ return <ITDatePicker {...args} value={date} onChange={handleChange} />;
39
+ };
40
+
41
+ export const Default: any = {
42
+ render: (args) => <DatePickerWrapper {...args} />,
43
+ args: {
44
+ name: 'birthdate',
45
+ label: 'Select Date',
46
+ placeholder: 'DD/MM/YYYY',
47
+ } as any,
48
+ };
49
+
50
+ export const WithError: any = {
51
+ render: (args) => <DatePickerWrapper {...args} />,
52
+ args: {
53
+ name: 'error_date',
54
+ label: 'Invalid Date',
55
+ error: 'This field is required',
56
+ touched: true,
57
+ } as any,
58
+ };
59
+
60
+ export const Disabled: any = {
61
+ args: {
62
+ name: 'disabled_date',
63
+ label: 'Disabled Input',
64
+ value: new Date(),
65
+ disabled: true,
66
+ } as any,
67
+ };
68
+
69
+ // Wrapper for range state
70
+ const RangePickerWrapper = (args: any) => {
71
+ const [range, setRange] = useState<[Date | null, Date | null]>([null, null]);
72
+
73
+ return (
74
+ <ITDatePicker
75
+ {...args}
76
+ value={range}
77
+ onChange={(e: any) => setRange(e.target.value)}
78
+ />
79
+ );
80
+ };
81
+
82
+ export const Range: any = {
83
+ render: (args) => <RangePickerWrapper {...args} />,
84
+ args: {
85
+ range: true,
86
+ name: 'audit_range',
87
+ label: 'Select Date Range',
88
+ placeholder: 'DD/MM/YYYY - DD/MM/YYYY',
89
+ } as any,
90
+ };