@axzydev/axzy_ui_system 1.4.7 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/README.md +2 -11
  2. package/dist/index.cjs +2174 -1570
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.css +1 -1
  5. package/dist/index.css.map +1 -1
  6. package/dist/index.d.cts +232 -19
  7. package/dist/index.d.ts +232 -19
  8. package/dist/index.js +1838 -1238
  9. package/dist/index.js.map +1 -1
  10. package/dist/layered.css +1 -1
  11. package/package.json +3 -16
  12. package/src/App.tsx +90 -73
  13. package/src/components/atoms/badget/badget.tsx +23 -5
  14. package/src/components/atoms/chip/chip.tsx +3 -1
  15. package/src/components/atoms/image/image.tsx +3 -1
  16. package/src/components/atoms/input/input.tsx +8 -5
  17. package/src/components/atoms/loader/loader.tsx +3 -1
  18. package/src/components/atoms/slide/slide.props.ts +12 -0
  19. package/src/components/atoms/slide/slide.tsx +3 -0
  20. package/src/components/molecules/alert/alert.tsx +3 -1
  21. package/src/components/molecules/breadcrumbs/breadcrumbs.tsx +3 -1
  22. package/src/components/molecules/calendar/calendar.tsx +9 -6
  23. package/src/components/molecules/card/card.tsx +5 -2
  24. package/src/components/molecules/chip-input/chip-input.tsx +9 -7
  25. package/src/components/molecules/date-picker/datePicker.tsx +9 -9
  26. package/src/components/molecules/dropdown-menu/dropdown-menu.props.ts +1 -1
  27. package/src/components/molecules/dropdown-menu/dropdown-menu.tsx +6 -3
  28. package/src/components/molecules/field/field.tsx +3 -1
  29. package/src/components/molecules/form-header/form-header.tsx +3 -1
  30. package/src/components/molecules/line-bar-chart/line-bar-chart.props.ts +2 -2
  31. package/src/components/molecules/line-bar-chart/line-bar-chart.tsx +20 -15
  32. package/src/components/molecules/masked-input/masked-input.tsx +3 -1
  33. package/src/components/molecules/multi-select/multi-select.tsx +12 -9
  34. package/src/components/molecules/pagination/pagination.tsx +11 -5
  35. package/src/components/molecules/search-select/search-select.tsx +11 -9
  36. package/src/components/molecules/select/select.tsx +6 -4
  37. package/src/components/molecules/stepper/stepper.tsx +6 -4
  38. package/src/components/molecules/table/table.props.ts +10 -2
  39. package/src/components/molecules/table/table.tsx +163 -114
  40. package/src/components/molecules/time-picker/timePicker.tsx +8 -6
  41. package/src/components/molecules/wysiwyg/wysiwyg.tsx +23 -12
  42. package/src/components/organisms/confirm-dialog/confirm-dialog.props.ts +4 -4
  43. package/src/components/organisms/confirm-dialog/confirm-dialog.tsx +16 -8
  44. package/src/components/organisms/data-table/dataTable.props.ts +3 -2
  45. package/src/components/organisms/data-table/dataTable.tsx +149 -81
  46. package/src/components/organisms/dialog/dialog.tsx +3 -0
  47. package/src/components/organisms/drawer/drawer.tsx +3 -0
  48. package/src/components/organisms/dropfile/dropfile.tsx +19 -17
  49. package/src/components/organisms/form-builder/fieldRenderer.tsx +4 -2
  50. package/src/components/organisms/navbar/navbar.tsx +4 -2
  51. package/src/components/organisms/page-header/page-header.tsx +3 -1
  52. package/src/components/organisms/searchTable/components/PaginationControls.tsx +8 -6
  53. package/src/components/organisms/searchTable/components/PaginationInfo.tsx +3 -1
  54. package/src/components/organisms/searchTable/components/SearchAndSortBar.tsx +7 -5
  55. package/src/components/organisms/searchTable/components/SearchInput.tsx +4 -2
  56. package/src/components/organisms/searchTable/components/SortButton.tsx +13 -11
  57. package/src/components/organisms/searchTable/components/TableEmptyState.tsx +4 -2
  58. package/src/components/organisms/searchTable/components/TableRow.tsx +6 -4
  59. package/src/components/organisms/searchTable/searchTable.tsx +4 -2
  60. package/src/components/organisms/sidebar/sidebar.props.ts +1 -1
  61. package/src/components/organisms/sidebar/sidebar.tsx +9 -4
  62. package/src/components/organisms/toast/toast.tsx +3 -1
  63. package/src/components/organisms/topbar/topbar.tsx +4 -2
  64. package/src/components/templates/page/page.props.ts +4 -4
  65. package/src/components/templates/page/page.tsx +6 -4
  66. package/src/components/theme-provider/themeProvider.tsx +28 -17
  67. package/src/dev.css +77 -2
  68. package/src/global.d.ts +10 -0
  69. package/src/i18n/context.ts +9 -0
  70. package/src/i18n/index.ts +22 -0
  71. package/src/i18n/locales/en.ts +163 -0
  72. package/src/i18n/locales/es.ts +165 -0
  73. package/src/i18n/provider.tsx +44 -0
  74. package/src/i18n/translator.ts +82 -0
  75. package/src/i18n/types.ts +54 -0
  76. package/src/i18n/useITTranslation.ts +20 -0
  77. package/src/index.css +0 -1
  78. package/src/index.ts +9 -3
  79. package/src/sandbox/LandingShowcase.tsx +224 -580
  80. package/src/sandbox/NotFoundShowcase.tsx +51 -36
  81. package/src/sandbox/TopbarSearch.tsx +6 -4
  82. package/src/sandbox/controls.tsx +180 -0
  83. package/src/sandbox/i18n.ts +1929 -0
  84. package/src/sandbox/icons.tsx +25 -0
  85. package/src/sandbox/locale.tsx +72 -0
  86. package/src/sandbox/ui.tsx +377 -0
  87. package/src/sandbox/useHashRoute.ts +46 -10
  88. package/src/showcases/DataShowcases.tsx +201 -80
  89. package/src/showcases/FeedbackShowcases.tsx +37 -30
  90. package/src/showcases/FormShowcases.tsx +302 -214
  91. package/src/showcases/GettingStartedShowcase.tsx +151 -145
  92. package/src/showcases/HelpShowcase.tsx +126 -128
  93. package/src/showcases/HomeShowcase.tsx +678 -482
  94. package/src/showcases/LayoutPrimitivesShowcases.tsx +129 -114
  95. package/src/showcases/NavigationShowcases.tsx +45 -37
  96. package/src/showcases/PageShowcases.tsx +171 -152
  97. package/src/showcases/ProductoDetalle.tsx +272 -129
  98. package/src/showcases/ShowcaseLayout.tsx +270 -216
  99. package/src/showcases/SizesShowcase.tsx +123 -64
  100. package/src/showcases/StructureShowcases.tsx +157 -131
  101. package/src/showcases/portfolioUi.tsx +153 -0
  102. package/src/showcases/techIcons.ts +3 -0
  103. package/src/types/table.types.ts +110 -0
  104. package/src/utils/table.utils.ts +10 -2
  105. package/src/components/atoms/avatar/avatar.doc.mdx +0 -48
  106. package/src/components/atoms/avatar/avatar.stories.tsx +0 -64
  107. package/src/components/atoms/badget/badget.doc.mdx +0 -46
  108. package/src/components/atoms/badget/badget.stories.tsx +0 -75
  109. package/src/components/atoms/button/button.doc.mdx +0 -59
  110. package/src/components/atoms/button/button.stories.tsx +0 -173
  111. package/src/components/atoms/checkbox/checkbox.doc.mdx +0 -54
  112. package/src/components/atoms/checkbox/checkbox.stories.tsx +0 -53
  113. package/src/components/atoms/chip/chip.doc.mdx +0 -47
  114. package/src/components/atoms/chip/chip.stories.tsx +0 -64
  115. package/src/components/atoms/divider/divider.doc.mdx +0 -42
  116. package/src/components/atoms/divider/divider.stories.tsx +0 -33
  117. package/src/components/atoms/flex/flex.doc.mdx +0 -59
  118. package/src/components/atoms/flex/flex.stories.tsx +0 -70
  119. package/src/components/atoms/grid/grid.doc.mdx +0 -54
  120. package/src/components/atoms/grid/grid.stories.tsx +0 -71
  121. package/src/components/atoms/image/image.doc.mdx +0 -44
  122. package/src/components/atoms/image/image.stories.tsx +0 -48
  123. package/src/components/atoms/input/input.doc.mdx +0 -70
  124. package/src/components/atoms/input/input.stories.tsx +0 -113
  125. package/src/components/atoms/input-number/input-number.doc.mdx +0 -74
  126. package/src/components/atoms/input-number/input-number.stories.tsx +0 -111
  127. package/src/components/atoms/loader/loader.doc.mdx +0 -43
  128. package/src/components/atoms/loader/loader.stories.tsx +0 -104
  129. package/src/components/atoms/popover/popover.doc.mdx +0 -53
  130. package/src/components/atoms/popover/popover.stories.tsx +0 -24
  131. package/src/components/atoms/progress/progress.doc.mdx +0 -48
  132. package/src/components/atoms/progress/progress.stories.tsx +0 -39
  133. package/src/components/atoms/radio/radio.doc.mdx +0 -62
  134. package/src/components/atoms/radio/radio.stories.tsx +0 -48
  135. package/src/components/atoms/segmented-control/segmented-control.doc.mdx +0 -60
  136. package/src/components/atoms/segmented-control/segmented-control.stories.tsx +0 -62
  137. package/src/components/atoms/skeleton/skeleton.doc.mdx +0 -43
  138. package/src/components/atoms/skeleton/skeleton.stories.tsx +0 -29
  139. package/src/components/atoms/slide/slide.doc.mdx +0 -46
  140. package/src/components/atoms/slide/slide.stories.tsx +0 -120
  141. package/src/components/atoms/slider/slider.doc.mdx +0 -49
  142. package/src/components/atoms/slider/slider.stories.tsx +0 -29
  143. package/src/components/atoms/stack/stack.doc.mdx +0 -126
  144. package/src/components/atoms/stack/stack.stories.tsx +0 -283
  145. package/src/components/atoms/text/text.doc.mdx +0 -41
  146. package/src/components/atoms/text/text.stories.tsx +0 -66
  147. package/src/components/atoms/textarea/textarea.doc.mdx +0 -64
  148. package/src/components/atoms/textarea/textarea.stories.tsx +0 -26
  149. package/src/components/atoms/tooltip/tooltip.doc.mdx +0 -47
  150. package/src/components/atoms/tooltip/tooltip.stories.tsx +0 -19
  151. package/src/components/isolation/isolation.stories.tsx +0 -202
  152. package/src/components/molecules/accordion/accordion.doc.mdx +0 -47
  153. package/src/components/molecules/accordion/accordion.stories.tsx +0 -68
  154. package/src/components/molecules/alert/alert.doc.mdx +0 -48
  155. package/src/components/molecules/alert/alert.stories.tsx +0 -40
  156. package/src/components/molecules/breadcrumbs/breadcrumbs.doc.mdx +0 -57
  157. package/src/components/molecules/breadcrumbs/breadcrumbs.stories.tsx +0 -20
  158. package/src/components/molecules/calendar/calendar.doc.mdx +0 -76
  159. package/src/components/molecules/calendar/calendar.stories.tsx +0 -90
  160. package/src/components/molecules/card/card.doc.mdx +0 -54
  161. package/src/components/molecules/card/card.stories.tsx +0 -57
  162. package/src/components/molecules/chip-input/chip-input.doc.mdx +0 -44
  163. package/src/components/molecules/chip-input/chip-input.stories.tsx +0 -52
  164. package/src/components/molecules/date-picker/date-picker.doc.mdx +0 -65
  165. package/src/components/molecules/date-picker/date-picker.stories.tsx +0 -88
  166. package/src/components/molecules/dropdown-menu/dropdown-menu.doc.mdx +0 -46
  167. package/src/components/molecules/dropdown-menu/dropdown-menu.stories.tsx +0 -41
  168. package/src/components/molecules/empty-state/empty-state.doc.mdx +0 -50
  169. package/src/components/molecules/empty-state/empty-state.stories.tsx +0 -19
  170. package/src/components/molecules/field/field.doc.mdx +0 -43
  171. package/src/components/molecules/field/field.stories.tsx +0 -42
  172. package/src/components/molecules/form-header/form-header.doc.mdx +0 -38
  173. package/src/components/molecules/form-header/form-header.stories.tsx +0 -52
  174. package/src/components/molecules/masked-input/masked-input.doc.mdx +0 -78
  175. package/src/components/molecules/masked-input/masked-input.stories.tsx +0 -126
  176. package/src/components/molecules/multi-select/multi-select.doc.mdx +0 -55
  177. package/src/components/molecules/multi-select/multi-select.stories.tsx +0 -59
  178. package/src/components/molecules/pagination/pagination.doc.mdx +0 -62
  179. package/src/components/molecules/pagination/pagination.stories.tsx +0 -110
  180. package/src/components/molecules/search-select/search-select.doc.mdx +0 -77
  181. package/src/components/molecules/search-select/search-select.stories.tsx +0 -146
  182. package/src/components/molecules/select/select.doc.mdx +0 -75
  183. package/src/components/molecules/select/select.stories.tsx +0 -85
  184. package/src/components/molecules/stat-card/stat-card.doc.mdx +0 -48
  185. package/src/components/molecules/stat-card/stat-card.stories.tsx +0 -40
  186. package/src/components/molecules/stepper/stepper.doc.mdx +0 -54
  187. package/src/components/molecules/stepper/stepper.stories.tsx +0 -154
  188. package/src/components/molecules/table/table.doc.mdx +0 -123
  189. package/src/components/molecules/table/table.stories.tsx +0 -402
  190. package/src/components/molecules/tabs/tabs.doc.mdx +0 -52
  191. package/src/components/molecules/tabs/tabs.stories.tsx +0 -31
  192. package/src/components/molecules/time-picker/timePicker.doc.mdx +0 -68
  193. package/src/components/molecules/time-picker/timePicker.stories.tsx +0 -130
  194. package/src/components/molecules/wysiwyg/wysiwyg.stories.tsx +0 -95
  195. package/src/components/organisms/confirm-dialog/confirm-dialog.doc.mdx +0 -60
  196. package/src/components/organisms/confirm-dialog/confirm-dialog.stories.tsx +0 -32
  197. package/src/components/organisms/data-table/ITDataTable.doc.mdx +0 -115
  198. package/src/components/organisms/data-table/ITDataTable.stories.tsx +0 -353
  199. package/src/components/organisms/dialog/dialog.doc.mdx +0 -54
  200. package/src/components/organisms/dialog/dialog.stories.tsx +0 -126
  201. package/src/components/organisms/drawer/drawer.doc.mdx +0 -59
  202. package/src/components/organisms/drawer/drawer.stories.tsx +0 -40
  203. package/src/components/organisms/dropfile/dropfile.doc.mdx +0 -74
  204. package/src/components/organisms/dropfile/dropfile.stories.tsx +0 -93
  205. package/src/components/organisms/form-builder/formBuilder.doc.mdx +0 -251
  206. package/src/components/organisms/form-builder/formBuilder.stories.tsx +0 -914
  207. package/src/components/organisms/navbar/navbar.doc.mdx +0 -77
  208. package/src/components/organisms/navbar/navbar.stories.tsx +0 -83
  209. package/src/components/organisms/page-header/page-header.doc.mdx +0 -54
  210. package/src/components/organisms/page-header/page-header.stories.tsx +0 -74
  211. package/src/components/organisms/searchTable/searchTable.doc.mdx +0 -79
  212. package/src/components/organisms/searchTable/searchTable.stories.tsx +0 -73
  213. package/src/components/organisms/sidebar/sidebar.doc.mdx +0 -176
  214. package/src/components/organisms/sidebar/sidebar.stories.tsx +0 -234
  215. package/src/components/organisms/toast/toast.doc.mdx +0 -50
  216. package/src/components/organisms/toast/toast.stories.tsx +0 -137
  217. package/src/components/organisms/topbar/topbar.doc.mdx +0 -72
  218. package/src/components/organisms/topbar/topbar.stories.tsx +0 -79
  219. package/src/components/organisms/triple-filter/tripleFilter.doc.mdx +0 -62
  220. package/src/components/organisms/triple-filter/tripleFilter.stories.tsx +0 -31
  221. package/src/components/templates/layout/layout.doc.mdx +0 -53
  222. package/src/components/templates/layout/layout.stories.tsx +0 -113
  223. package/src/components/templates/page/page.doc.mdx +0 -86
  224. package/src/components/templates/page/page.stories.tsx +0 -97
  225. package/src/components/theme-provider/themeProvider.doc.mdx +0 -85
  226. package/src/components/theme-provider/themeProvider.stories.tsx +0 -58
