@archbase/components 4.0.19 → 4.0.20

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 (55) hide show
  1. package/dist/archbase-components-4.0.20.tgz +0 -0
  2. package/dist/datagrid/ag-grid/ag-grid-locale-ptbr.d.ts +7 -0
  3. package/dist/datagrid/ag-grid/ag-grid-mantine-theme.d.ts +24 -0
  4. package/dist/datagrid/ag-grid/archbase-data-grid-ag-formatters.d.ts +88 -0
  5. package/dist/datagrid/ag-grid/archbase-data-grid-ag-types.d.ts +329 -0
  6. package/dist/datagrid/ag-grid/archbase-data-grid-ag-utils.d.ts +71 -0
  7. package/dist/datagrid/ag-grid/archbase-data-grid-ag.d.ts +14 -0
  8. package/dist/datagrid/ag-grid/index.d.ts +14 -0
  9. package/dist/datagrid/index.d.ts +9 -1
  10. package/dist/index.js +11175 -10592
  11. package/package.json +6 -4
  12. package/src/datagrid/ag-grid/ag-grid-locale-ptbr.ts +432 -0
  13. package/src/datagrid/ag-grid/ag-grid-mantine-theme.ts +176 -0
  14. package/src/datagrid/ag-grid/archbase-data-grid-ag-formatters.tsx +470 -0
  15. package/src/datagrid/ag-grid/archbase-data-grid-ag-types.tsx +413 -0
  16. package/src/datagrid/ag-grid/archbase-data-grid-ag-utils.ts +394 -0
  17. package/src/datagrid/ag-grid/archbase-data-grid-ag.tsx +1241 -0
  18. package/src/datagrid/ag-grid/index.tsx +84 -0
  19. package/src/datagrid/index.tsx +59 -8
  20. package/src/datagrid/main/archbase-data-grid-pagination.tsx +1 -2
  21. package/src/datagrid/main/archbase-data-grid-toolbar.tsx +1 -2
  22. package/src/editors/ArchbaseAsyncMultiSelect.tsx +2 -1
  23. package/src/editors/ArchbaseAsyncSelect.tsx +2 -1
  24. package/src/editors/ArchbaseAvatarEdit.tsx +1 -0
  25. package/src/editors/ArchbaseCheckbox.tsx +1 -0
  26. package/src/editors/ArchbaseChip.tsx +1 -0
  27. package/src/editors/ArchbaseChipGroup.tsx +1 -0
  28. package/src/editors/ArchbaseColorGradientPicker.tsx +2 -1
  29. package/src/editors/ArchbaseDatePickerEdit.tsx +1 -0
  30. package/src/editors/ArchbaseDateTimePickerEdit.tsx +1 -0
  31. package/src/editors/ArchbaseDualListbox.tsx +1 -0
  32. package/src/editors/ArchbaseEdit.tsx +1 -0
  33. package/src/editors/ArchbaseImageEdit.tsx +1 -0
  34. package/src/editors/ArchbaseJsonEdit.tsx +1 -0
  35. package/src/editors/ArchbaseLookupEdit.tsx +2 -1
  36. package/src/editors/ArchbaseLookupNumber.tsx +2 -1
  37. package/src/editors/ArchbaseLookupSelect.tsx +2 -1
  38. package/src/editors/ArchbaseMarkdownEdit.tsx +1 -0
  39. package/src/editors/ArchbaseMaskEdit.tsx +1 -0
  40. package/src/editors/ArchbaseMentionInput.tsx +1 -0
  41. package/src/editors/ArchbaseMultiEmail.tsx +1 -0
  42. package/src/editors/ArchbaseMultiSelect.tsx +2 -1
  43. package/src/editors/ArchbaseNumberEdit.tsx +1 -0
  44. package/src/editors/ArchbaseNumberStepper.tsx +2 -1
  45. package/src/editors/ArchbasePasswordEdit.tsx +1 -0
  46. package/src/editors/ArchbaseRadioGroup.tsx +1 -0
  47. package/src/editors/ArchbaseRating.tsx +1 -0
  48. package/src/editors/ArchbaseRichTextEdit.tsx +1 -0
  49. package/src/editors/ArchbaseSelect.tsx +2 -1
  50. package/src/editors/ArchbaseSignaturePad.tsx +1 -0
  51. package/src/editors/ArchbaseSwitch.tsx +1 -0
  52. package/src/editors/ArchbaseTagInputEdit.tsx +1 -0
  53. package/src/editors/ArchbaseTextArea.tsx +1 -0
  54. package/src/editors/ArchbaseTimeEdit.tsx +1 -0
  55. package/dist/archbase-components-4.0.19.tgz +0 -0
