@axzydev/axzy_ui_system 1.2.7 → 1.2.8

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 (184) hide show
  1. package/dist/index.cjs +576 -398
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +1 -1
  4. package/dist/index.css.map +1 -1
  5. package/dist/index.d.cts +1463 -86
  6. package/dist/index.d.ts +1463 -86
  7. package/dist/index.js +597 -417
  8. package/dist/index.js.map +1 -1
  9. package/package.json +1 -1
  10. package/src/App.tsx +19 -54
  11. package/src/components/alert/alert.doc.mdx +48 -0
  12. package/src/components/alert/alert.props.ts +7 -0
  13. package/src/components/alert/alert.tsx +8 -0
  14. package/src/components/avatar/avatar.doc.mdx +48 -0
  15. package/src/components/avatar/avatar.props.ts +8 -0
  16. package/src/components/avatar/avatar.tsx +25 -5
  17. package/src/components/badget/badget.doc.mdx +46 -0
  18. package/src/components/badget/badget.props.ts +6 -0
  19. package/src/components/badget/badget.tsx +11 -0
  20. package/src/components/breadcrumbs/breadcrumbs.doc.mdx +57 -0
  21. package/src/components/breadcrumbs/breadcrumbs.props.ts +6 -0
  22. package/src/components/breadcrumbs/breadcrumbs.tsx +12 -0
  23. package/src/components/button/button.doc.mdx +59 -0
  24. package/src/components/button/button.props.ts +12 -0
  25. package/src/components/button/button.tsx +11 -0
  26. package/src/components/calendar/calendar.doc.mdx +75 -0
  27. package/src/components/calendar/calendar.props.ts +27 -7
  28. package/src/components/calendar/calendar.tsx +13 -0
  29. package/src/components/card/card.doc.mdx +54 -0
  30. package/src/components/card/card.props.ts +11 -0
  31. package/src/components/card/card.tsx +13 -0
  32. package/src/components/checkbox/checkbox.doc.mdx +54 -0
  33. package/src/components/checkbox/checkbox.props.ts +7 -0
  34. package/src/components/checkbox/checkbox.tsx +9 -0
  35. package/src/components/confirm-dialog/confirm-dialog.doc.mdx +60 -0
  36. package/src/components/confirm-dialog/confirm-dialog.props.ts +9 -0
  37. package/src/components/confirm-dialog/confirm-dialog.tsx +19 -0
  38. package/src/components/data-table/ITDataTable.doc.mdx +59 -0
  39. package/src/components/data-table/dataTable.props.ts +15 -0
  40. package/src/components/data-table/dataTable.tsx +178 -73
  41. package/src/components/date-picker/date-picker.doc.mdx +65 -0
  42. package/src/components/date-picker/date-picker.props.ts +17 -0
  43. package/src/components/date-picker/datePicker.tsx +31 -1
  44. package/src/components/dialog/dialog.doc.mdx +54 -0
  45. package/src/components/dialog/dialog.props.ts +7 -0
  46. package/src/components/dialog/dialog.tsx +26 -0
  47. package/src/components/divider/divider.doc.mdx +42 -0
  48. package/src/components/divider/divider.props.ts +5 -0
  49. package/src/components/divider/divider.tsx +16 -0
  50. package/src/components/drawer/drawer.doc.mdx +59 -0
  51. package/src/components/drawer/drawer.props.ts +9 -0
  52. package/src/components/drawer/drawer.tsx +20 -0
  53. package/src/components/dropfile/dropfile.doc.mdx +59 -0
  54. package/src/components/dropfile/dropfile.props.ts +41 -0
  55. package/src/components/dropfile/dropfile.tsx +21 -33
  56. package/src/components/empty-state/empty-state.doc.mdx +50 -0
  57. package/src/components/empty-state/empty-state.props.ts +5 -0
  58. package/src/components/empty-state/empty-state.tsx +16 -0
  59. package/src/components/flex/flex.doc.mdx +59 -0
  60. package/src/components/flex/flex.props.ts +13 -0
  61. package/src/components/flex/flex.tsx +15 -0
  62. package/src/components/form-builder/fieldRenderer.tsx +52 -2
  63. package/src/components/form-builder/formBuilder.doc.mdx +124 -0
  64. package/src/components/form-builder/formBuilder.props.ts +12 -2
  65. package/src/components/form-builder/formBuilder.tsx +31 -0
  66. package/src/components/form-header/form-header.doc.mdx +38 -0
  67. package/src/components/form-header/form-header.props.ts +3 -0
  68. package/src/components/form-header/form-header.stories.tsx +53 -0
  69. package/src/components/form-header/form-header.tsx +11 -0
  70. package/src/components/grid/grid.doc.mdx +54 -0
  71. package/src/components/grid/grid.props.ts +13 -0
  72. package/src/components/grid/grid.tsx +19 -0
  73. package/src/components/image/image.doc.mdx +44 -0
  74. package/src/components/image/image.props.ts +5 -0
  75. package/src/components/image/image.stories.tsx +49 -0
  76. package/src/components/image/image.tsx +19 -0
  77. package/src/components/input/input.doc.mdx +70 -0
  78. package/src/components/input/input.props.ts +34 -2
  79. package/src/components/input/input.tsx +29 -0
  80. package/src/components/layout/layout.doc.mdx +51 -0
  81. package/src/components/layout/layout.props.ts +5 -0
  82. package/src/components/layout/layout.tsx +29 -2
  83. package/src/components/loader/loader.doc.mdx +43 -0
  84. package/src/components/loader/loader.props.ts +4 -0
  85. package/src/components/loader/loader.tsx +17 -0
  86. package/src/components/navbar/navbar.doc.mdx +77 -0
  87. package/src/components/navbar/navbar.props.ts +37 -1
  88. package/src/components/navbar/navbar.stories.tsx +84 -0
  89. package/src/components/navbar/navbar.tsx +27 -0
  90. package/src/components/page/page.doc.mdx +80 -0
  91. package/src/components/page/page.props.ts +21 -0
  92. package/src/components/page/page.tsx +18 -0
  93. package/src/components/page-header/page-header.doc.mdx +54 -0
  94. package/src/components/page-header/page-header.props.ts +9 -0
  95. package/src/components/page-header/page-header.tsx +15 -0
  96. package/src/components/pagination/pagination.doc.mdx +62 -0
  97. package/src/components/pagination/pagination.props.ts +11 -32
  98. package/src/components/pagination/pagination.tsx +17 -0
  99. package/src/components/popover/popover.doc.mdx +53 -0
  100. package/src/components/popover/popover.props.ts +8 -0
  101. package/src/components/popover/popover.tsx +13 -0
  102. package/src/components/progress/progress.doc.mdx +48 -0
  103. package/src/components/progress/progress.props.ts +8 -0
  104. package/src/components/progress/progress.tsx +9 -0
  105. package/src/components/radio/radio.doc.mdx +62 -0
  106. package/src/components/radio/radio.props.ts +11 -0
  107. package/src/components/radio/radio.tsx +18 -0
  108. package/src/components/search-select/search-select.doc.mdx +72 -0
  109. package/src/components/search-select/search-select.props.ts +23 -18
  110. package/src/components/search-select/search-select.tsx +27 -2
  111. package/src/components/searchTable/searchTable.doc.mdx +79 -0
  112. package/src/components/searchTable/searchTable.props.ts +42 -3
  113. package/src/components/searchTable/searchTable.stories.tsx +74 -0
  114. package/src/components/searchTable/searchTable.tsx +23 -0
  115. package/src/components/segmented-control/segmented-control.doc.mdx +60 -0
  116. package/src/components/segmented-control/segmented-control.props.ts +12 -0
  117. package/src/components/segmented-control/segmented-control.tsx +15 -0
  118. package/src/components/select/select.doc.mdx +75 -0
  119. package/src/components/select/select.props.ts +22 -0
  120. package/src/components/select/select.tsx +2 -5
  121. package/src/components/sidebar/sidebar.doc.mdx +86 -0
  122. package/src/components/sidebar/sidebar.props.ts +22 -0
  123. package/src/components/sidebar/sidebar.tsx +22 -0
  124. package/src/components/skeleton/skeleton.doc.mdx +43 -0
  125. package/src/components/skeleton/skeleton.props.ts +8 -0
  126. package/src/components/skeleton/skeleton.tsx +10 -0
  127. package/src/components/slide/slide.doc.mdx +46 -0
  128. package/src/components/slide/slide.props.ts +11 -24
  129. package/src/components/slide/slide.tsx +10 -1
  130. package/src/components/slider/slider.doc.mdx +49 -0
  131. package/src/components/slider/slider.props.ts +9 -0
  132. package/src/components/slider/slider.tsx +15 -0
  133. package/src/components/stack/stack.doc.mdx +126 -0
  134. package/src/components/stack/stack.props.ts +18 -0
  135. package/src/components/stack/stack.stories.tsx +221 -16
  136. package/src/components/stack/stack.tsx +21 -0
  137. package/src/components/stat-card/stat-card.doc.mdx +48 -0
  138. package/src/components/stat-card/stat-card.props.ts +9 -0
  139. package/src/components/stat-card/stat-card.tsx +10 -0
  140. package/src/components/stepper/stepper.doc.mdx +54 -0
  141. package/src/components/stepper/stepper.props.ts +11 -1
  142. package/src/components/stepper/stepper.tsx +15 -0
  143. package/src/components/table/table.doc.mdx +58 -0
  144. package/src/components/table/table.props.ts +17 -0
  145. package/src/components/table/table.tsx +199 -84
  146. package/src/components/tabs/tabs.doc.mdx +52 -0
  147. package/src/components/tabs/tabs.props.ts +11 -0
  148. package/src/components/tabs/tabs.tsx +14 -0
  149. package/src/components/text/text.doc.mdx +41 -0
  150. package/src/components/text/text.props.ts +5 -0
  151. package/src/components/text/text.stories.tsx +67 -0
  152. package/src/components/text/text.tsx +10 -0
  153. package/src/components/textarea/textarea.doc.mdx +64 -0
  154. package/src/components/textarea/textarea.props.ts +11 -0
  155. package/src/components/textarea/textarea.tsx +16 -0
  156. package/src/components/theme-provider/themeProvider.doc.mdx +75 -0
  157. package/src/components/theme-provider/themeProvider.props.ts +3 -0
  158. package/src/components/theme-provider/themeProvider.stories.tsx +59 -0
  159. package/src/components/theme-provider/themeProvider.tsx +14 -0
  160. package/src/components/time-picker/timePicker.doc.mdx +68 -0
  161. package/src/components/time-picker/timePicker.props.ts +14 -0
  162. package/src/components/time-picker/timePicker.tsx +22 -1
  163. package/src/components/toast/toast.doc.mdx +50 -0
  164. package/src/components/toast/toast.props.ts +5 -0
  165. package/src/components/toast/toast.tsx +21 -0
  166. package/src/components/tooltip/tooltip.doc.mdx +47 -0
  167. package/src/components/tooltip/tooltip.props.ts +6 -0
  168. package/src/components/tooltip/tooltip.tsx +19 -0
  169. package/src/components/topbar/topbar.doc.mdx +69 -0
  170. package/src/components/topbar/topbar.props.ts +15 -0
  171. package/src/components/topbar/topbar.tsx +38 -0
  172. package/src/components/triple-filter/tripleFilter.doc.mdx +62 -0
  173. package/src/components/triple-filter/tripleFilter.props.ts +7 -0
  174. package/src/components/triple-filter/tripleFilter.tsx +32 -0
  175. package/src/index.css +2 -0
  176. package/src/showcases/DataShowcases.tsx +529 -45
  177. package/src/showcases/FormShowcases.tsx +399 -29
  178. package/src/showcases/HomeShowcase.tsx +252 -272
  179. package/src/showcases/LayoutPrimitivesShowcases.tsx +1224 -248
  180. package/src/showcases/PageShowcases.tsx +688 -391
  181. package/src/showcases/ShowcaseLayout.tsx +237 -73
  182. package/src/showcases/StructureShowcases.tsx +846 -73
  183. package/src/types/table.types.ts +1 -1
  184. package/src/utils/styles.ts +2 -1
