@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,20 @@
1
+ import React from "react";
2
+ import ITText from "@/components/text/text";
3
+
4
+ interface PaginationInfoProps {
5
+ currentCount: number;
6
+ totalCount: number;
7
+ className?: string;
8
+ }
9
+
10
+ export default function PaginationInfo({
11
+ currentCount,
12
+ totalCount,
13
+ className = "",
14
+ }: PaginationInfoProps) {
15
+ return (
16
+ <ITText as="span" className={`text-sm text-gray-700 ${className}`}>
17
+ Mostrando {currentCount} de {totalCount} resultados
18
+ </ITText>
19
+ );
20
+ }
@@ -0,0 +1,53 @@
1
+ import React from "react";
2
+ import SearchInput from "./SearchInput";
3
+ import SortButton from "./SortButton";
4
+ import ITButton from "@/components/button/button";
5
+ import ITText from "@/components/text/text";
6
+
7
+ interface SearchAndSortBarProps {
8
+ searchTerm: string;
9
+ onSearchChange: (value: string) => void;
10
+ onClearSearch: () => void;
11
+ onGlobalSort: () => void;
12
+ sortConfig?: {
13
+ key: string;
14
+ direction: "asc" | "desc";
15
+ };
16
+ searchInputPlaceholder?: string;
17
+ }
18
+
19
+ export default function SearchAndSortBar({
20
+ searchTerm,
21
+ onSearchChange,
22
+ onClearSearch,
23
+ onGlobalSort,
24
+ sortConfig,
25
+ searchInputPlaceholder = "Buscar en todos los campos...",
26
+ }: SearchAndSortBarProps) {
27
+ return (
28
+ <div className="bg-gray-50 px-6 py-4 border-b border-gray-200">
29
+ <div className="flex items-center gap-4">
30
+ <SearchInput
31
+ placeholder={searchInputPlaceholder}
32
+ value={searchTerm}
33
+ onChange={onSearchChange}
34
+ />
35
+
36
+ <SortButton sortConfig={sortConfig} onClick={onGlobalSort} />
37
+
38
+ {searchTerm && (
39
+ <ITButton
40
+ size="small"
41
+ variant="outlined"
42
+ color="danger"
43
+ onClick={onClearSearch}
44
+ ariaLabel="Limpiar búsqueda"
45
+ title="Limpiar búsqueda"
46
+ >
47
+ <ITText as="span">Limpiar</ITText>
48
+ </ITButton>
49
+ )}
50
+ </div>
51
+ </div>
52
+ );
53
+ }
@@ -0,0 +1,33 @@
1
+ import ITInput from "@/components/input/input";
2
+ import React from "react";
3
+ import { FaSearch } from "react-icons/fa";
4
+
5
+ interface SearchInputProps {
6
+ placeholder?: string;
7
+ value: string;
8
+ onChange: (value: string) => void;
9
+ className?: string;
10
+ }
11
+
12
+ export default function SearchInput({
13
+ placeholder = "Buscar en todos los campos...",
14
+ value,
15
+ onChange,
16
+ className = "",
17
+ }: SearchInputProps) {
18
+ return (
19
+ <div className={`relative flex-1 ${className}`}>
20
+ <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
21
+ <FaSearch className="h-5 w-5 text-gray-400" />
22
+ </div>
23
+ <ITInput
24
+ name="global-search"
25
+ placeholder={placeholder}
26
+ value={value}
27
+ onChange={(e) => onChange(e.target.value)}
28
+ onBlur={() => {}}
29
+ className="pl-10 w-full"
30
+ />
31
+ </div>
32
+ );
33
+ }
@@ -0,0 +1,50 @@
1
+ import React from "react";
2
+ import { FaSort, FaSortUp, FaSortDown } from "react-icons/fa";
3
+ import ITText from "@/components/text/text";
4
+
5
+ interface SortButtonProps {
6
+ sortConfig?: {
7
+ key: string;
8
+ direction: "asc" | "desc";
9
+ };
10
+ onClick: () => void;
11
+ className?: string;
12
+ }
13
+
14
+ export default function SortButton({
15
+ sortConfig,
16
+ onClick,
17
+ className = "",
18
+ }: SortButtonProps) {
19
+ return (
20
+ <button
21
+ onClick={onClick}
22
+ className={`p-3 rounded-lg bg-white border border-gray-300 hover:bg-gray-50 transition-colors duration-200 flex items-center gap-2 min-w-[120px] ${className}`}
23
+ aria-label={`Ordenar tabla ${
24
+ sortConfig
25
+ ? sortConfig.direction === "asc"
26
+ ? "descendente"
27
+ : "ascendente"
28
+ : "ascendente"
29
+ }`}
30
+ title="Ordenar tabla"
31
+ >
32
+ {sortConfig ? (
33
+ sortConfig.direction === "asc" ? (
34
+ <FaSortUp className="w-4 h-4 text-slate-500" />
35
+ ) : (
36
+ <FaSortDown className="w-4 h-4 text-slate-500" />
37
+ )
38
+ ) : (
39
+ <FaSort className="w-4 h-4 text-gray-500" />
40
+ )}
41
+ <ITText as="span" className="text-sm font-medium text-gray-700">
42
+ {sortConfig
43
+ ? sortConfig.direction === "asc"
44
+ ? "Asc ↑"
45
+ : "Desc ↓"
46
+ : "Ordenar"}
47
+ </ITText>
48
+ </button>
49
+ );
50
+ }
@@ -0,0 +1,22 @@
1
+ import React from "react";
2
+ import ITText from "@/components/text/text";
3
+
4
+ interface TableEmptyStateProps {
5
+ colSpan: number;
6
+ searchTerm: string;
7
+ }
8
+
9
+ export default function TableEmptyState({
10
+ colSpan,
11
+ searchTerm,
12
+ }: TableEmptyStateProps) {
13
+ return (
14
+ <tr>
15
+ <td colSpan={colSpan} className="px-6 py-4 text-center">
16
+ {searchTerm
17
+ ? <ITText as="span">No se encontraron resultados para tu búsqueda</ITText>
18
+ : <ITText as="span">No se encontraron resultados</ITText>}
19
+ </td>
20
+ </tr>
21
+ );
22
+ }
@@ -0,0 +1,35 @@
1
+ import React from "react";
2
+ import TableHeaderCell from "./TableHeaderCell";
3
+ import { SearchColumn } from "../searchTable.props";
4
+
5
+ interface TableHeaderProps<T> {
6
+ columns: SearchColumn<T>[];
7
+ onSort: (key: string) => void;
8
+ sortConfig?: {
9
+ key: string;
10
+ direction: "asc" | "desc";
11
+ };
12
+ }
13
+
14
+ export default function TableHeader<T>({
15
+ columns,
16
+ onSort,
17
+ sortConfig,
18
+ }: TableHeaderProps<T>) {
19
+ return (
20
+ <thead>
21
+ <tr className="bg-white border-b border-gray-200">
22
+ {columns.map((col) => (
23
+ <TableHeaderCell
24
+ key={col.key}
25
+ label={col.label}
26
+ sortable={col.sortable && col.type !== "actions"}
27
+ onSort={() => onSort(col.key)}
28
+ sortConfig={sortConfig?.key === col.key ? sortConfig : undefined}
29
+ className="px-3 py-3 text-center align-middle"
30
+ />
31
+ ))}
32
+ </tr>
33
+ </thead>
34
+ );
35
+ }
@@ -0,0 +1,43 @@
1
+ import React from "react";
2
+ import SortButton from "./SortButton";
3
+ import ITText from "@/components/text/text";
4
+
5
+ interface TableHeaderCellProps {
6
+ label: string;
7
+ sortable?: boolean;
8
+ onSort: () => void;
9
+ sortConfig?: {
10
+ key: string;
11
+ direction: "asc" | "desc";
12
+ };
13
+ className?: string;
14
+ }
15
+
16
+ export default function TableHeaderCell({
17
+ label,
18
+ sortable = false,
19
+ onSort,
20
+ sortConfig,
21
+ className = "",
22
+ }: TableHeaderCellProps) {
23
+ return (
24
+ <th className={className}>
25
+ <div className="flex flex-col items-center gap-2 w-full">
26
+ <div className="flex items-center justify-center gap-2 w-full">
27
+ <ITText as="span"
28
+ className="inline-block w-[96%] text-sm font-medium text-white bg-slate-400 px-3 py-1.5 pb-2 rounded-lg text-center leading-tight"
29
+ style={{
30
+ display: "-webkit-box",
31
+ WebkitBoxOrient: "vertical",
32
+ WebkitLineClamp:4,
33
+ overflow: "hidden",
34
+ }}
35
+ >
36
+ {label}
37
+ </ITText>
38
+ {sortable && <SortButton sortConfig={sortConfig} onClick={onSort} />}
39
+ </div>
40
+ </div>
41
+ </th>
42
+ );
43
+ }
@@ -0,0 +1,144 @@
1
+ import { useEditableRow } from "@/hooks/useEditableRow";
2
+ import { formatCurrencyMX } from "@/utils/table.utils";
3
+ import clsx from "clsx";
4
+ import React from "react";
5
+ import { FaCheck, FaTimes } from "react-icons/fa";
6
+ import { SearchColumn } from "../searchTable.props";
7
+ import EditableCell from "./EditableCell";
8
+ import * as yup from "yup";
9
+
10
+ interface TableRowProps<T> {
11
+ row: T;
12
+ rowIndex: number;
13
+ columns: SearchColumn<T>[];
14
+ getNestedValue: (obj: unknown, path: string) => unknown;
15
+ onSave?: (row: T) => void;
16
+ onCancel?: () => void;
17
+ validationSchema?: yup.ObjectSchema<any>;
18
+ isEditing?: boolean;
19
+ onEdit?: (row: T) => void;
20
+ onDelete?: (row: T) => void;
21
+ }
22
+
23
+ export default function TableRow<T>({
24
+ row,
25
+ rowIndex,
26
+ columns,
27
+ getNestedValue,
28
+ onSave,
29
+ onCancel,
30
+ validationSchema,
31
+ isEditing = false,
32
+ onEdit,
33
+ }: TableRowProps<T>) {
34
+ const {
35
+ editedRow,
36
+ errors,
37
+ isHovered,
38
+ setIsHovered,
39
+ hasErrors,
40
+ handleEdit,
41
+ handleSave,
42
+ handleCancel,
43
+ handleChange,
44
+ } = useEditableRow({ row, columns, getNestedValue, validationSchema });
45
+
46
+ const onEditAction = () => handleEdit(onEdit);
47
+ const onSaveAction = () => handleSave(onSave);
48
+ const onCancelAction = () => handleCancel(onCancel);
49
+
50
+ const renderCellContent = (col: SearchColumn<T>, rowData: T) => {
51
+ const value = getNestedValue(rowData, col.key);
52
+
53
+ if (col.render) return col.render(rowData);
54
+
55
+ switch (col.type) {
56
+ case "number":
57
+ return typeof value === "number" && col.currencyMX
58
+ ? formatCurrencyMX(value)
59
+ : (value as React.ReactNode);
60
+
61
+ case "boolean":
62
+ return value ? (
63
+ <FaCheck
64
+ className="text-green-500"
65
+ aria-label="Verdadero"
66
+ title="Verdadero"
67
+ />
68
+ ) : (
69
+ <FaTimes className="text-red-500" aria-label="Falso" title="Falso" />
70
+ );
71
+
72
+ case "actions":
73
+ if (isEditing && col.saveActions) {
74
+ return col.saveActions(rowData, {
75
+ onSave: onSaveAction,
76
+ onCancel: onCancelAction,
77
+ hasErrors,
78
+ });
79
+ } else if (col.actions) {
80
+ return col.actions(rowData, { onEdit: onEditAction });
81
+ }
82
+ return null;
83
+
84
+ case "catalog":
85
+ if (col.catalogOptions) {
86
+ const catalogItem = col.catalogOptions.data.find(
87
+ (item) => item.id === value
88
+ );
89
+ return catalogItem?.name || (value as React.ReactNode);
90
+ }
91
+ return value as React.ReactNode;
92
+
93
+ default:
94
+ return value as React.ReactNode;
95
+ }
96
+ };
97
+
98
+ return (
99
+ <tr
100
+ onMouseEnter={() => setIsHovered(true)}
101
+ onMouseLeave={() => setIsHovered(false)}
102
+ className={`border-b border-gray-200 transition-colors duration-150 ${
103
+ isEditing
104
+ ? "bg-slate-50"
105
+ : rowIndex % 2 === 0
106
+ ? "bg-white"
107
+ : "bg-gray-50"
108
+ } ${isHovered && !isEditing ? "bg-gray-100" : ""}`}
109
+ >
110
+ {columns.map((col) => (
111
+ <td
112
+ key={`${rowIndex}-${col.key}`}
113
+ className={clsx("pl-5 py-2", col.className, {
114
+ "text-center": col.type === "actions" || col.type === "boolean",
115
+ })}
116
+ >
117
+ {isEditing && col.editable ? (
118
+ <EditableCell
119
+ column={col}
120
+ value={getNestedValue(editedRow, col.key)}
121
+ onChange={(value) => handleChange(col.key, value)}
122
+ error={errors[col.key]}
123
+ row={editedRow}
124
+ />
125
+ ) : (
126
+ <div
127
+ className={clsx({
128
+ "flex flex-col items-center justify-center gap-1 ":
129
+ col.type === "actions",
130
+ })}
131
+ >
132
+ {
133
+ renderCellContent(
134
+ col,
135
+ isEditing ? editedRow : row
136
+ ) as React.ReactNode
137
+ }
138
+ </div>
139
+ )}
140
+ </td>
141
+ ))}
142
+ </tr>
143
+ );
144
+ }
@@ -0,0 +1,56 @@
1
+ import { TableSize, TableVariants } from "@/types/table.types";
2
+ import * as yup from "yup";
3
+
4
+ export type ColumnType = "string" | "date" | "number" | "boolean" | "actions" | "catalog";
5
+
6
+ export interface CatalogOption {
7
+ id: string | number;
8
+ name: string;
9
+ }
10
+
11
+ export interface SearchColumn<T = any> {
12
+ key: string;
13
+ label: string;
14
+ type: "string" | "number" | "boolean" | "date" | "actions" | "catalog";
15
+ filter?: boolean | 'catalog';
16
+ sortable?: boolean;
17
+ editable?: boolean;
18
+ inputType?: "text" | "number" | "select" | "checkbox" | "date";
19
+ // OK: text number
20
+ // PENDING: select checkbox date
21
+ options?: { value: string | number; label: string }[];
22
+ validation?: (value: any, row?:any) => string | undefined;
23
+ className?: string;
24
+ currencyMX?: boolean;
25
+ catalogOptions?: {
26
+ data: Array<{ id: string | number; name: string }> | any[];
27
+ key?: string;
28
+ label?: string;
29
+ };
30
+ render?: (row: T) => React.ReactNode;
31
+ actions?: (row: T, helpers: { onEdit: (row: T) => void }) => React.ReactNode;
32
+ saveActions?: (row: T, helpers: { onSave: (row: T) => void, onCancel: () => void, hasErrors: any}) => React.ReactNode;
33
+ }
34
+
35
+ export interface ITSearchTableProps<T> {
36
+ columns: SearchColumn<T>[];
37
+ containerClassName?: string;
38
+ searchInputPlaceholder?: string;
39
+ data: T[];
40
+ variant?: TableVariants;
41
+ className?: string;
42
+ size?: TableSize;
43
+ itemsPerPageOptions?: Array<number>;
44
+ defaultItemsPerPage?: number;
45
+ validationSchema?: yup.ObjectSchema<any>
46
+ title?: string;
47
+ pageIndex: number;
48
+ totalCount: number;
49
+ totalPages: number;
50
+ hasPreviousPage: boolean;
51
+ hasNextPage: boolean;
52
+ onPageChange?: (page: number) => void;
53
+ onItemsPerPageChange?: (itemsPerPage: number) => void;
54
+ onSortChange?: (sortConfig: { key: string, direction: "asc" | "desc" }) => void; // Se actualizó para incluir `key`
55
+ onFilterChange?: (filters: Record<string, string | boolean | number>) => void;
56
+ }
@@ -0,0 +1,187 @@
1
+ import { useDebouncedSearch } from "@/hooks/useDebouncedSearch";
2
+ import clsx from "clsx";
3
+ import React, { useState } from "react";
4
+
5
+ import { sizeStyles, variantStyles } from "@/types/table.types";
6
+ import { ITSearchTableProps } from "./searchTable.props";
7
+ import SearchAndSortBar from "./components/SearchAndSortBar";
8
+ import TableHeader from "./components/TableHeader";
9
+ import TableRow from "./components/TableRow";
10
+ import { getNestedValue } from "@/utils/table.utils";
11
+ import TableEmptyState from "./components/TableEmptyState";
12
+ import PaginationControls from "./components/PaginationControls";
13
+ import ITText from "@/components/text/text";
14
+
15
+ interface CustomITSearchTableProps<T> extends ITSearchTableProps<T> {
16
+ editingRow?: number | null;
17
+ searchTermInitial?: string;
18
+ onClearSearch?: () => void;
19
+ onEdit?: (row: T, index: number) => void;
20
+ onSave?: (row: T, index: number) => void;
21
+ onCancel?: () => void;
22
+ sortConfig?: {
23
+ key: string;
24
+ direction: "asc" | "desc";
25
+ };
26
+ }
27
+
28
+ export default function ITSearchTable<T extends Record<string, unknown>>({
29
+ columns,
30
+ data,
31
+ containerClassName,
32
+ searchTermInitial = "",
33
+ searchInputPlaceholder = "Buscar en todos los campos...",
34
+ className,
35
+ variant = "default",
36
+ size = "md",
37
+ itemsPerPageOptions = [10, 20, 50, 100],
38
+ defaultItemsPerPage = 10,
39
+ title,
40
+ pageIndex,
41
+ totalCount,
42
+ totalPages,
43
+ hasPreviousPage,
44
+ hasNextPage,
45
+ onPageChange,
46
+ onItemsPerPageChange,
47
+ onSortChange,
48
+ onFilterChange,
49
+ sortConfig,
50
+ editingRow = null,
51
+ validationSchema,
52
+ onClearSearch,
53
+ onEdit,
54
+ onSave,
55
+ onCancel,
56
+ }: CustomITSearchTableProps<T>) {
57
+ const [itemsPerPage, setItemsPerPage] = useState(defaultItemsPerPage);
58
+
59
+ const { searchTerm, handleSearchChange, handleClearSearch } = useDebouncedSearch({
60
+ initialValue: searchTermInitial,
61
+ onSearch: (value) => {
62
+ if (onFilterChange) {
63
+ onFilterChange(value ? { query: value } : {});
64
+ }
65
+ },
66
+ });
67
+
68
+ const handleItemsPerPageChange = (value: number) => {
69
+ setItemsPerPage(value);
70
+ onItemsPerPageChange?.(value);
71
+ };
72
+
73
+ const goToPage = (page: number) => {
74
+ onPageChange?.(page);
75
+ };
76
+
77
+ const handleGlobalSort = () => {
78
+ const newDirection = sortConfig?.direction === "asc" ? "desc" : "asc";
79
+ onSortChange?.({ key: "id", direction: newDirection });
80
+ };
81
+
82
+ const handleSort = (key: string) => {
83
+ const column = columns.find((col) => col.key === key);
84
+ if (!column || !column.sortable) return;
85
+
86
+ let newDirection: "asc" | "desc" = "asc";
87
+ if (sortConfig && sortConfig.key === key) {
88
+ newDirection = sortConfig.direction === "asc" ? "desc" : "asc";
89
+ }
90
+
91
+ onSortChange?.({ key, direction: newDirection });
92
+ };
93
+
94
+ const handleEdit = (row: T, index: number) => onEdit?.(row, index);
95
+ const handleSave = (updatedRow: T, index: number) => onSave?.(updatedRow, index);
96
+ const handleCancelEdit = () => onCancel?.();
97
+
98
+ const handleClearSearchWithClear = () => {
99
+ handleClearSearch();
100
+ onClearSearch?.();
101
+ };
102
+
103
+ return (
104
+ <div className={clsx("space-y-4 w-full", containerClassName)}>
105
+ {/* Card principal con sombra */}
106
+ <div className="shadow-md sm:rounded-lg overflow-hidden">
107
+ {/* Header fijo */}
108
+ {title && (
109
+ <div className="bg-teal-500 text-white px-6 py-4">
110
+ <ITText as="h2" className="text-xl font-bold text-center whitespace-nowrap">
111
+ {title}
112
+ </ITText>
113
+ </div>
114
+ )}
115
+
116
+ {/* Contenido con scroll */}
117
+ <div className="bg-white">
118
+ {/* Barra de búsqueda y ordenamiento */}
119
+ <div className="p-4 border-b border-gray-200">
120
+ <SearchAndSortBar
121
+ searchTerm={searchTerm}
122
+ onSearchChange={handleSearchChange}
123
+ onClearSearch={handleClearSearchWithClear}
124
+ onGlobalSort={handleGlobalSort}
125
+ sortConfig={sortConfig}
126
+ searchInputPlaceholder={searchInputPlaceholder}
127
+ />
128
+ </div>
129
+
130
+ {/* Tabla con scroll horizontal */}
131
+ <div className="overflow-x-auto">
132
+ <table
133
+ className={clsx(
134
+ "min-w-full text-sm text-left bg-white text-gray-900 table-auto",
135
+ variantStyles[variant],
136
+ sizeStyles[size]
137
+ )}
138
+ >
139
+ <TableHeader
140
+ columns={columns}
141
+ onSort={handleSort}
142
+ sortConfig={sortConfig}
143
+ />
144
+ <tbody>
145
+ {data.length > 0 ? (
146
+ data.map((row, rowIndex) => (
147
+ <TableRow
148
+ key={rowIndex}
149
+ row={row}
150
+ rowIndex={rowIndex}
151
+ columns={columns}
152
+ validationSchema={validationSchema}
153
+ getNestedValue={getNestedValue}
154
+ isEditing={editingRow === rowIndex}
155
+ onEdit={() => handleEdit(row, rowIndex)}
156
+ onSave={(updatedRow) => handleSave(updatedRow, rowIndex)}
157
+ onCancel={handleCancelEdit}
158
+ />
159
+ ))
160
+ ) : (
161
+ <TableEmptyState
162
+ colSpan={columns.length + 1}
163
+ searchTerm={searchTerm}
164
+ />
165
+ )}
166
+ </tbody>
167
+ </table>
168
+ </div>
169
+ </div>
170
+ </div>
171
+
172
+ {/* Paginación */}
173
+ <PaginationControls
174
+ pageIndex={pageIndex}
175
+ totalPages={totalPages}
176
+ hasPreviousPage={hasPreviousPage}
177
+ hasNextPage={hasNextPage}
178
+ onPageChange={goToPage}
179
+ itemsPerPage={itemsPerPage}
180
+ itemsPerPageOptions={itemsPerPageOptions}
181
+ onItemsPerPageChange={handleItemsPerPageChange}
182
+ currentCount={data.length}
183
+ totalCount={totalCount}
184
+ />
185
+ </div>
186
+ );
187
+ }
@@ -0,0 +1,18 @@
1
+ import { ReactNode } from "react";
2
+
3
+ export type SegmentedControlSize = "sm" | "md";
4
+
5
+ export interface ISegmentedOption {
6
+ value: string;
7
+ label: string;
8
+ icon?: ReactNode;
9
+ }
10
+
11
+ export interface ITSegmentedControlProps {
12
+ options: ISegmentedOption[];
13
+ value: string;
14
+ onChange: (value: string) => void;
15
+ size?: SegmentedControlSize;
16
+ className?: string;
17
+ disabled?: boolean;
18
+ }