@@ -0,0 +1,470 @@
1
+ /**
2
+ * ArchbaseDataGridAG Cell Renderers
3
+ *
4
+ * AG Grid cell renderer components for various data types.
5
+ */
6
+ import React, { ReactNode } from 'react';
7
+ import { format } from 'date-fns';
8
+ import { Checkbox } from '@mantine/core';
9
+ import { ArchbaseMasker, MaskOptions, convertISOStringToDate } from '@archbase/core';
10
+ import type { ICellRendererParams } from 'ag-grid-community';
11
+ import type { FieldDataType } from './archbase-data-grid-ag-types';
12
+
13
+ /**
14
+ * Check if string is valid base64
15
+ */
16
+ const isBase64 = (str: string): boolean => {
17
+ if (!str || typeof str !== 'string' || str.length < 4) {
18
+ return false;
19
+ }
20
+
21
+ const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
22
+ if (!base64Regex.test(str)) {
23
+ return false;
24
+ }
25
+
26
+ try {
27
+ const decoded = atob(str);
28
+ const printableRatio =
29
+ decoded.split('').filter((c) => {
30
+ const code = c.charCodeAt(0);
31
+ return (code >= 32 && code <= 126) || code === 10 || code === 13 || code === 9;
32
+ }).length / decoded.length;
33
+
34
+ return printableRatio > 0.9;
35
+ } catch {
36
+ return false;
37
+ }
38
+ };
39
+
40
+ /**
41
+ * Decode base64 to UTF-8 text
42
+ */
43
+ const decodeBase64 = (str: string): string => {
44
+ try {
45
+ const binaryString = atob(str);
46
+ const bytes = new Uint8Array(binaryString.length);
47
+ for (let i = 0; i < binaryString.length; i++) {
48
+ bytes[i] = binaryString.charCodeAt(i);
49
+ }
50
+ return new TextDecoder('utf-8').decode(bytes);
51
+ } catch {
52
+ return str;
53
+ }
54
+ };
55
+
56
+ /**
57
+ * Text cell renderer with optional mask and auto base64 decoding
58
+ */
59
+ export const TextCellRenderer = (
60
+ params: ICellRendererParams,
61
+ maskOptions?: MaskOptions
62
+ ): ReactNode => {
63
+ const value = params.value;
64
+ if (value === null || value === undefined) {
65
+ return <span></span>;
66
+ }
67
+
68
+ let displayValue = String(value);
69
+
70
+ if (isBase64(displayValue)) {
71
+ displayValue = decodeBase64(displayValue);
72
+ }
73
+
74
+ if (maskOptions) {
75
+ displayValue = ArchbaseMasker.toPattern(displayValue, maskOptions);
76
+ }
77
+
78
+ return <span>{displayValue}</span>;
79
+ };
80
+
81
+ /**
82
+ * Integer cell renderer
83
+ */
84
+ export const IntegerCellRenderer = (params: ICellRendererParams): ReactNode => {
85
+ const value = params.value;
86
+ if (value === null || value === undefined) {
87
+ return <span></span>;
88
+ }
89
+
90
+ const numValue = Number.isNaN(Number(value)) ? 0 : Number(value);
91
+
92
+ return <span style={{ textAlign: 'right', display: 'block' }}>{numValue}</span>;
93
+ };
94
+
95
+ /**
96
+ * Float cell renderer
97
+ */
98
+ export const FloatCellRenderer = (params: ICellRendererParams): ReactNode => {
99
+ const value = params.value;
100
+ if (value === null || value === undefined) {
101
+ return <span></span>;
102
+ }
103
+
104
+ const numValue = Number.isNaN(Number(value)) ? 0 : Number(value);
105
+
106
+ return <span style={{ textAlign: 'right', display: 'block' }}>{numValue}</span>;
107
+ };
108
+
109
+ /**
110
+ * Currency cell renderer (BRL format)
111
+ */
112
+ export const CurrencyCellRenderer = (params: ICellRendererParams): ReactNode => {
113
+ const value = params.value;
114
+ if (value === null || value === undefined) {
115
+ return <span></span>;
116
+ }
117
+
118
+ const numValue = Number.isNaN(Number(value)) ? 0 : Number(value);
119
+
120
+ try {
121
+ const formatted = new Intl.NumberFormat('pt-BR', {
122
+ style: 'currency',
123
+ currency: 'BRL',
124
+ }).format(numValue);
125
+
126
+ return <span style={{ textAlign: 'right', display: 'block' }}>{formatted}</span>;
127
+ } catch (e) {
128
+ console.error('Error formatting currency:', e);
129
+ return <span style={{ textAlign: 'right', display: 'block' }}>{numValue}</span>;
130
+ }
131
+ };
132
+
133
+ /**
134
+ * Percent cell renderer
135
+ */
136
+ export const PercentCellRenderer = (
137
+ params: ICellRendererParams,
138
+ decimalPlaces: number = 2
139
+ ): ReactNode => {
140
+ const value = params.value;
141
+ if (value === null || value === undefined) {
142
+ return <span></span>;
143
+ }
144
+
145
+ const numValue = Number.isNaN(Number(value)) ? 0 : Number(value);
146
+
147
+ try {
148
+ const formatted = new Intl.NumberFormat('pt-BR', {
149
+ style: 'percent',
150
+ minimumFractionDigits: decimalPlaces,
151
+ maximumFractionDigits: decimalPlaces,
152
+ }).format(numValue / 100);
153
+
154
+ return <span style={{ textAlign: 'right', display: 'block' }}>{formatted}</span>;
155
+ } catch (e) {
156
+ console.error('Error formatting percent:', e);
157
+ return <span style={{ textAlign: 'right', display: 'block' }}>{numValue}%</span>;
158
+ }
159
+ };
160
+
161
+ /**
162
+ * Boolean cell renderer with Mantine checkbox
163
+ */
164
+ export const BooleanCellRenderer = (params: ICellRendererParams): ReactNode => {
165
+ const value = params.value;
166
+ const checked = Boolean(value);
167
+
168
+ return (
169
+ <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
170
+ <Checkbox readOnly checked={checked} />
171
+ </div>
172
+ );
173
+ };
174
+
175
+ /**
176
+ * Date cell renderer
177
+ */
178
+ export const DateCellRenderer = (
179
+ params: ICellRendererParams,
180
+ dateFormat: string = 'dd/MM/yyyy'
181
+ ): ReactNode => {
182
+ const value = params.value;
183
+ if (!value) {
184
+ return <span></span>;
185
+ }
186
+
187
+ try {
188
+ const date = convertISOStringToDate(value);
189
+ const formatted = format(date, dateFormat);
190
+
191
+ return <span style={{ textAlign: 'center', display: 'block' }}>{formatted}</span>;
192
+ } catch (error) {
193
+ console.error('Error formatting date:', error);
194
+ return <span>Data inválida</span>;
195
+ }
196
+ };
197
+
198
+ /**
199
+ * DateTime cell renderer
200
+ */
201
+ export const DateTimeCellRenderer = (
202
+ params: ICellRendererParams,
203
+ dateTimeFormat: string = 'dd/MM/yyyy HH:mm:ss'
204
+ ): ReactNode => {
205
+ const value = params.value;
206
+ if (!value) {
207
+ return <span></span>;
208
+ }
209
+
210
+ try {
211
+ const date = convertISOStringToDate(value);
212
+ const formatted = format(date, dateTimeFormat);
213
+
214
+ return <span style={{ textAlign: 'center', display: 'block' }}>{formatted}</span>;
215
+ } catch (error) {
216
+ console.error('Error formatting datetime:', error);
217
+ return <span>Data/hora inválida</span>;
218
+ }
219
+ };
220
+
221
+ /**
222
+ * Time cell renderer
223
+ */
224
+ export const TimeCellRenderer = (
225
+ params: ICellRendererParams,
226
+ timeFormat: string = 'HH:mm:ss'
227
+ ): ReactNode => {
228
+ const value = params.value;
229
+ if (!value) {
230
+ return <span></span>;
231
+ }
232
+
233
+ try {
234
+ if (typeof value === 'string') {
235
+ if (/^\d{2}:\d{2}(:\d{2})?$/.test(value)) {
236
+ return <span style={{ textAlign: 'center', display: 'block' }}>{value}</span>;
237
+ }
238
+
239
+ const date = new Date(value);
240
+ return <span style={{ textAlign: 'center', display: 'block' }}>{format(date, timeFormat)}</span>;
241
+ }
242
+
243
+ if (value instanceof Date) {
244
+ return <span style={{ textAlign: 'center', display: 'block' }}>{format(value, timeFormat)}</span>;
245
+ }
246
+
247
+ if (typeof value === 'number') {
248
+ const hours = Math.floor(value / 3600000);
249
+ const minutes = Math.floor((value % 3600000) / 60000);
250
+ const seconds = Math.floor((value % 60000) / 1000);
251
+
252
+ return (
253
+ <span style={{ textAlign: 'center', display: 'block' }}>
254
+ {`${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`}
255
+ </span>
256
+ );
257
+ }
258
+
259
+ return <span style={{ textAlign: 'center', display: 'block' }}>{String(value)}</span>;
260
+ } catch (error) {
261
+ console.error('Error formatting time:', error);
262
+ return <span>Hora inválida</span>;
263
+ }
264
+ };
265
+
266
+ /**
267
+ * Enum cell renderer
268
+ */
269
+ export const EnumCellRenderer = (
270
+ params: ICellRendererParams,
271
+ enumValues: Array<{ label: string; value: string }>
272
+ ): ReactNode => {
273
+ const value = params.value;
274
+ if (value === null || value === undefined) {
275
+ return <span></span>;
276
+ }
277
+
278
+ const option = enumValues.find((opt) => opt.value === value);
279
+ return <span>{option ? option.label : String(value)}</span>;
280
+ };
281
+
282
+ /**
283
+ * UUID cell renderer
284
+ */
285
+ export const UUIDCellRenderer = (params: ICellRendererParams): ReactNode => {
286
+ const value = params.value;
287
+ if (!value) {
288
+ return <span></span>;
289
+ }
290
+
291
+ const str = String(value);
292
+
293
+ if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str)) {
294
+ return <span>{str}</span>;
295
+ }
296
+
297
+ if (/^[0-9a-f]{32}$/i.test(str)) {
298
+ const formatted = `${str.substring(0, 8)}-${str.substring(8, 12)}-${str.substring(12, 16)}-${str.substring(16, 20)}-${str.substring(20)}`;
299
+ return <span>{formatted}</span>;
300
+ }
301
+
302
+ return <span>{str}</span>;
303
+ };
304
+
305
+ /**
306
+ * Image cell renderer
307
+ */
308
+ export const ImageCellRenderer = (
309
+ params: ICellRendererParams,
310
+ options?: { maxWidth?: number; maxHeight?: number }
311
+ ): ReactNode => {
312
+ const value = params.value;
313
+ if (!value) {
314
+ return <span></span>;
315
+ }
316
+
317
+ const { maxWidth = 40, maxHeight = 40 } = options || {};
318
+ let src = String(value);
319
+
320
+ // If it's base64 data without prefix, add it
321
+ if (isBase64(src) && !src.startsWith('data:')) {
322
+ src = `data:image/png;base64,${src}`;
323
+ }
324
+
325
+ return (
326
+ <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
327
+ <img
328
+ src={src}
329
+ alt=""
330
+ style={{
331
+ maxWidth,
332
+ maxHeight,
333
+ objectFit: 'contain',
334
+ }}
335
+ />
336
+ </div>
337
+ );
338
+ };
339
+
340
+ /**
341
+ * Get cell renderer by data type
342
+ */
343
+ export const getCellRendererByDataType = (
344
+ dataType: FieldDataType,
345
+ customRender?: (params: ICellRendererParams) => ReactNode,
346
+ options?: {
347
+ maskOptions?: MaskOptions;
348
+ dateFormat?: string;
349
+ dateTimeFormat?: string;
350
+ timeFormat?: string;
351
+ enumValues?: Array<{ label: string; value: string }>;
352
+ decimalPlaces?: number;
353
+ }
354
+ ): ((params: ICellRendererParams) => ReactNode) => {
355
+ if (customRender) {
356
+ return customRender;
357
+ }
358
+
359
+ switch (dataType) {
360
+ case 'text':
361
+ return (params) => TextCellRenderer(params, options?.maskOptions);
362
+ case 'integer':
363
+ return IntegerCellRenderer;
364
+ case 'float':
365
+ return FloatCellRenderer;
366
+ case 'currency':
367
+ return CurrencyCellRenderer;
368
+ case 'boolean':
369
+ return BooleanCellRenderer;
370
+ case 'date':
371
+ return (params) => DateCellRenderer(params, options?.dateFormat);
372
+ case 'datetime':
373
+ return (params) => DateTimeCellRenderer(params, options?.dateTimeFormat);
374
+ case 'time':
375
+ return (params) => TimeCellRenderer(params, options?.timeFormat);
376
+ case 'enum':
377
+ return (params) => EnumCellRenderer(params, options?.enumValues || []);
378
+ case 'uuid':
379
+ return UUIDCellRenderer;
380
+ case 'image':
381
+ return (params) => ImageCellRenderer(params);
382
+ default:
383
+ return (params) => TextCellRenderer(params);
384
+ }
385
+ };
386
+
387
+ /**
388
+ * Get recommended alignment by data type
389
+ */
390
+ export const getAlignmentByDataType = (
391
+ dataType: FieldDataType,
392
+ customAlign?: 'left' | 'center' | 'right'
393
+ ): 'left' | 'center' | 'right' => {
394
+ if (customAlign) {
395
+ return customAlign;
396
+ }
397
+
398
+ switch (dataType) {
399
+ case 'integer':
400
+ case 'currency':
401
+ case 'float':
402
+ return 'right';
403
+ case 'boolean':
404
+ case 'date':
405
+ case 'datetime':
406
+ case 'time':
407
+ case 'image':
408
+ return 'center';
409
+ default:
410
+ return 'left';
411
+ }
412
+ };
413
+
414
+ /**
415
+ * Create value formatter for AG Grid column
416
+ */
417
+ export const createValueFormatter = (
418
+ dataType: FieldDataType,
419
+ options?: {
420
+ dateFormat?: string;
421
+ dateTimeFormat?: string;
422
+ timeFormat?: string;
423
+ enumValues?: Array<{ label: string; value: string }>;
424
+ }
425
+ ): ((params: any) => string) | undefined => {
426
+ switch (dataType) {
427
+ case 'date':
428
+ return (params) => {
429
+ if (!params.value) return '';
430
+ try {
431
+ const date = convertISOStringToDate(params.value);
432
+ return format(date, options?.dateFormat || 'dd/MM/yyyy');
433
+ } catch {
434
+ return String(params.value);
435
+ }
436
+ };
437
+ case 'datetime':
438
+ return (params) => {
439
+ if (!params.value) return '';
440
+ try {
441
+ const date = convertISOStringToDate(params.value);
442
+ return format(date, options?.dateTimeFormat || 'dd/MM/yyyy HH:mm:ss');
443
+ } catch {
444
+ return String(params.value);
445
+ }
446
+ };
447
+ case 'currency':
448
+ return (params) => {
449
+ if (params.value === null || params.value === undefined) return '';
450
+ const numValue = Number.isNaN(Number(params.value)) ? 0 : Number(params.value);
451
+ return new Intl.NumberFormat('pt-BR', {
452
+ style: 'currency',
453
+ currency: 'BRL',
454
+ }).format(numValue);
455
+ };
456
+ case 'enum':
457
+ return (params) => {
458
+ if (params.value === null || params.value === undefined) return '';
459
+ const option = options?.enumValues?.find((opt) => opt.value === params.value);
460
+ return option ? option.label : String(params.value);
461
+ };
462
+ case 'boolean':
463
+ return (params) => {
464
+ if (params.value === null || params.value === undefined) return '';
465
+ return params.value ? 'Sim' : 'Não';
466
+ };
467
+ default:
468
+ return undefined;
469
+ }
470
+ };