@@ -2,7 +2,7 @@ import { useTableState } from "@/hooks/useTableState";
2
2
  import { sizeStyles, variantStyles } from "@/types/table.types";
3
3
  import clsx from "clsx";
4
4
  import React, { useState, useEffect, useCallback, useRef } from "react";
5
- import { FaCheck, FaSpinner, FaTimes } from "react-icons/fa";
5
+ import { FaCheck, FaSpinner, FaTimes, FaTable, FaThLarge } from "react-icons/fa";
6
6
  import { MdOutlineSwapVert } from "react-icons/md";
7
7
  import ITInput from "../input/input";
8
8
  import ITPagination from "../pagination/pagination";
@@ -18,6 +18,27 @@ const getNestedValue = (obj: unknown, path: string) => {
18
18
 
19
19
  const EMPTY_OBJECT = {};
20
20
 
21
+ /**
22
+ * Async server-side data table with sorting, filtering, and pagination.
23
+ *
24
+ * Fetches data via the `fetchData` callback whenever pagination, sorting, or
25
+ * filters change. Supports column-level text/catalog/boolean filters, sortable
26
+ * columns, and a loading overlay. Built on-top of internal table hooks for
27
+ * automatic state coordination.
28
+ *
29
+ * @example
30
+ * ```tsx
31
+ * <ITDataTable
32
+ * columns={[
33
+ * { key: "name", label: "Name", sortable: true, filter: true },
34
+ * { key: "status", label: "Status", type: "boolean", filter: true },
35
+ * ]}
36
+ * fetchData={async (params) => api.fetchItems(params)}
37
+ * title="Users"
38
+ * variant="bordered"
39
+ * />
40
+ * ```
41
+ */
21
42
  export default function ITDataTable<T extends Record<string, unknown>>({
22
43
  columns,
23
44
  fetchData,
@@ -33,7 +54,12 @@ export default function ITDataTable<T extends Record<string, unknown>>({
33
54
  itemsPerPageOptions = [5, 10, 20],
34
55
  defaultItemsPerPage = 10,
35
56
  title,
57
+ renderCard,
58
+ defaultView,
59
+ showVerticalBorder = true,
60
+ verticalBorderClassname,
36
61
  }: ITDataTableProps<T>) {
62
+ const [viewMode, setViewMode] = useState<"table" | "cards">(defaultView || "table");
37
63
  const [data, setData] = useState<T[]>([]);
38
64
  const [totalItems, setTotalItems] = useState(0);
39
65
  const [isLoading, setIsLoading] = useState(fetchOnMount);
@@ -194,17 +220,75 @@ export default function ITDataTable<T extends Record<string, unknown>>({
194
220
  }
195
221
  };
196
222
 
223
+ const renderDefaultCard = (row: T) => {
224
+ const dataCols = columns.filter((c) => c.type !== "actions");
225
+ const actionCol = columns.find((c) => c.type === "actions");
226
+ return (
227
+ <div className="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 p-3 space-y-2 shadow-sm">
228
+ {dataCols.map((col) => (
229
+ <div key={col.key} className="flex items-center justify-between gap-2">
230
+ <span className="text-[10px] font-bold uppercase tracking-wider text-slate-400 whitespace-nowrap flex-shrink-0 min-w-[70px]">
231
+ {col.label}
232
+ </span>
233
+ <span className="text-sm font-medium text-slate-800 dark:text-white text-right truncate">
234
+ {renderCellContent(col, row) as React.ReactNode}
235
+ </span>
236
+ </div>
237
+ ))}
238
+ {actionCol?.actions && (
239
+ <div className="flex items-center justify-end gap-2 pt-2 border-t border-slate-100 dark:border-slate-700">
240
+ {actionCol.actions(row)}
241
+ </div>
242
+ )}
243
+ </div>
244
+ );
245
+ };
246
+
247
+ const segCtrlClass = (mode: "table" | "cards") =>
248
+ `flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all ${
249
+ viewMode === mode
250
+ ? "bg-white dark:bg-slate-900 text-slate-900 dark:text-white shadow-sm border border-slate-200/50 dark:border-slate-700"
251
+ : "text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"
252
+ }`;
253
+
197
254
  return (
198
255
  <div className={clsx("space-y-4 w-full relative", containerClassName)}>
199
256
  <div className="rounded-xl shadow-sm overflow-hidden" style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)' }}>
200
257
  {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)' }}>
258
+ <div className="px-6 py-5 flex items-center justify-between" style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)' }}>
202
259
  <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" />}
260
+ <div className="flex items-center gap-3">
261
+ {isLoading && (
262
+ <div className="text-secondary-400">
263
+ {loadingIndicator || <FaSpinner className="animate-spin text-primary-500 text-xl" />}
264
+ </div>
265
+ )}
266
+ <div className="flex items-center bg-slate-100 dark:bg-slate-800/80 rounded-lg p-0.5 border border-slate-200 dark:border-slate-700/50">
267
+ <button onClick={() => setViewMode("table")} className={segCtrlClass("table")}>
268
+ <FaTable size={11} />
269
+ Table
270
+ </button>
271
+ <button onClick={() => setViewMode("cards")} className={segCtrlClass("cards")}>
272
+ <FaThLarge size={11} />
273
+ Cards
274
+ </button>
206
275
  </div>
207
- )}
276
+ </div>
277
+ </div>
278
+ )}
279
+
280
+ {!title && (
281
+ <div className="flex justify-end px-4 pt-3">
282
+ <div className="flex items-center bg-slate-100 dark:bg-slate-800/80 rounded-lg p-0.5 border border-slate-200 dark:border-slate-700/50">
283
+ <button onClick={() => setViewMode("table")} className={segCtrlClass("table")}>
284
+ <FaTable size={11} />
285
+ Table
286
+ </button>
287
+ <button onClick={() => setViewMode("cards")} className={segCtrlClass("cards")}>
288
+ <FaThLarge size={11} />
289
+ Cards
290
+ </button>
291
+ </div>
208
292
  </div>
209
293
  )}