@@ -1,4 +1,4 @@
1
- import { TableDensity, TableSize, TableVariants } from "@/types/table.types";
1
+ import { TableDensity, TableDesignProps, TableSize, TableVariants } from "@/types/table.types";
2
2
 
3
3
  /** Data type of a table column, controls default rendering, filter UI, and sort comparison. */
4
4
  export type ColumnType = "string" | "date" | "number" | "boolean" | "actions" | "catalog";
@@ -31,6 +31,14 @@ export interface Column<T = any> {
31
31
  label: string;
32
32
  /** Additional CSS classes applied to both the header (`<th>`) and body (`<td>`) cells of this column. */
33
33
  className?: string;
34
+ /** Extra CSS classes applied only to this column's header (`<th>`), merged after `className`. */
35
+ headerClassName?: string;
36
+ /** Inline styles applied only to this column's header (`<th>`), merged after the table-level header-cell style. */
37
+ headerStyle?: React.CSSProperties;
38
+ /** Extra CSS classes applied only to this column's body cells (`<td>`), merged after `className`. */
39
+ cellClassName?: string;
40
+ /** Inline styles applied only to this column's body cells (`<td>`), merged after the table-level cell style. */
41
+ cellStyle?: React.CSSProperties;
34
42
  /** Formats numeric values as Mexican pesos (MXN) via `Intl`-based currency formatting. Only applies when `type` is `"number"`. @default false */
35
43
  currencyMX?: boolean;
36
44
  /** Custom action buttons/content rendered for a `"actions"`-type column. Receives the full row object. */
@@ -109,7 +117,7 @@ export interface Column<T = any> {
109
117
  pinned?: "left" | "right";
110
118
  }
111
119
 
112
- export interface ITTableProps<T> {
120
+ export interface ITTableProps<T> extends TableDesignProps {
113
121
  /** Column definitions: key, label, type, sortable behavior, filters, and custom rendering. */
114
122
  columns: Column<T>[];
115
123
  /** Additional CSS classes for the outermost container. */
@@ -35,6 +35,7 @@ import {
35
35
  tableRowClickable,
36
36
  } from "@/utils/styles";
37
37
  import { formatCurrencyMX, getNestedValue, getPinnedColumnMeta, isInteractiveTarget } from "@/utils/table.utils";
38
+ import { useITTranslation, toIntlLocale } from "@/i18n";
38
39
 
39
40
  /**
40
41
  * A feature-rich data table with per-column filtering, sortable columns,
@@ -74,10 +75,52 @@ export default function ITTable<T extends Record<string, unknown>>({
74
75
  rowHeight,
75
76
  overscan = 5,
76
77
  stickyHeader = false,
78
+ showViewToggle = true,
79
+ design,
80
+ colors,
81
+ containerStyle,
82
+ cardClassName,
83
+ cardStyle,
84
+ toolbarClassName,
85
+ toolbarStyle,
86
+ headerClassName,
87
+ headerStyle,
88
+ headerCellClassName,
89
+ headerCellStyle,
90
+ rowClassName,
91
+ rowStyle,
92
+ cellClassName,
93
+ cellStyle,
94
+ cardsClassName,
95
+ cardsStyle,
96
+ footerClassName,
97
+ footerStyle,
77
98
  }: ITTableProps<T>) {
99
+ const { t, locale } = useITTranslation();
78
100
  const [viewMode, setViewMode] = useState<"table" | "cards">(defaultView);
79
101
  const { ref: rootRef, width: containerWidth } = useElementSize<HTMLDivElement>();
80
102
 
103
+ // Per-instance color overrides written as local `--color-table-*` variables.
104
+ // Declared on the wrapper (an ancestor), they beat the global theme's
105
+ // `:root` values for this subtree only.
106
+ const colorVars = {
107
+ ...(colors?.headerBg ? { "--color-table-headerBg": colors.headerBg } : {}),
108
+ ...(colors?.headerText ? { "--color-table-headerText": colors.headerText } : {}),
109
+ ...(colors?.rowBg ? { "--color-table-rowBg": colors.rowBg } : {}),
110
+ ...(colors?.rowText ? { "--color-table-rowText": colors.rowText } : {}),
111
+ ...(colors?.rowHover ? { "--color-table-rowHover": colors.rowHover } : {}),
112
+ } as React.CSSProperties;
113
+
114
+ /** Merge a `design` slot with its flat shortcut (flat wins) into className/style. */
115
+ const mergeSlot = (
116
+ slot: { className?: string; style?: React.CSSProperties } | undefined,
117
+ flatClassName?: string,
118
+ flatStyle?: React.CSSProperties
119
+ ) => ({
120
+ className: clsx(slot?.className, flatClassName),
121
+ style: { ...slot?.style, ...flatStyle } as React.CSSProperties,
122
+ });
123
+
81
124
  const isFixed = layout === "fixed";
82
125
  const forcedCards =
83
126
  autoCardBreakpoint > 0 && containerWidth > 0 && containerWidth < autoCardBreakpoint;
@@ -241,17 +284,17 @@ export default function ITTable<T extends Record<string, unknown>>({
241
284
  : undefined;
242
285
 
243
286
  const getToggleLabel = () => {
244
- if (currentValue === undefined) return "Mostrar todos";
245
- if (currentValue === true) return "Filtrar solo verdaderos";
246
- return "Filtrar solo falsos";
287
+ if (currentValue === undefined) return t("table.showAll");
288
+ if (currentValue === true) return t("table.filterTrue");
289
+ return t("table.filterFalse");
247
290
  };
248
291
 
249
292
  return (
250
293
  <button
251
294
  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"
252
295
  onClick={() => handleFilterChange(col.key, nextValue)}
253
- aria-label={`${getToggleLabel()} para ${col.label}`}
254
- title={`${getToggleLabel()} para ${col.label}`}
296
+ aria-label={t("table.filterToggle", { action: getToggleLabel(), label: col.label })}
297
+ title={t("table.filterToggle", { action: getToggleLabel(), label: col.label })}
255
298
  >
256
299
  <div className="relative w-10 h-5 bg-secondary-300 rounded-full">
257
300
  <div
@@ -274,21 +317,21 @@ export default function ITTable<T extends Record<string, unknown>>({
274
317
  return (
275
318
  <FaSpinner
276
319
  className="animate-spin"
277
- aria-label="Cargando opciones"
278
- title="Cargando opciones"
320
+ aria-label={t("common.loadingOptions")}
321
+ title={t("common.loadingOptions")}
279
322
  />
280
323
  );
281
324
  }
282
325
 
283
326
  if (col.catalogOptions.error) {
284
- return <ITText as="span" className="text-danger-500 text-xs">Error cargando</ITText>;
327
+ return <ITText as="span" className="text-danger-500 text-xs">{t("common.loadError")}</ITText>;
285
328
  }
286
329
 
287
330
  return (
288
331
  <ITSelect
289
332
  name={`filter-${col.key}`}
290
333
  options={[
291
- { value: "", label: "Todos" },
334
+ { value: "", label: t("common.all") },
292
335
  ...col.catalogOptions.data.map((item) => ({
293
336
  value: String(item.id),
294
337
  label: item.name,
@@ -310,14 +353,14 @@ export default function ITTable<T extends Record<string, unknown>>({
310
353
  return (
311
354
  <FaSpinner
312
355
  className="animate-spin"
313
- aria-label="Cargando opciones"
314
- title="Cargando opciones"
356
+ aria-label={t("common.loadingOptions")}
357
+ title={t("common.loadingOptions")}
315
358
  />
316
359
  );
317
360
  }
318
361
 
319
362
  if (col.catalogOptions.error) {
320
- return <ITText as="span" className="text-danger-500 text-xs">Error cargando</ITText>;
363
+ return <ITText as="span" className="text-danger-500 text-xs">{t("common.loadError")}</ITText>;
321
364
  }
322
365
 
323
366
  const searchValue = filters[col.key];
@@ -337,7 +380,7 @@ export default function ITTable<T extends Record<string, unknown>>({
337
380
  onSearch={col.catalogOptions.onSearch}
338
381
  isLoading={col.catalogOptions.loading}
339
382
  size="sm"
340
- placeholder="Buscar..."
383
+ placeholder={t("common.search")}
341
384
  clearable
342
385
  className="w-full"
343
386
  onBlur={() => { }}
@@ -355,7 +398,7 @@ export default function ITTable<T extends Record<string, unknown>>({
355
398
  minDate={col.dateFilterOptions?.minDate}
356
399
  maxDate={col.dateFilterOptions?.maxDate}
357
400
  size="sm"
358
- placeholder="dd/mm/aaaa"
401
+ placeholder={t("datePicker.placeholder")}
359
402
  className="w-full"
360
403
  />
361
404
  );
@@ -374,7 +417,7 @@ export default function ITTable<T extends Record<string, unknown>>({
374
417
  minDate={col.dateFilterOptions?.minDate}
375
418
  maxDate={col.dateFilterOptions?.maxDate}
376
419
  size="sm"
377
- placeholder="dd/mm/aaaa - dd/mm/aaaa"
420
+ placeholder={t("datePicker.rangePlaceholder")}
378
421
  className="w-full"
379
422
  />
380
423
  );
@@ -384,7 +427,7 @@ export default function ITTable<T extends Record<string, unknown>>({
384
427
  <ITInput
385
428
  name={`filter-${col.key}`}
386
429
  className="w-full text-xs"
387
- placeholder="Buscar..."
430
+ placeholder={t("common.search")}
388
431
  value={String(filters[col.key] || "")}
389
432
  onChange={(e) => handleFilterChange(col.key, e.target.value)}
390
433
  onBlur={() => { }}
@@ -401,19 +444,19 @@ export default function ITTable<T extends Record<string, unknown>>({
401
444
 
402
445
  switch (col.type) {
403
446
  case "number":
404
- return (typeof value === "number") && col.currencyMX ? formatCurrencyMX(value) : value;
447
+ return (typeof value === "number") && col.currencyMX ? formatCurrencyMX(value, toIntlLocale(locale)) : value;
405
448
  case "boolean":
406
449
  return value ? (
407
450
  <FaCheck
408
451
  className="text-success-500"
409
- aria-label="Verdadero"
410
- title="Verdadero"
452
+ aria-label={t("common.true")}
453
+ title={t("common.true")}
411
454
  />
412
455
  ) : (
413
456
  <FaTimes
414
457
  className="text-danger-500"
415
- aria-label="Falso"
416
- title="Falso"
458
+ aria-label={t("common.false")}
459
+ title={t("common.false")}
417
460
  />
418
461
  );
419
462
  case "actions":
@@ -468,73 +511,73 @@ export default function ITTable<T extends Record<string, unknown>>({
468
511
  onRowClick(row, event);
469
512
  };
470
513
 
514
+ const containerSlot = mergeSlot(design?.container, containerClassName, containerStyle);
515
+ const cardSlot = mergeSlot(design?.card, cardClassName, cardStyle);
516
+ const toolbarSlot = mergeSlot(design?.toolbar, toolbarClassName, toolbarStyle);
517
+ const headerSlot = mergeSlot(design?.header, headerClassName, headerStyle);
518
+ const headerCellSlot = mergeSlot(design?.headerCell, headerCellClassName, headerCellStyle);
519
+ const rowSlot = mergeSlot(design?.row, rowClassName, rowStyle);
520
+ const cellSlot = mergeSlot(design?.cell, cellClassName, cellStyle);
521
+ const cardsSlot = mergeSlot(design?.cards, cardsClassName, cardsStyle);
522
+ const footerSlot = mergeSlot(design?.footer, footerClassName, footerStyle);
523
+
524
+ const viewToggle = (
525
+ <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">
526
+ <button
527
+ onClick={() => setViewMode("table")}
528
+ disabled={forcedCards}
529
+ className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all ${
530
+ effectiveView === "table"
531
+ ? "bg-white dark:bg-slate-900 text-slate-900 dark:text-white shadow-sm border border-slate-200/50 dark:border-slate-700"
532
+ : "text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"
533
+ }`}
534
+ >
535
+ <FaTable size={11} />
536
+ {t("table.viewTable")}
537
+ </button>
538
+ <button
539
+ onClick={() => setViewMode("cards")}
540
+ className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all ${
541
+ effectiveView === "cards"
542
+ ? "bg-white dark:bg-slate-900 text-slate-900 dark:text-white shadow-sm border border-slate-200/50 dark:border-slate-700"
543
+ : "text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"
544
+ }`}
545
+ >
546
+ <FaThLarge size={11} />
547
+ {t("table.viewCards")}
548
+ </button>
549
+ </div>
550
+ );
551
+
471
552
  return (
472
- <div ref={rootRef} className={clsx("space-y-4 w-full", containerClassName)}>
473
- <div className={tableContainer} style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)' }}>
553
+ <div
554
+ ref={rootRef}
555
+ className={clsx("space-y-4 w-full", containerSlot.className)}
556
+ style={{ ...colorVars, ...containerSlot.style }}
557
+ >
558
+ <div
559
+ className={clsx(tableContainer, cardSlot.className)}
560
+ style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)', ...cardSlot.style }}
561
+ >
474
562
  {/* Header outside overflow */}
475
563
  {title && (
476
- <div className="px-6 py-5 flex items-center justify-between" style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)' }}>
564
+ <div
565
+ className={clsx("px-6 py-5 flex items-center justify-between", toolbarSlot.className)}
566
+ style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)', ...toolbarSlot.style }}
567
+ >
477
568
  <ITText as="h2" className="text-xl font-bold text-secondary-900 leading-tight">{title}</ITText>
478
- <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">
479
- <button
480
- onClick={() => setViewMode("table")}
481
- disabled={forcedCards}
482
- className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all ${
483
- effectiveView === "table"
484
- ? "bg-white dark:bg-slate-900 text-slate-900 dark:text-white shadow-sm border border-slate-200/50 dark:border-slate-700"
485
- : "text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"
486
- }`}
487
- >
488
- <FaTable size={11} />
489
- Table
490
- </button>
491
- <button
492
- onClick={() => setViewMode("cards")}
493
- className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all ${
494
- effectiveView === "cards"
495
- ? "bg-white dark:bg-slate-900 text-slate-900 dark:text-white shadow-sm border border-slate-200/50 dark:border-slate-700"
496
- : "text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"
497
- }`}
498
- >
499
- <FaThLarge size={11} />
500
- Cards
501
- </button>
502
- </div>
569
+ {showViewToggle && viewToggle}
503
570
  </div>
504
571
  )}
505
572
 
506
- {!title && (
507
- <div className="flex justify-end px-4 pt-3">
508
- <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">
509
- <button
510
- onClick={() => setViewMode("table")}
511
- disabled={forcedCards}
512
- className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all ${
513
- effectiveView === "table"
514
- ? "bg-white dark:bg-slate-900 text-slate-900 dark:text-white shadow-sm border border-slate-200/50 dark:border-slate-700"
515
- : "text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"
516
- }`}
517
- >
518
- <FaTable size={11} />
519
- Table
520
- </button>
521
- <button
522
- onClick={() => setViewMode("cards")}
523
- className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all ${
524
- effectiveView === "cards"
525
- ? "bg-white dark:bg-slate-900 text-slate-900 dark:text-white shadow-sm border border-slate-200/50 dark:border-slate-700"
526
- : "text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"
527
- }`}
528
- >
529
- <FaThLarge size={11} />
530
- Cards
531
- </button>
532
- </div>
573
+ {!title && showViewToggle && (
574
+ <div className={clsx("flex justify-end px-4 pt-3", toolbarSlot.className)} style={toolbarSlot.style}>
575
+ {viewToggle}
533
576
  </div>
534
577
  )}
535
578
 
536
579
  {effectiveView === "cards" ? (
537
- <div className="p-4 space-y-3 max-h-[400px] overflow-y-auto">
580
+ <div className={clsx("p-4 space-y-3 max-h-[400px] overflow-y-auto", cardsSlot.className)} style={cardsSlot.style}>
538
581
  {currentData.length > 0 ? (
539
582
  currentData.map((row, i) => (
540
583
  <div
@@ -550,8 +593,8 @@ export default function ITTable<T extends Record<string, unknown>>({
550
593
  ))
551
594
  ) : (
552
595
  <div className={clsx(tableEmptyContent, "py-12")}>
553
- <ITText as="span" className="text-lg">No se encontraron resultados</ITText>
554
- <ITText as="span" className="text-sm mt-1">Intenta ajustar los filtros</ITText>
596
+ <ITText as="span" className="text-lg">{t("table.noResults")}</ITText>
597
+ <ITText as="span" className="text-sm mt-1">{t("table.adjustFilters")}</ITText>
555
598
  </div>
556
599
  )}
557
600
  </div>
@@ -588,7 +631,8 @@ export default function ITTable<T extends Record<string, unknown>>({
588
631
  )}
589
632
  <thead>
590
633
  <tr
591
- className={clsx(tableHeaderRow, "dark:text-slate-200")}
634
+ className={clsx(tableHeaderRow, "dark:text-slate-200", headerSlot.className)}
635
+ style={headerSlot.style}
592
636
  aria-rowindex={isTableVirtual ? 1 : undefined}
593
637
  >
594
638
  {columns.map((col) => {
@@ -604,23 +648,23 @@ export default function ITTable<T extends Record<string, unknown>>({
604
648
  isPinned && "sticky",
605
649
  isStickyHeader && "sticky top-0 bg-secondary-50",
606
650
  isPinned ? "z-[15]" : isStickyHeader && "z-10",
607
- isPinned && (col.pinned === "left" ? "it-table-pinned-left" : "it-table-pinned-right")
651
+ isPinned && (col.pinned === "left" ? "it-table-pinned-left" : "it-table-pinned-right"),
652
+ headerCellSlot.className,
653
+ col.headerClassName
608
654
  )}
609
- style={
610
- col.minWidth != null || isStickyHeader || isPinned
611
- ? {
612
- ...(col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {}),
613
- ...(isStickyHeader || isPinned
614
- ? { backgroundColor: "var(--color-table-headerBg, #f8fafc)" }
615
- : {}),
616
- ...(isPinned
617
- ? pin.side === "left"
618
- ? { left: pin.offset }
619
- : { right: pin.offset }
620
- : {}),
621
- }
622
- : undefined
623
- }
655
+ style={{
656
+ ...(col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {}),
657
+ ...(isStickyHeader || isPinned
658
+ ? { backgroundColor: "var(--color-table-headerBg, #f8fafc)" }
659
+ : {}),
660
+ ...(isPinned
661
+ ? pin.side === "left"
662
+ ? { left: pin.offset }
663
+ : { right: pin.offset }
664
+ : {}),
665
+ ...headerCellSlot.style,
666
+ ...col.headerStyle,
667
+ }}
624
668
  >
625
669
  <div className={isFixed ? "flex flex-col gap-3" : "flex flex-col gap-3 min-w-[150px]"}>
626
670
  <div className="flex items-center justify-between gap-2">
@@ -632,7 +676,7 @@ export default function ITTable<T extends Record<string, unknown>>({
632
676
  ? "bg-secondary-200 text-secondary-900"
633
677
  : "hover:bg-secondary-200 text-secondary-400 hover:text-secondary-700"
634
678
  }`}
635
- title={`Ordenar por ${col.label}`}
679
+ title={t("table.sortBy", { label: col.label })}
636
680
  >
637
681
  <MdOutlineSwapVert className="w-4 h-4" aria-hidden="true" />
638
682
  </button>
@@ -664,8 +708,10 @@ export default function ITTable<T extends Record<string, unknown>>({
664
708
  className={clsx(
665
709
  tableRow,
666
710
  variant === "striped" && absoluteIndex % 2 === 0 && "bg-secondary-50/40 dark:bg-slate-800/20",
667
- onRowClick && tableRowClickable
711
+ onRowClick && tableRowClickable,
712
+ rowSlot.className
668
713
  )}
714
+ style={rowSlot.style}
669
715
  tabIndex={onRowClick ? 0 : undefined}
670
716
  onClick={onRowClick ? handleRowClick(row) : undefined}
671
717
  onKeyDown={onRowClick ? handleRowKeyDown(row) : undefined}
@@ -687,20 +733,20 @@ export default function ITTable<T extends Record<string, unknown>>({
687
733
  col.align && tableAlignClasses[col.align],
688
734
  isPinned && "sticky bg-[var(--color-table-rowBg,white)] group-hover:bg-[var(--color-table-rowHover,var(--color-secondary-50))]",
689
735
  isPinned && (col.pinned === "left" ? "it-table-pinned-left" : "it-table-pinned-right"),
690
- isPinned && "z-[1]"
736
+ isPinned && "z-[1]",
737
+ cellSlot.className,
738
+ col.cellClassName
691
739
  )}
692
- style={
693
- col.minWidth != null || isPinned
694
- ? {
695
- ...(col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {}),
696
- ...(isPinned
697
- ? pin.side === "left"
698
- ? { left: pin.offset }
699
- : { right: pin.offset }
700
- : {}),
701
- }
702
- : undefined
703
- }
740
+ style={{
741
+ ...(col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {}),
742
+ ...(isPinned
743
+ ? pin.side === "left"
744
+ ? { left: pin.offset }
745
+ : { right: pin.offset }
746
+ : {}),
747
+ ...cellSlot.style,
748
+ ...col.cellStyle,
749
+ }}
704
750
  title={truncateTitle}
705
751
  >
706
752
  {col.type === "actions" ? (
@@ -728,8 +774,8 @@ export default function ITTable<T extends Record<string, unknown>>({
728
774
  <tr>
729
775
  <td colSpan={columns.length} className="px-6 py-12 text-center">
730
776
  <div className={tableEmptyContent}>
731
- <ITText as="span" className="text-lg">No se encontraron resultados</ITText>
732
- <ITText as="span" className="text-sm mt-1">Intenta ajustar los filtros</ITText>
777
+ <ITText as="span" className="text-lg">{t("table.noResults")}</ITText>
778
+ <ITText as="span" className="text-sm mt-1">{t("table.adjustFilters")}</ITText>
733
779
  </div>
734
780
  </td>
735
781
  </tr>
@@ -740,7 +786,10 @@ export default function ITTable<T extends Record<string, unknown>>({
740
786
  )}
741
787
 
742
788
  {/* Pagination */}
743
- <div className="rounded-b-xl px-6 py-4" style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)' }}>
789
+ <div
790
+ className={clsx("rounded-b-xl px-6 py-4", footerSlot.className)}
791
+ style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)', ...footerSlot.style }}
792
+ >
744
793
  <ITPagination
745
794
  currentPage={currentPage}
746
795
  totalPages={computedTotalPages}
@@ -9,6 +9,7 @@ import { useFloatingPanel } from "@/hooks/useFloatingPanel";
9
9
  import { theme } from "@/theme/theme";
10
10
  import { ITTimePickerProps } from "./timePicker.props";
11
11
  import ITText from "@/components/atoms/text/text";
12
+ import { useITTranslation } from "@/i18n";
12
13
 
13
14
  /**
14
15
  * Time selection input with a dual-column dropdown (hours / minutes).
@@ -35,7 +36,7 @@ export default function ITTimePicker({
35
36
  name,
36
37
  value,
37
38
  label,
38
- placeholder = "HH:MM",
39
+ placeholder,
39
40
  onChange,
40
41
  onBlur,
41
42
  required,
@@ -47,6 +48,7 @@ export default function ITTimePicker({
47
48
  variant = "primary",
48
49
  color = "primary",
49
50
  }: ITTimePickerProps) {
51
+ const { t } = useITTranslation();
50
52
  const [isOpen, setIsOpen] = useState(false);
51
53
  const [inputValue, setInputValue] = useState(value || "");
52
54
  const [isValidTime, setIsValidTime] = useState(true);
@@ -185,7 +187,7 @@ export default function ITTimePicker({
185
187
  <ITInput
186
188
  name={name}
187
189
  label={label}
188
- placeholder={placeholder}
190
+ placeholder={placeholder ?? t("timePicker.placeholder")}
189
191
  type="text"
190
192
  value={inputValue}
191
193
  onChange={handleInputChange}
@@ -196,7 +198,7 @@ export default function ITTimePicker({
196
198
  variant={variant}
197
199
  size={size}
198
200
  touched={touched}
199
- error={!isValidTime ? "Hora inválida" : typeof error === 'string' ? error : undefined}
201
+ error={!isValidTime ? t("timePicker.invalid") : typeof error === 'string' ? error : undefined}
200
202
  iconRight={
201
203
  <FaClock
202
204
  onClick={() => {
@@ -223,9 +225,9 @@ export default function ITTimePicker({
223
225
  >
224
226
  <div className="flex bg-secondary-50 border-b border-secondary-100 text-xs font-semibold text-secondary-500 uppercase tracking-wider">
225
227
  <ITText as="div" className="flex-1 text-center py-2 border-r border-secondary-100">
226
- Horas
228
+ {t("timePicker.hours")}
227
229
  </ITText>
228
- <ITText as="div" className="flex-1 text-center py-2">Minutos</ITText>
230
+ <ITText as="div" className="flex-1 text-center py-2">{t("timePicker.minutes")}</ITText>
229
231
  </div>
230
232
 
231
233
  <div className="flex h-56 relative bg-white">
@@ -316,7 +318,7 @@ export default function ITTimePicker({
316
318
  size="sm"
317
319
  onClick={handleConfirm}
318
320
  >
319
- <ITText as="span">Aceptar</ITText>
321
+ <ITText as="span">{t("timePicker.accept")}</ITText>
320
322
  </ITButton>
321
323
  </div>
322
324
  </div>,
@@ -20,20 +20,30 @@ import ITTooltip from "@/components/atoms/tooltip/tooltip";
20
20
  import ITText from "@/components/atoms/text/text";
21
21
  import { inputError, inputLabel, inputWrapper } from "@/utils/styles";
22
22
  import { inputSizeTokens } from "@/theme/theme";
23
+ import { useITTranslation } from "@/i18n";
23
24
 
24
25
  const INLINE_TAGS = new Set(["STRONG", "B", "EM", "I", "U", "MARK"]);
25
26
 
26
- const ACTION_META: Record<
27
- ToolbarAction,
28
- { label: string; icon: ReactNode }
29
- > = {
30
- bold: { label: "Negrita", icon: <FaBold /> },
31
- italic: { label: "Itálica", icon: <FaItalic /> },
32
- underline: { label: "Subrayado", icon: <FaUnderline /> },
33
- highlight: { label: "Marcador", icon: <FaHighlighter /> },
34
- ul: { label: "Lista con viñetas", icon: <FaListUl /> },
35
- ol: { label: "Lista numerada", icon: <FaListOl /> },
36
- clear: { label: "Limpiar formato", icon: <FaEraser /> },
27
+ /** Catálogo de key por acción de la barra de herramientas. */
28
+ const ACTION_LABEL_KEYS: Record<ToolbarAction, string> = {
29
+ bold: "wysiwyg.bold",
30
+ italic: "wysiwyg.italic",
31
+ underline: "wysiwyg.underline",
32
+ highlight: "wysiwyg.highlight",
33
+ ul: "wysiwyg.bulletList",
34
+ ol: "wysiwyg.numberedList",
35
+ clear: "wysiwyg.clearFormat",
36
+ };
37
+
38
+ /** Icono por acción de la barra de herramientas. */
39
+ const ACTION_ICONS: Record<ToolbarAction, ReactNode> = {
40
+ bold: <FaBold />,
41
+ italic: <FaItalic />,
42
+ underline: <FaUnderline />,
43
+ highlight: <FaHighlighter />,
44
+ ul: <FaListUl />,
45
+ ol: <FaListOl />,
46
+ clear: <FaEraser />,
37
47
  };
38
48
 
39
49
  type ActiveState = Partial<Record<ToolbarAction, boolean>>;
@@ -73,6 +83,7 @@ export default function ITWysiwyg({
73
83
  toolbar = toolbarActions,
74
84
  className,
75
85
  }: ITWysiwygProps) {
86
+ const { t } = useITTranslation();
76
87
  const editorRef = useRef<HTMLDivElement>(null);
77
88
  const focusedRef = useRef(false);
78
89
  const [active, setActive] = useState<ActiveState>({});
@@ -516,7 +527,7 @@ export default function ITWysiwyg({
516
527
  }: {
517
528
  action: ToolbarAction;
518
529
  }) => {
519
- const meta = ACTION_META[action];
530
+ const meta = { label: t(ACTION_LABEL_KEYS[action]), icon: ACTION_ICONS[action] };
520
531
  const isActive = !!active[action];
521
532
  return (
522
533
  <ITTooltip content={meta.label}>
@@ -8,13 +8,13 @@ export interface ITConfirmDialogProps {
8
8
  onClose: () => void;
9
9
  /** Callback fired when the user confirms the destructive action. */
10
10
  onConfirm: () => void;
11
- /** Heading text displayed at the top of the dialog. @default "Confirmar acción" */
11
+ /** Heading text displayed at the top of the dialog. @default i18n `confirmDialog.title` ("Confirmar acción") */
12
12
  title?: string;
13
- /** Body content — accepts plain strings or React nodes. @default "¿Estás seguro de que deseas continuar?" */
13
+ /** Body content — accepts plain strings or React nodes. @default i18n `confirmDialog.message` ("¿Estás seguro de que deseas continuar?") */
14
14
  message?: ReactNode;
15
- /** Label for the confirm button. @default "Confirmar" */
15
+ /** Label for the confirm button. @default i18n `common.confirm` ("Confirmar") */
16
16
  confirmLabel?: string;
17
- /** Label for the cancel button. @default "Cancelar" */
17
+ /** Label for the cancel button. @default i18n `common.cancel` ("Cancelar") */
18
18
  cancelLabel?: string;
19
19
  /** Color variant applied to the confirm button. Accepts any ColorsTypes value (e.g. "primary", "danger", "warning", "info"). @default "primary" */
20
20
  variant?: ColorsTypes;