@archbase/components 4.0.35 → 4.0.37
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.37.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/ArchbaseAsyncSelect.d.ts +3 -1
- package/dist/editors/ArchbaseAvatarEdit.d.ts +6 -1
- package/dist/editors/ArchbaseSelect.d.ts +3 -1
- package/dist/index.js +5211 -5143
- 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/ArchbaseAsyncSelect.tsx +9 -2
- package/src/editors/ArchbaseAvatarEdit.tsx +23 -0
- package/src/editors/ArchbaseNumberEdit.tsx +43 -0
- package/src/editors/ArchbaseSelect.tsx +20 -3
- package/dist/archbase-components-4.0.35.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.37",
|
|
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.37",
|
|
122
|
+
"@archbase/data": "4.0.37",
|
|
123
|
+
"@archbase/layout": "4.0.37"
|
|
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
|
}
|
|
@@ -135,6 +135,8 @@ export interface ArchbaseAsyncSelectProps<T, ID, O> {
|
|
|
135
135
|
converter?: (value: O) => any;
|
|
136
136
|
/** Function que busca o valor original antes de converter pelo valor de retorno do converter */
|
|
137
137
|
getConvertedOption?: (value: any) => Promise<O>;
|
|
138
|
+
/** Função que determina se uma opção individual está desabilitada */
|
|
139
|
+
isOptionDisabled?: (option: O) => boolean;
|
|
138
140
|
}
|
|
139
141
|
function buildOptions<O>(
|
|
140
142
|
initialOptions: O[],
|
|
@@ -210,7 +212,8 @@ export function ArchbaseAsyncSelect<T, ID, O>({
|
|
|
210
212
|
innerRef,
|
|
211
213
|
onSearchChange,
|
|
212
214
|
converter,
|
|
213
|
-
getConvertedOption
|
|
215
|
+
getConvertedOption,
|
|
216
|
+
isOptionDisabled,
|
|
214
217
|
}: ArchbaseAsyncSelectProps<T, ID, O>) {
|
|
215
218
|
const forceUpdate = useForceUpdate();
|
|
216
219
|
|
|
@@ -539,7 +542,11 @@ export function ArchbaseAsyncSelect<T, ID, O>({
|
|
|
539
542
|
{filteredOptions.slice(0, limit ? limit : filteredOptions.length).map((option) => {
|
|
540
543
|
const {key, ...rest} = option
|
|
541
544
|
return (
|
|
542
|
-
<Combobox.Option
|
|
545
|
+
<Combobox.Option
|
|
546
|
+
value={option.value}
|
|
547
|
+
key={option.key}
|
|
548
|
+
disabled={isOptionDisabled ? isOptionDisabled(option.origin) : false}
|
|
549
|
+
>
|
|
543
550
|
{ItemComponent ? <ItemComponent {...rest} /> : option.label}
|
|
544
551
|
</Combobox.Option>
|
|
545
552
|
)
|
|
@@ -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',
|
|
@@ -117,6 +117,8 @@ export interface ArchbaseSelectProps<T, ID, O> {
|
|
|
117
117
|
* Por exemplo: (id) => fetchObjectById(id) para converter ID de volta ao objeto
|
|
118
118
|
*/
|
|
119
119
|
getConvertedOption?: (value: any) => Promise<O>
|
|
120
|
+
/** Função que determina se uma opção individual está desabilitada */
|
|
121
|
+
isOptionDisabled?: (option: O) => boolean
|
|
120
122
|
}
|
|
121
123
|
|
|
122
124
|
function buildGroupOptions(
|
|
@@ -248,7 +250,8 @@ export function ArchbaseSelect<T, ID, O>({
|
|
|
248
250
|
classNames,
|
|
249
251
|
styles,
|
|
250
252
|
converter,
|
|
251
|
-
getConvertedOption
|
|
253
|
+
getConvertedOption,
|
|
254
|
+
isOptionDisabled,
|
|
252
255
|
}: ArchbaseSelectProps<T, ID, O>) {
|
|
253
256
|
const forceUpdate = useForceUpdate();
|
|
254
257
|
|
|
@@ -282,7 +285,7 @@ export function ArchbaseSelect<T, ID, O>({
|
|
|
282
285
|
const contextError = validationContext?.getError(fieldKey);
|
|
283
286
|
|
|
284
287
|
const currentOptions: any[] = useMemo(() => {
|
|
285
|
-
|
|
288
|
+
const opts = buildOptions<O>(
|
|
286
289
|
options,
|
|
287
290
|
initialOptions,
|
|
288
291
|
children,
|
|
@@ -290,6 +293,19 @@ export function ArchbaseSelect<T, ID, O>({
|
|
|
290
293
|
getOptionValue,
|
|
291
294
|
optionsLabelField
|
|
292
295
|
)
|
|
296
|
+
if (!isOptionDisabled) return opts
|
|
297
|
+
return opts.map((opt: any) => {
|
|
298
|
+
if (opt.group !== undefined) {
|
|
299
|
+
return {
|
|
300
|
+
...opt,
|
|
301
|
+
items: opt.items.map((item: any) => ({
|
|
302
|
+
...item,
|
|
303
|
+
disabled: isOptionDisabled(item.origin ?? item),
|
|
304
|
+
})),
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return { ...opt, disabled: isOptionDisabled(opt.origin ?? opt) }
|
|
308
|
+
})
|
|
293
309
|
}, [
|
|
294
310
|
updateCounter,
|
|
295
311
|
options,
|
|
@@ -297,7 +313,8 @@ export function ArchbaseSelect<T, ID, O>({
|
|
|
297
313
|
children,
|
|
298
314
|
getOptionLabel,
|
|
299
315
|
getOptionValue,
|
|
300
|
-
optionsLabelField
|
|
316
|
+
optionsLabelField,
|
|
317
|
+
isOptionDisabled,
|
|
301
318
|
])
|
|
302
319
|
|
|
303
320
|
const handleConverter = (value) => {
|
|
Binary file
|