210
294
 
@@ -222,81 +306,102 @@ export default function ITDataTable<T extends Record<string, unknown>>({
222
306
  </div>
223
307
  )}
224
308
 
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-white 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">
309
+ {viewMode === "cards" ? (
310
+ <div className="p-4 space-y-3 max-h-[400px] overflow-y-auto">
264
311
  {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>
312
+ data.map((row, i) => (
313
+ <div key={i}>
314
+ {renderCard ? renderCard(row) : renderDefaultCard(row)}
315
+ </div>
281
316
  ))
282
317
  ) : (
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>
318
+ !isLoading && (
319
+ <div className="flex flex-col items-center justify-center py-12 text-secondary-400">
320
+ <ITText as="span" className="text-lg">No se encontraron resultados</ITText>
321
+ <ITText as="span" className="text-sm mt-1">Intenta ajustar los filtros</ITText>
322
+ </div>
323
+ )
324
+ )}
325
+ </div>
326
+ ) : (
327
+ <table
328
+ className={clsx(
329
+ "min-w-max w-full text-sm text-left text-secondary-600 transition-opacity duration-300",
330
+ showVerticalBorder && "[&_th]:border-r [&_th:last-child]:border-r-0 [&_td]:border-r [&_td:last-child]:border-r-0",
331
+ showVerticalBorder && (verticalBorderClassname || "[&_th]:border-slate-100 dark:[&_th]:border-slate-700/30 [&_td]:border-slate-100 dark:[&_td]:border-slate-700/30"),
332
+ isLoading ? "opacity-50" : "opacity-100",
333
+ variantStyles[variant],
334
+ sizeStyles[size],
335
+ className
336
+ )}
337
+ >
338
+ <thead>
339
+ <tr className="bg-secondary-50 text-xs uppercase tracking-wider font-semibold text-slate-700 dark:text-slate-200">
340
+ {columns.map((col) => (
341
+ <th key={col.key} scope="col" className={clsx("px-4 py-4 align-top", col.className)}>
342
+ <div className="flex flex-col gap-3 min-w-[150px]">
343
+ <div className="flex items-center justify-between gap-2">
344
+ <ITText as="span" className="text-slate-900 dark:text-white font-bold">{col.label}</ITText>
345
+ {col.sortable && col.type !== "actions" && (
346
+ <button
347
+ onClick={() => handleSort(col.key)}
348
+ disabled={isLoading}
349
+ className={`p-1 rounded-md transition-colors ${
350
+ sortConfig?.key === col.key
351
+ ? "bg-secondary-200 text-secondary-900"
352
+ : "hover:bg-secondary-200 text-secondary-400 hover:text-secondary-700"
353
+ } disabled:opacity-50`}
354
+ title={`Ordenar por ${col.label}`}
355
+ >
356
+ <MdOutlineSwapVert className="w-4 h-4" aria-hidden="true" />
357
+ </button>
358
+ )}
359
+ </div>
360
+
361
+ <div className="w-full">{col.filter ? renderFilterInput(col) : null}</div>
289
362
  </div>
290
- )}
291
- </td>
363
+ </th>
364
+ ))}
292
365
  </tr>
