@zauru-sdk/components 6.14.1 → 6.15.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.
- package/CHANGELOG.md +19 -0
- package/dist/DynamicTable/GenericDynamicTable.d.ts +6 -1
- package/dist/Table/ZauruTable.d.ts +2 -0
- package/dist/esm/DynamicTable/GenericDynamicTable.js +9 -8
- package/dist/esm/Table/ZauruTable.js +57 -23
- package/package.json +6 -6
- package/src/DynamicTable/GenericDynamicTable.tsx +15 -8
- package/src/Table/ZauruTable.tsx +68 -21
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [6.15.0](https://github.com/intuitiva/zauru-typescript-sdk/compare/@zauru-sdk/components@6.14.2...@zauru-sdk/components@6.15.0) (2026-10-28)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* permitir editar GenericDynamicTable sin agregar o borrar filas ([7fc9b41](https://github.com/intuitiva/zauru-typescript-sdk/commit/7fc9b41a7aebf2627a674bc8d9d70b772c378056))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## [6.14.2](https://github.com/intuitiva/zauru-typescript-sdk/compare/@zauru-sdk/components@6.14.1...@zauru-sdk/components@6.14.2) (2026-10-26)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* alinear encabezados y celdas de ZauruTable ([46783d1](https://github.com/intuitiva/zauru-typescript-sdk/commit/46783d1f))
|
|
23
|
+
|
|
24
|
+
|
|
6
25
|
## [6.14.1](https://github.com/intuitiva/zauru-typescript-sdk/compare/@zauru-sdk/components@6.14.0...@zauru-sdk/components@6.14.1) (2026-10-26)
|
|
7
26
|
|
|
8
27
|
**Note:** Version bump only for package @zauru-sdk/components
|
|
@@ -15,8 +15,13 @@ type Props = {
|
|
|
15
15
|
footerRow?: FooterColumnConfig[];
|
|
16
16
|
thCSSProperties?: React.CSSProperties;
|
|
17
17
|
thElementsClassName?: string;
|
|
18
|
-
/** Controla si se pueden
|
|
18
|
+
/** Controla si se pueden editar los campos. */
|
|
19
19
|
editable?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Si es false, no muestra agregar/eliminar filas aunque `editable` esté activo.
|
|
22
|
+
* Útil para catálogos fijos cuyos valores sí se editan.
|
|
23
|
+
*/
|
|
24
|
+
rowActions?: boolean;
|
|
20
25
|
/** Opciones de búsqueda. */
|
|
21
26
|
searcheables?: SelectFieldOption[];
|
|
22
27
|
/** Activa o desactiva el “skeleton” de carga. */
|
|
@@ -21,5 +21,7 @@ type Props = TableProps<any> & {
|
|
|
21
21
|
theme?: "solarized" | "subTable";
|
|
22
22
|
className?: string;
|
|
23
23
|
};
|
|
24
|
+
export declare const normalizeZauruTableColumns: (columns: any) => any;
|
|
25
|
+
export declare const zauruTableFlexBasisCss: (tableClassName: string, columns: any) => string;
|
|
24
26
|
export declare const ZauruTable: (props: Props) => import("react/jsx-runtime").JSX.Element;
|
|
25
27
|
export {};
|
|
@@ -97,12 +97,13 @@ const GenericDynamicTableErrorComponent = ({ name }) => {
|
|
|
97
97
|
*/
|
|
98
98
|
export const GenericDynamicTable = (props) => {
|
|
99
99
|
const { columns, onChange, className, footerRow, defaultValue = [], thCSSProperties, thElementsClassName = "", editable = true, readOnly = false, // Nuevo prop
|
|
100
|
-
searcheables = [], loading = false, paginated = true, defaultItemsPerPage = 10, itemsPerPageOptions = [10, 50, 100], name, withoutBg = false, orientation = "horizontal", maxRows, confirmDelete = true, addRowButtonHandler, rowSummary, } = props;
|
|
100
|
+
rowActions = true, searcheables = [], loading = false, paginated = true, defaultItemsPerPage = 10, itemsPerPageOptions = [10, 50, 100], name, withoutBg = false, orientation = "horizontal", maxRows, confirmDelete = true, addRowButtonHandler, rowSummary, } = props;
|
|
101
101
|
/**
|
|
102
102
|
* Definimos una variable interna para saber si los campos son
|
|
103
103
|
* efectivamente editables: solo si `editable` es true y `readOnly` es false.
|
|
104
104
|
*/
|
|
105
105
|
const isEditable = editable && !readOnly;
|
|
106
|
+
const showRowActions = isEditable && rowActions;
|
|
106
107
|
try {
|
|
107
108
|
const [tableData, setTableData] = useState(defaultValue);
|
|
108
109
|
const [deletedData, setDeletedData] = useState([]);
|
|
@@ -174,9 +175,9 @@ export const GenericDynamicTable = (props) => {
|
|
|
174
175
|
if (orientation === "horizontal") {
|
|
175
176
|
return (_jsxs("tr", { style: { ...thCSSProperties }, children: [rendereableColumns.map((column, index) => {
|
|
176
177
|
const ancho = column.width ??
|
|
177
|
-
(
|
|
178
|
+
(showRowActions ? 94 : 100) / (rendereableColumns.length ?? 1);
|
|
178
179
|
return (_jsx("th", { className: `text-left align-middle p-2 ${thElementsClassName} ${column.headerClassName || ""}`, style: { width: `${ancho}%` }, children: column.label }, index));
|
|
179
|
-
}),
|
|
180
|
+
}), showRowActions && _jsx("th", { style: { width: "4%" } })] }));
|
|
180
181
|
}
|
|
181
182
|
else {
|
|
182
183
|
return null;
|
|
@@ -186,13 +187,13 @@ export const GenericDynamicTable = (props) => {
|
|
|
186
187
|
const rendereableColumns = columns.filter((column) => column.type !== "hidden");
|
|
187
188
|
if (orientation === "horizontal") {
|
|
188
189
|
const rowClassName = index % 2 === 0 ? `${withoutBg ? "" : "bg-gray-200"}` : "";
|
|
189
|
-
const summaryColSpan = rendereableColumns.length + (
|
|
190
|
+
const summaryColSpan = rendereableColumns.length + (showRowActions ? 1 : 0);
|
|
190
191
|
const summaryContent = rowSummary?.(rowData);
|
|
191
|
-
return (_jsxs(React.Fragment, { children: [_jsxs("tr", { className: rowClassName, children: [rendereableColumns.map((column) => renderCell(rowData, column)),
|
|
192
|
+
return (_jsxs(React.Fragment, { children: [_jsxs("tr", { className: rowClassName, children: [rendereableColumns.map((column) => renderCell(rowData, column)), showRowActions && renderDeleteButton(rowData)] }), summaryContent ? (_jsx("tr", { className: rowClassName, children: _jsxs("td", { colSpan: summaryColSpan, className: "px-2 pb-3 pt-0 text-sm text-gray-700 border-b border-gray-300", children: [_jsx("span", { className: "font-medium text-gray-500", children: "Resumen: " }), summaryContent] }) })) : null] }, rowData.id));
|
|
192
193
|
}
|
|
193
194
|
else {
|
|
194
195
|
// Orientación vertical
|
|
195
|
-
return rendereableColumns.map((column) => (_jsxs("tr", { className: index % 2 === 0 ? `${withoutBg ? "" : "bg-gray-200"}` : "", children: [_jsx("th", { className: `text-left align-middle p-2 ${thElementsClassName} ${column.headerClassName || ""}`, children: column.label }), renderCell(rowData, column),
|
|
196
|
+
return rendereableColumns.map((column) => (_jsxs("tr", { className: index % 2 === 0 ? `${withoutBg ? "" : "bg-gray-200"}` : "", children: [_jsx("th", { className: `text-left align-middle p-2 ${thElementsClassName} ${column.headerClassName || ""}`, children: column.label }), renderCell(rowData, column), showRowActions &&
|
|
196
197
|
column === rendereableColumns[rendereableColumns.length - 1] &&
|
|
197
198
|
renderDeleteButton(rowData)] }, `${rowData.id}-${column.name}`)));
|
|
198
199
|
}
|
|
@@ -303,7 +304,7 @@ export const GenericDynamicTable = (props) => {
|
|
|
303
304
|
};
|
|
304
305
|
return (_jsxs(_Fragment, { children: [name && (_jsxs(_Fragment, { children: [_jsx(GenericDynamicTableErrorComponent, { name: name }), _jsx("input", { name: name, type: "hidden", value: JSON.stringify(tableData), hidden: true }), _jsx("input", { name: `deleted_${name}`, type: "hidden", value: JSON.stringify(deletedData), hidden: true })] })), _jsxs("div", { className: `${className}`, children: [searcheables.length > 0 && (_jsx("div", { children: _jsx(TextField, { className: "mb-2", name: "search", title: `Buscar por: ${searcheables
|
|
305
306
|
.map((x) => x.label)
|
|
306
|
-
.join(", ")}`, onChange: handleChangeSearch, disabled: loading || readOnly }) })), _jsxs("table", { className: "w-full", children: [orientation === "horizontal" && _jsx("thead", { children: renderHeader() }), _jsx("tbody", { children: renderRows() }),
|
|
307
|
+
.join(", ")}`, onChange: handleChangeSearch, disabled: loading || readOnly }) })), _jsxs("table", { className: "w-full", children: [orientation === "horizontal" && _jsx("thead", { children: renderHeader() }), _jsx("tbody", { children: renderRows() }), showRowActions && (_jsx("tfoot", { children: _jsx("tr", { children: _jsx("td", { colSpan: orientation === "horizontal" ? columns.length + 1 : 2, className: "align-middle text-right", children: (!maxRows || tableData.length < maxRows) && (_jsx("button", { className: "bg-blue-500 hover:bg-blue-600 font-bold py-2 px-4 rounded", onClick: (event) => {
|
|
307
308
|
event.preventDefault();
|
|
308
309
|
event.stopPropagation();
|
|
309
310
|
if (addRowButtonHandler) {
|
|
@@ -317,7 +318,7 @@ export const GenericDynamicTable = (props) => {
|
|
|
317
318
|
.map((column, index) => {
|
|
318
319
|
const footerCell = footerRow.find((fc) => fc.name === column.name);
|
|
319
320
|
return (_jsx("td", { colSpan: orientation === "vertical" ? 2 : 1, className: `align-middle ${footerCell?.className || ""}`, children: footerCell ? (footerCell.cell ? (footerCell.cell(tableData)) : (footerCell.content)) : (_jsx(_Fragment, {})) }, index));
|
|
320
|
-
}),
|
|
321
|
+
}), showRowActions && _jsx("td", {})] }) }))] }), paginated && totalPages() > 1 && (_jsxs("div", { className: "flex justify-between items-center mt-4", children: [_jsxs("div", { className: "flex items-center", children: [_jsx(Button, { type: "button", disabled: currentPage === 1 || readOnly, onClickSave: () => setCurrentPage((old) => Math.max(old - 1, 1)), children: "Anterior" }), _jsx("span", { className: "mx-2", children: `Página ${currentPage} de ${totalPages()}` }), _jsx(Button, { type: "button", disabled: currentPage === totalPages() || readOnly, onClickSave: () => setCurrentPage((old) => Math.min(old + 1, totalPages())), children: "Siguiente" })] }), _jsx("div", { children: _jsx("select", { value: itemsPerPage, onChange: (e) => {
|
|
321
322
|
setItemsPerPage(Number(e.target.value));
|
|
322
323
|
setCurrentPage(1); // resetear la página al cambiar los elementos por página
|
|
323
324
|
}, children: itemsPerPageOptions.map((option) => (_jsxs("option", { value: option, children: [option, " elementos por p\u00E1gina"] }, option))) }) })] }))] })] }));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useSearchParams } from "@remix-run/react";
|
|
3
|
-
import { useEffect, useState } from "react";
|
|
3
|
+
import { useEffect, useId, useMemo, useState } from "react";
|
|
4
4
|
import { createTheme } from "react-data-table-component";
|
|
5
5
|
import { SearchSVG } from "@zauru-sdk/icons";
|
|
6
6
|
import * as ReactDataTableComponent from "react-data-table-component";
|
|
@@ -160,6 +160,56 @@ createTheme("subTable", {
|
|
|
160
160
|
background: "black",
|
|
161
161
|
},
|
|
162
162
|
});
|
|
163
|
+
export const normalizeZauruTableColumns = (columns) => {
|
|
164
|
+
if (!Array.isArray(columns)) {
|
|
165
|
+
return columns;
|
|
166
|
+
}
|
|
167
|
+
return columns.map((column, index) => {
|
|
168
|
+
if (!column || typeof column !== "object") {
|
|
169
|
+
return column;
|
|
170
|
+
}
|
|
171
|
+
const next = { wrap: true, ...column };
|
|
172
|
+
if (next.id == null) {
|
|
173
|
+
next.id = index + 1;
|
|
174
|
+
}
|
|
175
|
+
// RDT `width` sets both min-width and max-width, wiping a px floor.
|
|
176
|
+
// Keep % as flex-basis so minWidth/maxWidth/grow still apply.
|
|
177
|
+
if (typeof next.width === "string" && next.width.endsWith("%")) {
|
|
178
|
+
const pct = next.width;
|
|
179
|
+
delete next.width;
|
|
180
|
+
next.style = {
|
|
181
|
+
flexBasis: pct,
|
|
182
|
+
...next.style,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return next;
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
export const zauruTableFlexBasisCss = (tableClassName, columns) => {
|
|
189
|
+
if (!tableClassName || !Array.isArray(columns)) {
|
|
190
|
+
return "";
|
|
191
|
+
}
|
|
192
|
+
const safeClass = tableClassName.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
193
|
+
if (!safeClass) {
|
|
194
|
+
return "";
|
|
195
|
+
}
|
|
196
|
+
return columns
|
|
197
|
+
.flatMap((column) => {
|
|
198
|
+
const basis = column?.style?.flexBasis;
|
|
199
|
+
if (basis == null || column?.id == null) {
|
|
200
|
+
return [];
|
|
201
|
+
}
|
|
202
|
+
const id = String(column.id).replace(/[^a-zA-Z0-9_-]/g, "");
|
|
203
|
+
const safeBasis = String(basis).replace(/[^\d.%]/g, "");
|
|
204
|
+
if (!id || !safeBasis) {
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
return [
|
|
208
|
+
`.${safeClass} [data-column-id="${id}"] { flex-basis: ${safeBasis} !important; }`,
|
|
209
|
+
];
|
|
210
|
+
})
|
|
211
|
+
.join("\n");
|
|
212
|
+
};
|
|
163
213
|
//Documentación de la tabla https://react-data-table-component.netlify.app/?path=/docs/getting-started-intro--docs
|
|
164
214
|
export const ZauruTable = (props) => {
|
|
165
215
|
const { columns, conditionalRowStyles, data, loading = false, pagination, search, expandable, theme, className, offlineSearch = [], whitOutPagination = false, ...others } = props;
|
|
@@ -176,6 +226,9 @@ export const ZauruTable = (props) => {
|
|
|
176
226
|
useEffect(() => {
|
|
177
227
|
setFilteredData(data);
|
|
178
228
|
}, [data]);
|
|
229
|
+
const tableInstanceClass = `zauru-table-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
230
|
+
const normalizedColumns = useMemo(() => normalizeZauruTableColumns(columns), [columns]);
|
|
231
|
+
const flexBasisCss = useMemo(() => zauruTableFlexBasisCss(tableInstanceClass, normalizedColumns), [tableInstanceClass, normalizedColumns]);
|
|
179
232
|
const subHeaderComponentMemo = (_jsxs(_Fragment, { children: [_jsx("input", { name: "search", type: "text", placeholder: search?.placeholderSearch ?? "Filtrar", "aria-label": "Search Input", className: "bg-gray-50 border border-gray-300 text-gray-900 rounded-lg px-2", onChange: (event) => {
|
|
180
233
|
const searchTerm = event.target.value;
|
|
181
234
|
if (offlineSearch.length > 0) {
|
|
@@ -228,26 +281,7 @@ export const ZauruTable = (props) => {
|
|
|
228
281
|
};
|
|
229
282
|
const loadSubHeader = !!(search || offlineSearch.length > 0);
|
|
230
283
|
const subHeaderComponent = loadSubHeader ? subHeaderComponentMemo : undefined;
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
return column;
|
|
235
|
-
}
|
|
236
|
-
const next = { wrap: true, ...column };
|
|
237
|
-
// RDT `width` sets both min-width and max-width, wiping a px floor.
|
|
238
|
-
// Keep % as flex-basis so minWidth/maxWidth/grow still apply.
|
|
239
|
-
if (typeof next.width === "string" && next.width.endsWith("%")) {
|
|
240
|
-
const pct = next.width;
|
|
241
|
-
delete next.width;
|
|
242
|
-
next.style = {
|
|
243
|
-
flexBasis: pct,
|
|
244
|
-
...next.style,
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
return next;
|
|
248
|
-
})
|
|
249
|
-
: columns;
|
|
250
|
-
return (_jsx("div", { className: "w-full min-w-0 max-w-full overflow-x-auto", children: _jsx(DataTable, { className: className, subHeaderWrap: true, theme: theme ?? "solarized", columns: normalizedColumns, conditionalRowStyles: conditionalRowStyles, data: filteredData, customStyles: customStyles, progressPending: loading, highlightOnHover: true, pointerOnHover: true, dense: true, striped: true, pagination: !whitOutPagination, persistTableHead: true, responsive: true, noHeader: true, expandableRows: !!expandable, expandOnRowClicked: !!expandable, expandableRowExpanded: expandable ? expandable.expandableRowExpanded : undefined, expandableRowsComponent: expandable ? expandable.expandableRowsComponent : undefined, subHeader: loadSubHeader, subHeaderComponent: subHeaderComponent, paginationServer: !!pagination, paginationTotalRows: pagination?.totalRows ?? undefined, onChangeRowsPerPage: pagination ? handlePerRowsChange : undefined, onChangePage: pagination ? handlePageChange : undefined, paginationComponentOptions: paginationComponentOptions, paginationRowsPerPageOptions: pagination?.rowsPerPageOptions
|
|
251
|
-
? pagination.rowsPerPageOptions
|
|
252
|
-
: [10, 50, 100], ...others }) }));
|
|
284
|
+
return (_jsxs("div", { className: `w-full min-w-0 max-w-full overflow-x-auto ${tableInstanceClass}`, children: [flexBasisCss ? _jsx("style", { children: flexBasisCss }) : null, _jsx(DataTable, { className: className, subHeaderWrap: true, theme: theme ?? "solarized", columns: normalizedColumns, conditionalRowStyles: conditionalRowStyles, data: filteredData, customStyles: customStyles, progressPending: loading, highlightOnHover: true, pointerOnHover: true, dense: true, striped: true, pagination: !whitOutPagination, persistTableHead: true, responsive: true, noHeader: true, expandableRows: !!expandable, expandOnRowClicked: !!expandable, expandableRowExpanded: expandable ? expandable.expandableRowExpanded : undefined, expandableRowsComponent: expandable ? expandable.expandableRowsComponent : undefined, subHeader: loadSubHeader, subHeaderComponent: subHeaderComponent, paginationServer: !!pagination, paginationTotalRows: pagination?.totalRows ?? undefined, onChangeRowsPerPage: pagination ? handlePerRowsChange : undefined, onChangePage: pagination ? handlePageChange : undefined, paginationComponentOptions: paginationComponentOptions, paginationRowsPerPageOptions: pagination?.rowsPerPageOptions
|
|
285
|
+
? pagination.rowsPerPageOptions
|
|
286
|
+
: [10, 50, 100], ...others })] }));
|
|
253
287
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zauru-sdk/components",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.15.0",
|
|
4
4
|
"description": "Componentes reutilizables en las WebApps de Zauru.",
|
|
5
5
|
"main": "./dist/esm/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -45,11 +45,11 @@
|
|
|
45
45
|
"@remix-run/node": "^2.8.1",
|
|
46
46
|
"@remix-run/react": "^2.8.1",
|
|
47
47
|
"@zauru-sdk/common": "^6.12.0",
|
|
48
|
-
"@zauru-sdk/hooks": "^6.
|
|
49
|
-
"@zauru-sdk/icons": "^6.
|
|
50
|
-
"@zauru-sdk/redux": "^6.
|
|
48
|
+
"@zauru-sdk/hooks": "^6.4.0",
|
|
49
|
+
"@zauru-sdk/icons": "^6.2.0",
|
|
50
|
+
"@zauru-sdk/redux": "^6.8.1",
|
|
51
51
|
"@zauru-sdk/types": "^6.28.0",
|
|
52
|
-
"@zauru-sdk/utils": "^6.
|
|
52
|
+
"@zauru-sdk/utils": "^6.27.0",
|
|
53
53
|
"browser-image-compression": "^2.0.2",
|
|
54
54
|
"framer-motion": "^12.0.0",
|
|
55
55
|
"jsonwebtoken": "^9.0.2",
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
"styled-components": "^5.3.5",
|
|
63
63
|
"zod": "^3.23.8"
|
|
64
64
|
},
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "322f29f8eff1085aba8924ca290f3a04aa54d477"
|
|
66
66
|
}
|
|
@@ -31,8 +31,13 @@ type Props = {
|
|
|
31
31
|
footerRow?: FooterColumnConfig[];
|
|
32
32
|
thCSSProperties?: React.CSSProperties;
|
|
33
33
|
thElementsClassName?: string;
|
|
34
|
-
/** Controla si se pueden
|
|
34
|
+
/** Controla si se pueden editar los campos. */
|
|
35
35
|
editable?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Si es false, no muestra agregar/eliminar filas aunque `editable` esté activo.
|
|
38
|
+
* Útil para catálogos fijos cuyos valores sí se editan.
|
|
39
|
+
*/
|
|
40
|
+
rowActions?: boolean;
|
|
36
41
|
/** Opciones de búsqueda. */
|
|
37
42
|
searcheables?: SelectFieldOption[];
|
|
38
43
|
/** Activa o desactiva el “skeleton” de carga. */
|
|
@@ -169,6 +174,7 @@ export const GenericDynamicTable = (props: Props) => {
|
|
|
169
174
|
thElementsClassName = "",
|
|
170
175
|
editable = true,
|
|
171
176
|
readOnly = false, // Nuevo prop
|
|
177
|
+
rowActions = true,
|
|
172
178
|
searcheables = [],
|
|
173
179
|
loading = false,
|
|
174
180
|
paginated = true,
|
|
@@ -188,6 +194,7 @@ export const GenericDynamicTable = (props: Props) => {
|
|
|
188
194
|
* efectivamente editables: solo si `editable` es true y `readOnly` es false.
|
|
189
195
|
*/
|
|
190
196
|
const isEditable = editable && !readOnly;
|
|
197
|
+
const showRowActions = isEditable && rowActions;
|
|
191
198
|
|
|
192
199
|
try {
|
|
193
200
|
const [tableData, setTableData] = useState<RowDataType[]>(defaultValue);
|
|
@@ -276,7 +283,7 @@ export const GenericDynamicTable = (props: Props) => {
|
|
|
276
283
|
{rendereableColumns.map((column, index) => {
|
|
277
284
|
const ancho =
|
|
278
285
|
column.width ??
|
|
279
|
-
(
|
|
286
|
+
(showRowActions ? 94 : 100) / (rendereableColumns.length ?? 1);
|
|
280
287
|
return (
|
|
281
288
|
<th
|
|
282
289
|
key={index}
|
|
@@ -289,7 +296,7 @@ export const GenericDynamicTable = (props: Props) => {
|
|
|
289
296
|
</th>
|
|
290
297
|
);
|
|
291
298
|
})}
|
|
292
|
-
{
|
|
299
|
+
{showRowActions && <th style={{ width: "4%" }}></th>}
|
|
293
300
|
</tr>
|
|
294
301
|
);
|
|
295
302
|
} else {
|
|
@@ -306,14 +313,14 @@ export const GenericDynamicTable = (props: Props) => {
|
|
|
306
313
|
const rowClassName =
|
|
307
314
|
index % 2 === 0 ? `${withoutBg ? "" : "bg-gray-200"}` : "";
|
|
308
315
|
const summaryColSpan =
|
|
309
|
-
rendereableColumns.length + (
|
|
316
|
+
rendereableColumns.length + (showRowActions ? 1 : 0);
|
|
310
317
|
const summaryContent = rowSummary?.(rowData);
|
|
311
318
|
|
|
312
319
|
return (
|
|
313
320
|
<React.Fragment key={rowData.id}>
|
|
314
321
|
<tr className={rowClassName}>
|
|
315
322
|
{rendereableColumns.map((column) => renderCell(rowData, column))}
|
|
316
|
-
{
|
|
323
|
+
{showRowActions && renderDeleteButton(rowData)}
|
|
317
324
|
</tr>
|
|
318
325
|
{summaryContent ? (
|
|
319
326
|
<tr className={rowClassName}>
|
|
@@ -345,7 +352,7 @@ export const GenericDynamicTable = (props: Props) => {
|
|
|
345
352
|
{column.label}
|
|
346
353
|
</th>
|
|
347
354
|
{renderCell(rowData, column)}
|
|
348
|
-
{
|
|
355
|
+
{showRowActions &&
|
|
349
356
|
column === rendereableColumns[rendereableColumns.length - 1] &&
|
|
350
357
|
renderDeleteButton(rowData)}
|
|
351
358
|
</tr>
|
|
@@ -572,7 +579,7 @@ export const GenericDynamicTable = (props: Props) => {
|
|
|
572
579
|
<table className="w-full">
|
|
573
580
|
{orientation === "horizontal" && <thead>{renderHeader()}</thead>}
|
|
574
581
|
<tbody>{renderRows()}</tbody>
|
|
575
|
-
{
|
|
582
|
+
{showRowActions && (
|
|
576
583
|
<tfoot>
|
|
577
584
|
<tr>
|
|
578
585
|
<td
|
|
@@ -633,7 +640,7 @@ export const GenericDynamicTable = (props: Props) => {
|
|
|
633
640
|
</td>
|
|
634
641
|
);
|
|
635
642
|
})}
|
|
636
|
-
{
|
|
643
|
+
{showRowActions && <td></td>}
|
|
637
644
|
</tr>
|
|
638
645
|
</tfoot>
|
|
639
646
|
)}
|
package/src/Table/ZauruTable.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useSearchParams } from "@remix-run/react";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
2
|
+
import { useEffect, useId, useMemo, useState } from "react";
|
|
3
3
|
import type {
|
|
4
4
|
PaginationOptions,
|
|
5
5
|
TableProps,
|
|
@@ -193,6 +193,61 @@ type Props = TableProps<any> & {
|
|
|
193
193
|
className?: string;
|
|
194
194
|
};
|
|
195
195
|
|
|
196
|
+
export const normalizeZauruTableColumns = (columns: any): any => {
|
|
197
|
+
if (!Array.isArray(columns)) {
|
|
198
|
+
return columns;
|
|
199
|
+
}
|
|
200
|
+
return columns.map((column: any, index: number) => {
|
|
201
|
+
if (!column || typeof column !== "object") {
|
|
202
|
+
return column;
|
|
203
|
+
}
|
|
204
|
+
const next = { wrap: true, ...column };
|
|
205
|
+
if (next.id == null) {
|
|
206
|
+
next.id = index + 1;
|
|
207
|
+
}
|
|
208
|
+
// RDT `width` sets both min-width and max-width, wiping a px floor.
|
|
209
|
+
// Keep % as flex-basis so minWidth/maxWidth/grow still apply.
|
|
210
|
+
if (typeof next.width === "string" && next.width.endsWith("%")) {
|
|
211
|
+
const pct = next.width;
|
|
212
|
+
delete next.width;
|
|
213
|
+
next.style = {
|
|
214
|
+
flexBasis: pct,
|
|
215
|
+
...next.style,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return next;
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
export const zauruTableFlexBasisCss = (
|
|
223
|
+
tableClassName: string,
|
|
224
|
+
columns: any
|
|
225
|
+
): string => {
|
|
226
|
+
if (!tableClassName || !Array.isArray(columns)) {
|
|
227
|
+
return "";
|
|
228
|
+
}
|
|
229
|
+
const safeClass = tableClassName.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
230
|
+
if (!safeClass) {
|
|
231
|
+
return "";
|
|
232
|
+
}
|
|
233
|
+
return columns
|
|
234
|
+
.flatMap((column: any) => {
|
|
235
|
+
const basis = column?.style?.flexBasis;
|
|
236
|
+
if (basis == null || column?.id == null) {
|
|
237
|
+
return [];
|
|
238
|
+
}
|
|
239
|
+
const id = String(column.id).replace(/[^a-zA-Z0-9_-]/g, "");
|
|
240
|
+
const safeBasis = String(basis).replace(/[^\d.%]/g, "");
|
|
241
|
+
if (!id || !safeBasis) {
|
|
242
|
+
return [];
|
|
243
|
+
}
|
|
244
|
+
return [
|
|
245
|
+
`.${safeClass} [data-column-id="${id}"] { flex-basis: ${safeBasis} !important; }`,
|
|
246
|
+
];
|
|
247
|
+
})
|
|
248
|
+
.join("\n");
|
|
249
|
+
};
|
|
250
|
+
|
|
196
251
|
//Documentación de la tabla https://react-data-table-component.netlify.app/?path=/docs/getting-started-intro--docs
|
|
197
252
|
export const ZauruTable = (props: Props) => {
|
|
198
253
|
const {
|
|
@@ -227,6 +282,16 @@ export const ZauruTable = (props: Props) => {
|
|
|
227
282
|
setFilteredData(data);
|
|
228
283
|
}, [data]);
|
|
229
284
|
|
|
285
|
+
const tableInstanceClass = `zauru-table-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
286
|
+
const normalizedColumns = useMemo(
|
|
287
|
+
() => normalizeZauruTableColumns(columns),
|
|
288
|
+
[columns]
|
|
289
|
+
);
|
|
290
|
+
const flexBasisCss = useMemo(
|
|
291
|
+
() => zauruTableFlexBasisCss(tableInstanceClass, normalizedColumns),
|
|
292
|
+
[tableInstanceClass, normalizedColumns]
|
|
293
|
+
);
|
|
294
|
+
|
|
230
295
|
const subHeaderComponentMemo = (
|
|
231
296
|
<>
|
|
232
297
|
<input
|
|
@@ -307,28 +372,10 @@ export const ZauruTable = (props: Props) => {
|
|
|
307
372
|
|
|
308
373
|
const loadSubHeader = !!(search || offlineSearch.length > 0);
|
|
309
374
|
const subHeaderComponent = loadSubHeader ? subHeaderComponentMemo : undefined;
|
|
310
|
-
const normalizedColumns = Array.isArray(columns)
|
|
311
|
-
? columns.map((column: any) => {
|
|
312
|
-
if (!column || typeof column !== "object") {
|
|
313
|
-
return column;
|
|
314
|
-
}
|
|
315
|
-
const next = { wrap: true, ...column };
|
|
316
|
-
// RDT `width` sets both min-width and max-width, wiping a px floor.
|
|
317
|
-
// Keep % as flex-basis so minWidth/maxWidth/grow still apply.
|
|
318
|
-
if (typeof next.width === "string" && next.width.endsWith("%")) {
|
|
319
|
-
const pct = next.width;
|
|
320
|
-
delete next.width;
|
|
321
|
-
next.style = {
|
|
322
|
-
flexBasis: pct,
|
|
323
|
-
...next.style,
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
return next;
|
|
327
|
-
})
|
|
328
|
-
: columns;
|
|
329
375
|
|
|
330
376
|
return (
|
|
331
|
-
<div className=
|
|
377
|
+
<div className={`w-full min-w-0 max-w-full overflow-x-auto ${tableInstanceClass}`}>
|
|
378
|
+
{flexBasisCss ? <style>{flexBasisCss}</style> : null}
|
|
332
379
|
<DataTable
|
|
333
380
|
className={className}
|
|
334
381
|
subHeaderWrap
|