@praxisui/dynamic-fields 9.0.0-beta.17 → 9.0.0-beta.18
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/ai/component-registry.json +112 -112
- package/docs/dynamic-fields-field-catalog.md +1 -2
- package/fesm2022/praxisui-dynamic-fields.mjs +426 -63
- package/package.json +3 -3
- package/src/lib/components/material-file-upload/pdx-material-file-upload.json-api.md +58 -27
- package/types/praxisui-dynamic-fields.d.ts +51 -5
|
@@ -130,6 +130,7 @@ const PRAXIS_DYNAMIC_FIELDS_EN_US = {
|
|
|
130
130
|
'praxis.dynamicFields.validation.unique': 'Value is already in use',
|
|
131
131
|
'praxis.dynamicFields.validation.fileType': 'File type is not allowed',
|
|
132
132
|
'praxis.dynamicFields.validation.maxFileSize': 'File exceeds the maximum size',
|
|
133
|
+
'praxis.dynamicFields.validation.maxFiles': 'Select at most {{count}} file(s)',
|
|
133
134
|
'praxis.dynamicFields.validation.minWords': 'Text has too few words',
|
|
134
135
|
'praxis.dynamicFields.validation.conditional': 'Validation rule not satisfied',
|
|
135
136
|
'praxis.dynamicFields.validation.invalidValue': 'Invalid value',
|
|
@@ -142,6 +143,16 @@ const PRAXIS_DYNAMIC_FIELDS_EN_US = {
|
|
|
142
143
|
'praxis.dynamicFields.actions.clear.tooltip': 'Clear',
|
|
143
144
|
'praxis.dynamicFields.actions.clear.ariaLabel': 'Clear field',
|
|
144
145
|
'praxis.dynamicFields.actions.clear.ariaLabelWithLabel': 'Clear {{label}}',
|
|
146
|
+
'praxis.dynamicFields.fileUpload.emptySummary': 'No file selected',
|
|
147
|
+
'praxis.dynamicFields.fileUpload.multipleSummary': '{{count}} files selected',
|
|
148
|
+
'praxis.dynamicFields.fileUpload.clearSelection': 'Clear',
|
|
149
|
+
'praxis.dynamicFields.fileUpload.clearSelectionAriaLabel': 'Clear selected file',
|
|
150
|
+
'praxis.dynamicFields.fileUpload.selectedSummaryAriaLabel': 'Selected file',
|
|
151
|
+
'praxis.dynamicFields.fileUpload.previewAlt': 'Selected image preview',
|
|
152
|
+
'praxis.dynamicFields.fileUpload.sizeUnitBytes': 'B',
|
|
153
|
+
'praxis.dynamicFields.fileUpload.sizeUnitKb': 'KB',
|
|
154
|
+
'praxis.dynamicFields.fileUpload.sizeUnitMb': 'MB',
|
|
155
|
+
'praxis.dynamicFields.fileUpload.sizeUnitGb': 'GB',
|
|
145
156
|
'praxis.dynamicFields.array.add': 'Add item',
|
|
146
157
|
'praxis.dynamicFields.array.remove': 'Remove',
|
|
147
158
|
'praxis.dynamicFields.array.empty': 'No items registered.',
|
|
@@ -509,6 +520,7 @@ const PRAXIS_DYNAMIC_FIELDS_PT_BR = {
|
|
|
509
520
|
'praxis.dynamicFields.validation.unique': 'Valor já utilizado',
|
|
510
521
|
'praxis.dynamicFields.validation.fileType': 'Tipo de arquivo não permitido',
|
|
511
522
|
'praxis.dynamicFields.validation.maxFileSize': 'Arquivo excede o tamanho máximo',
|
|
523
|
+
'praxis.dynamicFields.validation.maxFiles': 'Selecione no máximo {{count}} arquivo(s)',
|
|
512
524
|
'praxis.dynamicFields.validation.minWords': 'Texto com poucas palavras',
|
|
513
525
|
'praxis.dynamicFields.validation.conditional': 'Regra de validação não atendida',
|
|
514
526
|
'praxis.dynamicFields.validation.invalidValue': 'Valor inválido',
|
|
@@ -521,6 +533,16 @@ const PRAXIS_DYNAMIC_FIELDS_PT_BR = {
|
|
|
521
533
|
'praxis.dynamicFields.actions.clear.tooltip': 'Limpar',
|
|
522
534
|
'praxis.dynamicFields.actions.clear.ariaLabel': 'Limpar campo',
|
|
523
535
|
'praxis.dynamicFields.actions.clear.ariaLabelWithLabel': 'Limpar {{label}}',
|
|
536
|
+
'praxis.dynamicFields.fileUpload.emptySummary': 'Nenhum arquivo selecionado',
|
|
537
|
+
'praxis.dynamicFields.fileUpload.multipleSummary': '{{count}} arquivos selecionados',
|
|
538
|
+
'praxis.dynamicFields.fileUpload.clearSelection': 'Limpar',
|
|
539
|
+
'praxis.dynamicFields.fileUpload.clearSelectionAriaLabel': 'Limpar arquivo selecionado',
|
|
540
|
+
'praxis.dynamicFields.fileUpload.selectedSummaryAriaLabel': 'Arquivo selecionado',
|
|
541
|
+
'praxis.dynamicFields.fileUpload.previewAlt': 'Pré-visualização da imagem selecionada',
|
|
542
|
+
'praxis.dynamicFields.fileUpload.sizeUnitBytes': 'B',
|
|
543
|
+
'praxis.dynamicFields.fileUpload.sizeUnitKb': 'KB',
|
|
544
|
+
'praxis.dynamicFields.fileUpload.sizeUnitMb': 'MB',
|
|
545
|
+
'praxis.dynamicFields.fileUpload.sizeUnitGb': 'GB',
|
|
524
546
|
'praxis.dynamicFields.array.add': 'Adicionar item',
|
|
525
547
|
'praxis.dynamicFields.array.remove': 'Remover',
|
|
526
548
|
'praxis.dynamicFields.array.empty': 'Nenhum item cadastrado.',
|
|
@@ -775,7 +797,7 @@ const PRAXIS_DYNAMIC_FIELDS_PT_BR = {
|
|
|
775
797
|
'praxis.dynamicFields.entityLookup.action.create': 'Novo',
|
|
776
798
|
'praxis.dynamicFields.entityLookup.action.clear': 'Limpar',
|
|
777
799
|
'praxis.dynamicFields.entityLookup.sort.label': 'Ordenar por',
|
|
778
|
-
'praxis.dynamicFields.entityLookup.sort.default': '
|
|
800
|
+
'praxis.dynamicFields.entityLookup.sort.default': 'Padrão',
|
|
779
801
|
'praxis.dynamicFields.entityLookup.filter.clearAll': 'Limpar filtros',
|
|
780
802
|
'praxis.dynamicFields.entityLookup.dialog.open': 'Busca avançada',
|
|
781
803
|
'praxis.dynamicFields.entityLookup.dialog.openSupporting': 'Refine a busca com filtros, ordenacao e contexto.',
|
|
@@ -812,7 +834,7 @@ const PRAXIS_DYNAMIC_FIELDS_PT_BR = {
|
|
|
812
834
|
'praxis.dynamicFields.entityLookup.dialog.preview.legacy': 'Valor legado',
|
|
813
835
|
'praxis.dynamicFields.entityLookup.dialog.preview.blocked': 'Bloqueado',
|
|
814
836
|
'praxis.dynamicFields.entityLookup.dialog.preview.selectable': 'Selecionavel',
|
|
815
|
-
'praxis.dynamicFields.entityLookup.selectionLimitReached': 'Limite de {max}
|
|
837
|
+
'praxis.dynamicFields.entityLookup.selectionLimitReached': 'Limite de {max} seleções atingido.',
|
|
816
838
|
'praxis.dynamicFields.entityLookup.action.removeSelection': 'Remover {label}',
|
|
817
839
|
'praxis.dynamicFields.entityLookup.noResults': 'Nenhuma entidade encontrada para os filtros atuais.',
|
|
818
840
|
'praxis.dynamicFields.entityLookup.unmetDependencies': 'Preencha os campos dependentes antes de buscar.',
|
|
@@ -864,7 +886,7 @@ const PRAXIS_DYNAMIC_FIELDS_PT_BR = {
|
|
|
864
886
|
'praxis.dynamicFields.editorial.avatar.inputs.emphasis.description': 'Estado de destaque visual usado para avatares selecionados, principais ou de atenção sem alterar valores submetidos.',
|
|
865
887
|
'praxis.dynamicFields.editorial.avatar.inputs.emphasisColor.description': 'Token de cor usado pelo anel ou halo de destaque.',
|
|
866
888
|
'praxis.dynamicFields.editorial.avatar.inputs.emphasisLabel.description': 'Rotulo acessivel que descreve o significado do destaque visual.',
|
|
867
|
-
'praxis.dynamicFields.editorial.avatar.inputs.initialsMaxLength.description': '
|
|
889
|
+
'praxis.dynamicFields.editorial.avatar.inputs.initialsMaxLength.description': 'Número máximo de iniciais renderizadas',
|
|
868
890
|
'praxis.dynamicFields.editorial.avatar.inputs.tooltip.description': 'Texto do tooltip',
|
|
869
891
|
'praxis.dynamicFields.editorial.avatar.inputs.ariaLabel.description': 'Rótulo ARIA',
|
|
870
892
|
'praxis.dynamicFields.editorial.avatar.inputs.class.description': 'Classes CSS adicionais no host',
|
|
@@ -2980,8 +3002,8 @@ class SimpleBaseButtonComponent {
|
|
|
2980
3002
|
// Adicionar confirmação se configurada
|
|
2981
3003
|
if (action && meta.confirmDialog) {
|
|
2982
3004
|
action.confirmation = {
|
|
2983
|
-
title: meta.confirmDialog.title || this.tDynamicFields('button.confirmTitle', 'Confirmar
|
|
2984
|
-
message: meta.confirmDialog.message || this.tDynamicFields('button.confirmMessage', 'Deseja continuar com esta
|
|
3005
|
+
title: meta.confirmDialog.title || this.tDynamicFields('button.confirmTitle', 'Confirmar ação'),
|
|
3006
|
+
message: meta.confirmDialog.message || this.tDynamicFields('button.confirmMessage', 'Deseja continuar com esta ação?'),
|
|
2985
3007
|
confirmLabel: meta.confirmDialog.confirmLabel || this.tDynamicFields('dialog.confirm', 'Confirmar'),
|
|
2986
3008
|
cancelLabel: meta.confirmDialog.cancelLabel || this.tDynamicFields('dialog.cancel', 'Cancelar'),
|
|
2987
3009
|
};
|
|
@@ -8809,7 +8831,7 @@ const LoggerPresets = {
|
|
|
8809
8831
|
}
|
|
8810
8832
|
};
|
|
8811
8833
|
|
|
8812
|
-
const EMPTY_DISPLAY = '--
|
|
8834
|
+
const EMPTY_DISPLAY = '-- Não informado';
|
|
8813
8835
|
function isISODate(v) {
|
|
8814
8836
|
return /^\d{4}-\d{2}-\d{2}$/.test(v);
|
|
8815
8837
|
}
|
|
@@ -9356,7 +9378,7 @@ function formatBooleanPresentation(value, locale) {
|
|
|
9356
9378
|
function resolveBooleanLabels(locale) {
|
|
9357
9379
|
const normalized = String(locale || '').trim().toLowerCase();
|
|
9358
9380
|
if (normalized.startsWith('pt')) {
|
|
9359
|
-
return ['Sim', '
|
|
9381
|
+
return ['Sim', 'Não'];
|
|
9360
9382
|
}
|
|
9361
9383
|
if (normalized.startsWith('es')) {
|
|
9362
9384
|
return ['Si', 'No'];
|
|
@@ -13117,7 +13139,7 @@ class InlineEntityLookupComponent extends MaterialAsyncSelectComponent {
|
|
|
13117
13139
|
}
|
|
13118
13140
|
selectionLimitReachedText(maxSelections) {
|
|
13119
13141
|
const max = Number(maxSelections ?? 0);
|
|
13120
|
-
const template = this.tDynamicFields('entityLookup.selectionLimitReached', 'Limite de {max}
|
|
13142
|
+
const template = this.tDynamicFields('entityLookup.selectionLimitReached', 'Limite de {max} seleções atingido.', { max: Number.isFinite(max) && max > 0 ? max : 0 });
|
|
13121
13143
|
return template.replace('{max}', String(Number.isFinite(max) && max > 0 ? max : 0));
|
|
13122
13144
|
}
|
|
13123
13145
|
onDetailAction(event, item) {
|
|
@@ -13287,7 +13309,7 @@ class InlineEntityLookupComponent extends MaterialAsyncSelectComponent {
|
|
|
13287
13309
|
}
|
|
13288
13310
|
resetOptionText() {
|
|
13289
13311
|
const custom = String(this.metadata()?.resetLabel || '').trim();
|
|
13290
|
-
return custom || 'Limpar
|
|
13312
|
+
return custom || 'Limpar seleção';
|
|
13291
13313
|
}
|
|
13292
13314
|
showQuickClear() {
|
|
13293
13315
|
const clearCfg = this.currentMetadata().clearButton;
|
|
@@ -13391,7 +13413,7 @@ class InlineEntityLookupComponent extends MaterialAsyncSelectComponent {
|
|
|
13391
13413
|
this.retry();
|
|
13392
13414
|
}
|
|
13393
13415
|
errorStateLabel() {
|
|
13394
|
-
return this.error() || this.tDynamicFields('select.loadOptionsError', 'Erro ao carregar
|
|
13416
|
+
return this.error() || this.tDynamicFields('select.loadOptionsError', 'Erro ao carregar opções.');
|
|
13395
13417
|
}
|
|
13396
13418
|
dependencyStateLabel() {
|
|
13397
13419
|
const dependencyLabels = this.missingDependencyLabels();
|
|
@@ -13462,7 +13484,7 @@ class InlineEntityLookupComponent extends MaterialAsyncSelectComponent {
|
|
|
13462
13484
|
return this.tDynamicFields('entityLookup.sort.label', 'Ordenar por');
|
|
13463
13485
|
}
|
|
13464
13486
|
sortDefaultOptionText() {
|
|
13465
|
-
return this.tDynamicFields('entityLookup.sort.default', '
|
|
13487
|
+
return this.tDynamicFields('entityLookup.sort.default', 'Padrão');
|
|
13466
13488
|
}
|
|
13467
13489
|
clearAllFiltersText() {
|
|
13468
13490
|
return this.tDynamicFields('entityLookup.filter.clearAll', 'Limpar filtros');
|
|
@@ -17635,11 +17657,11 @@ function createInlinePhoneComponentMetadata(locale = 'en-US') {
|
|
|
17635
17657
|
}
|
|
17636
17658
|
|
|
17637
17659
|
/**
|
|
17638
|
-
*
|
|
17660
|
+
* Baseline file upload field.
|
|
17639
17661
|
*
|
|
17640
|
-
*
|
|
17641
|
-
*
|
|
17642
|
-
*
|
|
17662
|
+
* This component owns local file selection, validation and preview. Persisting
|
|
17663
|
+
* the selected file remains a host/backend concern; use @praxisui/files-upload
|
|
17664
|
+
* when the flow needs presign, progress, conflict policy or storage events.
|
|
17643
17665
|
*/
|
|
17644
17666
|
class MaterialFileUploadComponent extends SimpleBaseInputComponent {
|
|
17645
17667
|
// Praxis Field States
|
|
@@ -17647,13 +17669,55 @@ class MaterialFileUploadComponent extends SimpleBaseInputComponent {
|
|
|
17647
17669
|
disabledMode = false;
|
|
17648
17670
|
visible = true;
|
|
17649
17671
|
presentationMode = false;
|
|
17672
|
+
selectedFiles = signal([], ...(ngDevMode ? [{ debugName: "selectedFiles" }] : /* istanbul ignore next */ []));
|
|
17673
|
+
previewUrl = signal(null, ...(ngDevMode ? [{ debugName: "previewUrl" }] : /* istanbul ignore next */ []));
|
|
17674
|
+
externalValueSyncSubscription = new Subscription();
|
|
17675
|
+
selectedSummaryText = computed(() => {
|
|
17676
|
+
const files = this.selectedFiles();
|
|
17677
|
+
if (!files.length) {
|
|
17678
|
+
return this.dynamicFieldsText('fileUpload.emptySummary', 'No file selected');
|
|
17679
|
+
}
|
|
17680
|
+
if (files.length === 1) {
|
|
17681
|
+
return files[0].name;
|
|
17682
|
+
}
|
|
17683
|
+
return this.dynamicFieldsText('fileUpload.multipleSummary', '{{count}} files selected', {
|
|
17684
|
+
count: files.length,
|
|
17685
|
+
});
|
|
17686
|
+
}, ...(ngDevMode ? [{ debugName: "selectedSummaryText" }] : /* istanbul ignore next */ []));
|
|
17687
|
+
selectedDetailText = computed(() => {
|
|
17688
|
+
const files = this.selectedFiles();
|
|
17689
|
+
if (!files.length)
|
|
17690
|
+
return '';
|
|
17691
|
+
const total = files.reduce((sum, file) => sum + file.size, 0);
|
|
17692
|
+
return this.formatBytes(total);
|
|
17693
|
+
}, ...(ngDevMode ? [{ debugName: "selectedDetailText" }] : /* istanbul ignore next */ []));
|
|
17650
17694
|
/**
|
|
17651
17695
|
* Updates the control value when the user selects a file.
|
|
17652
17696
|
*/
|
|
17653
17697
|
onFileSelected(event) {
|
|
17654
17698
|
const input = event.target;
|
|
17655
|
-
const
|
|
17656
|
-
|
|
17699
|
+
const files = Array.from(input.files ?? []);
|
|
17700
|
+
if (!files.length) {
|
|
17701
|
+
this.clearSelectedFiles({ resetInput: false });
|
|
17702
|
+
return;
|
|
17703
|
+
}
|
|
17704
|
+
const selected = this.allowsMultiple() ? files : files.slice(0, 1);
|
|
17705
|
+
const validationError = this.validateSelectedFiles(selected);
|
|
17706
|
+
if (validationError) {
|
|
17707
|
+
this.clearPreview();
|
|
17708
|
+
this.selectedFiles.set([]);
|
|
17709
|
+
this.setValue(this.allowsMultiple() ? [] : null, { emitEvent: true });
|
|
17710
|
+
this.applyFileError(validationError);
|
|
17711
|
+
input.value = '';
|
|
17712
|
+
return;
|
|
17713
|
+
}
|
|
17714
|
+
this.clearFileErrors();
|
|
17715
|
+
this.selectedFiles.set(selected);
|
|
17716
|
+
this.updatePreview(selected);
|
|
17717
|
+
this.setValue(this.allowsMultiple() ? selected : selected[0], { emitEvent: true });
|
|
17718
|
+
const control = this.control();
|
|
17719
|
+
control.markAsDirty();
|
|
17720
|
+
control.markAsTouched();
|
|
17657
17721
|
}
|
|
17658
17722
|
/**
|
|
17659
17723
|
* Exposes metadata setter for integration with dynamic form loader.
|
|
@@ -17669,8 +17733,71 @@ class MaterialFileUploadComponent extends SimpleBaseInputComponent {
|
|
|
17669
17733
|
allowsMultiple() {
|
|
17670
17734
|
return this.metadataRecord()?.['multiple'] === true;
|
|
17671
17735
|
}
|
|
17736
|
+
imagePreviewEnabled() {
|
|
17737
|
+
const metadata = this.metadataRecord();
|
|
17738
|
+
if (metadata?.['imagePreview'] === true)
|
|
17739
|
+
return true;
|
|
17740
|
+
if (metadata?.['preview'] === 'image')
|
|
17741
|
+
return true;
|
|
17742
|
+
const accept = this.fileAccept()?.toLowerCase() ?? '';
|
|
17743
|
+
return accept.includes('image/');
|
|
17744
|
+
}
|
|
17672
17745
|
isInteractionDisabled() {
|
|
17673
|
-
return this.
|
|
17746
|
+
return this.isInteractionBlockedByState();
|
|
17747
|
+
}
|
|
17748
|
+
clearSelectedFiles(options = {}) {
|
|
17749
|
+
this.clearPreview();
|
|
17750
|
+
this.selectedFiles.set([]);
|
|
17751
|
+
this.clearFileErrors();
|
|
17752
|
+
this.setValue(this.allowsMultiple() ? [] : null, { emitEvent: true });
|
|
17753
|
+
const control = this.control();
|
|
17754
|
+
control.markAsDirty();
|
|
17755
|
+
control.markAsTouched();
|
|
17756
|
+
if (options.resetInput !== false) {
|
|
17757
|
+
const input = this.elementRef.nativeElement.querySelector('input[type="file"]');
|
|
17758
|
+
if (input)
|
|
17759
|
+
input.value = '';
|
|
17760
|
+
}
|
|
17761
|
+
}
|
|
17762
|
+
clearLabel() {
|
|
17763
|
+
return this.dynamicFieldsText('fileUpload.clearSelection', 'Clear');
|
|
17764
|
+
}
|
|
17765
|
+
clearAriaLabel() {
|
|
17766
|
+
return this.dynamicFieldsText('fileUpload.clearSelectionAriaLabel', 'Clear selected file');
|
|
17767
|
+
}
|
|
17768
|
+
selectedSummaryAriaLabel() {
|
|
17769
|
+
return this.dynamicFieldsText('fileUpload.selectedSummaryAriaLabel', 'Selected file');
|
|
17770
|
+
}
|
|
17771
|
+
fileInputDescribedBy() {
|
|
17772
|
+
const ids = [
|
|
17773
|
+
this.metadata()?.ariaDescribedby,
|
|
17774
|
+
this.hasValidationError() ? this.errorId() : null,
|
|
17775
|
+
this.metadata()?.hint && !this.hasValidationError() ? this.hintId() : null,
|
|
17776
|
+
]
|
|
17777
|
+
.map((id) => (typeof id === 'string' ? id.trim() : ''))
|
|
17778
|
+
.filter(Boolean);
|
|
17779
|
+
return ids.length ? ids.join(' ') : null;
|
|
17780
|
+
}
|
|
17781
|
+
hintId() {
|
|
17782
|
+
return `${this.componentId()}-hint`;
|
|
17783
|
+
}
|
|
17784
|
+
errorId() {
|
|
17785
|
+
return `${this.componentId()}-error`;
|
|
17786
|
+
}
|
|
17787
|
+
previewAltText() {
|
|
17788
|
+
const label = this.metadataRecord()?.['previewAlt'];
|
|
17789
|
+
if (typeof label === 'string' && label.trim())
|
|
17790
|
+
return label.trim();
|
|
17791
|
+
return this.dynamicFieldsText('fileUpload.previewAlt', 'Selected image preview');
|
|
17792
|
+
}
|
|
17793
|
+
writeValue(value) {
|
|
17794
|
+
super.writeValue(value);
|
|
17795
|
+
this.syncSelectedFilesFromValue(value);
|
|
17796
|
+
}
|
|
17797
|
+
ngOnDestroy() {
|
|
17798
|
+
this.externalValueSyncSubscription.unsubscribe();
|
|
17799
|
+
this.clearPreview();
|
|
17800
|
+
super.ngOnDestroy();
|
|
17674
17801
|
}
|
|
17675
17802
|
/**
|
|
17676
17803
|
* CSS classes specific to the file upload wrapper.
|
|
@@ -17678,12 +17805,168 @@ class MaterialFileUploadComponent extends SimpleBaseInputComponent {
|
|
|
17678
17805
|
getSpecificCssClasses() {
|
|
17679
17806
|
return ['pdx-material-file-upload'];
|
|
17680
17807
|
}
|
|
17808
|
+
onActiveControlChanged(previousControl, currentControl) {
|
|
17809
|
+
super.onActiveControlChanged(previousControl, currentControl);
|
|
17810
|
+
this.externalValueSyncSubscription.unsubscribe();
|
|
17811
|
+
this.externalValueSyncSubscription = currentControl.valueChanges.subscribe((value) => {
|
|
17812
|
+
this.syncSelectedFilesFromValue(value);
|
|
17813
|
+
});
|
|
17814
|
+
this.syncSelectedFilesFromValue(currentControl.value);
|
|
17815
|
+
}
|
|
17681
17816
|
metadataRecord() {
|
|
17682
17817
|
const metadata = this.metadata();
|
|
17683
17818
|
return metadata && typeof metadata === 'object'
|
|
17684
17819
|
? metadata
|
|
17685
17820
|
: null;
|
|
17686
17821
|
}
|
|
17822
|
+
updatePreview(files) {
|
|
17823
|
+
this.clearPreview();
|
|
17824
|
+
if (!this.imagePreviewEnabled())
|
|
17825
|
+
return;
|
|
17826
|
+
const image = files.find((file) => this.isImageFile(file));
|
|
17827
|
+
if (!image || typeof URL === 'undefined' || typeof URL.createObjectURL !== 'function') {
|
|
17828
|
+
return;
|
|
17829
|
+
}
|
|
17830
|
+
this.previewUrl.set(URL.createObjectURL(image));
|
|
17831
|
+
}
|
|
17832
|
+
clearPreview() {
|
|
17833
|
+
const current = this.previewUrl();
|
|
17834
|
+
if (current && typeof URL !== 'undefined' && typeof URL.revokeObjectURL === 'function') {
|
|
17835
|
+
URL.revokeObjectURL(current);
|
|
17836
|
+
}
|
|
17837
|
+
this.previewUrl.set(null);
|
|
17838
|
+
}
|
|
17839
|
+
validateSelectedFiles(files) {
|
|
17840
|
+
const maxFileSize = this.maxFileSize();
|
|
17841
|
+
const maxFiles = this.maxFiles();
|
|
17842
|
+
if (maxFiles !== null && files.length > maxFiles) {
|
|
17843
|
+
return {
|
|
17844
|
+
key: 'maxFiles',
|
|
17845
|
+
message: this.dynamicFieldsText('validation.maxFiles', 'Too many files selected', {
|
|
17846
|
+
count: maxFiles,
|
|
17847
|
+
}),
|
|
17848
|
+
};
|
|
17849
|
+
}
|
|
17850
|
+
for (const file of files) {
|
|
17851
|
+
if (!this.isAcceptedFile(file)) {
|
|
17852
|
+
return {
|
|
17853
|
+
key: 'fileType',
|
|
17854
|
+
message: this.dynamicFieldsText('validation.fileType', 'File type is not allowed'),
|
|
17855
|
+
};
|
|
17856
|
+
}
|
|
17857
|
+
if (maxFileSize !== null && file.size > maxFileSize) {
|
|
17858
|
+
return {
|
|
17859
|
+
key: 'maxFileSize',
|
|
17860
|
+
message: this.dynamicFieldsText('validation.maxFileSize', 'File exceeds the maximum size'),
|
|
17861
|
+
};
|
|
17862
|
+
}
|
|
17863
|
+
}
|
|
17864
|
+
return null;
|
|
17865
|
+
}
|
|
17866
|
+
isAcceptedFile(file) {
|
|
17867
|
+
const accept = this.fileAccept();
|
|
17868
|
+
if (!accept)
|
|
17869
|
+
return true;
|
|
17870
|
+
const fileName = file.name.toLowerCase();
|
|
17871
|
+
const fileType = file.type.toLowerCase();
|
|
17872
|
+
return accept
|
|
17873
|
+
.split(',')
|
|
17874
|
+
.map((token) => token.trim().toLowerCase())
|
|
17875
|
+
.filter(Boolean)
|
|
17876
|
+
.some((token) => {
|
|
17877
|
+
if (token === '*/*')
|
|
17878
|
+
return true;
|
|
17879
|
+
if (token === 'image/*')
|
|
17880
|
+
return fileType.startsWith('image/') || this.hasKnownImageExtension(fileName);
|
|
17881
|
+
if (token.endsWith('/*'))
|
|
17882
|
+
return fileType.startsWith(token.slice(0, -1));
|
|
17883
|
+
if (token.startsWith('.'))
|
|
17884
|
+
return fileName.endsWith(token);
|
|
17885
|
+
return fileType === token;
|
|
17886
|
+
});
|
|
17887
|
+
}
|
|
17888
|
+
maxFileSize() {
|
|
17889
|
+
const raw = this.metadataRecord()?.['maxFileSize'];
|
|
17890
|
+
const value = typeof raw === 'number' ? raw : Number(raw);
|
|
17891
|
+
return Number.isFinite(value) && value > 0 ? value : null;
|
|
17892
|
+
}
|
|
17893
|
+
maxFiles() {
|
|
17894
|
+
const raw = this.metadataRecord()?.['maxFiles'];
|
|
17895
|
+
const value = typeof raw === 'number' ? raw : Number(raw);
|
|
17896
|
+
return Number.isInteger(value) && value > 0 ? value : null;
|
|
17897
|
+
}
|
|
17898
|
+
applyFileError(error) {
|
|
17899
|
+
const control = this.control();
|
|
17900
|
+
const current = control.errors ?? {};
|
|
17901
|
+
control.setErrors({
|
|
17902
|
+
...current,
|
|
17903
|
+
[error.key]: { message: error.message },
|
|
17904
|
+
});
|
|
17905
|
+
control.markAsDirty();
|
|
17906
|
+
control.markAsTouched();
|
|
17907
|
+
}
|
|
17908
|
+
clearFileErrors() {
|
|
17909
|
+
const control = this.control();
|
|
17910
|
+
const current = control.errors;
|
|
17911
|
+
if (!current)
|
|
17912
|
+
return;
|
|
17913
|
+
const { fileType: _fileType, maxFileSize: _maxFileSize, maxFiles: _maxFiles, ...rest } = current;
|
|
17914
|
+
control.setErrors(Object.keys(rest).length ? rest : null);
|
|
17915
|
+
}
|
|
17916
|
+
syncSelectedFilesFromValue(value) {
|
|
17917
|
+
const files = this.extractFilesFromValue(value);
|
|
17918
|
+
this.selectedFiles.set(files);
|
|
17919
|
+
this.updatePreview(files);
|
|
17920
|
+
}
|
|
17921
|
+
extractFilesFromValue(value) {
|
|
17922
|
+
if (!value)
|
|
17923
|
+
return [];
|
|
17924
|
+
if (this.isFile(value))
|
|
17925
|
+
return [value];
|
|
17926
|
+
if (Array.isArray(value))
|
|
17927
|
+
return value.filter((item) => this.isFile(item));
|
|
17928
|
+
return [];
|
|
17929
|
+
}
|
|
17930
|
+
isFile(value) {
|
|
17931
|
+
return typeof File !== 'undefined' && value instanceof File;
|
|
17932
|
+
}
|
|
17933
|
+
isImageFile(file) {
|
|
17934
|
+
return file.type.toLowerCase().startsWith('image/') || this.hasKnownImageExtension(file.name.toLowerCase());
|
|
17935
|
+
}
|
|
17936
|
+
hasKnownImageExtension(fileName) {
|
|
17937
|
+
return [
|
|
17938
|
+
'.apng',
|
|
17939
|
+
'.avif',
|
|
17940
|
+
'.bmp',
|
|
17941
|
+
'.gif',
|
|
17942
|
+
'.jpeg',
|
|
17943
|
+
'.jpg',
|
|
17944
|
+
'.png',
|
|
17945
|
+
'.svg',
|
|
17946
|
+
'.webp',
|
|
17947
|
+
].some((extension) => fileName.endsWith(extension));
|
|
17948
|
+
}
|
|
17949
|
+
formatBytes(bytes) {
|
|
17950
|
+
const units = [
|
|
17951
|
+
this.dynamicFieldsText('fileUpload.sizeUnitBytes', 'B'),
|
|
17952
|
+
this.dynamicFieldsText('fileUpload.sizeUnitKb', 'KB'),
|
|
17953
|
+
this.dynamicFieldsText('fileUpload.sizeUnitMb', 'MB'),
|
|
17954
|
+
this.dynamicFieldsText('fileUpload.sizeUnitGb', 'GB'),
|
|
17955
|
+
];
|
|
17956
|
+
if (!Number.isFinite(bytes) || bytes <= 0)
|
|
17957
|
+
return `0 ${units[0]}`;
|
|
17958
|
+
let value = bytes;
|
|
17959
|
+
let index = 0;
|
|
17960
|
+
while (value >= 1024 && index < units.length - 1) {
|
|
17961
|
+
value /= 1024;
|
|
17962
|
+
index += 1;
|
|
17963
|
+
}
|
|
17964
|
+
const rounded = value >= 10 || index === 0 ? Math.round(value) : Math.round(value * 10) / 10;
|
|
17965
|
+
return `${rounded} ${units[index]}`;
|
|
17966
|
+
}
|
|
17967
|
+
dynamicFieldsText(keySuffix, fallback, params) {
|
|
17968
|
+
return this.i18n.t(`praxis.dynamicFields.${keySuffix}`, params, fallback, 'dynamicFields');
|
|
17969
|
+
}
|
|
17687
17970
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: MaterialFileUploadComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
17688
17971
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: MaterialFileUploadComponent, isStandalone: true, selector: "pdx-material-file-upload", inputs: { readonlyMode: "readonlyMode", disabledMode: "disabledMode", visible: "visible", presentationMode: "presentationMode" }, host: { properties: { "class": "componentCssClasses()", "class.praxis-disabled": "disabledMode", "style.display": "visible ? null : \"none\"", "attr.aria-hidden": "visible ? null : \"true\"", "attr.data-field-type": "\"file-upload\"", "attr.data-field-name": "metadata()?.name", "attr.data-component-id": "componentId()" } }, providers: [
|
|
17689
17972
|
{
|
|
@@ -17706,24 +17989,51 @@ class MaterialFileUploadComponent extends SimpleBaseInputComponent {
|
|
|
17706
17989
|
[attr.accept]="fileAccept()"
|
|
17707
17990
|
[attr.multiple]="allowsMultiple() ? '' : null"
|
|
17708
17991
|
[disabled]="isInteractionDisabled()"
|
|
17709
|
-
[attr.aria-disabled]="
|
|
17992
|
+
[attr.aria-disabled]="isInteractionDisabled() ? 'true' : null"
|
|
17993
|
+
[attr.aria-describedby]="fileInputDescribedBy()"
|
|
17994
|
+
[attr.aria-invalid]="hasValidationError() ? 'true' : null"
|
|
17995
|
+
[attr.aria-label]="inputAriaLabel()"
|
|
17710
17996
|
/>
|
|
17997
|
+
@if (selectedFiles().length) {
|
|
17998
|
+
<div
|
|
17999
|
+
class="pdx-file-upload__selection"
|
|
18000
|
+
aria-live="polite"
|
|
18001
|
+
[attr.aria-label]="selectedSummaryAriaLabel()"
|
|
18002
|
+
>
|
|
18003
|
+
@if (previewUrl()) {
|
|
18004
|
+
<img
|
|
18005
|
+
class="pdx-file-upload__preview"
|
|
18006
|
+
[src]="previewUrl()!"
|
|
18007
|
+
[attr.alt]="previewAltText()"
|
|
18008
|
+
/>
|
|
18009
|
+
}
|
|
18010
|
+
<div class="pdx-file-upload__summary">
|
|
18011
|
+
<span class="pdx-file-upload__summary-title">{{ selectedSummaryText() }}</span>
|
|
18012
|
+
<span class="pdx-file-upload__summary-detail">{{ selectedDetailText() }}</span>
|
|
18013
|
+
</div>
|
|
18014
|
+
<button
|
|
18015
|
+
class="pdx-file-upload__clear"
|
|
18016
|
+
type="button"
|
|
18017
|
+
[disabled]="isInteractionDisabled()"
|
|
18018
|
+
[attr.aria-label]="clearAriaLabel()"
|
|
18019
|
+
(click)="clearSelectedFiles()"
|
|
18020
|
+
>
|
|
18021
|
+
{{ clearLabel() }}
|
|
18022
|
+
</button>
|
|
18023
|
+
</div>
|
|
18024
|
+
}
|
|
17711
18025
|
@if (hasValidationError()) {
|
|
17712
|
-
<div class="error">{{ errorMessage() }}</div>
|
|
18026
|
+
<div class="error" [attr.id]="errorId()">{{ errorMessage() }}</div>
|
|
17713
18027
|
}
|
|
17714
18028
|
@if (metadata()?.hint && !hasValidationError()) {
|
|
17715
|
-
<div class="hint">{{ metadata()!.hint }}</div>
|
|
18029
|
+
<div class="hint" [attr.id]="hintId()">{{ metadata()!.hint }}</div>
|
|
17716
18030
|
}
|
|
17717
18031
|
</div>
|
|
17718
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
|
|
18032
|
+
`, isInline: true, styles: [".pdx-file-upload{display:flex;flex-direction:column;gap:8px}.pdx-file-upload label{font-size:12px;font-weight:500;line-height:1.25;color:var(--md-sys-color-on-surface, rgba(0, 0, 0, .87))}.pdx-file-upload input[type=file]{max-width:100%}.pdx-file-upload__selection{display:flex;align-items:center;gap:10px;min-width:0;padding:8px;border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .16));border-radius:8px;background:var(--md-sys-color-surface-container-low, rgba(0, 0, 0, .03))}.pdx-file-upload__preview{width:48px;height:48px;border-radius:9999px;object-fit:cover;flex:0 0 48px;border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .16))}.pdx-file-upload__summary{display:flex;min-width:0;flex:1 1 auto;flex-direction:column;gap:2px}.pdx-file-upload__summary-title,.pdx-file-upload__summary-detail{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pdx-file-upload__summary-title{font-size:13px;font-weight:600;color:var(--md-sys-color-on-surface, rgba(0, 0, 0, .87))}.pdx-file-upload__summary-detail,.hint{font-size:12px;color:var(--md-sys-color-on-surface-variant, rgba(0, 0, 0, .6))}.pdx-file-upload__clear{border:0;background:transparent;color:var(--md-sys-color-primary, #6750a4);font:inherit;font-size:12px;font-weight:600;cursor:pointer;padding:6px}.pdx-file-upload__clear:disabled{cursor:default;opacity:.5}.error{color:var(--md-sys-color-error, #b3261e);font-size:12px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
|
|
17719
18033
|
}
|
|
17720
18034
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: MaterialFileUploadComponent, decorators: [{
|
|
17721
18035
|
type: Component,
|
|
17722
|
-
args: [{
|
|
17723
|
-
selector: 'pdx-material-file-upload',
|
|
17724
|
-
standalone: true,
|
|
17725
|
-
imports: [ReactiveFormsModule, MatTooltipModule],
|
|
17726
|
-
template: `
|
|
18036
|
+
args: [{ selector: 'pdx-material-file-upload', standalone: true, imports: [ReactiveFormsModule, MatTooltipModule], template: `
|
|
17727
18037
|
<div
|
|
17728
18038
|
class="pdx-file-upload"
|
|
17729
18039
|
[matTooltip]="tooltipEnabled() ? errorMessage() : null"
|
|
@@ -17738,24 +18048,53 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
17738
18048
|
[attr.accept]="fileAccept()"
|
|
17739
18049
|
[attr.multiple]="allowsMultiple() ? '' : null"
|
|
17740
18050
|
[disabled]="isInteractionDisabled()"
|
|
17741
|
-
[attr.aria-disabled]="
|
|
18051
|
+
[attr.aria-disabled]="isInteractionDisabled() ? 'true' : null"
|
|
18052
|
+
[attr.aria-describedby]="fileInputDescribedBy()"
|
|
18053
|
+
[attr.aria-invalid]="hasValidationError() ? 'true' : null"
|
|
18054
|
+
[attr.aria-label]="inputAriaLabel()"
|
|
17742
18055
|
/>
|
|
18056
|
+
@if (selectedFiles().length) {
|
|
18057
|
+
<div
|
|
18058
|
+
class="pdx-file-upload__selection"
|
|
18059
|
+
aria-live="polite"
|
|
18060
|
+
[attr.aria-label]="selectedSummaryAriaLabel()"
|
|
18061
|
+
>
|
|
18062
|
+
@if (previewUrl()) {
|
|
18063
|
+
<img
|
|
18064
|
+
class="pdx-file-upload__preview"
|
|
18065
|
+
[src]="previewUrl()!"
|
|
18066
|
+
[attr.alt]="previewAltText()"
|
|
18067
|
+
/>
|
|
18068
|
+
}
|
|
18069
|
+
<div class="pdx-file-upload__summary">
|
|
18070
|
+
<span class="pdx-file-upload__summary-title">{{ selectedSummaryText() }}</span>
|
|
18071
|
+
<span class="pdx-file-upload__summary-detail">{{ selectedDetailText() }}</span>
|
|
18072
|
+
</div>
|
|
18073
|
+
<button
|
|
18074
|
+
class="pdx-file-upload__clear"
|
|
18075
|
+
type="button"
|
|
18076
|
+
[disabled]="isInteractionDisabled()"
|
|
18077
|
+
[attr.aria-label]="clearAriaLabel()"
|
|
18078
|
+
(click)="clearSelectedFiles()"
|
|
18079
|
+
>
|
|
18080
|
+
{{ clearLabel() }}
|
|
18081
|
+
</button>
|
|
18082
|
+
</div>
|
|
18083
|
+
}
|
|
17743
18084
|
@if (hasValidationError()) {
|
|
17744
|
-
<div class="error">{{ errorMessage() }}</div>
|
|
18085
|
+
<div class="error" [attr.id]="errorId()">{{ errorMessage() }}</div>
|
|
17745
18086
|
}
|
|
17746
18087
|
@if (metadata()?.hint && !hasValidationError()) {
|
|
17747
|
-
<div class="hint">{{ metadata()!.hint }}</div>
|
|
18088
|
+
<div class="hint" [attr.id]="hintId()">{{ metadata()!.hint }}</div>
|
|
17748
18089
|
}
|
|
17749
18090
|
</div>
|
|
17750
|
-
`,
|
|
17751
|
-
providers: [
|
|
18091
|
+
`, providers: [
|
|
17752
18092
|
{
|
|
17753
18093
|
provide: NG_VALUE_ACCESSOR,
|
|
17754
18094
|
useExisting: forwardRef(() => MaterialFileUploadComponent),
|
|
17755
18095
|
multi: true,
|
|
17756
18096
|
},
|
|
17757
|
-
],
|
|
17758
|
-
host: {
|
|
18097
|
+
], host: {
|
|
17759
18098
|
'[class]': 'componentCssClasses()',
|
|
17760
18099
|
'[class.praxis-disabled]': 'disabledMode',
|
|
17761
18100
|
'[style.display]': 'visible ? null : "none"',
|
|
@@ -17763,8 +18102,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
17763
18102
|
'[attr.data-field-type]': '"file-upload"',
|
|
17764
18103
|
'[attr.data-field-name]': 'metadata()?.name',
|
|
17765
18104
|
'[attr.data-component-id]': 'componentId()',
|
|
17766
|
-
},
|
|
17767
|
-
}]
|
|
18105
|
+
}, styles: [".pdx-file-upload{display:flex;flex-direction:column;gap:8px}.pdx-file-upload label{font-size:12px;font-weight:500;line-height:1.25;color:var(--md-sys-color-on-surface, rgba(0, 0, 0, .87))}.pdx-file-upload input[type=file]{max-width:100%}.pdx-file-upload__selection{display:flex;align-items:center;gap:10px;min-width:0;padding:8px;border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .16));border-radius:8px;background:var(--md-sys-color-surface-container-low, rgba(0, 0, 0, .03))}.pdx-file-upload__preview{width:48px;height:48px;border-radius:9999px;object-fit:cover;flex:0 0 48px;border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .16))}.pdx-file-upload__summary{display:flex;min-width:0;flex:1 1 auto;flex-direction:column;gap:2px}.pdx-file-upload__summary-title,.pdx-file-upload__summary-detail{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pdx-file-upload__summary-title{font-size:13px;font-weight:600;color:var(--md-sys-color-on-surface, rgba(0, 0, 0, .87))}.pdx-file-upload__summary-detail,.hint{font-size:12px;color:var(--md-sys-color-on-surface-variant, rgba(0, 0, 0, .6))}.pdx-file-upload__clear{border:0;background:transparent;color:var(--md-sys-color-primary, #6750a4);font:inherit;font-size:12px;font-weight:600;cursor:pointer;padding:6px}.pdx-file-upload__clear:disabled{cursor:default;opacity:.5}.error{color:var(--md-sys-color-error, #b3261e);font-size:12px}\n"] }]
|
|
17768
18106
|
}], propDecorators: { readonlyMode: [{
|
|
17769
18107
|
type: Input
|
|
17770
18108
|
}], disabledMode: [{
|
|
@@ -43619,7 +43957,7 @@ class InlineDistanceRadiusComponent extends InlineRangeSliderComponent {
|
|
|
43619
43957
|
const subtitle = String(md.distanceSubtitle ?? md.inlinePanelSubtitle ?? md.inlineSubtitle ?? md.hint ?? '').trim();
|
|
43620
43958
|
if (subtitle.length)
|
|
43621
43959
|
return subtitle;
|
|
43622
|
-
return this.distanceText('inlineDistance.panelSubtitle', '
|
|
43960
|
+
return this.distanceText('inlineDistance.panelSubtitle', 'Visualização radial com controle de raio e unidade');
|
|
43623
43961
|
}
|
|
43624
43962
|
unitToggleAriaLabel() {
|
|
43625
43963
|
return this.distanceText('inlineDistance.unitToggleAriaLabel', 'Unidade de distancia atual: {{unit}}', {
|
|
@@ -59414,7 +59752,7 @@ const PDX_INLINE_DATE_RANGE_COMPONENT_METADATA = {
|
|
|
59414
59752
|
selector: 'pdx-inline-date-range',
|
|
59415
59753
|
component: InlineDateRangeComponent,
|
|
59416
59754
|
friendlyName: 'Inline Date Range',
|
|
59417
|
-
description: 'Intervalo de datas compacto para barras de filtro
|
|
59755
|
+
description: 'Intervalo de datas compacto para barras de filtro dinâmico, com autosize e presets rápidos no overlay do calendário.',
|
|
59418
59756
|
icon: 'date_range',
|
|
59419
59757
|
inputs: [
|
|
59420
59758
|
{ name: 'metadata', type: 'MaterialDateRangeMetadata', description: 'Configuração do campo' },
|
|
@@ -59432,10 +59770,10 @@ const PDX_INLINE_TIME_COMPONENT_METADATA = {
|
|
|
59432
59770
|
selector: 'pdx-inline-time',
|
|
59433
59771
|
component: InlineTimeComponent,
|
|
59434
59772
|
friendlyName: 'Inline Time',
|
|
59435
|
-
description: 'Timepicker compacto para barras de filtro
|
|
59773
|
+
description: 'Timepicker compacto para barras de filtro dinâmico, com largura por conteúdo e seleção inline em lista ou colunas Hor/Min/Seg.',
|
|
59436
59774
|
icon: 'schedule',
|
|
59437
59775
|
inputs: [
|
|
59438
|
-
{ name: 'metadata', type: 'MaterialTimepickerMetadata', description: '
|
|
59776
|
+
{ name: 'metadata', type: 'MaterialTimepickerMetadata', description: 'Configuração do campo' },
|
|
59439
59777
|
{ name: 'readonlyMode', type: 'boolean', default: false, description: 'Define modo somente leitura' },
|
|
59440
59778
|
{ name: 'disabledMode', type: 'boolean', default: false, description: 'Desabilita o campo' },
|
|
59441
59779
|
{ name: 'visible', type: 'boolean', default: true, description: 'Controla a visibilidade' },
|
|
@@ -59453,7 +59791,7 @@ const PDX_INLINE_TIME_RANGE_COMPONENT_METADATA = {
|
|
|
59453
59791
|
description: 'Intervalo de horário compacto para barras de filtro dinâmico, com pill responsiva, slider de faixa, atalhos rápidos e popover não-modal com foco de teclado tratado para uso corporativo.',
|
|
59454
59792
|
icon: 'schedule',
|
|
59455
59793
|
inputs: [
|
|
59456
|
-
{ name: 'metadata', type: 'MaterialTimeRangeMetadata', description: '
|
|
59794
|
+
{ name: 'metadata', type: 'MaterialTimeRangeMetadata', description: 'Configuração do campo' },
|
|
59457
59795
|
{ name: 'readonlyMode', type: 'boolean', default: false, description: 'Define modo somente leitura' },
|
|
59458
59796
|
{ name: 'disabledMode', type: 'boolean', default: false, description: 'Desabilita o campo' },
|
|
59459
59797
|
{ name: 'visible', type: 'boolean', default: true, description: 'Controla a visibilidade' },
|
|
@@ -59468,10 +59806,10 @@ const PDX_INLINE_TREE_SELECT_COMPONENT_METADATA = {
|
|
|
59468
59806
|
selector: 'pdx-inline-tree-select',
|
|
59469
59807
|
component: InlineTreeSelectComponent,
|
|
59470
59808
|
friendlyName: 'Inline Tree Select',
|
|
59471
|
-
description: '
|
|
59809
|
+
description: 'Seleção hierárquica compacta para barras de filtro dinâmico, com busca no popover e resumo em pill.',
|
|
59472
59810
|
icon: 'account_tree',
|
|
59473
59811
|
inputs: [
|
|
59474
|
-
{ name: 'metadata', type: 'MaterialTreeSelectMetadata', description: '
|
|
59812
|
+
{ name: 'metadata', type: 'MaterialTreeSelectMetadata', description: 'Configuração do campo' },
|
|
59475
59813
|
{ name: 'readonlyMode', type: 'boolean', default: false, description: 'Define modo somente leitura' },
|
|
59476
59814
|
{ name: 'disabledMode', type: 'boolean', default: false, description: 'Desabilita o campo' },
|
|
59477
59815
|
{ name: 'visible', type: 'boolean', default: true, description: 'Controla a visibilidade' },
|
|
@@ -59504,14 +59842,14 @@ const PDX_INLINE_DISTANCE_RADIUS_COMPONENT_METADATA = {
|
|
|
59504
59842
|
selector: 'pdx-inline-distance-radius',
|
|
59505
59843
|
component: InlineDistanceRadiusComponent,
|
|
59506
59844
|
friendlyName: 'Inline Distance Radius',
|
|
59507
|
-
description: 'Filtro inline de raio de
|
|
59845
|
+
description: 'Filtro inline de raio de distância com visual radial, slider single/range, toggle de unidade (km/mi) e presets.',
|
|
59508
59846
|
icon: 'place',
|
|
59509
59847
|
inputs: [
|
|
59510
|
-
{ name: 'metadata', type: 'MaterialRangeSliderMetadata', description: '
|
|
59848
|
+
{ name: 'metadata', type: 'MaterialRangeSliderMetadata', description: 'Configuração do campo' },
|
|
59511
59849
|
{ name: 'readonlyMode', type: 'boolean', default: false, description: 'Define modo somente leitura' },
|
|
59512
59850
|
{ name: 'disabledMode', type: 'boolean', default: false, description: 'Desabilita o campo' },
|
|
59513
59851
|
{ name: 'visible', type: 'boolean', default: true, description: 'Controla a visibilidade' },
|
|
59514
|
-
{ name: 'presentationMode', type: 'boolean', default: false, description: 'Modo de
|
|
59852
|
+
{ name: 'presentationMode', type: 'boolean', default: false, description: 'Modo de apresentação' },
|
|
59515
59853
|
],
|
|
59516
59854
|
tags: ['widget', 'field', 'distance', 'radius', 'filter', 'inline'],
|
|
59517
59855
|
lib: '@praxisui/dynamic-fields',
|
|
@@ -59522,14 +59860,14 @@ const PDX_INLINE_PIPELINE_STATUS_COMPONENT_METADATA = {
|
|
|
59522
59860
|
selector: 'pdx-inline-pipeline-status',
|
|
59523
59861
|
component: InlinePipelineStatusComponent,
|
|
59524
59862
|
friendlyName: 'Inline Pipeline Status',
|
|
59525
|
-
description: 'Filtro inline de status/etapas com popover, barra segmentada e
|
|
59863
|
+
description: 'Filtro inline de status/etapas com popover, barra segmentada e seleção single ou múltipla totalmente configurável por metadados.',
|
|
59526
59864
|
icon: 'timeline',
|
|
59527
59865
|
inputs: [
|
|
59528
|
-
{ name: 'metadata', type: 'MaterialSelectMetadata', description: '
|
|
59866
|
+
{ name: 'metadata', type: 'MaterialSelectMetadata', description: 'Configuração do campo' },
|
|
59529
59867
|
{ name: 'readonlyMode', type: 'boolean', default: false, description: 'Define modo somente leitura' },
|
|
59530
59868
|
{ name: 'disabledMode', type: 'boolean', default: false, description: 'Desabilita o campo' },
|
|
59531
59869
|
{ name: 'visible', type: 'boolean', default: true, description: 'Controla a visibilidade' },
|
|
59532
|
-
{ name: 'presentationMode', type: 'boolean', default: false, description: 'Modo de
|
|
59870
|
+
{ name: 'presentationMode', type: 'boolean', default: false, description: 'Modo de apresentação' },
|
|
59533
59871
|
],
|
|
59534
59872
|
tags: ['widget', 'field', 'pipeline', 'status', 'filter', 'inline', 'multiselect'],
|
|
59535
59873
|
lib: '@praxisui/dynamic-fields',
|
|
@@ -59543,7 +59881,7 @@ const PDX_INLINE_SCORE_PRIORITY_COMPONENT_METADATA = {
|
|
|
59543
59881
|
description: 'Filtro inline de score/prioridade com faixa colorida, slider single/range, bandas configuráveis por metadados preservadas integralmente para semântica decisória, rótulos de escala com autoajuste de densidade e painel em popover não-modal.',
|
|
59544
59882
|
icon: 'speed',
|
|
59545
59883
|
inputs: [
|
|
59546
|
-
{ name: 'metadata', type: 'MaterialRangeSliderMetadata', description: '
|
|
59884
|
+
{ name: 'metadata', type: 'MaterialRangeSliderMetadata', description: 'Configuração do campo' },
|
|
59547
59885
|
{ name: 'readonlyMode', type: 'boolean', default: false, description: 'Define modo somente leitura' },
|
|
59548
59886
|
{ name: 'disabledMode', type: 'boolean', default: false, description: 'Desabilita o campo' },
|
|
59549
59887
|
{ name: 'visible', type: 'boolean', default: true, description: 'Controla a visibilidade' },
|
|
@@ -59594,10 +59932,10 @@ const PDX_INLINE_COLOR_LABEL_COMPONENT_METADATA = {
|
|
|
59594
59932
|
selector: 'pdx-inline-color-label',
|
|
59595
59933
|
component: InlineColorLabelComponent,
|
|
59596
59934
|
friendlyName: 'Inline Color Label',
|
|
59597
|
-
description: 'Filtro inline de cor/label com grid de cores,
|
|
59935
|
+
description: 'Filtro inline de cor/label com grid de cores, seleção visual e badges removíveis.',
|
|
59598
59936
|
icon: 'palette',
|
|
59599
59937
|
inputs: [
|
|
59600
|
-
{ name: 'metadata', type: 'MaterialSelectMetadata', description: '
|
|
59938
|
+
{ name: 'metadata', type: 'MaterialSelectMetadata', description: 'Configuração do campo' },
|
|
59601
59939
|
{ name: 'readonlyMode', type: 'boolean', default: false, description: 'Define modo somente leitura' },
|
|
59602
59940
|
{ name: 'disabledMode', type: 'boolean', default: false, description: 'Desabilita o campo' },
|
|
59603
59941
|
{ name: 'visible', type: 'boolean', default: true, description: 'Controla a visibilidade' },
|
|
@@ -61265,7 +61603,7 @@ const INLINE_DISTANCE_RADIUS_PREVIEW_METADATA = {
|
|
|
61265
61603
|
distanceUnit: 'km',
|
|
61266
61604
|
distanceBaseUnit: 'km',
|
|
61267
61605
|
distanceAllowUnitToggle: true,
|
|
61268
|
-
distanceSubtitle: '
|
|
61606
|
+
distanceSubtitle: 'Visualização radial com controle de raio e unidade',
|
|
61269
61607
|
distanceRadialRings: 5,
|
|
61270
61608
|
distanceAccentColor: '#3f5be6',
|
|
61271
61609
|
inlineAutoSize: {
|
|
@@ -62370,10 +62708,13 @@ const DYNAMIC_FIELDS_PLAYGROUND_CATALOG = [
|
|
|
62370
62708
|
apiPath: jsonApiPath('material-file-upload/pdx-material-file-upload.json-api.md'),
|
|
62371
62709
|
metadata: {
|
|
62372
62710
|
accept: '.pdf,.png,.jpg',
|
|
62373
|
-
|
|
62711
|
+
maxFileSize: 4194304,
|
|
62712
|
+
maxFiles: 1,
|
|
62713
|
+
imagePreview: true,
|
|
62714
|
+
hint: 'Select a file locally; image flows show a preview before the host persists the file.',
|
|
62374
62715
|
},
|
|
62375
|
-
snippet: `{ "name": "attachment", "controlType": "upload", "accept": ".pdf,.png,.jpg", "hint": "
|
|
62376
|
-
snippetNote: 'This preview
|
|
62716
|
+
snippet: `{ "name": "attachment", "controlType": "upload", "accept": ".pdf,.png,.jpg", "maxFileSize": 4194304, "maxFiles": 1, "imagePreview": true, "hint": "Select a file locally; image flows show a preview before the host persists the file." }`,
|
|
62717
|
+
snippetNote: 'This preview demonstrates local selection, validation and image preview. Use @praxisui/files-upload for presign, progress and persisted storage.',
|
|
62377
62718
|
}),
|
|
62378
62719
|
createEntry({
|
|
62379
62720
|
id: 'color-input',
|
|
@@ -62479,7 +62820,7 @@ const DYNAMIC_FIELDS_PLAYGROUND_CATALOG = [
|
|
|
62479
62820
|
metadataPatch: {
|
|
62480
62821
|
extra: {
|
|
62481
62822
|
icon: 'person',
|
|
62482
|
-
ariaLabel: 'Avatar com
|
|
62823
|
+
ariaLabel: 'Avatar com ícone de pessoa',
|
|
62483
62824
|
size: 'medium',
|
|
62484
62825
|
fillMode: 'outline',
|
|
62485
62826
|
themeColor: 'primary',
|
|
@@ -64068,7 +64409,7 @@ const DISPLAY_ACTION_AI_CAPABILITIES = {
|
|
|
64068
64409
|
category: 'appearance',
|
|
64069
64410
|
valueKind: 'enum',
|
|
64070
64411
|
allowedValues: ['primary', 'secondary', 'tertiary', 'base', 'info', 'success', 'warning', 'error', 'dark', 'light', 'inverse', 'none'],
|
|
64071
|
-
description: 'Cor
|
|
64412
|
+
description: 'Cor semântica do avatar baseada nos tokens de tema Praxis.',
|
|
64072
64413
|
},
|
|
64073
64414
|
{
|
|
64074
64415
|
path: 'rounded',
|
|
@@ -64212,23 +64553,26 @@ const FILE_UPLOAD_AI_CAPABILITIES = {
|
|
|
64212
64553
|
uploadMethod: ['POST', 'PUT', 'PATCH'],
|
|
64213
64554
|
},
|
|
64214
64555
|
notes: [
|
|
64215
|
-
'Capabilities for file upload controls.',
|
|
64556
|
+
'Capabilities for file upload controls. The baseline pdx-material-file-upload runtime owns local selection, local validation and optional local image preview.',
|
|
64216
64557
|
'Inherits basic capabilities from FieldMetadata (label, hint, validators).',
|
|
64558
|
+
'Persistence capabilities such as uploadUrl, autoUpload, chunkSize, headers, credentials and method must be grounded by @praxisui/files-upload or a backend upload capability; they are not executed by the baseline local selector alone.',
|
|
64217
64559
|
],
|
|
64218
64560
|
capabilities: [
|
|
64219
64561
|
{
|
|
64220
64562
|
path: 'uploadUrl',
|
|
64221
64563
|
category: 'data',
|
|
64222
64564
|
valueKind: 'string',
|
|
64223
|
-
description: 'URL do endpoint para upload de arquivos.',
|
|
64565
|
+
description: 'URL do endpoint para upload de arquivos em fluxo persistente governado.',
|
|
64224
64566
|
intentExamples: ['endpoint de upload de imagens', 'salvar arquivos em /api/docs'],
|
|
64567
|
+
safetyNotes: 'Requer runtime/capability de persistencia como @praxisui/files-upload; o seletor baseline nao executa upload HTTP.',
|
|
64225
64568
|
},
|
|
64226
64569
|
{
|
|
64227
64570
|
path: 'autoUpload',
|
|
64228
64571
|
category: 'behavior',
|
|
64229
64572
|
valueKind: 'boolean',
|
|
64230
|
-
description: 'Se true, inicia o upload automaticamente após a seleção do arquivo.',
|
|
64573
|
+
description: 'Se true, inicia o upload automaticamente após a seleção do arquivo em fluxo persistente governado.',
|
|
64231
64574
|
intentExamples: ['upload automático', 'não iniciar upload imediatamente'],
|
|
64575
|
+
safetyNotes: 'Requer runtime/capability de persistencia; o seletor baseline apenas emite File/File[].',
|
|
64232
64576
|
},
|
|
64233
64577
|
{
|
|
64234
64578
|
path: 'multiple',
|
|
@@ -64244,6 +64588,21 @@ const FILE_UPLOAD_AI_CAPABILITIES = {
|
|
|
64244
64588
|
description: 'Tipos de arquivo aceitos (ex: "image/*", ".pdf").',
|
|
64245
64589
|
intentExamples: ['aceitar apenas imagens', 'apenas PDF'],
|
|
64246
64590
|
},
|
|
64591
|
+
{
|
|
64592
|
+
path: 'imagePreview',
|
|
64593
|
+
category: 'appearance',
|
|
64594
|
+
valueKind: 'boolean',
|
|
64595
|
+
description: 'Exibe preview local para imagens selecionadas antes da persistencia pelo host.',
|
|
64596
|
+
intentExamples: ['mostrar preview da foto escolhida', 'pré-visualizar avatar antes de salvar'],
|
|
64597
|
+
},
|
|
64598
|
+
{
|
|
64599
|
+
path: 'preview',
|
|
64600
|
+
category: 'appearance',
|
|
64601
|
+
valueKind: 'string',
|
|
64602
|
+
allowedValues: ['image'],
|
|
64603
|
+
description: 'Modo de preview local. Use "image" para fluxos de foto/avatar.',
|
|
64604
|
+
safetyNotes: 'Preview local não substitui upload, presign, crop persistido ou validação backend.',
|
|
64605
|
+
},
|
|
64247
64606
|
{
|
|
64248
64607
|
path: 'maxFileSize',
|
|
64249
64608
|
category: 'validation',
|
|
@@ -64270,18 +64629,21 @@ const FILE_UPLOAD_AI_CAPABILITIES = {
|
|
|
64270
64629
|
category: 'behavior',
|
|
64271
64630
|
valueKind: 'number',
|
|
64272
64631
|
description: 'Tamanho dos chunks em bytes para uploads grandes (file chunking).',
|
|
64632
|
+
safetyNotes: 'Aplicavel ao fluxo @praxisui/files-upload ou backend equivalente, nao ao seletor local baseline.',
|
|
64273
64633
|
},
|
|
64274
64634
|
{
|
|
64275
64635
|
path: 'withCredentials',
|
|
64276
64636
|
category: 'data',
|
|
64277
64637
|
valueKind: 'boolean',
|
|
64278
64638
|
description: 'Envia cookies e headers de autorização com a requisição de upload.',
|
|
64639
|
+
safetyNotes: 'Aplicavel ao fluxo @praxisui/files-upload ou backend equivalente, nao ao seletor local baseline.',
|
|
64279
64640
|
},
|
|
64280
64641
|
{
|
|
64281
64642
|
path: 'headers',
|
|
64282
64643
|
category: 'data',
|
|
64283
64644
|
valueKind: 'object',
|
|
64284
64645
|
description: 'Cabeçalhos HTTP personalizados para a requisição de upload.',
|
|
64646
|
+
safetyNotes: 'Aplicavel ao fluxo @praxisui/files-upload ou backend equivalente, nao ao seletor local baseline.',
|
|
64285
64647
|
},
|
|
64286
64648
|
{
|
|
64287
64649
|
path: 'method',
|
|
@@ -64289,6 +64651,7 @@ const FILE_UPLOAD_AI_CAPABILITIES = {
|
|
|
64289
64651
|
valueKind: 'enum',
|
|
64290
64652
|
allowedValues: ['POST', 'PUT', 'PATCH'],
|
|
64291
64653
|
description: 'Método HTTP para a requisição de upload.',
|
|
64654
|
+
safetyNotes: 'Aplicavel ao fluxo @praxisui/files-upload ou backend equivalente, nao ao seletor local baseline.',
|
|
64292
64655
|
},
|
|
64293
64656
|
{
|
|
64294
64657
|
path: 'saveField',
|
|
@@ -66169,7 +66532,7 @@ function mapValuePresentation(value) {
|
|
|
66169
66532
|
const typeToken = String(value.type ?? '').trim();
|
|
66170
66533
|
if (!typeToken || !VALUE_PRESENTATION_TYPES.has(typeToken)) {
|
|
66171
66534
|
if (typeToken) {
|
|
66172
|
-
logger.warn(`[JsonSchemaMapper] Ignorando x-ui.valuePresentation.type
|
|
66535
|
+
logger.warn(`[JsonSchemaMapper] Ignorando x-ui.valuePresentation.type inválido: ${typeToken}`);
|
|
66173
66536
|
}
|
|
66174
66537
|
return undefined;
|
|
66175
66538
|
}
|
|
@@ -66182,7 +66545,7 @@ function mapValuePresentation(value) {
|
|
|
66182
66545
|
presentation.style = styleToken;
|
|
66183
66546
|
}
|
|
66184
66547
|
else {
|
|
66185
|
-
logger.warn(`[JsonSchemaMapper] Ignorando x-ui.valuePresentation.style
|
|
66548
|
+
logger.warn(`[JsonSchemaMapper] Ignorando x-ui.valuePresentation.style inválido: ${styleToken}`);
|
|
66186
66549
|
}
|
|
66187
66550
|
}
|
|
66188
66551
|
const formatToken = String(value.format ?? '').trim();
|