293
- )}
294
- </tbody>
295
- </table>
366
+ </thead>
367
+ <tbody className="divide-y divide-slate-100 dark:divide-slate-700/30">
368
+ {data.length > 0 ? (
369
+ data.map((row, rowIndex) => (
370
+ <tr key={rowIndex} className={clsx("hover:bg-secondary-50/50 transition-colors duration-150 group", variant === "striped" && "odd:bg-secondary-50/40 dark:odd:bg-slate-800/20")}>
371
+ {columns.map((col) => (
372
+ <td key={`${rowIndex}-${col.key}`} className={clsx("px-4 py-3 align-middle", col.className)}>
373
+ {col.type === "actions" ? (
374
+ <div className="flex items-center justify-center gap-2">
375
+ {renderCellContent(col, row) as React.ReactNode}
376
+ </div>
377
+ ) : (
378
+ <div className="text-secondary-700 font-medium">
379
+ {renderCellContent(col, row) as React.ReactNode}
380
+ </div>
381
+ )}
382
+ </td>
383
+ ))}
384
+ </tr>
385
+ ))
386
+ ) : (
387
+ <tr>
388
+ <td colSpan={columns.length} className="px-6 py-12 text-center">
389
+ {!isLoading && (
390
+ <div className="flex flex-col items-center justify-center text-secondary-400">
391
+ <ITText as="span" className="text-lg">No se encontraron resultados</ITText>
392
+ <ITText as="span" className="text-sm mt-1">Intenta ajustar los filtros</ITText>
393
+ </div>
394
+ )}
395
+ </td>
396
+ </tr>
397
+ )}
398
+ </tbody>
399
+ </table>
400
+ )}
296
401
  </div>
