@zauru-sdk/components 1.0.53 → 1.0.60

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 (94) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/LICENCE.md +11 -11
  3. package/package.json +7 -7
  4. package/src/Alerts/ErrorBoundaryAlert/ErrorBoundaryAlert.tsx +66 -66
  5. package/src/Alerts/StaticAlert.tsx +121 -121
  6. package/src/Alerts/index.ts +2 -2
  7. package/src/BlockUI/BlockUI.tsx +50 -50
  8. package/src/BlockUI/index.tsx +1 -1
  9. package/src/Buttons/Button.tsx +90 -90
  10. package/src/Buttons/index.ts +1 -1
  11. package/src/Card/Card.tsx +24 -24
  12. package/src/Card/index.ts +1 -1
  13. package/src/Chat/ChatLayout.tsx +131 -131
  14. package/src/Chat/ChatMessageHistory.tsx +142 -142
  15. package/src/Chat/index.ts +2 -2
  16. package/src/ConnectionState/ConnectionState.tsx +27 -27
  17. package/src/ConnectionState/index.tsx +1 -1
  18. package/src/Containers/BodyContainer.tsx +14 -14
  19. package/src/Containers/ButtonSectionContainer.tsx +21 -21
  20. package/src/Containers/Container.tsx +39 -39
  21. package/src/Containers/DoubleContainer.tsx +48 -48
  22. package/src/Containers/MainContainer.tsx +17 -17
  23. package/src/Containers/OutletContainer.tsx +14 -14
  24. package/src/Containers/SubContainer.tsx +37 -37
  25. package/src/Containers/index.ts +7 -7
  26. package/src/DynamicTable/BasicPrintDynamicTable.tsx +73 -73
  27. package/src/DynamicTable/DynamicPrintTable.tsx +288 -288
  28. package/src/DynamicTable/DynamicTable.tsx +405 -405
  29. package/src/DynamicTable/GenericDynamicTable.tsx +456 -456
  30. package/src/DynamicTable/index.tsx +4 -4
  31. package/src/Footer/Footer.tsx +50 -50
  32. package/src/Footer/index.tsx +1 -1
  33. package/src/Form/Checkbox/index.tsx +96 -96
  34. package/src/Form/Checklist/index.tsx +35 -35
  35. package/src/Form/DatePicker/index.tsx +132 -132
  36. package/src/Form/DynamicBaculoForm/index.tsx +361 -361
  37. package/src/Form/FieldContainer/DoubleFieldContainer.tsx +35 -35
  38. package/src/Form/FieldContainer/QuadrupleFieldContainer.tsx +36 -36
  39. package/src/Form/FieldContainer/TripleFieldContainer.tsx +35 -35
  40. package/src/Form/FieldContainer/index.ts +3 -3
  41. package/src/Form/FileUpload/index.tsx +184 -184
  42. package/src/Form/FormButtons/index.tsx +78 -78
  43. package/src/Form/FormLayout/index.tsx +37 -37
  44. package/src/Form/SelectField/index.tsx +237 -237
  45. package/src/Form/TextArea/index.tsx +125 -125
  46. package/src/Form/TextField/index.tsx +194 -194
  47. package/src/Form/TimePicker/index.tsx +127 -127
  48. package/src/Form/YesNo/index.tsx +77 -77
  49. package/src/Form/index.ts +13 -13
  50. package/src/Labels/InfoLabel/index.tsx +21 -21
  51. package/src/Labels/index.tsx +1 -1
  52. package/src/Layouts/homeLayout/index.tsx +34 -34
  53. package/src/Layouts/index.ts +1 -1
  54. package/src/LineSeparator/LineSeparator.tsx +3 -3
  55. package/src/LineSeparator/index.tsx +1 -1
  56. package/src/Modal/Modal.tsx +104 -104
  57. package/src/Modal/index.tsx +1 -1
  58. package/src/NavBar/NavBar.tsx +223 -223
  59. package/src/NavBar/NavBar.types.ts +64 -64
  60. package/src/NavBar/NavBar.utils.ts +58 -58
  61. package/src/NavBar/index.tsx +5 -5
  62. package/src/ProgressBar/ProgressBar.tsx +25 -25
  63. package/src/ProgressBar/ProgressCircle.tsx +75 -75
  64. package/src/ProgressBar/index.tsx +2 -2
  65. package/src/Skeletons/LoadingInputSkeleton.tsx +12 -12
  66. package/src/Skeletons/index.ts +1 -1
  67. package/src/Tab/Tab.tsx +63 -63
  68. package/src/Tab/index.ts +1 -1
  69. package/src/Table/ZauruTable.tsx +265 -265
  70. package/src/Table/index.tsx +1 -1
  71. package/src/TaskList/TaskList.tsx +88 -88
  72. package/src/TaskList/index.ts +1 -1
  73. package/src/Titles/LabelArray.tsx +17 -17
  74. package/src/Titles/TableColumnTitle.tsx +9 -9
  75. package/src/Titles/TitleH1.tsx +10 -10
  76. package/src/Titles/TitleH2.tsx +10 -10
  77. package/src/Titles/TitleH3.tsx +10 -10
  78. package/src/Titles/index.ts +5 -5
  79. package/src/Tooltip/Tooltip.tsx +42 -42
  80. package/src/Tooltip/index.ts +1 -1
  81. package/src/WithTooltip/WithTooltip.tsx +21 -21
  82. package/src/WithTooltip/index.tsx +1 -1
  83. package/src/Wizards/StepWizard.tsx +88 -88
  84. package/src/Wizards/index.ts +1 -1
  85. package/src/Zendesk/Chat.tsx +83 -83
  86. package/src/Zendesk/index.ts +2 -2
  87. package/src/Zendesk/zendesk.config.ts +40 -40
  88. package/src/index.ts +24 -24
  89. package/src/postcss.config.mjs +5 -5
  90. package/src/tailwind.config.ts +10 -10
  91. package/src/tailwind.css +3 -3
  92. package/tsconfig.cjs.json +8 -8
  93. package/tsconfig.esm.json +11 -11
  94. package/tsconfig.json +17 -17
