@archbase/components 4.0.36 → 4.0.38
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/dist/archbase-components-4.0.38.tgz +0 -0
- package/dist/datagrid/ag-grid/archbase-data-grid-ag-types.d.ts +6 -0
- package/dist/datagrid/main/archbase-data-grid-types.d.ts +2 -0
- package/dist/editors/ArchbaseAvatarEdit.d.ts +6 -1
- package/dist/index.js +4558 -4506
- package/package.json +4 -4
- package/src/datagrid/ag-grid/archbase-data-grid-ag-types.tsx +8 -0
- package/src/datagrid/ag-grid/archbase-data-grid-ag.tsx +3 -1
- package/src/datagrid/main/archbase-data-grid-types.tsx +3 -0
- package/src/datagrid/main/archbase-data-grid.tsx +3 -1
- package/src/datagrid/modals/export-data.tsx +29 -3
- package/src/editors/ArchbaseAvatarEdit.tsx +23 -0
- package/src/editors/ArchbaseNumberEdit.tsx +43 -0
- package/src/editors/ArchbaseRichTextEdit.tsx +16 -1
- package/dist/archbase-components-4.0.36.tgz +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@archbase/components",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.38",
|
|
4
4
|
"description": "UI Components for Archbase React v3 - Form editors, data visualization, and business components",
|
|
5
5
|
"author": "Edson Martins <edsonmartins2005@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -118,9 +118,9 @@
|
|
|
118
118
|
"vis-timeline": "^7.7.3",
|
|
119
119
|
"xlsx": "^0.18.5",
|
|
120
120
|
"yet-another-react-lightbox": "^3.21.0",
|
|
121
|
-
"@archbase/core": "4.0.
|
|
122
|
-
"@archbase/data": "4.0.
|
|
123
|
-
"@archbase/layout": "4.0.
|
|
121
|
+
"@archbase/core": "4.0.38",
|
|
122
|
+
"@archbase/data": "4.0.38",
|
|
123
|
+
"@archbase/layout": "4.0.38"
|
|
124
124
|
},
|
|
125
125
|
"devDependencies": {
|
|
126
126
|
"@types/d3": "^7.4.3",
|
|
@@ -118,6 +118,12 @@ export interface ArchbaseDataGridAGColumnProps<T = any> {
|
|
|
118
118
|
hideWhenNoPermission?: boolean;
|
|
119
119
|
/** Auto-register column permission */
|
|
120
120
|
autoRegisterPermission?: boolean;
|
|
121
|
+
|
|
122
|
+
/** Função para formatar o valor da célula para exportação (CSV/Excel). Útil quando render usa componentes React (ex: badges, arrays de objetos). */
|
|
123
|
+
exportValue?: (row: T) => string;
|
|
124
|
+
|
|
125
|
+
/** Se false, a coluna não aparece nas opções de exportação/impressão (ex: colunas de imagem). Padrão: true. */
|
|
126
|
+
exportable?: boolean;
|
|
121
127
|
}
|
|
122
128
|
|
|
123
129
|
/**
|
|
@@ -412,4 +418,6 @@ export function GridToolBarActions(props: GridToolBarActionsProps) {
|
|
|
412
418
|
export interface ExtendedColDef<TData = any, TValue = any> extends ColDef<TData, TValue> {
|
|
413
419
|
enableGlobalFilter?: boolean;
|
|
414
420
|
dataType?: FieldDataType;
|
|
421
|
+
exportValue?: (row: TData) => string;
|
|
422
|
+
exportable?: boolean;
|
|
415
423
|
}
|
|
@@ -541,6 +541,8 @@ function ArchbaseDataGridAG<T extends object = any, ID = any>(
|
|
|
541
541
|
// Custom properties
|
|
542
542
|
enableGlobalFilter: columnProps.enableGlobalFilter,
|
|
543
543
|
dataType: columnProps.dataType,
|
|
544
|
+
exportValue: columnProps.exportValue,
|
|
545
|
+
exportable: columnProps.exportable !== false,
|
|
544
546
|
};
|
|
545
547
|
|
|
546
548
|
cols.push(colDef);
|
|
@@ -1131,7 +1133,7 @@ function ArchbaseDataGridAG<T extends object = any, ID = any>(
|
|
|
1131
1133
|
// Modal columns for export/print
|
|
1132
1134
|
const modalColumns = useMemo(() => {
|
|
1133
1135
|
return columnDefs
|
|
1134
|
-
.filter((col) => col.field && !col.field.startsWith('__'))
|
|
1136
|
+
.filter((col) => col.field && !col.field.startsWith('__') && col.exportable !== false)
|
|
1135
1137
|
.map((col) => ({
|
|
1136
1138
|
id: col.field!,
|
|
1137
1139
|
title: col.headerName || col.field!,
|
|
@@ -358,4 +358,7 @@ export interface ArchbaseDataGridColumnProps<T = any> {
|
|
|
358
358
|
|
|
359
359
|
/** Auto-registra a permissão da coluna (padrão: true) */
|
|
360
360
|
autoRegisterPermission?: boolean;
|
|
361
|
+
|
|
362
|
+
/** Função para formatar o valor da célula para exportação (CSV/Excel). Útil quando render usa componentes React (ex: badges, arrays de objetos). */
|
|
363
|
+
exportValue?: (row: T) => string;
|
|
361
364
|
}
|
|
@@ -1152,7 +1152,8 @@ function ArchbaseDataGrid<T extends object = any, ID = any>(props: ArchbaseDataG
|
|
|
1152
1152
|
// Armazenar metadados personalizados
|
|
1153
1153
|
columnMetadata[columnProps.dataField] = {
|
|
1154
1154
|
enableGlobalFilter: columnProps.enableGlobalFilter,
|
|
1155
|
-
dataType: columnProps.dataType
|
|
1155
|
+
dataType: columnProps.dataType,
|
|
1156
|
+
exportValue: columnProps.exportValue
|
|
1156
1157
|
}
|
|
1157
1158
|
|
|
1158
1159
|
// Obter o renderizador adequado para o tipo de dados
|
|
@@ -1246,6 +1247,7 @@ function ArchbaseDataGrid<T extends object = any, ID = any>(props: ArchbaseDataG
|
|
|
1246
1247
|
if (metadata) {
|
|
1247
1248
|
;(col as any).enableGlobalFilter = metadata.enableGlobalFilter
|
|
1248
1249
|
;(col as any).dataType = metadata.dataType
|
|
1250
|
+
;(col as any).exportValue = metadata.exportValue
|
|
1249
1251
|
}
|
|
1250
1252
|
})
|
|
1251
1253
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { saveAs } from 'file-saver';
|
|
3
3
|
import { utils, write } from 'xlsx';
|
|
4
4
|
import { format } from 'date-fns';
|
|
5
|
+
import { jsPDF } from 'jspdf';
|
|
6
|
+
import autoTable from 'jspdf-autotable';
|
|
5
7
|
|
|
6
8
|
// Tipos de exportação suportados
|
|
7
9
|
export type ExportFormat = 'csv' | 'excel' | 'pdf';
|
|
@@ -37,6 +39,16 @@ const getCellValue = (row: any, column: any): any => {
|
|
|
37
39
|
return value;
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
// Usar exportValue se disponível (tem prioridade sobre valueGetter para exportação)
|
|
43
|
+
if (column.exportValue) {
|
|
44
|
+
try {
|
|
45
|
+
return column.exportValue(row);
|
|
46
|
+
} catch (e) {
|
|
47
|
+
console.error('Error in exportValue:', e);
|
|
48
|
+
return '';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
40
52
|
// Usar valueGetter se disponível
|
|
41
53
|
if (column.valueGetter) {
|
|
42
54
|
try {
|
|
@@ -176,8 +188,22 @@ async function exportToExcel(data: any[], config: ExportConfig): Promise<void> {
|
|
|
176
188
|
saveAs(blob, `${config.filename || 'export'}.xlsx`);
|
|
177
189
|
}
|
|
178
190
|
|
|
179
|
-
// Exportação para PDF
|
|
191
|
+
// Exportação para PDF
|
|
180
192
|
async function exportToPDF(data: any[], config: ExportConfig): Promise<void> {
|
|
181
|
-
|
|
182
|
-
|
|
193
|
+
if (!data || data.length === 0) return;
|
|
194
|
+
|
|
195
|
+
const doc = new jsPDF({ orientation: 'landscape', unit: 'mm', format: 'A4' }) as any;
|
|
196
|
+
|
|
197
|
+
const headers = Object.keys(data[0]);
|
|
198
|
+
const tableData = data.map(row => headers.map(h => (row[h] !== null && row[h] !== undefined ? row[h] : '')));
|
|
199
|
+
|
|
200
|
+
autoTable(doc, {
|
|
201
|
+
head: [headers],
|
|
202
|
+
body: tableData,
|
|
203
|
+
theme: 'grid',
|
|
204
|
+
styles: { fontSize: 9, cellPadding: 2, font: 'helvetica', overflow: 'linebreak' },
|
|
205
|
+
headStyles: { fillColor: [51, 51, 51], textColor: 255, fontStyle: 'bold', halign: 'center' },
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
saveAs(doc.output('blob'), `${config.filename || 'export'}.pdf`);
|
|
183
209
|
}
|
|
@@ -52,6 +52,10 @@ export interface ArchbaseAvatarEditProps<T, ID> {
|
|
|
52
52
|
maxSizeKB?: number;
|
|
53
53
|
/** Qualidade da compressão da imagem (0 a 1), sendo 1 melhor qualidade */
|
|
54
54
|
imageQuality?: number;
|
|
55
|
+
/** Maior dimensão (px) da imagem final: o recorte é redimensionado automaticamente
|
|
56
|
+
* para caber neste limite antes da compressão, independente do tamanho da foto
|
|
57
|
+
* enviada pelo usuário. 0 mantém a resolução original do recorte. */
|
|
58
|
+
maxOutputSizePx?: number;
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
export function ArchbaseAvatarEdit<T, ID>({
|
|
@@ -75,6 +79,7 @@ export function ArchbaseAvatarEdit<T, ID>({
|
|
|
75
79
|
hoverBackgroundColor = 'rgba(0, 0, 0, 0.6)',
|
|
76
80
|
maxSizeKB = 0, // 0 significa sem limite
|
|
77
81
|
imageQuality = 0.95,
|
|
82
|
+
maxOutputSizePx = 512, // avatar não precisa de resolução maior que isso
|
|
78
83
|
...otherProps
|
|
79
84
|
}: ArchbaseAvatarEditProps<T, ID>) {
|
|
80
85
|
const [value, setValue] = useState<string | undefined>(undefined);
|
|
@@ -342,6 +347,24 @@ export function ArchbaseAvatarEdit<T, ID>({
|
|
|
342
347
|
// Colocar os dados da imagem rotacionada de volta no canvas
|
|
343
348
|
ctx.putImageData(data, -pixelCrop.x, - pixelCrop.y);
|
|
344
349
|
|
|
350
|
+
// Redimensionar para a dimensão máxima de saída: reduzir a resolução (e não só a
|
|
351
|
+
// qualidade JPEG) garante arquivos pequenos mesmo para fotos de celular gigantes,
|
|
352
|
+
// sem o usuário precisar escolher uma "imagem menor"
|
|
353
|
+
const maiorDimensao = Math.max(pixelCrop.width, pixelCrop.height);
|
|
354
|
+
if (maxOutputSizePx > 0 && maiorDimensao > maxOutputSizePx) {
|
|
355
|
+
const escala = maxOutputSizePx / maiorDimensao;
|
|
356
|
+
const canvasSaida = document.createElement('canvas');
|
|
357
|
+
canvasSaida.width = Math.max(1, Math.round(pixelCrop.width * escala));
|
|
358
|
+
canvasSaida.height = Math.max(1, Math.round(pixelCrop.height * escala));
|
|
359
|
+
const ctxSaida = canvasSaida.getContext('2d');
|
|
360
|
+
if (ctxSaida) {
|
|
361
|
+
ctxSaida.imageSmoothingEnabled = true;
|
|
362
|
+
ctxSaida.imageSmoothingQuality = 'high';
|
|
363
|
+
ctxSaida.drawImage(canvas, 0, 0, canvasSaida.width, canvasSaida.height);
|
|
364
|
+
return canvasSaida.toDataURL('image/jpeg', quality);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
345
368
|
// Retornar como base64 com a qualidade especificada
|
|
346
369
|
return canvas.toDataURL('image/jpeg', quality);
|
|
347
370
|
}
|
|
@@ -448,6 +448,48 @@ export function ArchbaseNumberEdit<T, ID>({
|
|
|
448
448
|
}
|
|
449
449
|
};
|
|
450
450
|
|
|
451
|
+
const handlePaste = (event: React.ClipboardEvent<HTMLInputElement>) => {
|
|
452
|
+
event.preventDefault();
|
|
453
|
+
|
|
454
|
+
let pastedText = event.clipboardData.getData('text').trim();
|
|
455
|
+
|
|
456
|
+
if (!allowNegative) {
|
|
457
|
+
pastedText = pastedText.replace(/-/g, '');
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Normaliza separador decimal: aceita tanto '.' quanto ',' como entrada
|
|
461
|
+
const otherSeparator = decimalSeparator === '.' ? ',' : '.';
|
|
462
|
+
pastedText = pastedText
|
|
463
|
+
.replace(new RegExp(`\\${thousandSeparator}`, 'g'), '')
|
|
464
|
+
.replace(otherSeparator, decimalSeparator);
|
|
465
|
+
|
|
466
|
+
const { maskedValue: newMaskedValue, value: newValue } = formatNumber(
|
|
467
|
+
pastedText,
|
|
468
|
+
precision,
|
|
469
|
+
decimalSeparator,
|
|
470
|
+
thousandSeparator,
|
|
471
|
+
allowNegative,
|
|
472
|
+
prefix,
|
|
473
|
+
suffix,
|
|
474
|
+
minValue,
|
|
475
|
+
maxValue,
|
|
476
|
+
false
|
|
477
|
+
);
|
|
478
|
+
|
|
479
|
+
if (newMaskedValue === null && newValue === null) return;
|
|
480
|
+
|
|
481
|
+
setMaskedValue(newMaskedValue);
|
|
482
|
+
setCurrentValue(newValue);
|
|
483
|
+
|
|
484
|
+
if (dataSource && !dataSource.isBrowsing() && dataField) {
|
|
485
|
+
v1v2Compatibility.handleValueChange(newValue);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (onChangeValue) {
|
|
489
|
+
onChangeValue(newMaskedValue, newValue, event as any);
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
|
|
451
493
|
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
|
452
494
|
const input = event.currentTarget;
|
|
453
495
|
const selectionStart = input.selectionStart || 0;
|
|
@@ -601,6 +643,7 @@ export function ArchbaseNumberEdit<T, ID>({
|
|
|
601
643
|
onBlur={handleFocusExit}
|
|
602
644
|
onFocus={handleFocusEnter}
|
|
603
645
|
onKeyDown={handleKeyDown}
|
|
646
|
+
onPaste={handlePaste}
|
|
604
647
|
styles={{
|
|
605
648
|
input: {
|
|
606
649
|
textAlign: 'right',
|
|
@@ -17,6 +17,21 @@ let SunEditorComponent: React.ComponentType<any> | null = null;
|
|
|
17
17
|
let langModules: { en: any; es: any; ptBR: any } = { en: {}, es: {}, ptBR: {} };
|
|
18
18
|
let loadPromise: Promise<void> | null = null;
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Resolve o componente de um módulo importado dinamicamente lidando com o
|
|
22
|
+
* interop CJS→ESM. `suneditor-react` é publicado como CJS (`exports.default = SunEditor`
|
|
23
|
+
* com `__esModule: true`); dependendo do empacotador (ex.: build de produção com Rollup),
|
|
24
|
+
* `mod.default` pode chegar como o objeto `{ default: SunEditor, __esModule: true }` em vez
|
|
25
|
+
* do próprio componente, fazendo o React lançar "Element type is invalid ... got: object".
|
|
26
|
+
*/
|
|
27
|
+
function resolveDefaultComponent(mod: any): any {
|
|
28
|
+
const candidate = mod?.default ?? mod;
|
|
29
|
+
if (candidate && typeof candidate !== 'function' && candidate.__esModule && candidate.default) {
|
|
30
|
+
return candidate.default;
|
|
31
|
+
}
|
|
32
|
+
return candidate;
|
|
33
|
+
}
|
|
34
|
+
|
|
20
35
|
// Função para carregar suneditor e dependências
|
|
21
36
|
async function loadSunEditor(): Promise<void> {
|
|
22
37
|
if (loadPromise) return loadPromise;
|
|
@@ -31,7 +46,7 @@ async function loadSunEditor(): Promise<void> {
|
|
|
31
46
|
import('suneditor/src/lang/es'),
|
|
32
47
|
import('suneditor/src/lang/pt_br'),
|
|
33
48
|
]);
|
|
34
|
-
SunEditorComponent = sunEditorModule
|
|
49
|
+
SunEditorComponent = resolveDefaultComponent(sunEditorModule);
|
|
35
50
|
langModules = {
|
|
36
51
|
en: enModule.default,
|
|
37
52
|
es: esModule.default,
|
|
Binary file
|