297
402
  </div>
298
403
 
299
- <div className="rounded-b-xl border-t border-secondary-200 px-6 py-4" style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)' }}>
404
+ <div className="rounded-b-xl px-6 py-4" style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)' }}>
300
405
  <ITPagination
301
406
  currentPage={currentPage}
302
407
  totalPages={computedTotalPages}
@@ -0,0 +1,65 @@
1
+ import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
2
+ import * as Stories from './date-picker.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # ITDatePicker
7
+
8
+ A date picker supporting single date and date range selection. Includes built-in validation error display, min/max date constraints, and placeholder formatting.
9
+
10
+ ## Props
11
+
12
+ | Prop | Type | Default | Description |
13
+ |------|------|---------|-------------|
14
+ | `name` | `string` | — | Unique name attribute for the input. |
15
+ | `value` | `Date \| [Date \| null, Date \| null]` | — | Selected date or start–end tuple when `range` is true. |
16
+ | `onChange` | `(event) => void` | — | Callback with `{ target: { name, value } }` on date selection. |
17
+ | `onBlur` | `(event) => void` | — | Callback when the input loses focus. |
18
+ | `range` | `boolean` | `false` | Enable date-range selection mode. |
19
+ | `variant` | `ColorsTypes` | `"primary"` | Color variant from design system. |
20
+ | `size` | `SizesTypes` | `"medium"` | Size variant from design system. |
21
+ | `className` | `string` | — | CSS classes for the wrapper. |
22
+ | `calendarClassName` | `string` | — | CSS classes for the calendar popover. |
23
+ | `disabled` | `boolean` | `false` | Disables the date picker. |
24
+ | `placeholder` | `string` | — | Placeholder text when no date is selected. |
25
+ | `label` | `string` | — | Accessible label rendered above the input. |
26
+ | `required` | `boolean` | — | Marks the field as required. |
27
+ | `touched` | `boolean` | — | Visually indicates the field has been interacted with. |
28
+ | `error` | `string \| boolean` | — | Error message string or `true` for default error styling. |
29
+ | `minDate` | `Date` | — | Earliest selectable date. |
30
+ | `maxDate` | `Date` | — | Latest selectable date. |
31
+
32
+ ## Usage
33
+
34
+ ```tsx
35
+ import { ITDatePicker } from '@axzydev/axzy_ui_system';
36
+
37
+ <ITDatePicker
38
+ name="birthdate"
39
+ label="Birth Date"
40
+ placeholder="DD/MM/YYYY"
41
+ value={date}
42
+ onChange={(e) => setDate(e.target.value)}
43
+ />
44
+
45
+ <ITDatePicker
46
+ range
47
+ name="audit_range"
48
+ label="Audit Range"
49
+ value={range}
50
+ onChange={(e) => setRange(e.target.value)}
51
+ />
52
+ ```
53
+
54
+ ## Notes
55
+
56
+ - When `range` is true, `value` must be a tuple `[startDate, endDate]` and the onChange target value will be the same shape.
57
+ - The component emits a synthetic event with `target.name` and `target.value`, compatible with Formik integration.
58
+ - Error state is shown when both `error` and `touched` are truthy.
59
+ - Date format follows the locale configuration; placeholder text like `DD/MM/YYYY` guides the user.
60
+
61
+ ## Stories
62
+
63
+ <Primary />
64
+ <Controls />
65
+ <Stories />
@@ -2,29 +2,46 @@ import { ColorsTypes } from "@/types/colors.types";
2
2
  import { SizesTypes } from "@/types/sizes.types";