@@ -1,405 +1,405 @@
1
- import React, { useEffect, useState } from "react";
2
- import { TextAreaWithoutValidation } from "../Form/TextArea/index.js";
3
- import { TextFieldWithoutValidation } from "../Form/TextField/index.js";
4
- import { CheckboxWithoutValidation } from "../Form/Checkbox/index.js";
5
-
6
- type Props = {
7
- cellInputs?: boolean;
8
- intersectionTitle?: string;
9
- className?: string;
10
- onChange?: (data: string) => void;
11
- defaultValue?: string;
12
- onValidate?: (headerValue: string, rowValue: string) => boolean;
13
- onRemove?: () => void;
14
- margins?: {
15
- marginLeft?: number;
16
- marginTop?: number;
17
- verticalGap?: number;
18
- horizontalGap?: number;
19
- };
20
- forwardedRef?: React.RefObject<{
21
- getTotalForRows: () => number;
22
- getTotalForColumns: () => number;
23
- getColumnsCount: () => number;
24
- getRowsCount: () => number;
25
- }>;
26
- };
27
-
28
- export const DynamicTable = (
29
- { forwardedRef, ...props }: Props,
30
- ref: React.ForwardedRef<any>
31
- ) => {
32
- const [tableData, setTableData] = useState<Record<string, any>>({});
33
-
34
- const {
35
- cellInputs,
36
- intersectionTitle,
37
- className,
38
- onChange,
39
- defaultValue,
40
- margins,
41
- } = props;
42
-
43
- useEffect(() => {
44
- if (onChange) {
45
- onChange(JSON.stringify(tableData));
46
- }
47
- // eslint-disable-next-line react-hooks/exhaustive-deps
48
- }, [tableData]);
49
-
50
- useEffect(() => {
51
- if (defaultValue) {
52
- initializeTable(defaultValue);
53
- } else {
54
- initializeTableWithDefaults();
55
- }
56
- }, [defaultValue]);
57
-
58
- const getRows = () => {
59
- const rowsIds = Object.keys(tableData)
60
- .filter((key) => key.startsWith("row"))
61
- .map((key) => parseInt(key.slice(3)));
62
- return rowsIds.sort().map((id) => ({ id }));
63
- };
64
-
65
- const getCols = () => {
66
- const colsIds = Object.keys(tableData)
67
- .filter((key) => key.startsWith("column"))
68
- .map((key) => parseInt(key.slice(6)));
69
- return colsIds.sort().map((id) => ({ id }));
70
- };
71
-
72
- const addRow = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
73
- event.stopPropagation();
74
- event.preventDefault();
75
- const rows = getRows();
76
- const lastId = rows[rows.length - 1].id;
77
- handleInputChange(`row${lastId + 1}`, 1);
78
- };
79
-
80
- const addCol = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
81
- event.stopPropagation();
82
- event.preventDefault();
83
- const cols = getCols();
84
- const lastId = cols[cols.length - 1].id;
85
- handleInputChange(`column${lastId + 1}`, 1);
86
- };
87
-
88
- const removeRow = (rowId: number) => {
89
- const newRowData = { ...tableData };
90
- for (const key in newRowData) {
91
- if (key.startsWith(`row${rowId}`) || key.startsWith(`cell-${rowId}-`)) {
92
- delete newRowData[key];
93
- }
94
- }
95
- setTableData(newRowData);
96
- };
97
-
98
- const removeCol = (colId: number) => {
99
- const newRowData = { ...tableData };
100
- for (const key in newRowData) {
101
- if (key.startsWith(`column${colId}`) || key.endsWith(`-${colId}`)) {
102
- delete newRowData[key];
103
- }
104
- }
105
- setTableData(newRowData);
106
- };
107
-
108
- const getTotalForRow = (rowId: number) => {
109
- return Number(tableData[`row${rowId}`] ?? 0) ?? 0;
110
- };
111
-
112
- const getTotalForColumn = (colId: number) => {
113
- return Number(tableData[`column${colId}`] ?? 0) ?? 0;
114
- };
115
-
116
- const getTotalForRows = (): number => {
117
- return getRows()
118
- .map((row) => getTotalForRow(row.id))
119
- .reduce((a, b) => a + b, 0);
120
- };
121
-
122
- const getTotalForColumns = (): number => {
123
- return getCols()
124
- .map((col) => getTotalForColumn(col.id))
125
- .reduce((a, b) => a + b, 0);
126
- };
127
-
128
- const getRowsCount = (): number => {
129
- return getRows().length;
130
- };
131
-
132
- const getColumnsCount = (): number => {
133
- return getCols().length;
134
- };
135
-
136
- const handleInputChange = (name: string, value: any) => {
137
- setTableData((prevData) => ({ ...prevData, [name]: value }));
138
- };
139
-
140
- const handleValidation = (
141
- cellId: string,
142
- colId: number,
143
- rowId: number
144
- ): { stopUIChange: boolean } | void => {
145
- const headerValue = tableData[`column${colId}`];
146
- const rowValue = tableData[`row${rowId}`];
147
-
148
- if (props.onValidate && props.onValidate(headerValue, rowValue)) {
149
- return handleInputChange(cellId, true);
150
- }
151
- return { stopUIChange: true };
152
- };
153
-
154
- const handleRemoveValidation = (cellId: string) => {
155
- handleInputChange(cellId, false);
156
- };
157
-
158
- const initializeTableWithDefaults = () => {
159
- const initialData = { row0: 1, column0: 1 };
160
- setTableData(initialData);
161
- };
162
-
163
- const initializeTable = (tableJson: string) => {
164
- try {
165
- const initialData = JSON.parse(tableJson);
166
- setTableData(initialData);
167
- } catch (error) {
168
- console.error("Error al inicializar la tabla:", error);
169
- }
170
- };
171
-
172
- const cellBordered = {
173
- border: "1px solid #ccc",
174
- } as React.CSSProperties;
175
-
176
- const pastelGrayBackground = {
177
- backgroundColor: "#B69E99",
178
- } as React.CSSProperties;
179
-
180
- const cellCenteredContent = {
181
- textAlign: "center",
182
- verticalAlign: "middle",
183
- } as React.CSSProperties;
184
-
185
- const renderTotalHeight = () => {
186
- const sumaFilas = getRows()
187
- .map((row) => getTotalForRow(row.id))
188
- .reduce((a, b) => a + b, 0);
189
-
190
- const sumTotalFilas =
191
- sumaFilas +
192
- (margins?.marginTop ?? 0) +
193
- (getRows().length - 1) * (margins?.verticalGap ?? 0);
194
-
195
- return (
196
- <div className="ml-4 inline-block">
197
- <strong>Total alto: {sumTotalFilas} </strong>
198
- {margins && (
199
- <>
200
- (Celdas: {sumaFilas} + Márgen superior: {margins?.marginTop ?? 0} +{" "}
201
- {getRows().length - 1} Brechas verticales:{" "}
202
- {Math.round((getRows().length - 1) * (margins?.verticalGap ?? 0))})
203
- </>
204
- )}
205
- </div>
206
- );
207
- };
208
-
209
- const renderTotalWidth = () => {
210
- const cols = getCols();
211
- const sumaColumnas = cols
212
- .map((col) => getTotalForColumn(col.id))
213
- .reduce((a, b) => a + b, 0);
214
- const sumaTotal =
215
- sumaColumnas +
216
- (margins?.marginLeft ?? 0) +
217
- (getCols().length - 1) * (margins?.horizontalGap ?? 0);
218
- return (
219
- <div className="ml-4 inline-block">
220
- <strong>Total ancho: {sumaTotal} </strong>
221
- {margins && (
222
- <>
223
- (Celdas: {sumaColumnas} + Márgen izquierdo:{" "}
224
- {margins?.marginLeft ?? 0} + {getCols().length - 1} Brechas
225
- horizontales:{" "}
226
- {Math.round((getCols().length - 1) * (margins?.horizontalGap ?? 0))}
227
- )
228
- </>
229
- )}
230
- </div>
231
- );
232
- };
233
-
234
- const renderHeader = () => {
235
- const cols = getCols();
236
- return (
237
- <tr>
238
- <th
239
- className="align-middle py-2 text-center"
240
- style={{
241
- ...cellBordered,
242
- ...pastelGrayBackground,
243
- }}
244
- >
245
- {intersectionTitle ?? ""}
246
- </th>
247
- {cols.map((col) => (
248
- <th
249
- key={col.id}
250
- className="align-middle py-2 text-center"
251
- style={{ ...cellBordered, ...pastelGrayBackground }}
252
- >
253
- <div className="inline-flex">
254
- <TextFieldWithoutValidation
255
- style={{ maxWidth: "45%", minWidth: "45%" }}
256
- name={`column${col.id}`}
257
- defaultValue={tableData[`column${col.id}`] || 1}
258
- type="number"
259
- onChange={(value) =>
260
- handleInputChange(`column${col.id}`, value)
261
- }
262
- />
263
- {col.id > 0 && (
264
- <button
265
- className="bg-red-500 hover:bg-red-600 font-bold py-1 px-2 rounded ml-2"
266
- onClick={() => removeCol(col.id)}
267
- >
268
- x
269
- </button>
270
- )}
271
- </div>
272
- </th>
273
- ))}
274
- <th>
275
- <button
276
- className="bg-blue-500 hover:bg-blue-600 font-bold py-2 px-4 rounded"
277
- onClick={addCol}
278
- >
279
- +
280
- </button>
281
- </th>
282
- </tr>
283
- );
284
- };
285
-
286
- const renderRow = (rowId: number) => {
287
- const cols = getCols();
288
- return (
289
- <tr key={rowId}>
290
- <td
291
- className="align-middle"
292
- style={{
293
- ...cellBordered,
294
- ...pastelGrayBackground,
295
- textOverflow: "ellipsis",
296
- msTextOverflow: "ellipsis",
297
- maxWidth: "200px",
298
- }}
299
- >
300
- <div className="inline-flex">
301
- <TextFieldWithoutValidation
302
- style={{ maxWidth: "45%", minWidth: "45%" }}
303
- name={`row${rowId}`}
304
- defaultValue={tableData[`row${rowId}`] || 1}
305
- type="number"
306
- onChange={(value) => handleInputChange(`row${rowId}`, value)}
307
- />
308
- {rowId > 0 && (
309
- <button
310
- className="bg-red-500 hover:bg-red-600 font-bold py-1 px-2 rounded ml-2"
311
- onClick={() => {
312
- removeRow(rowId);
313
- }}
314
- >
315
- x
316
- </button>
317
- )}
318
- </div>
319
- </td>
320
- {cols.map((col) => {
321
- const cellId = `cell-${rowId}-${col.id}`;
322
- const cellValidation = tableData[cellId] === true;
323
- if (!cellInputs) tableData[cellId] = cellValidation;
324
-
325
- return (
326
- <td
327
- key={col.id}
328
- id={cellId}
329
- style={{ ...cellBordered, ...cellCenteredContent }}
330
- >
331
- {cellInputs ? (
332
- <TextAreaWithoutValidation
333
- name={cellId}
334
- defaultValue={tableData[cellId] || ""}
335
- onChange={(value) => handleInputChange(cellId, value)}
336
- />
337
- ) : (
338
- <CheckboxWithoutValidation
339
- name={cellId}
340
- defaultValue={cellValidation}
341
- onChange={(value) => {
342
- if (value) {
343
- return handleValidation(cellId, col.id, rowId);
344
- } else {
345
- handleRemoveValidation(cellId);
346
- }
347
- }}
348
- />
349
- )}
350
- </td>
351
- );
352
- })}
353
- {rowId === 0 && (
354
- <td rowSpan={getRows().length} style={{ maxWidth: "100px" }}>
355
- {renderTotalHeight()}
356
- </td>
357
- )}
358
- </tr>
359
- );
360
- };
361
-
362
- const renderRows = () => {
363
- const rows = getRows();
364
- return rows.map((row) => renderRow(row.id));
365
- };
366
-
367
- // Use el "useImperativeHandle" para que el componente padre pueda acceder a los métodos deseados
368
- React.useImperativeHandle(forwardedRef, () => ({
369
- getTotalForRows,
370
- getTotalForColumns,
371
- getColumnsCount,
372
- getRowsCount,
373
- }));
374
-
375
- return (
376
- <div className={`${className}`}>
377
- <table className="border-collapse">
378
- <thead>{renderHeader()}</thead>
379
- <tbody>{renderRows()}</tbody>
380
- <tfoot>
381
- <tr>
382
- <td>
383
- <button
384
- className="bg-blue-500 hover:bg-blue-600 font-bold py-2 px-4 rounded"
385
- onClick={addRow}
386
- >
387
- +
388
- </button>
389
- </td>
390
- <td
391
- colSpan={getCols().length + 1}
392
- className="text-left align-middle"
393
- style={{
394
- textOverflow: "ellipsis",
395
- msTextOverflow: "ellipsis",
396
- }}
397
- >
398
- {renderTotalWidth()}
399
- </td>
400
- </tr>
401
- </tfoot>
402
- </table>
403
- </div>
404
- );
405
- };
1
+ import React, { useEffect, useState } from "react";
2
+ import { TextAreaWithoutValidation } from "../Form/TextArea/index.js";
3
+ import { TextFieldWithoutValidation } from "../Form/TextField/index.js";
4
+ import { CheckboxWithoutValidation } from "../Form/Checkbox/index.js";
5
+
6
+ type Props = {
7
+ cellInputs?: boolean;
8
+ intersectionTitle?: string;
9
+ className?: string;
10
+ onChange?: (data: string) => void;
11
+ defaultValue?: string;
12
+ onValidate?: (headerValue: string, rowValue: string) => boolean;
13
+ onRemove?: () => void;
14
+ margins?: {
15
+ marginLeft?: number;
16
+ marginTop?: number;
17
+ verticalGap?: number;
18
+ horizontalGap?: number;
19
+ };
20
+ forwardedRef?: React.RefObject<{
21
+ getTotalForRows: () => number;
22
+ getTotalForColumns: () => number;
23
+ getColumnsCount: () => number;
24
+ getRowsCount: () => number;
25
+ }>;
26
+ };
27
+
28
+ export const DynamicTable = (
29
+ { forwardedRef, ...props }: Props,
30
+ ref: React.ForwardedRef<any>
31
+ ) => {
32
+ const [tableData, setTableData] = useState<Record<string, any>>({});
33
+
34
+ const {
35
+ cellInputs,
36
+ intersectionTitle,
37
+ className,
38
+ onChange,
39
+ defaultValue,
40
+ margins,
41
+ } = props;
42
+
43
+ useEffect(() => {
44
+ if (onChange) {
45
+ onChange(JSON.stringify(tableData));
46
+ }
47
+ // eslint-disable-next-line react-hooks/exhaustive-deps
48
+ }, [tableData]);
49
+
50
+ useEffect(() => {
51
+ if (defaultValue) {
52
+ initializeTable(defaultValue);
53
+ } else {
54
+ initializeTableWithDefaults();
55
+ }
56
+ }, [defaultValue]);
57
+
58
+ const getRows = () => {
59
+ const rowsIds = Object.keys(tableData)
60
+ .filter((key) => key.startsWith("row"))
61
+ .map((key) => parseInt(key.slice(3)));
62
+ return rowsIds.sort().map((id) => ({ id }));
63
+ };
64
+
65
+ const getCols = () => {
66
+ const colsIds = Object.keys(tableData)
67
+ .filter((key) => key.startsWith("column"))
68
+ .map((key) => parseInt(key.slice(6)));
69
+ return colsIds.sort().map((id) => ({ id }));
70
+ };
71
+
72
+ const addRow = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
73
+ event.stopPropagation();
74
+ event.preventDefault();
75
+ const rows = getRows();
76
+ const lastId = rows[rows.length - 1].id;
77
+ handleInputChange(`row${lastId + 1}`, 1);
78
+ };
79
+
80
+ const addCol = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
81
+ event.stopPropagation();
82
+ event.preventDefault();
83
+ const cols = getCols();
84
+ const lastId = cols[cols.length - 1].id;
85
+ handleInputChange(`column${lastId + 1}`, 1);
86
+ };
87
+
88
+ const removeRow = (rowId: number) => {
89
+ const newRowData = { ...tableData };
90
+ for (const key in newRowData) {
91
+ if (key.startsWith(`row${rowId}`) || key.startsWith(`cell-${rowId}-`)) {
92
+ delete newRowData[key];
93
+ }
94
+ }
95
+ setTableData(newRowData);
96
+ };
97
+
98
+ const removeCol = (colId: number) => {
99
+ const newRowData = { ...tableData };
100
+ for (const key in newRowData) {
101
+ if (key.startsWith(`column${colId}`) || key.endsWith(`-${colId}`)) {
102
+ delete newRowData[key];
103
+ }
104
+ }
105
+ setTableData(newRowData);
106
+ };
107
+
108
+ const getTotalForRow = (rowId: number) => {
109
+ return Number(tableData[`row${rowId}`] ?? 0) ?? 0;
110
+ };
111
+
112
+ const getTotalForColumn = (colId: number) => {
113
+ return Number(tableData[`column${colId}`] ?? 0) ?? 0;
114
+ };
115
+
116
+ const getTotalForRows = (): number => {
117
+ return getRows()
118
+ .map((row) => getTotalForRow(row.id))
119
+ .reduce((a, b) => a + b, 0);
120
+ };
121
+
122
+ const getTotalForColumns = (): number => {
123
+ return getCols()
124
+ .map((col) => getTotalForColumn(col.id))
125
+ .reduce((a, b) => a + b, 0);
126
+ };
127
+
128
+ const getRowsCount = (): number => {
129
+ return getRows().length;
130
+ };
131
+
132
+ const getColumnsCount = (): number => {
133
+ return getCols().length;
134
+ };
135
+
136
+ const handleInputChange = (name: string, value: any) => {
137
+ setTableData((prevData) => ({ ...prevData, [name]: value }));
138
+ };
139
+
140
+ const handleValidation = (
141
+ cellId: string,
142
+ colId: number,
143
+ rowId: number
144
+ ): { stopUIChange: boolean } | void => {
145
+ const headerValue = tableData[`column${colId}`];
146
+ const rowValue = tableData[`row${rowId}`];
147
+
148
+ if (props.onValidate && props.onValidate(headerValue, rowValue)) {
149
+ return handleInputChange(cellId, true);
150
+ }
151
+ return { stopUIChange: true };
152
+ };
153
+
154
+ const handleRemoveValidation = (cellId: string) => {
155
+ handleInputChange(cellId, false);
156
+ };
157
+
158
+ const initializeTableWithDefaults = () => {
159
+ const initialData = { row0: 1, column0: 1 };
160
+ setTableData(initialData);
161
+ };
162
+
163
+ const initializeTable = (tableJson: string) => {
164
+ try {
165
+ const initialData = JSON.parse(tableJson);
166
+ setTableData(initialData);
167
+ } catch (error) {
168
+ console.error("Error al inicializar la tabla:", error);
169
+ }
170
+ };
171
+
172
+ const cellBordered = {
173
+ border: "1px solid #ccc",
174
+ } as React.CSSProperties;
175
+
176
+ const pastelGrayBackground = {
177
+ backgroundColor: "#B69E99",
178
+ } as React.CSSProperties;
179
+
180
+ const cellCenteredContent = {
181
+ textAlign: "center",
182
+ verticalAlign: "middle",
183
+ } as React.CSSProperties;
184
+
185
+ const renderTotalHeight = () => {
186
+ const sumaFilas = getRows()
187
+ .map((row) => getTotalForRow(row.id))
188
+ .reduce((a, b) => a + b, 0);
189
+
190
+ const sumTotalFilas =
191
+ sumaFilas +
192
+ (margins?.marginTop ?? 0) +
193
+ (getRows().length - 1) * (margins?.verticalGap ?? 0);
194
+
195
+ return (
196
+ <div className="ml-4 inline-block">
197
+ <strong>Total alto: {sumTotalFilas} </strong>
198
+ {margins && (
199
+ <>
200
+ (Celdas: {sumaFilas} + Márgen superior: {margins?.marginTop ?? 0} +{" "}
201
+ {getRows().length - 1} Brechas verticales:{" "}
202
+ {Math.round((getRows().length - 1) * (margins?.verticalGap ?? 0))})
203
+ </>
204
+ )}
205
+ </div>
206
+ );
207
+ };
208
+
209
+ const renderTotalWidth = () => {
210
+ const cols = getCols();
211
+ const sumaColumnas = cols
212
+ .map((col) => getTotalForColumn(col.id))
213
+ .reduce((a, b) => a + b, 0);
214
+ const sumaTotal =
215
+ sumaColumnas +
216
+ (margins?.marginLeft ?? 0) +
217
+ (getCols().length - 1) * (margins?.horizontalGap ?? 0);
218
+ return (
219
+ <div className="ml-4 inline-block">
220
+ <strong>Total ancho: {sumaTotal} </strong>
221
+ {margins && (
222
+ <>
223
+ (Celdas: {sumaColumnas} + Márgen izquierdo:{" "}
224
+ {margins?.marginLeft ?? 0} + {getCols().length - 1} Brechas
225
+ horizontales:{" "}
226
+ {Math.round((getCols().length - 1) * (margins?.horizontalGap ?? 0))}
227
+ )
228
+ </>
229
+ )}
230
+ </div>
231
+ );
232
+ };
233
+
234
+ const renderHeader = () => {
235
+ const cols = getCols();
236
+ return (
237
+ <tr>
238
+ <th
239
+ className="align-middle py-2 text-center"
240
+ style={{
241
+ ...cellBordered,
242
+ ...pastelGrayBackground,
243
+ }}
244
+ >
245
+ {intersectionTitle ?? ""}
246
+ </th>
247
+ {cols.map((col) => (
248
+ <th
249
+ key={col.id}
250
+ className="align-middle py-2 text-center"
251
+ style={{ ...cellBordered, ...pastelGrayBackground }}
252
+ >
253
+ <div className="inline-flex">
254
+ <TextFieldWithoutValidation
255
+ style={{ maxWidth: "45%", minWidth: "45%" }}
256
+ name={`column${col.id}`}
257
+ defaultValue={tableData[`column${col.id}`] || 1}
258
+ type="number"
259
+ onChange={(value) =>
260
+ handleInputChange(`column${col.id}`, value)
261
+ }
262
+ />
263
+ {col.id > 0 && (
264
+ <button
265
+ className="bg-red-500 hover:bg-red-600 font-bold py-1 px-2 rounded ml-2"
266
+ onClick={() => removeCol(col.id)}
267
+ >
268
+ x
269
+ </button>
270
+ )}
271
+ </div>
272
+ </th>
273
+ ))}
274
+ <th>
275
+ <button
276
+ className="bg-blue-500 hover:bg-blue-600 font-bold py-2 px-4 rounded"
277
+ onClick={addCol}
278
+ >
279
+ +
280
+ </button>
281
+ </th>
282
+ </tr>
283
+ );
284
+ };
285
+
286
+ const renderRow = (rowId: number) => {
287
+ const cols = getCols();
288
+ return (
289
+ <tr key={rowId}>
290
+ <td
291
+ className="align-middle"
292
+ style={{
293
+ ...cellBordered,
294
+ ...pastelGrayBackground,
295
+ textOverflow: "ellipsis",
296
+ msTextOverflow: "ellipsis",
297
+ maxWidth: "200px",
298
+ }}
299
+ >
300
+ <div className="inline-flex">
301
+ <TextFieldWithoutValidation
302
+ style={{ maxWidth: "45%", minWidth: "45%" }}
303
+ name={`row${rowId}`}
304
+ defaultValue={tableData[`row${rowId}`] || 1}
305
+ type="number"
306
+ onChange={(value) => handleInputChange(`row${rowId}`, value)}
307
+ />
308
+ {rowId > 0 && (
309
+ <button
310
+ className="bg-red-500 hover:bg-red-600 font-bold py-1 px-2 rounded ml-2"
311
+ onClick={() => {
312
+ removeRow(rowId);
313
+ }}
314
+ >
315
+ x
316
+ </button>
317
+ )}
318
+ </div>
319
+ </td>
320
+ {cols.map((col) => {
321
+ const cellId = `cell-${rowId}-${col.id}`;
322
+ const cellValidation = tableData[cellId] === true;
323
+ if (!cellInputs) tableData[cellId] = cellValidation;
324
+
325
+ return (
326
+ <td
327
+ key={col.id}
328
+ id={cellId}
329
+ style={{ ...cellBordered, ...cellCenteredContent }}
330
+ >
331
+ {cellInputs ? (
332
+ <TextAreaWithoutValidation
333
+ name={cellId}
334
+ defaultValue={tableData[cellId] || ""}
335
+ onChange={(value) => handleInputChange(cellId, value)}
336
+ />
337
+ ) : (
338
+ <CheckboxWithoutValidation
339
+ name={cellId}
340
+ defaultValue={cellValidation}
341
+ onChange={(value) => {
342
+ if (value) {
343
+ return handleValidation(cellId, col.id, rowId);
344
+ } else {
345
+ handleRemoveValidation(cellId);
346
+ }
347
+ }}
348
+ />
349
+ )}
350
+ </td>
351
+ );
352
+ })}
353
+ {rowId === 0 && (
354
+ <td rowSpan={getRows().length} style={{ maxWidth: "100px" }}>
355
+ {renderTotalHeight()}
356
+ </td>
357
+ )}
358
+ </tr>
359
+ );
360
+ };
361
+
362
+ const renderRows = () => {
363
+ const rows = getRows();
364
+ return rows.map((row) => renderRow(row.id));
365
+ };
366
+
367
+ // Use el "useImperativeHandle" para que el componente padre pueda acceder a los métodos deseados
368
+ React.useImperativeHandle(forwardedRef, () => ({
369
+ getTotalForRows,
370
+ getTotalForColumns,
371
+ getColumnsCount,
372
+ getRowsCount,
373
+ }));
374
+
375
+ return (
376
+ <div className={`${className}`}>
377
+ <table className="border-collapse">
378
+ <thead>{renderHeader()}</thead>
379
+ <tbody>{renderRows()}</tbody>
380
+ <tfoot>
381
+ <tr>
382
+ <td>
383
+ <button
384
+ className="bg-blue-500 hover:bg-blue-600 font-bold py-2 px-4 rounded"
385
+ onClick={addRow}
386
+ >
387
+ +
388
+ </button>
389
+ </td>
390
+ <td
391
+ colSpan={getCols().length + 1}
392
+ className="text-left align-middle"
393
+ style={{
394
+ textOverflow: "ellipsis",
395
+ msTextOverflow: "ellipsis",
396
+ }}
397
+ >
398
+ {renderTotalWidth()}
399
+ </td>
400
+ </tr>
401
+ </tfoot>
402
+ </table>
403
+ </div>
404
+ );
405
+ };