3
3
 
4
4
  export interface ITDatePickerProps {
5
+ /** Unique name attribute for the underlying input element. */
5
6
  name: string;
7
+ /** Selected date. Accepts a single Date or a tuple `[startDate, endDate]` when `range` is true. */
6
8
  value?: Date | [Date | null, Date | null];
9
+ /** Called when the selected date changes. The event object carries `name` and `value` in its target. */
7
10
  onChange: (
8
11
  event:
9
12
  | React.ChangeEvent<HTMLInputElement>
10
13
  | { target: { name: string; value: Date | [Date | null, Date | null] } }
11
14
  ) => void;
15
+ /** Called when the input loses focus. */
12
16
  onBlur?: (
13
17
  event:
14
18
  | React.FocusEvent<HTMLInputElement>
15
19
  | { target: { name: string; value: Date | [Date | null, Date | null] } }
16
20
  ) => void;
21
+ /** Enables date-range selection mode. When true, `value` is treated as a start-end tuple. @default false */
17
22
  range?: boolean;
23
+ /** Color variant matching the design system (ColorsTypes). @default "primary" */
18
24
  variant?: ColorsTypes;
25
+ /** Size variant matching the design system (SizesTypes). @default "medium" */
19
26
  size?: SizesTypes;
27
+ /** Additional CSS classes for the wrapper element. */
20
28
  className?: string;
29
+ /** Additional CSS classes for the calendar popover. */
21
30
  calendarClassName?: string;
31
+ /** Disables the date picker. @default false */
22
32
  disabled?: boolean;
33
+ /** Placeholder text shown when no date is selected. */
23
34
  placeholder?: string;
35
+ /** Accessible label rendered above the input. */
24
36
  label?: string;
37
+ /** Marks the field as required. */
25
38
  required?: boolean;
39
+ /** Visually indicates the field has been interacted with. */
26
40
  touched?: boolean;
41
+ /** Error state — pass a string message or `true` for default styling. */
27
42
  error?: string | boolean;
43
+ /** Earliest selectable date. */
28
44
  minDate?: Date;
45
+ /** Latest selectable date. */
29
46
  maxDate?: Date;
30
47
  }
@@ -7,6 +7,36 @@ import ITInput from "../input/input";
7
7
  import { ITDatePickerProps } from "./date-picker.props";
8
8
  import { theme } from "@/theme/theme";
9
9
 
10
+ /**
11
+ * Date picker component with single-date and date-range modes.
12
+ *
13
+ * Supports manual text input (DD/MM/YYYY format) and a calendar popover.
14
+ * In range mode the user selects a start date then an end date; the calendar
15
+ * highlights the interval. Position-aware popover flips above the input when
16
+ * near the bottom of the viewport.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * <ITDatePicker
21
+ * name="birthDate"
22
+ * label="Date of birth"
23
+ * value={date}
24
+ * onChange={(e) => setDate(e.target.value)}
25
+ * maxDate={new Date()}
26
+ * />
27
+ * ```
28
+ *
29
+ * @example
30
+ * ```tsx
31
+ * <ITDatePicker
32
+ * name="travelRange"
33
+ * label="Travel dates"
34
+ * range
35
+ * value={[startDate, endDate]}
36
+ * onChange={(e) => setRange(e.target.value)}
37
+ * />
38
+ * ```
39
+ */
10
40
  export default function ITDatePicker({
11
41
  name,
12
42
  value,
@@ -257,7 +287,7 @@ export default function ITDatePicker({
257
287
  <span>
258
288
  <FaCalendarAlt
259
289
  onClick={handleIconClick}
260
- className="text-slate-900 cursor-pointer"
290
+ className="text-slate-500 dark:text-slate-400 cursor-pointer"
261
291
  />
262
292
  </span>
263
293
  }
@@ -0,0 +1,54 @@
1
+ import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
2
+ import * as Stories from './dialog.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # ITDialog
7
+
8
+ Modal dialog rendered via a React portal with a semi-transparent overlay backdrop. Supports optional title bar (plain or ITFormHeader), Escape-key dismissal, and a full-screen variant.
9
+
10
+ ## Props
11
+
12
+ | Prop | Type | Default | Description |
13
+ |------|------|---------|-------------|
14
+ | `isOpen` | `boolean` | — | Controls dialog visibility. |
15
+ | `onClose` | `() => void` | — | Called on overlay click, close button, or Escape key. |
16
+ | `children` | `ReactNode` | — | Content rendered in the dialog body. |
17
+ | `className` | `string` | — | CSS classes for the dialog panel (e.g., `"w-96"` for width). |
18
+ | `title` | `string` | — | Optional heading at the top of the dialog. |
19
+ | `useFormHeader` | `boolean` | `false` | When true and `title` is set, renders an ITFormHeader with colored styling. |
20
+ | `fullScreen` | `boolean` | `false` | Makes the dialog fill the entire viewport. |
21
+
22
+ ## Usage
23
+
24
+ ```tsx
25
+ import { ITDialog } from '@axzydev/axzy_ui_system';
26
+
27
+ <ITDialog
28
+ isOpen={open}
29
+ onClose={() => setOpen(false)}
30
+ title="User Details"
31
+ useFormHeader
32
+ className="w-[500px]"
33
+ >
34
+ <UserForm />
35
+ </ITDialog>
36
+
37
+ <ITDialog isOpen={open} onClose={close} fullScreen>
38
+ <FullPageEditor />
39
+ </ITDialog>
40
+ ```
41
+
42
+ ## Notes
43
+
44
+ - Content is portaled to `document.body` via `createPortal`, ensuring it renders above all page layers.
45
+ - Click outside the dialog panel or pressing Escape dismisses it.
46
+ - When `useFormHeader` is true, the header uses the ITFormHeader design pattern with brand coloring.
47
+ - Control the dialog width via the `className` prop (e.g., `"w-96"`, `"w-[600px]"`).
48
+ - The overlay uses `bg-black/50` for a darkened backdrop effect.
49
+
50
+ ## Stories
51
+
52
+ <Primary />
53
+ <Controls />
54
+ <Stories />
@@ -1,9 +1,16 @@
1
1
  export interface ITDialogProps {
2
+ /** Controls whether the dialog is visible. */
2
3
  isOpen: boolean;
4
+ /** Callback fired when the overlay or close button is clicked, or Escape is pressed. */
3
5
  onClose: () => void;
6
+ /** Content rendered inside the dialog body. */
4
7
  children: React.ReactNode;
8
+ /** Additional CSS classes for the dialog panel. */
5
9
  className?: string;
10
+ /** Optional heading displayed at the top of the dialog. */
6
11
  title?: string;
12
+ /** When true and `title` is provided, renders an ITFormHeader instead of the default title bar. @default false */
7
13
  useFormHeader?: boolean;
14
+ /** Makes the dialog fill the entire viewport. @default false */
8
15
  fullScreen?: boolean;
9
16
  }
@@ -7,6 +7,32 @@ import useClickOutside from "@/hooks/useClickOutside";
7
7
  import ITFormHeader from "../form-header/form-header";
8
8
  import ITText from "@/components/text/text";
9
9
 
10
+ /**
11
+ * Modal dialog rendered via React portal with overlay backdrop.
12
+ *
13
+ * Supports Escape-key dismissal, click-outside-to-close, optional title bar
14
+ * (plain or ITFormHeader), and a full-screen variant. Content is portaled to
15
+ * `document.body` so it sits above all other page layers.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * <ITDialog
20
+ * isOpen={open}
21
+ * onClose={() => setOpen(false)}
22
+ * title="User details"
23
+ * useFormHeader
24
+ * >
25
+ * <UserForm />
26
+ * </ITDialog>
27
+ * ```
28
+ *
29
+ * @example
30
+ * ```tsx
31
+ * <ITDialog isOpen={open} onClose={close} fullScreen>
32
+ * <FullPageEditor />
33
+ * </ITDialog>
34
+ * ```
35
+ */
10
36
  export default function ITDialog({
11
37
  isOpen,
12
38
  onClose,
@@ -0,0 +1,42 @@
1
+ import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
2
+ import * as Stories from './divider.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # ITDivider
7
+
8
+ A thin horizontal or vertical separator line for visually dividing content sections. Supports custom color and thickness via Tailwind utility classes.
9
+
10
+ ## Props
11
+
12
+ | Prop | Type | Default | Description |
13
+ |------|------|---------|-------------|
14
+ | `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Direction the divider flows. |
15
+ | `className` | `string` | — | Additional CSS classes. |
16
+ | `color` | `string` | `"bg-slate-200 dark:bg-slate-700"` | Tailwind background color class(es). |
17
+ | `thickness` | `string` | `"h-px"` (horizontal) / `"w-px"` (vertical) | Tailwind width/height utility. |
18
+
19
+ ## Usage
20
+
21
+ ```tsx
22
+ import { ITDivider } from '@axzydev/axzy_ui_system';
23
+
24
+ <ITDivider />
25
+
26
+ <ITDivider orientation="vertical" color="bg-red-500" thickness="w-1" />
27
+
28
+ <ITDivider color="bg-primary-300" thickness="h-0.5" />
29
+ ```
30
+
31
+ ## Notes
32
+
33
+ - Horizontal divider is full-width by default; vertical divider is full-height of its parent.
34
+ - Use in combination with ITStack or ITFlex for consistent layout spacing between sections.
35
+ - Auto-detects orientation for default thickness: `h-px` for horizontal, `w-px` for vertical.
36
+ - The `color` prop accepts any valid Tailwind background color class, including dark mode variants.
37
+
38
+ ## Stories
39
+
40
+ <Primary />
41
+ <Controls />
42
+ <Stories />
@@ -1,8 +1,13 @@
1
+ /** Direction the divider flows: "horizontal" | "vertical". */
1
2
  export type DividerOrientation = "horizontal" | "vertical";
2
3
 
3
4
  export interface ITDividerProps {
5
+ /** Layout direction. @default "horizontal" */
4
6
  orientation?: DividerOrientation;
7
+ /** Additional CSS classes for the divider element. */
5
8
  className?: string;
9
+ /** Tailwind background color class(es). @default "bg-slate-200 dark:bg-slate-700" */
6
10
  color?: string;
11
+ /** Tailwind width/height utility (e.g. "h-px", "h-1", "w-px"). Auto-set based on orientation if omitted. */
7
12
  thickness?: string;
8
13
  }
@@ -1,6 +1,22 @@
1
1
  import clsx from "clsx";
2
2
  import { ITDividerProps } from "./divider.props";
3
3
 
4
+ /**
5
+ * Horizontal or vertical separator line.
6
+ *
7
+ * Renders a thin full-width (horizontal) or full-height (vertical) bar using
8
+ * Tailwind utility classes. Supports custom color and thickness overrides.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * <ITDivider />
13
+ * ```
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * <ITDivider orientation="vertical" color="bg-red-500" thickness="w-1" />
18
+ * ```
19
+ */
4
20
  export default function ITDivider({
5
21
  orientation = "horizontal",
6
22
  className,