@praxisui/dynamic-fields 8.0.0-beta.20 → 8.0.0-beta.21

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/README.md CHANGED
@@ -115,6 +115,12 @@ Notas:
115
115
  - A classe de tema é decisão do host (`.dark-theme` ou `.theme-dark`/`.theme-light`); mantenha tokens e componentes no mesmo escopo.
116
116
  - Datepicker usa `panelClass="pdx-datepicker-panel"`; personalize o overlay via essa classe no tema do host.
117
117
 
118
+ ### Prefixos Material e labels flutuantes
119
+
120
+ O Angular Material documenta uma limitação real em `mat-form-field` com aparência `fill` ou `outline`: prefixos/sufixos de texto não alinham bem com o label em repouso, e a recomendação oficial atual é usar `floatLabel="always"` nesses casos. A plataforma segue essa recomendação para adornos estruturais permanentes, como swatches de cor e símbolos que fazem parte do valor visual.
121
+
122
+ Não substitua essa política por offsets CSS locais. Offsets dependem de densidade, fonte, idioma, aparência Material e do tamanho do prefixo, e tendem a quebrar quando o Angular Material muda a estrutura MDC interna. Se o Angular Material passar a oferecer suporte nativo melhor para prefixos em `fill`/`outline`, reavalie esta decisão de plataforma e prefira voltar a delegar o alinhamento ao Material.
123
+
118
124
  Peers (instale no app host):
119
125
  - `@angular/core` `^20.1.0`, `@angular/common` `^20.1.0`, `@angular/forms` `^20.1.0`
120
126
  - `@angular/material` `^20.1.0`, `@angular/cdk` `^20.1.0`, `@angular/router` `^20.1.0`
@@ -330,6 +330,9 @@ const PRAXIS_DYNAMIC_FIELDS_EN_US = {
330
330
  'praxis.dynamicFields.entityLookup.dialog.filters.placeholder.between': 'Use start value, end value',
331
331
  'praxis.dynamicFields.entityLookup.dialog.filters.placeholder.date': 'YYYY-MM-DD',
332
332
  'praxis.dynamicFields.entityLookup.dialog.filters.placeholder.default': 'Enter a value',
333
+ 'praxis.dynamicFields.entityLookup.dialog.filters.selectEmpty': 'Select {label}',
334
+ 'praxis.dynamicFields.entityLookup.dialog.filters.startAriaLabel': '{label} start',
335
+ 'praxis.dynamicFields.entityLookup.dialog.filters.endAriaLabel': '{label} end',
333
336
  'praxis.dynamicFields.entityLookup.dialog.filters.operator.contains': 'Operator: contains',
334
337
  'praxis.dynamicFields.entityLookup.dialog.filters.operator.startsWith': 'Operator: starts with',
335
338
  'praxis.dynamicFields.entityLookup.dialog.filters.operator.equals': 'Operator: equals',
@@ -622,6 +625,9 @@ const PRAXIS_DYNAMIC_FIELDS_PT_BR = {
622
625
  'praxis.dynamicFields.entityLookup.dialog.filters.placeholder.between': 'Use valor inicial, valor final',
623
626
  'praxis.dynamicFields.entityLookup.dialog.filters.placeholder.date': 'AAAA-MM-DD',
624
627
  'praxis.dynamicFields.entityLookup.dialog.filters.placeholder.default': 'Digite um valor',
628
+ 'praxis.dynamicFields.entityLookup.dialog.filters.selectEmpty': 'Selecione {label}',
629
+ 'praxis.dynamicFields.entityLookup.dialog.filters.startAriaLabel': '{label} inicial',
630
+ 'praxis.dynamicFields.entityLookup.dialog.filters.endAriaLabel': '{label} final',
625
631
  'praxis.dynamicFields.entityLookup.dialog.filters.operator.contains': 'Operador: contem',
626
632
  'praxis.dynamicFields.entityLookup.dialog.filters.operator.startsWith': 'Operador: comeca com',
627
633
  'praxis.dynamicFields.entityLookup.dialog.filters.operator.equals': 'Operador: igual a',
@@ -6185,6 +6191,7 @@ class MaterialDateRangeComponent extends SimpleBaseInputComponent {
6185
6191
  }, ...(ngDevMode ? [{ debugName: "startAt" }] : []));
6186
6192
  // Overlay state
6187
6193
  overlayOpen = false;
6194
+ pickerOpen = false;
6188
6195
  dateAdapter = inject(DateAdapter);
6189
6196
  picker;
6190
6197
  shouldShowShortcuts = () => !!(this.metadata()?.showShortcuts);
@@ -6286,6 +6293,9 @@ class MaterialDateRangeComponent extends SimpleBaseInputComponent {
6286
6293
  if (!this.shouldPropagateRangeGroupChanges()) {
6287
6294
  return;
6288
6295
  }
6296
+ if (!start && !end && this.isEmptyRangeValue(this.control().value)) {
6297
+ return;
6298
+ }
6289
6299
  const value = {
6290
6300
  startDate: start ?? null,
6291
6301
  endDate: end ?? null,
@@ -6301,25 +6311,85 @@ class MaterialDateRangeComponent extends SimpleBaseInputComponent {
6301
6311
  this.control()
6302
6312
  .valueChanges.pipe(takeUntilDestroyed(this.destroyRef))
6303
6313
  .subscribe((val) => {
6314
+ if (this.pickerOpen) {
6315
+ return;
6316
+ }
6304
6317
  const normalized = this.normalizeDateRangeValue(val);
6318
+ const current = this.rangeGroup.getRawValue();
6319
+ const nextStart = normalized?.startDate ?? null;
6320
+ const nextEnd = normalized?.endDate ?? null;
6321
+ if (this.areDatesEqual(current.start ?? null, nextStart) &&
6322
+ this.areDatesEqual(current.end ?? null, nextEnd)) {
6323
+ return;
6324
+ }
6305
6325
  this.rangeGroup.patchValue({
6306
- start: normalized?.startDate ?? null,
6307
- end: normalized?.endDate ?? null,
6326
+ start: nextStart,
6327
+ end: nextEnd,
6308
6328
  }, { emitEvent: false });
6309
6329
  });
6310
6330
  // Sync overlay with picker lifecycle
6311
6331
  const p = this.picker;
6312
6332
  p.openedStream.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
6333
+ this.pickerOpen = true;
6313
6334
  if (this.shouldShowShortcuts())
6314
6335
  this.openShortcuts();
6315
6336
  });
6316
6337
  p.closedStream.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
6338
+ this.pickerOpen = false;
6317
6339
  this.closeShortcuts();
6340
+ this.propagateRangeValue();
6318
6341
  });
6319
6342
  super.ngOnInit();
6320
6343
  }
6321
6344
  shouldPropagateRangeGroupChanges() {
6322
- return true;
6345
+ return !this.pickerOpen;
6346
+ }
6347
+ propagateRangeValue() {
6348
+ const { start, end } = this.rangeGroup.getRawValue();
6349
+ if (!start && !end) {
6350
+ this.setValue(null);
6351
+ return;
6352
+ }
6353
+ const current = this.control().value;
6354
+ this.setValue({
6355
+ startDate: start ?? null,
6356
+ endDate: end ?? null,
6357
+ ...(current?.preset ? { preset: current.preset } : {}),
6358
+ ...(current?.timezone ? { timezone: current.timezone } : {}),
6359
+ ...(current?.label ? { label: current.label } : {}),
6360
+ ...(current?.isComparison !== undefined ? { isComparison: current.isComparison } : {}),
6361
+ });
6362
+ }
6363
+ isEmptyRangeValue(value) {
6364
+ if (value === null || value === undefined) {
6365
+ return true;
6366
+ }
6367
+ if (!value || typeof value !== 'object') {
6368
+ return false;
6369
+ }
6370
+ const record = value;
6371
+ const start = record['startDate'] ??
6372
+ record['start'] ??
6373
+ record['fromDate'] ??
6374
+ record['from'] ??
6375
+ record['beginDate'] ??
6376
+ record['begin'];
6377
+ const end = record['endDate'] ??
6378
+ record['end'] ??
6379
+ record['toDate'] ??
6380
+ record['to'] ??
6381
+ record['finishDate'] ??
6382
+ record['finish'];
6383
+ return start == null && end == null;
6384
+ }
6385
+ areDatesEqual(left, right) {
6386
+ if (left === right) {
6387
+ return true;
6388
+ }
6389
+ if (!left || !right) {
6390
+ return false;
6391
+ }
6392
+ return left.getTime() === right.getTime();
6323
6393
  }
6324
6394
  async validateField() {
6325
6395
  const errors = await super.validateField();
@@ -6886,6 +6956,9 @@ class MaterialDatepickerComponent extends SimpleBaseInputComponent {
6886
6956
  });
6887
6957
  return st.readonly;
6888
6958
  }
6959
+ isInputReadonly() {
6960
+ return this.isReadonlyEffective() || this.metadata()?.manualInput === false;
6961
+ }
6889
6962
  errorStateMatcher() {
6890
6963
  return getErrorStateMatcherForField(this.metadata());
6891
6964
  }
@@ -6974,7 +7047,7 @@ class MaterialDatepickerComponent extends SimpleBaseInputComponent {
6974
7047
  shouldShowPlaceholder && placeholder ? placeholder : null
6975
7048
  "
6976
7049
  [required]="metadata()?.required || false"
6977
- [readonly]="isReadonlyEffective()"
7050
+ [readonly]="isInputReadonly()"
6978
7051
  [min]="minDate()"
6979
7052
  [max]="maxDate()"
6980
7053
  [attr.aria-disabled]="disabledMode ? 'true' : null"
@@ -7065,7 +7138,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
7065
7138
  shouldShowPlaceholder && placeholder ? placeholder : null
7066
7139
  "
7067
7140
  [required]="metadata()?.required || false"
7068
- [readonly]="isReadonlyEffective()"
7141
+ [readonly]="isInputReadonly()"
7069
7142
  [min]="minDate()"
7070
7143
  [max]="maxDate()"
7071
7144
  [attr.aria-disabled]="disabledMode ? 'true' : null"
@@ -9320,6 +9393,22 @@ class DynamicFieldLoaderDirective {
9320
9393
  this.rebindControlsOnly();
9321
9394
  return;
9322
9395
  }
9396
+ const sameRenderShape = this.hasSameRenderShape(this.lastFieldsSnapshot, newSnapshot);
9397
+ if (sameRenderShape && this.updateExistingFieldMetadata(this.fields || [])) {
9398
+ this.dbg('[DFL] ngOnChanges: updated existing field metadata in place');
9399
+ this.traceLog('ngOnChanges:update-metadata-in-place', {
9400
+ reason: 'same field names/controlTypes with metadata changes',
9401
+ changedKeys: Object.keys(changes || {}),
9402
+ formGroupRefChanged,
9403
+ });
9404
+ this._dbgPrevFieldsRef = this.fields;
9405
+ this._dbgPrevFormGroupRef = this.formGroup;
9406
+ if (formGroupRefChanged) {
9407
+ this.rebindControlsOnly();
9408
+ }
9409
+ this.lastFieldsSnapshot = newSnapshot;
9410
+ return;
9411
+ }
9323
9412
  this._dbgPrevFieldsRef = this.fields;
9324
9413
  this._dbgPrevFormGroupRef = this.formGroup;
9325
9414
  this.traceLog('ngOnChanges:renderFields', {
@@ -9652,6 +9741,69 @@ class DynamicFieldLoaderDirective {
9652
9741
  /**
9653
9742
  * Reatribui apenas os FormControls existentes aos componentes/shells sem refazer a renderização.
9654
9743
  */
9744
+ hasSameRenderShape(previous, next) {
9745
+ if (!previous.length || previous.length !== next.length) {
9746
+ return false;
9747
+ }
9748
+ return next.every((field, index) => {
9749
+ const current = previous[index];
9750
+ return current?.name === field.name && current?.controlType === field.controlType;
9751
+ });
9752
+ }
9753
+ updateExistingFieldMetadata(fields) {
9754
+ if (!fields.length || fields.length !== this.currentOrder.length) {
9755
+ return false;
9756
+ }
9757
+ for (const field of fields) {
9758
+ if (!this.componentRefs.has(field.name) || !this.shellRefs.has(field.name)) {
9759
+ return false;
9760
+ }
9761
+ }
9762
+ for (const [index, field] of fields.entries()) {
9763
+ const fieldWithId = field.id ? field : { ...field, id: field.name };
9764
+ const shellRef = this.shellRefs.get(field.name);
9765
+ if (shellRef) {
9766
+ shellRef.instance.field = fieldWithId;
9767
+ shellRef.instance.index = index;
9768
+ shellRef.instance.control = this.formGroup?.get(field.name);
9769
+ try {
9770
+ shellRef.changeDetectorRef.detectChanges();
9771
+ }
9772
+ catch { }
9773
+ }
9774
+ const compRef = this.componentRefs.get(field.name);
9775
+ if (!compRef) {
9776
+ return false;
9777
+ }
9778
+ const instance = compRef.instance;
9779
+ if (typeof instance.setInputMetadata === 'function') {
9780
+ try {
9781
+ instance.setInputMetadata(fieldWithId);
9782
+ }
9783
+ catch {
9784
+ return false;
9785
+ }
9786
+ }
9787
+ else if (instance?.metadata && typeof instance.metadata === 'function' && 'set' in instance.metadata) {
9788
+ try {
9789
+ instance.metadata.set(fieldWithId);
9790
+ }
9791
+ catch {
9792
+ return false;
9793
+ }
9794
+ }
9795
+ else {
9796
+ return false;
9797
+ }
9798
+ try {
9799
+ compRef.changeDetectorRef.detectChanges();
9800
+ }
9801
+ catch { }
9802
+ }
9803
+ this.currentOrder = fields.map((field) => field.name);
9804
+ this.componentsCreated.emit(new Map(this.componentRefs));
9805
+ return true;
9806
+ }
9655
9807
  rebindControlsOnly() {
9656
9808
  this.dbg('[DFL] rebindControlsOnly: start');
9657
9809
  const fieldNames = this.currentOrder.length
@@ -11777,6 +11929,15 @@ class InlineEntityLookupComponent extends MaterialAsyncSelectComponent {
11777
11929
  dialogClearFiltersActionText() {
11778
11930
  return this.tDynamicFields('entityLookup.dialog.filters.clear', 'Limpar filtros');
11779
11931
  }
11932
+ dialogFilterSelectEmptyText(label) {
11933
+ return this.tDynamicFields('entityLookup.dialog.filters.selectEmpty', 'Selecione {label}', { label: label.toLowerCase() });
11934
+ }
11935
+ dialogFilterStartAriaLabelText(label) {
11936
+ return this.tDynamicFields('entityLookup.dialog.filters.startAriaLabel', '{label} inicial', { label });
11937
+ }
11938
+ dialogFilterEndAriaLabelText(label) {
11939
+ return this.tDynamicFields('entityLookup.dialog.filters.endAriaLabel', '{label} final', { label });
11940
+ }
11780
11941
  dialogPreviewSelectionStateLabelText() {
11781
11942
  return this.tDynamicFields('entityLookup.dialog.preview.selectionState', 'Estado');
11782
11943
  }
@@ -13322,6 +13483,7 @@ class EntityLookupDialogComponent {
13322
13483
  dialogSearchControl = new FormControl('');
13323
13484
  filterPanelOpen = new FormControl(false, { nonNullable: true });
13324
13485
  dialogFilterControls = new Map();
13486
+ dialogFilterSecondaryControls = new Map();
13325
13487
  previewIdentity = null;
13326
13488
  activeResultIndex = 0;
13327
13489
  ngAfterViewInit() {
@@ -13411,6 +13573,15 @@ class EntityLookupDialogComponent {
13411
13573
  this.dialogFilterControls.set(field, created);
13412
13574
  return created;
13413
13575
  }
13576
+ filterSecondaryControl(field) {
13577
+ const existing = this.dialogFilterSecondaryControls.get(field);
13578
+ if (existing) {
13579
+ return existing;
13580
+ }
13581
+ const created = new FormControl('', { nonNullable: true });
13582
+ this.dialogFilterSecondaryControls.set(field, created);
13583
+ return created;
13584
+ }
13414
13585
  dialogFilterLabel(definition) {
13415
13586
  return definition.label || this.humanizeColumnField(definition.field);
13416
13587
  }
@@ -13418,6 +13589,62 @@ class EntityLookupDialogComponent {
13418
13589
  const operator = definition.defaultOperator ?? definition.operators[0];
13419
13590
  return this.lookup().dialogFilterPlaceholderText(operator, definition.type);
13420
13591
  }
13592
+ dialogFilterRangeEndPlaceholder(definition) {
13593
+ return definition.type === 'date'
13594
+ ? this.lookup().dialogFilterPlaceholderText('between', 'date')
13595
+ : this.lookup().dialogFilterPlaceholderText('between', definition.type);
13596
+ }
13597
+ dialogFilterStartAriaLabel(definition) {
13598
+ return this.lookup().dialogFilterStartAriaLabelText(this.dialogFilterLabel(definition));
13599
+ }
13600
+ dialogFilterEndAriaLabel(definition) {
13601
+ return this.lookup().dialogFilterEndAriaLabelText(this.dialogFilterLabel(definition));
13602
+ }
13603
+ dialogFilterInputType(definition) {
13604
+ if (definition.type === 'date') {
13605
+ return 'date';
13606
+ }
13607
+ if (definition.type === 'number') {
13608
+ return 'number';
13609
+ }
13610
+ return 'text';
13611
+ }
13612
+ useDialogEnumSelect(definition) {
13613
+ return definition.type === 'enum' && !this.useDialogMultiSelect(definition);
13614
+ }
13615
+ useDialogMultiSelect(definition) {
13616
+ const operator = definition.defaultOperator ?? definition.operators[0];
13617
+ return definition.type === 'enum' && operator === 'in';
13618
+ }
13619
+ useDialogRangeInputs(definition) {
13620
+ const operator = definition.defaultOperator ?? definition.operators[0];
13621
+ return operator === 'between' && (definition.type === 'date' || definition.type === 'number');
13622
+ }
13623
+ dialogFilterSelectEmptyText(definition) {
13624
+ return this.lookup().dialogFilterSelectEmptyText(this.dialogFilterLabel(definition));
13625
+ }
13626
+ dialogEnumOptions(definition) {
13627
+ const values = new Map();
13628
+ const defaultValues = this.data.metadata.optionSource?.filtering?.defaultFilters?.[definition.field];
13629
+ if (Array.isArray(defaultValues)) {
13630
+ for (const value of defaultValues) {
13631
+ this.pushDialogEnumOption(values, value);
13632
+ }
13633
+ }
13634
+ const activeFilter = this.lookup().lookupFilterForField(definition.field)?.value;
13635
+ if (Array.isArray(activeFilter)) {
13636
+ for (const value of activeFilter) {
13637
+ this.pushDialogEnumOption(values, value);
13638
+ }
13639
+ }
13640
+ else if (activeFilter !== null && activeFilter !== undefined && activeFilter !== '') {
13641
+ this.pushDialogEnumOption(values, activeFilter);
13642
+ }
13643
+ for (const option of this.resultOptions()) {
13644
+ this.pushDialogEnumOption(values, this.resolveDialogFilterFieldValue(option, definition.field));
13645
+ }
13646
+ return Array.from(values.entries()).map(([value, label]) => ({ value, label }));
13647
+ }
13421
13648
  dialogOperatorHint(definition) {
13422
13649
  const operator = definition.defaultOperator ?? definition.operators[0];
13423
13650
  return this.lookup().dialogFilterOperatorHintText(operator);
@@ -13436,7 +13663,8 @@ class EntityLookupDialogComponent {
13436
13663
  }
13437
13664
  resetDialogFilters() {
13438
13665
  for (const definition of this.dialogFilterDefinitions()) {
13439
- this.filterControl(definition.field).setValue('');
13666
+ this.filterControl(definition.field).setValue(this.dialogFilterEmptyValue(definition));
13667
+ this.filterSecondaryControl(definition.field).setValue('');
13440
13668
  }
13441
13669
  this.lookup().clearLookupFilters();
13442
13670
  }
@@ -13703,46 +13931,114 @@ class EntityLookupDialogComponent {
13703
13931
  initializeDialogFilters() {
13704
13932
  for (const definition of this.dialogFilterDefinitions()) {
13705
13933
  const current = this.lookup().lookupFilterForField(definition.field);
13706
- this.filterControl(definition.field).setValue(this.serializeDialogFilterValue(current?.value));
13934
+ const operator = definition.defaultOperator ?? definition.operators[0];
13935
+ if (this.useDialogMultiSelect(definition)) {
13936
+ const values = Array.isArray(current?.value)
13937
+ ? current?.value.map((item) => this.serializeDialogFilterScalarValue(item))
13938
+ : current?.value === null || current?.value === undefined || current?.value === ''
13939
+ ? []
13940
+ : [this.serializeDialogFilterScalarValue(current.value)];
13941
+ this.filterControl(definition.field).setValue(values);
13942
+ this.filterSecondaryControl(definition.field).setValue('');
13943
+ continue;
13944
+ }
13945
+ if (this.useDialogRangeInputs(definition)) {
13946
+ const values = Array.isArray(current?.value) ? current.value : [];
13947
+ this.filterControl(definition.field).setValue(this.serializeDialogFilterScalarValue(values[0]));
13948
+ this.filterSecondaryControl(definition.field).setValue(this.serializeDialogFilterScalarValue(values[1]));
13949
+ continue;
13950
+ }
13951
+ this.filterControl(definition.field).setValue(this.serializeDialogFilterSingleValue(current?.value, operator));
13952
+ this.filterSecondaryControl(definition.field).setValue('');
13707
13953
  }
13708
13954
  }
13709
- serializeDialogFilterValue(value) {
13955
+ dialogFilterEmptyValue(definition) {
13956
+ return this.useDialogMultiSelect(definition) ? [] : '';
13957
+ }
13958
+ serializeDialogFilterSingleValue(value, operator) {
13710
13959
  if (Array.isArray(value)) {
13711
- return value.map((item) => this.serializeDialogFilterValue(item)).join(', ');
13960
+ if (operator === 'in') {
13961
+ return value.map((item) => this.serializeDialogFilterScalarValue(item)).join(', ');
13962
+ }
13963
+ return this.serializeDialogFilterScalarValue(value[0]);
13712
13964
  }
13965
+ return this.serializeDialogFilterScalarValue(value);
13966
+ }
13967
+ serializeDialogFilterScalarValue(value) {
13713
13968
  if (value === null || value === undefined) {
13714
13969
  return '';
13715
13970
  }
13716
13971
  return String(value);
13717
13972
  }
13718
13973
  buildDialogFilterRequest(definition) {
13719
- const rawInput = this.filterControl(definition.field).value.trim();
13720
- if (!rawInput) {
13974
+ const operator = definition.defaultOperator ?? definition.operators[0];
13975
+ const value = this.normalizeDialogFilterControlValue(definition, operator, this.filterControl(definition.field).value, this.filterSecondaryControl(definition.field).value);
13976
+ if (value === undefined) {
13721
13977
  return undefined;
13722
13978
  }
13723
- const operator = definition.defaultOperator ?? definition.operators[0];
13724
13979
  return {
13725
13980
  field: definition.field,
13726
13981
  operator,
13727
- value: this.parseDialogFilterValue(definition.type, operator, rawInput),
13982
+ value,
13728
13983
  };
13729
13984
  }
13730
- parseDialogFilterValue(type, operator, rawInput) {
13731
- const parts = rawInput
13732
- .split(',')
13733
- .map((item) => item.trim())
13734
- .filter((item) => !!item);
13735
- const values = operator === 'between' ? parts.slice(0, 2) : operator === 'in' ? parts : [rawInput];
13736
- return operator === 'between' || operator === 'in'
13737
- ? values.map((item) => this.parseDialogFilterPrimitive(type, item))
13738
- : this.parseDialogFilterPrimitive(type, values[0] ?? rawInput);
13985
+ normalizeDialogFilterControlValue(definition, operator, primaryValue, secondaryValue) {
13986
+ if (this.useDialogMultiSelect(definition)) {
13987
+ const values = Array.isArray(primaryValue)
13988
+ ? primaryValue
13989
+ .map((item) => this.normalizeDialogFilterScalarValue(definition.type, item))
13990
+ .filter((item) => item !== undefined)
13991
+ : [];
13992
+ return values.length ? values : undefined;
13993
+ }
13994
+ if (this.useDialogRangeInputs(definition)) {
13995
+ const start = this.normalizeDialogFilterScalarValue(definition.type, primaryValue);
13996
+ const end = this.normalizeDialogFilterScalarValue(definition.type, secondaryValue);
13997
+ if (start === undefined && end === undefined) {
13998
+ return undefined;
13999
+ }
14000
+ if (start === undefined || end === undefined) {
14001
+ return undefined;
14002
+ }
14003
+ return [start, end];
14004
+ }
14005
+ if (operator === 'in') {
14006
+ const rawInput = String(primaryValue ?? '').trim();
14007
+ if (!rawInput) {
14008
+ return undefined;
14009
+ }
14010
+ const values = rawInput
14011
+ .split(',')
14012
+ .map((item) => this.normalizeDialogFilterScalarValue(definition.type, item))
14013
+ .filter((item) => item !== undefined);
14014
+ return values.length ? values : undefined;
14015
+ }
14016
+ return this.normalizeDialogFilterScalarValue(definition.type, primaryValue);
13739
14017
  }
13740
- parseDialogFilterPrimitive(type, value) {
13741
- if (type !== 'number') {
13742
- return value;
14018
+ normalizeDialogFilterScalarValue(type, value) {
14019
+ const text = String(value ?? '').trim();
14020
+ if (!text) {
14021
+ return undefined;
13743
14022
  }
13744
- const numeric = Number(value);
13745
- return Number.isFinite(numeric) ? numeric : value;
14023
+ if (type === 'date' || type === 'text' || type === 'reference' || type === 'enum') {
14024
+ return text;
14025
+ }
14026
+ const numeric = Number(text);
14027
+ return Number.isFinite(numeric) ? numeric : undefined;
14028
+ }
14029
+ resolveDialogFilterFieldValue(option, field) {
14030
+ const value = option.value;
14031
+ if (value && typeof value === 'object' && field in value) {
14032
+ return value[field];
14033
+ }
14034
+ return undefined;
14035
+ }
14036
+ pushDialogEnumOption(target, value) {
14037
+ const normalized = this.serializeDialogFilterScalarValue(value);
14038
+ if (!normalized || target.has(normalized)) {
14039
+ return;
14040
+ }
14041
+ target.set(normalized, normalized);
13746
14042
  }
13747
14043
  syncPreviewIdentity() {
13748
14044
  const selected = this.lookup().selectedLookupView();
@@ -13897,11 +14193,57 @@ class EntityLookupDialogComponent {
13897
14193
  *ngFor="let definition of dialogFilterDefinitions()"
13898
14194
  >
13899
14195
  <span>{{ dialogFilterLabel(definition) }}</span>
13900
- <input
13901
- type="text"
13902
- [formControl]="filterControl(definition.field)"
13903
- [placeholder]="dialogFilterPlaceholder(definition)"
13904
- />
14196
+ @if (useDialogMultiSelect(definition)) {
14197
+ <select
14198
+ multiple
14199
+ class="pdx-lookup-dialog-filter-select is-multiple"
14200
+ [formControl]="filterControl(definition.field)"
14201
+ [attr.aria-label]="dialogFilterLabel(definition)"
14202
+ >
14203
+ <option
14204
+ *ngFor="let option of dialogEnumOptions(definition)"
14205
+ [value]="option.value"
14206
+ >
14207
+ {{ option.label }}
14208
+ </option>
14209
+ </select>
14210
+ } @else if (useDialogRangeInputs(definition)) {
14211
+ <span class="pdx-lookup-dialog-filter-range">
14212
+ <input
14213
+ [type]="dialogFilterInputType(definition)"
14214
+ [formControl]="filterControl(definition.field)"
14215
+ [placeholder]="dialogFilterPlaceholder(definition)"
14216
+ [attr.aria-label]="dialogFilterStartAriaLabel(definition)"
14217
+ />
14218
+ <input
14219
+ [type]="dialogFilterInputType(definition)"
14220
+ [formControl]="filterSecondaryControl(definition.field)"
14221
+ [placeholder]="dialogFilterRangeEndPlaceholder(definition)"
14222
+ [attr.aria-label]="dialogFilterEndAriaLabel(definition)"
14223
+ />
14224
+ </span>
14225
+ } @else if (useDialogEnumSelect(definition)) {
14226
+ <select
14227
+ class="pdx-lookup-dialog-filter-select"
14228
+ [formControl]="filterControl(definition.field)"
14229
+ [attr.aria-label]="dialogFilterLabel(definition)"
14230
+ >
14231
+ <option value="">{{ dialogFilterSelectEmptyText(definition) }}</option>
14232
+ <option
14233
+ *ngFor="let option of dialogEnumOptions(definition)"
14234
+ [value]="option.value"
14235
+ >
14236
+ {{ option.label }}
14237
+ </option>
14238
+ </select>
14239
+ } @else {
14240
+ <input
14241
+ [type]="dialogFilterInputType(definition)"
14242
+ [formControl]="filterControl(definition.field)"
14243
+ [placeholder]="dialogFilterPlaceholder(definition)"
14244
+ [attr.aria-label]="dialogFilterLabel(definition)"
14245
+ />
14246
+ }
13905
14247
  <small>{{ dialogOperatorHint(definition) }}</small>
13906
14248
  </label>
13907
14249
  </div>
@@ -14156,7 +14498,7 @@ class EntityLookupDialogComponent {
14156
14498
  {{ applyText() }}
14157
14499
  </button>
14158
14500
  </mat-dialog-actions>
14159
- `, isInline: true, styles: [".pdx-lookup-dialog-toolbar{display:flex;flex-wrap:wrap;gap:12px;align-items:start}.pdx-lookup-dialog-intro{display:grid;gap:4px;margin:0 0 12px}.pdx-lookup-dialog-intro strong{color:var(--md-sys-color-on-surface);font-size:.96rem;line-height:1.3}.pdx-lookup-dialog-intro span{color:var(--md-sys-color-on-surface-variant);font-size:.82rem;line-height:1.35}.pdx-lookup-dialog-search{flex:1 1 320px}.pdx-lookup-dialog-sort{display:inline-flex;align-items:center;gap:8px;min-height:56px;color:var(--md-sys-color-on-surface-variant);font-size:.85rem}.pdx-lookup-dialog-sort select{min-width:180px;min-height:40px;border:1px solid var(--md-sys-color-outline-variant);border-radius:6px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);padding:0 10px}.pdx-lookup-dialog-filter-panel{display:flex;flex-direction:column;gap:12px;padding:12px;margin:8px 0 12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-lowest)}.pdx-lookup-dialog-filter-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}.pdx-lookup-dialog-filter-field{display:flex;flex-direction:column;gap:6px;color:var(--md-sys-color-on-surface);font-size:.9rem}.pdx-lookup-dialog-filter-field input{min-height:40px;border:1px solid var(--md-sys-color-outline-variant);border-radius:6px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);padding:0 10px}.pdx-lookup-dialog-filter-field small{color:var(--md-sys-color-on-surface-variant)}.pdx-lookup-dialog-filter-actions{display:flex;justify-content:flex-end;gap:8px}.pdx-lookup-dialog-summary{margin:8px 0 12px;display:flex;flex-wrap:wrap;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:.85rem}.pdx-lookup-dialog-summary-warning{color:var(--md-sys-color-error)}.pdx-lookup-dialog-content-grid{display:block}.pdx-lookup-dialog-content-grid.has-preview{display:grid;grid-template-columns:minmax(0,1fr) 280px;gap:16px;align-items:start}.pdx-lookup-dialog-results{display:flex;flex-direction:column;gap:10px;max-height:52vh;overflow:auto;padding-right:4px}.pdx-lookup-dialog-results.is-card-layout{gap:12px}.pdx-lookup-dialog-results.is-compact-layout{gap:6px}.pdx-lookup-dialog-table{display:flex;flex-direction:column;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;overflow:hidden}.pdx-lookup-dialog-table-head,.pdx-lookup-dialog-table-row{display:flex;align-items:stretch}.pdx-lookup-dialog-table-head{background:var(--md-sys-color-surface-container-low);border-bottom:1px solid var(--md-sys-color-outline-variant)}.pdx-lookup-dialog-table-row{width:100%;text-align:left;border:0;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);cursor:pointer}.pdx-lookup-dialog-table-row:last-child{border-bottom:0}.pdx-lookup-dialog-table-row.is-selected{background:color-mix(in srgb,var(--md-sys-color-primary) 8%,var(--md-sys-color-surface))}.pdx-lookup-dialog-table-row.is-disabled{opacity:.65;cursor:not-allowed}.pdx-lookup-dialog-table-row.is-blocked,.pdx-lookup-dialog-row.is-blocked{background:color-mix(in srgb,var(--md-sys-color-error) 4%,var(--md-sys-color-surface))}.pdx-lookup-dialog-table-row.is-legacy,.pdx-lookup-dialog-row.is-legacy{background:color-mix(in srgb,var(--md-sys-color-tertiary) 8%,var(--md-sys-color-surface))}.pdx-lookup-dialog-table-cell{min-width:0;padding:10px 12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pdx-lookup-dialog-table-cell.is-head{font-size:.78rem;font-weight:600;color:var(--md-sys-color-on-surface-variant)}.pdx-lookup-dialog-row{display:block;width:100%;text-align:left;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);padding:12px 14px;cursor:pointer}.pdx-lookup-dialog-row.is-selected{border-color:var(--md-sys-color-primary);box-shadow:inset 0 0 0 1px var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 8%,var(--md-sys-color-surface))}.pdx-lookup-dialog-row.is-disabled{opacity:.65;cursor:not-allowed}.pdx-lookup-dialog-row-main,.pdx-lookup-dialog-row-heading,.pdx-lookup-dialog-row-meta{display:flex;flex-wrap:wrap;gap:8px}.pdx-lookup-dialog-row-main{flex-direction:column;gap:8px}.pdx-lookup-dialog-row-heading strong{font-size:.98rem;line-height:1.3}.pdx-lookup-dialog-row-heading small{border-radius:6px;padding:2px 6px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface-variant);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.74rem;line-height:1.2}.pdx-lookup-dialog-results.is-card-layout .pdx-lookup-dialog-row-main{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;gap:12px}.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row{padding:8px 10px}.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row-heading,.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row-meta{gap:6px}.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row-description{font-size:.85rem}.pdx-lookup-dialog-row-description{color:var(--md-sys-color-on-surface-variant);line-height:1.35}.pdx-lookup-dialog-row-meta{align-items:center}.pdx-lookup-dialog-row-note,.pdx-lookup-option-note{display:inline-flex;align-items:center;min-height:24px;padding:4px 8px;border-radius:8px;font-size:.76rem;line-height:1.3}.pdx-lookup-dialog-row-note.is-warning,.pdx-lookup-option-note.is-warning{background:#fffbeb;color:#92400e}.pdx-lookup-dialog-row-note.is-danger,.pdx-lookup-option-note.is-danger{background:#fef2f2;color:#991b1b}.pdx-lookup-dialog-state,.pdx-lookup-dialog-footer-row{display:flex;align-items:center;gap:10px;justify-content:center;padding:16px 0 4px}.pdx-lookup-dialog-runtime-host{display:none}.pdx-lookup-dialog-preview{border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-lowest);padding:14px;display:flex;flex-direction:column;gap:10px;position:sticky;top:0}.pdx-lookup-dialog-preview-meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.pdx-lookup-dialog-preview-heading{display:flex;flex-direction:column;gap:4px}.pdx-lookup-dialog-preview-heading small,.pdx-lookup-dialog-preview-description,.pdx-lookup-dialog-preview-grid dt{color:var(--md-sys-color-on-surface-variant)}.pdx-lookup-dialog-preview-badges{display:flex;flex-wrap:wrap;gap:8px}.pdx-lookup-dialog-preview-note{display:grid;gap:2px;padding:8px 10px;border-radius:8px;border:1px solid transparent;font-size:.78rem;line-height:1.35}.pdx-lookup-dialog-preview-note strong{font-size:.72rem;line-height:1.2;text-transform:uppercase;letter-spacing:.02em}.pdx-lookup-dialog-preview-note.is-warning{background:#fffbeb;border-color:#fde68a;color:#92400e}.pdx-lookup-dialog-preview-note.is-danger{background:#fef2f2;border-color:#fecaca;color:#991b1b}.pdx-lookup-dialog-preview-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:0}.pdx-lookup-dialog-preview-grid div{min-width:0}.pdx-lookup-dialog-preview-grid dt{font-size:.78rem;margin-bottom:2px}.pdx-lookup-dialog-preview-grid dd{margin:0;overflow-wrap:anywhere}.pdx-lookup-dialog-preview-actions{display:flex;flex-wrap:wrap;gap:8px}@media(max-width:960px){.pdx-lookup-dialog-toolbar{flex-direction:column;align-items:stretch}.pdx-lookup-dialog-search,.pdx-lookup-dialog-sort{width:100%;flex:1 1 auto}.pdx-lookup-dialog-sort{min-height:0;flex-direction:column;align-items:stretch}.pdx-lookup-dialog-sort select{width:100%;min-width:0}.pdx-lookup-dialog-content-grid.has-preview{grid-template-columns:minmax(0,1fr)}.pdx-lookup-dialog-preview{position:static}}@media(max-width:640px){.pdx-lookup-dialog-intro{margin-bottom:10px}.pdx-lookup-dialog-results{max-height:none;padding-right:0}.pdx-lookup-dialog-row{padding:10px 12px}.pdx-lookup-dialog-results.is-card-layout .pdx-lookup-dialog-row-main{grid-template-columns:minmax(0,1fr)}.pdx-lookup-dialog-preview{padding:12px}.pdx-lookup-dialog-preview-grid{grid-template-columns:minmax(0,1fr)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1$3.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$3.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1$3.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: InlineEntityLookupComponent, selector: "pdx-inline-entity-lookup", inputs: ["initialMetadata"] }] });
14501
+ `, isInline: true, styles: [".pdx-lookup-dialog-toolbar{display:flex;flex-wrap:wrap;gap:12px;align-items:start}.pdx-lookup-dialog-intro{display:grid;gap:4px;margin:0 0 12px}.pdx-lookup-dialog-intro strong{color:var(--md-sys-color-on-surface);font-size:.96rem;line-height:1.3}.pdx-lookup-dialog-intro span{color:var(--md-sys-color-on-surface-variant);font-size:.82rem;line-height:1.35}.pdx-lookup-dialog-search{flex:1 1 320px}.pdx-lookup-dialog-sort{display:inline-flex;align-items:center;gap:8px;min-height:56px;color:var(--md-sys-color-on-surface-variant);font-size:.85rem}.pdx-lookup-dialog-sort select{min-width:180px;min-height:40px;border:1px solid var(--md-sys-color-outline-variant);border-radius:6px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);padding:0 10px}.pdx-lookup-dialog-filter-panel{display:flex;flex-direction:column;gap:12px;padding:12px;margin:8px 0 12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-lowest)}.pdx-lookup-dialog-filter-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}.pdx-lookup-dialog-filter-field{display:flex;flex-direction:column;gap:6px;color:var(--md-sys-color-on-surface);font-size:.9rem}.pdx-lookup-dialog-filter-field input,.pdx-lookup-dialog-filter-field select{min-height:40px;border:1px solid var(--md-sys-color-outline-variant);border-radius:6px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);padding:0 10px}.pdx-lookup-dialog-filter-field select.is-multiple{min-height:96px;padding:8px 10px}.pdx-lookup-dialog-filter-range{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:8px}.pdx-lookup-dialog-filter-field small{color:var(--md-sys-color-on-surface-variant)}.pdx-lookup-dialog-filter-actions{display:flex;justify-content:flex-end;gap:8px}.pdx-lookup-dialog-summary{margin:8px 0 12px;display:flex;flex-wrap:wrap;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:.85rem}.pdx-lookup-dialog-summary-warning{color:var(--md-sys-color-error)}.pdx-lookup-dialog-content-grid{display:block}.pdx-lookup-dialog-content-grid.has-preview{display:grid;grid-template-columns:minmax(0,1fr) 280px;gap:16px;align-items:start}.pdx-lookup-dialog-results{display:flex;flex-direction:column;gap:10px;max-height:52vh;overflow:auto;padding-right:4px}.pdx-lookup-dialog-results.is-card-layout{gap:12px}.pdx-lookup-dialog-results.is-compact-layout{gap:6px}.pdx-lookup-dialog-table{display:flex;flex-direction:column;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;overflow:hidden}.pdx-lookup-dialog-table-head,.pdx-lookup-dialog-table-row{display:flex;align-items:stretch}.pdx-lookup-dialog-table-head{background:var(--md-sys-color-surface-container-low);border-bottom:1px solid var(--md-sys-color-outline-variant)}.pdx-lookup-dialog-table-row{width:100%;text-align:left;border:0;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);cursor:pointer}.pdx-lookup-dialog-table-row:last-child{border-bottom:0}.pdx-lookup-dialog-table-row.is-selected{background:color-mix(in srgb,var(--md-sys-color-primary) 8%,var(--md-sys-color-surface))}.pdx-lookup-dialog-table-row.is-disabled{opacity:.65;cursor:not-allowed}.pdx-lookup-dialog-table-row.is-blocked,.pdx-lookup-dialog-row.is-blocked{background:color-mix(in srgb,var(--md-sys-color-error) 4%,var(--md-sys-color-surface))}.pdx-lookup-dialog-table-row.is-legacy,.pdx-lookup-dialog-row.is-legacy{background:color-mix(in srgb,var(--md-sys-color-tertiary) 8%,var(--md-sys-color-surface))}.pdx-lookup-dialog-table-cell{min-width:0;padding:10px 12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pdx-lookup-dialog-table-cell.is-head{font-size:.78rem;font-weight:600;color:var(--md-sys-color-on-surface-variant)}.pdx-lookup-dialog-row{display:block;width:100%;text-align:left;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);padding:12px 14px;cursor:pointer}.pdx-lookup-dialog-row.is-selected{border-color:var(--md-sys-color-primary);box-shadow:inset 0 0 0 1px var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 8%,var(--md-sys-color-surface))}.pdx-lookup-dialog-row.is-disabled{opacity:.65;cursor:not-allowed}.pdx-lookup-dialog-row-main,.pdx-lookup-dialog-row-heading,.pdx-lookup-dialog-row-meta{display:flex;flex-wrap:wrap;gap:8px}.pdx-lookup-dialog-row-main{flex-direction:column;gap:8px}.pdx-lookup-dialog-row-heading strong{font-size:.98rem;line-height:1.3}.pdx-lookup-dialog-row-heading small{border-radius:6px;padding:2px 6px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface-variant);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.74rem;line-height:1.2}.pdx-lookup-dialog-results.is-card-layout .pdx-lookup-dialog-row-main{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;gap:12px}.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row{padding:8px 10px}.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row-heading,.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row-meta{gap:6px}.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row-description{font-size:.85rem}.pdx-lookup-dialog-row-description{color:var(--md-sys-color-on-surface-variant);line-height:1.35}.pdx-lookup-dialog-row-meta{align-items:center}.pdx-lookup-dialog-row-note,.pdx-lookup-option-note{display:inline-flex;align-items:center;min-height:24px;padding:4px 8px;border-radius:8px;font-size:.76rem;line-height:1.3}.pdx-lookup-dialog-row-note.is-warning,.pdx-lookup-option-note.is-warning{background:#fffbeb;color:#92400e}.pdx-lookup-dialog-row-note.is-danger,.pdx-lookup-option-note.is-danger{background:#fef2f2;color:#991b1b}.pdx-lookup-dialog-state,.pdx-lookup-dialog-footer-row{display:flex;align-items:center;gap:10px;justify-content:center;padding:16px 0 4px}.pdx-lookup-dialog-runtime-host{display:none}.pdx-lookup-dialog-preview{border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-lowest);padding:14px;display:flex;flex-direction:column;gap:10px;position:sticky;top:0}.pdx-lookup-dialog-preview-meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.pdx-lookup-dialog-preview-heading{display:flex;flex-direction:column;gap:4px}.pdx-lookup-dialog-preview-heading small,.pdx-lookup-dialog-preview-description,.pdx-lookup-dialog-preview-grid dt{color:var(--md-sys-color-on-surface-variant)}.pdx-lookup-dialog-preview-badges{display:flex;flex-wrap:wrap;gap:8px}.pdx-lookup-dialog-preview-note{display:grid;gap:2px;padding:8px 10px;border-radius:8px;border:1px solid transparent;font-size:.78rem;line-height:1.35}.pdx-lookup-dialog-preview-note strong{font-size:.72rem;line-height:1.2;text-transform:uppercase;letter-spacing:.02em}.pdx-lookup-dialog-preview-note.is-warning{background:#fffbeb;border-color:#fde68a;color:#92400e}.pdx-lookup-dialog-preview-note.is-danger{background:#fef2f2;border-color:#fecaca;color:#991b1b}.pdx-lookup-dialog-preview-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:0}.pdx-lookup-dialog-preview-grid div{min-width:0}.pdx-lookup-dialog-preview-grid dt{font-size:.78rem;margin-bottom:2px}.pdx-lookup-dialog-preview-grid dd{margin:0;overflow-wrap:anywhere}.pdx-lookup-dialog-preview-actions{display:flex;flex-wrap:wrap;gap:8px}@media(max-width:960px){.pdx-lookup-dialog-toolbar{flex-direction:column;align-items:stretch}.pdx-lookup-dialog-search,.pdx-lookup-dialog-sort{width:100%;flex:1 1 auto}.pdx-lookup-dialog-sort{min-height:0;flex-direction:column;align-items:stretch}.pdx-lookup-dialog-sort select{width:100%;min-width:0}.pdx-lookup-dialog-content-grid.has-preview{grid-template-columns:minmax(0,1fr)}.pdx-lookup-dialog-preview{position:static}}@media(max-width:640px){.pdx-lookup-dialog-intro{margin-bottom:10px}.pdx-lookup-dialog-results{max-height:none;padding-right:0}.pdx-lookup-dialog-row{padding:10px 12px}.pdx-lookup-dialog-results.is-card-layout .pdx-lookup-dialog-row-main{grid-template-columns:minmax(0,1fr)}.pdx-lookup-dialog-preview{padding:12px}.pdx-lookup-dialog-preview-grid{grid-template-columns:minmax(0,1fr)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.SelectMultipleControlValueAccessor, selector: "select[multiple][formControlName],select[multiple][formControl],select[multiple][ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1$3.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$3.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1$3.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: InlineEntityLookupComponent, selector: "pdx-inline-entity-lookup", inputs: ["initialMetadata"] }] });
14160
14502
  }
14161
14503
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: EntityLookupDialogComponent, decorators: [{
14162
14504
  type: Component,
@@ -14229,11 +14571,57 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
14229
14571
  *ngFor="let definition of dialogFilterDefinitions()"
14230
14572
  >
14231
14573
  <span>{{ dialogFilterLabel(definition) }}</span>
14232
- <input
14233
- type="text"
14234
- [formControl]="filterControl(definition.field)"
14235
- [placeholder]="dialogFilterPlaceholder(definition)"
14236
- />
14574
+ @if (useDialogMultiSelect(definition)) {
14575
+ <select
14576
+ multiple
14577
+ class="pdx-lookup-dialog-filter-select is-multiple"
14578
+ [formControl]="filterControl(definition.field)"
14579
+ [attr.aria-label]="dialogFilterLabel(definition)"
14580
+ >
14581
+ <option
14582
+ *ngFor="let option of dialogEnumOptions(definition)"
14583
+ [value]="option.value"
14584
+ >
14585
+ {{ option.label }}
14586
+ </option>
14587
+ </select>
14588
+ } @else if (useDialogRangeInputs(definition)) {
14589
+ <span class="pdx-lookup-dialog-filter-range">
14590
+ <input
14591
+ [type]="dialogFilterInputType(definition)"
14592
+ [formControl]="filterControl(definition.field)"
14593
+ [placeholder]="dialogFilterPlaceholder(definition)"
14594
+ [attr.aria-label]="dialogFilterStartAriaLabel(definition)"
14595
+ />
14596
+ <input
14597
+ [type]="dialogFilterInputType(definition)"
14598
+ [formControl]="filterSecondaryControl(definition.field)"
14599
+ [placeholder]="dialogFilterRangeEndPlaceholder(definition)"
14600
+ [attr.aria-label]="dialogFilterEndAriaLabel(definition)"
14601
+ />
14602
+ </span>
14603
+ } @else if (useDialogEnumSelect(definition)) {
14604
+ <select
14605
+ class="pdx-lookup-dialog-filter-select"
14606
+ [formControl]="filterControl(definition.field)"
14607
+ [attr.aria-label]="dialogFilterLabel(definition)"
14608
+ >
14609
+ <option value="">{{ dialogFilterSelectEmptyText(definition) }}</option>
14610
+ <option
14611
+ *ngFor="let option of dialogEnumOptions(definition)"
14612
+ [value]="option.value"
14613
+ >
14614
+ {{ option.label }}
14615
+ </option>
14616
+ </select>
14617
+ } @else {
14618
+ <input
14619
+ [type]="dialogFilterInputType(definition)"
14620
+ [formControl]="filterControl(definition.field)"
14621
+ [placeholder]="dialogFilterPlaceholder(definition)"
14622
+ [attr.aria-label]="dialogFilterLabel(definition)"
14623
+ />
14624
+ }
14237
14625
  <small>{{ dialogOperatorHint(definition) }}</small>
14238
14626
  </label>
14239
14627
  </div>
@@ -14488,7 +14876,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
14488
14876
  {{ applyText() }}
14489
14877
  </button>
14490
14878
  </mat-dialog-actions>
14491
- `, styles: [".pdx-lookup-dialog-toolbar{display:flex;flex-wrap:wrap;gap:12px;align-items:start}.pdx-lookup-dialog-intro{display:grid;gap:4px;margin:0 0 12px}.pdx-lookup-dialog-intro strong{color:var(--md-sys-color-on-surface);font-size:.96rem;line-height:1.3}.pdx-lookup-dialog-intro span{color:var(--md-sys-color-on-surface-variant);font-size:.82rem;line-height:1.35}.pdx-lookup-dialog-search{flex:1 1 320px}.pdx-lookup-dialog-sort{display:inline-flex;align-items:center;gap:8px;min-height:56px;color:var(--md-sys-color-on-surface-variant);font-size:.85rem}.pdx-lookup-dialog-sort select{min-width:180px;min-height:40px;border:1px solid var(--md-sys-color-outline-variant);border-radius:6px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);padding:0 10px}.pdx-lookup-dialog-filter-panel{display:flex;flex-direction:column;gap:12px;padding:12px;margin:8px 0 12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-lowest)}.pdx-lookup-dialog-filter-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}.pdx-lookup-dialog-filter-field{display:flex;flex-direction:column;gap:6px;color:var(--md-sys-color-on-surface);font-size:.9rem}.pdx-lookup-dialog-filter-field input{min-height:40px;border:1px solid var(--md-sys-color-outline-variant);border-radius:6px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);padding:0 10px}.pdx-lookup-dialog-filter-field small{color:var(--md-sys-color-on-surface-variant)}.pdx-lookup-dialog-filter-actions{display:flex;justify-content:flex-end;gap:8px}.pdx-lookup-dialog-summary{margin:8px 0 12px;display:flex;flex-wrap:wrap;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:.85rem}.pdx-lookup-dialog-summary-warning{color:var(--md-sys-color-error)}.pdx-lookup-dialog-content-grid{display:block}.pdx-lookup-dialog-content-grid.has-preview{display:grid;grid-template-columns:minmax(0,1fr) 280px;gap:16px;align-items:start}.pdx-lookup-dialog-results{display:flex;flex-direction:column;gap:10px;max-height:52vh;overflow:auto;padding-right:4px}.pdx-lookup-dialog-results.is-card-layout{gap:12px}.pdx-lookup-dialog-results.is-compact-layout{gap:6px}.pdx-lookup-dialog-table{display:flex;flex-direction:column;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;overflow:hidden}.pdx-lookup-dialog-table-head,.pdx-lookup-dialog-table-row{display:flex;align-items:stretch}.pdx-lookup-dialog-table-head{background:var(--md-sys-color-surface-container-low);border-bottom:1px solid var(--md-sys-color-outline-variant)}.pdx-lookup-dialog-table-row{width:100%;text-align:left;border:0;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);cursor:pointer}.pdx-lookup-dialog-table-row:last-child{border-bottom:0}.pdx-lookup-dialog-table-row.is-selected{background:color-mix(in srgb,var(--md-sys-color-primary) 8%,var(--md-sys-color-surface))}.pdx-lookup-dialog-table-row.is-disabled{opacity:.65;cursor:not-allowed}.pdx-lookup-dialog-table-row.is-blocked,.pdx-lookup-dialog-row.is-blocked{background:color-mix(in srgb,var(--md-sys-color-error) 4%,var(--md-sys-color-surface))}.pdx-lookup-dialog-table-row.is-legacy,.pdx-lookup-dialog-row.is-legacy{background:color-mix(in srgb,var(--md-sys-color-tertiary) 8%,var(--md-sys-color-surface))}.pdx-lookup-dialog-table-cell{min-width:0;padding:10px 12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pdx-lookup-dialog-table-cell.is-head{font-size:.78rem;font-weight:600;color:var(--md-sys-color-on-surface-variant)}.pdx-lookup-dialog-row{display:block;width:100%;text-align:left;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);padding:12px 14px;cursor:pointer}.pdx-lookup-dialog-row.is-selected{border-color:var(--md-sys-color-primary);box-shadow:inset 0 0 0 1px var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 8%,var(--md-sys-color-surface))}.pdx-lookup-dialog-row.is-disabled{opacity:.65;cursor:not-allowed}.pdx-lookup-dialog-row-main,.pdx-lookup-dialog-row-heading,.pdx-lookup-dialog-row-meta{display:flex;flex-wrap:wrap;gap:8px}.pdx-lookup-dialog-row-main{flex-direction:column;gap:8px}.pdx-lookup-dialog-row-heading strong{font-size:.98rem;line-height:1.3}.pdx-lookup-dialog-row-heading small{border-radius:6px;padding:2px 6px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface-variant);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.74rem;line-height:1.2}.pdx-lookup-dialog-results.is-card-layout .pdx-lookup-dialog-row-main{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;gap:12px}.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row{padding:8px 10px}.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row-heading,.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row-meta{gap:6px}.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row-description{font-size:.85rem}.pdx-lookup-dialog-row-description{color:var(--md-sys-color-on-surface-variant);line-height:1.35}.pdx-lookup-dialog-row-meta{align-items:center}.pdx-lookup-dialog-row-note,.pdx-lookup-option-note{display:inline-flex;align-items:center;min-height:24px;padding:4px 8px;border-radius:8px;font-size:.76rem;line-height:1.3}.pdx-lookup-dialog-row-note.is-warning,.pdx-lookup-option-note.is-warning{background:#fffbeb;color:#92400e}.pdx-lookup-dialog-row-note.is-danger,.pdx-lookup-option-note.is-danger{background:#fef2f2;color:#991b1b}.pdx-lookup-dialog-state,.pdx-lookup-dialog-footer-row{display:flex;align-items:center;gap:10px;justify-content:center;padding:16px 0 4px}.pdx-lookup-dialog-runtime-host{display:none}.pdx-lookup-dialog-preview{border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-lowest);padding:14px;display:flex;flex-direction:column;gap:10px;position:sticky;top:0}.pdx-lookup-dialog-preview-meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.pdx-lookup-dialog-preview-heading{display:flex;flex-direction:column;gap:4px}.pdx-lookup-dialog-preview-heading small,.pdx-lookup-dialog-preview-description,.pdx-lookup-dialog-preview-grid dt{color:var(--md-sys-color-on-surface-variant)}.pdx-lookup-dialog-preview-badges{display:flex;flex-wrap:wrap;gap:8px}.pdx-lookup-dialog-preview-note{display:grid;gap:2px;padding:8px 10px;border-radius:8px;border:1px solid transparent;font-size:.78rem;line-height:1.35}.pdx-lookup-dialog-preview-note strong{font-size:.72rem;line-height:1.2;text-transform:uppercase;letter-spacing:.02em}.pdx-lookup-dialog-preview-note.is-warning{background:#fffbeb;border-color:#fde68a;color:#92400e}.pdx-lookup-dialog-preview-note.is-danger{background:#fef2f2;border-color:#fecaca;color:#991b1b}.pdx-lookup-dialog-preview-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:0}.pdx-lookup-dialog-preview-grid div{min-width:0}.pdx-lookup-dialog-preview-grid dt{font-size:.78rem;margin-bottom:2px}.pdx-lookup-dialog-preview-grid dd{margin:0;overflow-wrap:anywhere}.pdx-lookup-dialog-preview-actions{display:flex;flex-wrap:wrap;gap:8px}@media(max-width:960px){.pdx-lookup-dialog-toolbar{flex-direction:column;align-items:stretch}.pdx-lookup-dialog-search,.pdx-lookup-dialog-sort{width:100%;flex:1 1 auto}.pdx-lookup-dialog-sort{min-height:0;flex-direction:column;align-items:stretch}.pdx-lookup-dialog-sort select{width:100%;min-width:0}.pdx-lookup-dialog-content-grid.has-preview{grid-template-columns:minmax(0,1fr)}.pdx-lookup-dialog-preview{position:static}}@media(max-width:640px){.pdx-lookup-dialog-intro{margin-bottom:10px}.pdx-lookup-dialog-results{max-height:none;padding-right:0}.pdx-lookup-dialog-row{padding:10px 12px}.pdx-lookup-dialog-results.is-card-layout .pdx-lookup-dialog-row-main{grid-template-columns:minmax(0,1fr)}.pdx-lookup-dialog-preview{padding:12px}.pdx-lookup-dialog-preview-grid{grid-template-columns:minmax(0,1fr)}}\n"] }]
14879
+ `, styles: [".pdx-lookup-dialog-toolbar{display:flex;flex-wrap:wrap;gap:12px;align-items:start}.pdx-lookup-dialog-intro{display:grid;gap:4px;margin:0 0 12px}.pdx-lookup-dialog-intro strong{color:var(--md-sys-color-on-surface);font-size:.96rem;line-height:1.3}.pdx-lookup-dialog-intro span{color:var(--md-sys-color-on-surface-variant);font-size:.82rem;line-height:1.35}.pdx-lookup-dialog-search{flex:1 1 320px}.pdx-lookup-dialog-sort{display:inline-flex;align-items:center;gap:8px;min-height:56px;color:var(--md-sys-color-on-surface-variant);font-size:.85rem}.pdx-lookup-dialog-sort select{min-width:180px;min-height:40px;border:1px solid var(--md-sys-color-outline-variant);border-radius:6px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);padding:0 10px}.pdx-lookup-dialog-filter-panel{display:flex;flex-direction:column;gap:12px;padding:12px;margin:8px 0 12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-lowest)}.pdx-lookup-dialog-filter-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}.pdx-lookup-dialog-filter-field{display:flex;flex-direction:column;gap:6px;color:var(--md-sys-color-on-surface);font-size:.9rem}.pdx-lookup-dialog-filter-field input,.pdx-lookup-dialog-filter-field select{min-height:40px;border:1px solid var(--md-sys-color-outline-variant);border-radius:6px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);padding:0 10px}.pdx-lookup-dialog-filter-field select.is-multiple{min-height:96px;padding:8px 10px}.pdx-lookup-dialog-filter-range{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:8px}.pdx-lookup-dialog-filter-field small{color:var(--md-sys-color-on-surface-variant)}.pdx-lookup-dialog-filter-actions{display:flex;justify-content:flex-end;gap:8px}.pdx-lookup-dialog-summary{margin:8px 0 12px;display:flex;flex-wrap:wrap;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:.85rem}.pdx-lookup-dialog-summary-warning{color:var(--md-sys-color-error)}.pdx-lookup-dialog-content-grid{display:block}.pdx-lookup-dialog-content-grid.has-preview{display:grid;grid-template-columns:minmax(0,1fr) 280px;gap:16px;align-items:start}.pdx-lookup-dialog-results{display:flex;flex-direction:column;gap:10px;max-height:52vh;overflow:auto;padding-right:4px}.pdx-lookup-dialog-results.is-card-layout{gap:12px}.pdx-lookup-dialog-results.is-compact-layout{gap:6px}.pdx-lookup-dialog-table{display:flex;flex-direction:column;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;overflow:hidden}.pdx-lookup-dialog-table-head,.pdx-lookup-dialog-table-row{display:flex;align-items:stretch}.pdx-lookup-dialog-table-head{background:var(--md-sys-color-surface-container-low);border-bottom:1px solid var(--md-sys-color-outline-variant)}.pdx-lookup-dialog-table-row{width:100%;text-align:left;border:0;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);cursor:pointer}.pdx-lookup-dialog-table-row:last-child{border-bottom:0}.pdx-lookup-dialog-table-row.is-selected{background:color-mix(in srgb,var(--md-sys-color-primary) 8%,var(--md-sys-color-surface))}.pdx-lookup-dialog-table-row.is-disabled{opacity:.65;cursor:not-allowed}.pdx-lookup-dialog-table-row.is-blocked,.pdx-lookup-dialog-row.is-blocked{background:color-mix(in srgb,var(--md-sys-color-error) 4%,var(--md-sys-color-surface))}.pdx-lookup-dialog-table-row.is-legacy,.pdx-lookup-dialog-row.is-legacy{background:color-mix(in srgb,var(--md-sys-color-tertiary) 8%,var(--md-sys-color-surface))}.pdx-lookup-dialog-table-cell{min-width:0;padding:10px 12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pdx-lookup-dialog-table-cell.is-head{font-size:.78rem;font-weight:600;color:var(--md-sys-color-on-surface-variant)}.pdx-lookup-dialog-row{display:block;width:100%;text-align:left;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);padding:12px 14px;cursor:pointer}.pdx-lookup-dialog-row.is-selected{border-color:var(--md-sys-color-primary);box-shadow:inset 0 0 0 1px var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 8%,var(--md-sys-color-surface))}.pdx-lookup-dialog-row.is-disabled{opacity:.65;cursor:not-allowed}.pdx-lookup-dialog-row-main,.pdx-lookup-dialog-row-heading,.pdx-lookup-dialog-row-meta{display:flex;flex-wrap:wrap;gap:8px}.pdx-lookup-dialog-row-main{flex-direction:column;gap:8px}.pdx-lookup-dialog-row-heading strong{font-size:.98rem;line-height:1.3}.pdx-lookup-dialog-row-heading small{border-radius:6px;padding:2px 6px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface-variant);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.74rem;line-height:1.2}.pdx-lookup-dialog-results.is-card-layout .pdx-lookup-dialog-row-main{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;gap:12px}.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row{padding:8px 10px}.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row-heading,.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row-meta{gap:6px}.pdx-lookup-dialog-results.is-compact-layout .pdx-lookup-dialog-row-description{font-size:.85rem}.pdx-lookup-dialog-row-description{color:var(--md-sys-color-on-surface-variant);line-height:1.35}.pdx-lookup-dialog-row-meta{align-items:center}.pdx-lookup-dialog-row-note,.pdx-lookup-option-note{display:inline-flex;align-items:center;min-height:24px;padding:4px 8px;border-radius:8px;font-size:.76rem;line-height:1.3}.pdx-lookup-dialog-row-note.is-warning,.pdx-lookup-option-note.is-warning{background:#fffbeb;color:#92400e}.pdx-lookup-dialog-row-note.is-danger,.pdx-lookup-option-note.is-danger{background:#fef2f2;color:#991b1b}.pdx-lookup-dialog-state,.pdx-lookup-dialog-footer-row{display:flex;align-items:center;gap:10px;justify-content:center;padding:16px 0 4px}.pdx-lookup-dialog-runtime-host{display:none}.pdx-lookup-dialog-preview{border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-lowest);padding:14px;display:flex;flex-direction:column;gap:10px;position:sticky;top:0}.pdx-lookup-dialog-preview-meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.pdx-lookup-dialog-preview-heading{display:flex;flex-direction:column;gap:4px}.pdx-lookup-dialog-preview-heading small,.pdx-lookup-dialog-preview-description,.pdx-lookup-dialog-preview-grid dt{color:var(--md-sys-color-on-surface-variant)}.pdx-lookup-dialog-preview-badges{display:flex;flex-wrap:wrap;gap:8px}.pdx-lookup-dialog-preview-note{display:grid;gap:2px;padding:8px 10px;border-radius:8px;border:1px solid transparent;font-size:.78rem;line-height:1.35}.pdx-lookup-dialog-preview-note strong{font-size:.72rem;line-height:1.2;text-transform:uppercase;letter-spacing:.02em}.pdx-lookup-dialog-preview-note.is-warning{background:#fffbeb;border-color:#fde68a;color:#92400e}.pdx-lookup-dialog-preview-note.is-danger{background:#fef2f2;border-color:#fecaca;color:#991b1b}.pdx-lookup-dialog-preview-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:0}.pdx-lookup-dialog-preview-grid div{min-width:0}.pdx-lookup-dialog-preview-grid dt{font-size:.78rem;margin-bottom:2px}.pdx-lookup-dialog-preview-grid dd{margin:0;overflow-wrap:anywhere}.pdx-lookup-dialog-preview-actions{display:flex;flex-wrap:wrap;gap:8px}@media(max-width:960px){.pdx-lookup-dialog-toolbar{flex-direction:column;align-items:stretch}.pdx-lookup-dialog-search,.pdx-lookup-dialog-sort{width:100%;flex:1 1 auto}.pdx-lookup-dialog-sort{min-height:0;flex-direction:column;align-items:stretch}.pdx-lookup-dialog-sort select{width:100%;min-width:0}.pdx-lookup-dialog-content-grid.has-preview{grid-template-columns:minmax(0,1fr)}.pdx-lookup-dialog-preview{position:static}}@media(max-width:640px){.pdx-lookup-dialog-intro{margin-bottom:10px}.pdx-lookup-dialog-results{max-height:none;padding-right:0}.pdx-lookup-dialog-row{padding:10px 12px}.pdx-lookup-dialog-results.is-card-layout .pdx-lookup-dialog-row-main{grid-template-columns:minmax(0,1fr)}.pdx-lookup-dialog-preview{padding:12px}.pdx-lookup-dialog-preview-grid{grid-template-columns:minmax(0,1fr)}}\n"] }]
14492
14880
  }], propDecorators: { lookup: [{ type: i0.ViewChild, args: [i0.forwardRef(() => InlineEntityLookupComponent), { isSignal: true }] }] } });
14493
14881
 
14494
14882
  const PDX_ENTITY_LOOKUP_EDITORIAL_DESCRIPTOR = {
@@ -17614,6 +18002,12 @@ class ColorInputComponent extends SimpleBaseInputComponent {
17614
18002
  getSpecificCssClasses() {
17615
18003
  return ['pdx-color-input'];
17616
18004
  }
18005
+ // Angular Material recommends always-floating labels for text-like prefixes
18006
+ // in fill/outline fields. Keep this until Material supports prefix alignment
18007
+ // without forcing the label to float.
18008
+ effectiveFloatLabelBehavior() {
18009
+ return 'always';
18010
+ }
17617
18011
  /** Applies component metadata with strong typing. */
17618
18012
  setInputMetadata(metadata) {
17619
18013
  const { placeholder, ...rest } = metadata;
@@ -17950,7 +18344,7 @@ class ColorInputComponent extends SimpleBaseInputComponent {
17950
18344
  [appearance]="materialAppearance()"
17951
18345
  [color]="materialColor()"
17952
18346
  [class]="componentCssClasses()"
17953
- [floatLabel]="floatLabelBehavior()"
18347
+ [floatLabel]="effectiveFloatLabelBehavior()"
17954
18348
  [subscriptSizing]="metadata()?.materialDesign?.subscriptSizing || 'fixed'"
17955
18349
  [hideRequiredMarker]="metadata()?.materialDesign?.hideRequiredMarker || false"
17956
18350
  >
@@ -18077,7 +18471,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
18077
18471
  [appearance]="materialAppearance()"
18078
18472
  [color]="materialColor()"
18079
18473
  [class]="componentCssClasses()"
18080
- [floatLabel]="floatLabelBehavior()"
18474
+ [floatLabel]="effectiveFloatLabelBehavior()"
18081
18475
  [subscriptSizing]="metadata()?.materialDesign?.subscriptSizing || 'fixed'"
18082
18476
  [hideRequiredMarker]="metadata()?.materialDesign?.hideRequiredMarker || false"
18083
18477
  >
@@ -49100,6 +49494,12 @@ class MaterialColorPickerComponent extends SimpleBaseInputComponent {
49100
49494
  getSpecificCssClasses() {
49101
49495
  return ['pdx-material-colorpicker'];
49102
49496
  }
49497
+ // Angular Material recommends always-floating labels for text-like prefixes
49498
+ // in fill/outline fields. Keep this until Material supports prefix alignment
49499
+ // without forcing the label to float.
49500
+ effectiveFloatLabelBehavior() {
49501
+ return 'always';
49502
+ }
49103
49503
  errorStateMatcher() {
49104
49504
  return getErrorStateMatcherForField(this.metadata());
49105
49505
  }
@@ -49198,7 +49598,7 @@ class MaterialColorPickerComponent extends SimpleBaseInputComponent {
49198
49598
  [appearance]="materialAppearance()"
49199
49599
  [color]="materialColor()"
49200
49600
  [class]="componentCssClasses()"
49201
- [floatLabel]="floatLabelBehavior()"
49601
+ [floatLabel]="effectiveFloatLabelBehavior()"
49202
49602
  [subscriptSizing]="metadata()?.materialDesign?.subscriptSizing || 'fixed'"
49203
49603
  [hideRequiredMarker]="metadata()?.materialDesign?.hideRequiredMarker || false"
49204
49604
  >
@@ -49282,7 +49682,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
49282
49682
  [appearance]="materialAppearance()"
49283
49683
  [color]="materialColor()"
49284
49684
  [class]="componentCssClasses()"
49285
- [floatLabel]="floatLabelBehavior()"
49685
+ [floatLabel]="effectiveFloatLabelBehavior()"
49286
49686
  [subscriptSizing]="metadata()?.materialDesign?.subscriptSizing || 'fixed'"
49287
49687
  [hideRequiredMarker]="metadata()?.materialDesign?.hideRequiredMarker || false"
49288
49688
  >
@@ -50358,6 +50758,12 @@ class PdxColorPickerComponent extends SimpleBaseInputComponent {
50358
50758
  }
50359
50759
  errorStateMatcher() { return getErrorStateMatcherForField(this.metadata()); }
50360
50760
  getSpecificCssClasses() { return ['pdx-color-picker']; }
50761
+ // Angular Material recommends always-floating labels for text-like prefixes
50762
+ // in fill/outline fields. Keep this until Material supports prefix alignment
50763
+ // without forcing the label to float.
50764
+ effectiveFloatLabelBehavior() {
50765
+ return 'always';
50766
+ }
50361
50767
  // Accept hot metadata updates from DynamicFieldLoader / DynamicForm
50362
50768
  setInputMetadata(meta) {
50363
50769
  try {
@@ -50628,7 +51034,7 @@ class PdxColorPickerComponent extends SimpleBaseInputComponent {
50628
51034
  [appearance]="materialAppearance()"
50629
51035
  [color]="materialColor()"
50630
51036
  [class]="componentCssClasses()"
50631
- [floatLabel]="floatLabelBehavior()"
51037
+ [floatLabel]="effectiveFloatLabelBehavior()"
50632
51038
  [subscriptSizing]="metadata()?.materialDesign?.subscriptSizing || 'fixed'"
50633
51039
  [hideRequiredMarker]="metadata()?.materialDesign?.hideRequiredMarker || false"
50634
51040
  >
@@ -50799,7 +51205,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
50799
51205
  [appearance]="materialAppearance()"
50800
51206
  [color]="materialColor()"
50801
51207
  [class]="componentCssClasses()"
50802
- [floatLabel]="floatLabelBehavior()"
51208
+ [floatLabel]="effectiveFloatLabelBehavior()"
50803
51209
  [subscriptSizing]="metadata()?.materialDesign?.subscriptSizing || 'fixed'"
50804
51210
  [hideRequiredMarker]="metadata()?.materialDesign?.hideRequiredMarker || false"
50805
51211
  >
package/index.d.ts CHANGED
@@ -1555,6 +1555,8 @@ declare class DynamicFieldLoaderDirective implements OnInit, OnDestroy, OnChange
1555
1555
  /**
1556
1556
  * Reatribui apenas os FormControls existentes aos componentes/shells sem refazer a renderização.
1557
1557
  */
1558
+ private hasSameRenderShape;
1559
+ private updateExistingFieldMetadata;
1558
1560
  private rebindControlsOnly;
1559
1561
  /** Destroi todos os componentes e limpa o container */
1560
1562
  private destroyComponents;
@@ -1761,6 +1763,7 @@ declare class ColorInputComponent extends SimpleBaseInputComponent {
1761
1763
  ngOnInit(): void;
1762
1764
  validateField(): Promise<ValidationErrors | null>;
1763
1765
  protected getSpecificCssClasses(): string[];
1766
+ effectiveFloatLabelBehavior(): 'always';
1764
1767
  /** Applies component metadata with strong typing. */
1765
1768
  setInputMetadata(metadata: MaterialColorInputMetadata): void;
1766
1769
  /** Programmatically opens the native color picker if supported. */
@@ -1852,6 +1855,7 @@ declare class MaterialDatepickerComponent extends SimpleBaseInputComponent {
1852
1855
  /** Applies component metadata with strong typing. */
1853
1856
  setDatepickerMetadata(metadata: MaterialDatepickerMetadata): void;
1854
1857
  isReadonlyEffective(): boolean;
1858
+ isInputReadonly(): boolean;
1855
1859
  errorStateMatcher(): _angular_material_error_options_d_CGdTZUYk.E;
1856
1860
  showClear(): boolean;
1857
1861
  onClearClick(): void;
@@ -1895,6 +1899,7 @@ declare class MaterialDateRangeComponent extends SimpleBaseInputComponent implem
1895
1899
  readonly maxDate: _angular_core.Signal<any>;
1896
1900
  readonly startAt: _angular_core.Signal<any>;
1897
1901
  overlayOpen: boolean;
1902
+ private pickerOpen;
1898
1903
  private readonly dateAdapter;
1899
1904
  picker: MatDateRangePicker<Date>;
1900
1905
  readonly shouldShowShortcuts: () => boolean;
@@ -1905,6 +1910,9 @@ declare class MaterialDateRangeComponent extends SimpleBaseInputComponent implem
1905
1910
  writeValue(value: unknown): void;
1906
1911
  ngOnInit(): void;
1907
1912
  protected shouldPropagateRangeGroupChanges(): boolean;
1913
+ private propagateRangeValue;
1914
+ private isEmptyRangeValue;
1915
+ private areDatesEqual;
1908
1916
  validateField(): Promise<ValidationErrors | null>;
1909
1917
  protected getSpecificCssClasses(): string[];
1910
1918
  /** Applies component metadata with strong typing. */
@@ -2794,6 +2802,9 @@ declare class InlineEntityLookupComponent extends MaterialAsyncSelectComponent {
2794
2802
  dialogFilterOperatorHintText(operator: LookupFilterOperator): string;
2795
2803
  dialogApplyFiltersActionText(): string;
2796
2804
  dialogClearFiltersActionText(): string;
2805
+ dialogFilterSelectEmptyText(label: string): string;
2806
+ dialogFilterStartAriaLabelText(label: string): string;
2807
+ dialogFilterEndAriaLabelText(label: string): string;
2797
2808
  dialogPreviewSelectionStateLabelText(): string;
2798
2809
  dialogPreviewSelectionStateText(state: EntityLookupResultState): string;
2799
2810
  dialogSearchAriaLabelText(): string;
@@ -2877,6 +2888,7 @@ declare class EntityLookupDialogComponent implements AfterViewInit {
2877
2888
  readonly dialogSearchControl: FormControl<string | null>;
2878
2889
  readonly filterPanelOpen: FormControl<boolean>;
2879
2890
  private readonly dialogFilterControls;
2891
+ private readonly dialogFilterSecondaryControls;
2880
2892
  private previewIdentity;
2881
2893
  private activeResultIndex;
2882
2894
  ngAfterViewInit(): void;
@@ -2902,9 +2914,22 @@ declare class EntityLookupDialogComponent implements AfterViewInit {
2902
2914
  toggleFilterPanel(): void;
2903
2915
  dialogFilterDefinitions(): LookupFilterDefinitionMetadata[];
2904
2916
  filterPanelToggleText(): string;
2905
- filterControl(field: string): FormControl<string>;
2917
+ filterControl(field: string): FormControl<unknown>;
2918
+ filterSecondaryControl(field: string): FormControl<unknown>;
2906
2919
  dialogFilterLabel(definition: LookupFilterDefinitionMetadata): string;
2907
2920
  dialogFilterPlaceholder(definition: LookupFilterDefinitionMetadata): string;
2921
+ dialogFilterRangeEndPlaceholder(definition: LookupFilterDefinitionMetadata): string;
2922
+ dialogFilterStartAriaLabel(definition: LookupFilterDefinitionMetadata): string;
2923
+ dialogFilterEndAriaLabel(definition: LookupFilterDefinitionMetadata): string;
2924
+ dialogFilterInputType(definition: LookupFilterDefinitionMetadata): 'text' | 'date' | 'number';
2925
+ useDialogEnumSelect(definition: LookupFilterDefinitionMetadata): boolean;
2926
+ useDialogMultiSelect(definition: LookupFilterDefinitionMetadata): boolean;
2927
+ useDialogRangeInputs(definition: LookupFilterDefinitionMetadata): boolean;
2928
+ dialogFilterSelectEmptyText(definition: LookupFilterDefinitionMetadata): string;
2929
+ dialogEnumOptions(definition: LookupFilterDefinitionMetadata): Array<{
2930
+ value: string;
2931
+ label: string;
2932
+ }>;
2908
2933
  dialogOperatorHint(definition: LookupFilterDefinitionMetadata): string;
2909
2934
  applyDialogFiltersText(): string;
2910
2935
  clearDialogFiltersText(): string;
@@ -2950,10 +2975,14 @@ declare class EntityLookupDialogComponent implements AfterViewInit {
2950
2975
  previewSelectionStateLabel(): string;
2951
2976
  previewSelectionStateText(item: EntityLookupViewModel): string;
2952
2977
  private initializeDialogFilters;
2953
- private serializeDialogFilterValue;
2978
+ private dialogFilterEmptyValue;
2979
+ private serializeDialogFilterSingleValue;
2980
+ private serializeDialogFilterScalarValue;
2954
2981
  private buildDialogFilterRequest;
2955
- private parseDialogFilterValue;
2956
- private parseDialogFilterPrimitive;
2982
+ private normalizeDialogFilterControlValue;
2983
+ private normalizeDialogFilterScalarValue;
2984
+ private resolveDialogFilterFieldValue;
2985
+ private pushDialogEnumOption;
2957
2986
  private syncPreviewIdentity;
2958
2987
  private focusResultRow;
2959
2988
  private normalizeOptionValue;
@@ -5723,6 +5752,7 @@ declare class MaterialColorPickerComponent extends SimpleBaseInputComponent {
5723
5752
  /** Handles color selection from the native input. */
5724
5753
  onNativeColorChange(event: Event): void;
5725
5754
  protected getSpecificCssClasses(): string[];
5755
+ effectiveFloatLabelBehavior(): 'always';
5726
5756
  errorStateMatcher(): _angular_material_error_options_d_CGdTZUYk.E;
5727
5757
  isReadonlyEffective(): boolean;
5728
5758
  previewColor(): string;
@@ -5920,6 +5950,7 @@ declare class PdxColorPickerComponent extends SimpleBaseInputComponent implement
5920
5950
  readonlyEffective(): boolean;
5921
5951
  errorStateMatcher(): _angular_material_error_options_d_CGdTZUYk.E;
5922
5952
  protected getSpecificCssClasses(): string[];
5953
+ effectiveFloatLabelBehavior(): 'always';
5923
5954
  setInputMetadata(meta: ComponentMetadata | null): void;
5924
5955
  private currentMetadataRecord;
5925
5956
  private asRecord;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisui/dynamic-fields",
3
- "version": "8.0.0-beta.20",
3
+ "version": "8.0.0-beta.21",
4
4
  "description": "Angular Material-based dynamic form fields for Praxis UI with lazy loading and metadata-driven rendering.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^20.1.0",
@@ -11,8 +11,8 @@
11
11
  "@angular/platform-browser": "^20.1.0",
12
12
  "@angular/router": "^20.1.0",
13
13
  "rxjs": "^7.8.0",
14
- "@praxisui/core": "^8.0.0-beta.20",
15
- "@praxisui/cron-builder": "^8.0.0-beta.20"
14
+ "@praxisui/core": "^8.0.0-beta.21",
15
+ "@praxisui/cron-builder": "^8.0.0-beta.21"
16
16
  },
17
17
  "dependencies": {
18
18
  "libphonenumber-js": "^1.12.41",
@@ -300,6 +300,7 @@ Use quando precisar:
300
300
 
301
301
  Observacao:
302
302
  - valor do campo segue `DateRangeValue` com `startDate` e `endDate` (e opcionalmente `preset`, `label`, `timezone`).
303
+ - Durante a selecao pelo `mat-date-range-picker`, o componente nao propaga um range parcial enquanto o overlay esta aberto; `valueChange` e write-back externo sao emitidos quando inicio e fim estao preenchidos ou quando o picker fecha.
303
304
 
304
305
  ### 3. Matriz de Cobertura JSON (Completa)
305
306
  #### 3.1 Campos especificos do componente
@@ -349,7 +350,7 @@ Resumo de composicao deste componente:
349
350
  - Paginacao: nao se aplica.
350
351
  - Ordenacao: nao se aplica.
351
352
  - Selecao: objeto `DateRangeValue` (`startDate`, `endDate`, opcional `preset`).
352
- - Eventos: `validationChange` + outputs herdados (`valueChange`, `focusChange`, `nativeBlur`, `nativeChange`).
353
+ - Eventos: `validationChange` + outputs herdados (`valueChange`, `focusChange`, `nativeBlur`, `nativeChange`). `valueChange` evita range parcial durante a selecao aberta para preservar o fluxo de escolha de inicio e fim.
353
354
  - Renderizacao: `mat-date-range-input` + `mat-date-range-picker` + overlay opcional de atalhos.
354
355
 
355
356
  ### 5. Exemplo Minimo (JSON + Uso)
@@ -455,7 +456,7 @@ Correcao: verificar `applyOnShortcutClick`; com `false`, o fluxo exige acao manu
455
456
  | Event | Payload | Trigger | Stability | Notes |
456
457
  | --- | --- | --- | --- | --- |
457
458
  | `validationChange` | unknown | runtime-event | Experimental | Check component/runtime implementation. |
458
- | `valueChange` | unknown | runtime-event | Experimental | Check component/runtime implementation. |
459
+ | `valueChange` | unknown | runtime-event | Experimental | Durante seleção pelo picker, o valor é publicado apenas após o fechamento do calendário; digitação manual fora do picker continua propagando pelas regras normais do CVA. |
459
460
  | `focusChange` | unknown | runtime-event | Experimental | Check component/runtime implementation. |
460
461
  | `nativeBlur` | unknown | runtime-event | Experimental | Check component/runtime implementation. |
461
462
  | `nativeChange` | unknown | runtime-event | Experimental | Check component/runtime implementation. |
@@ -22,8 +22,8 @@ source_of_truth:
22
22
  - "projects/praxis-dynamic-fields/src/lib/components/material-datepicker/material-datepicker.component.ts"
23
23
  - "projects/praxis-core/src/lib/models/material-field-metadata.interface.ts"
24
24
  - "projects/praxis-dynamic-fields/src/lib/base/simple-base-input.component.ts"
25
- source_of_truth_last_verified: "2026-03-06"
26
- last_updated: "2026-03-06"
25
+ source_of_truth_last_verified: "2026-05-04"
26
+ last_updated: "2026-05-04"
27
27
  toc: true
28
28
  sidebar: true
29
29
  tags:
@@ -118,6 +118,7 @@ Este documento e a referencia canonica da API JSON de pdx-material-datepicker.
118
118
  | `metadata.controlType` | string | false | n/a | Partial | See Detailed API reference for runtime semantics. |
119
119
  | `metadata.minDate` | string | false | n/a | Partial | See Detailed API reference for runtime semantics. |
120
120
  | `metadata.maxDate` | string | false | n/a | Partial | See Detailed API reference for runtime semantics. |
121
+ | `metadata.manualInput` | boolean | false | `true` | Active | `false` keeps calendar selection enabled while making the text input readonly. |
121
122
 
122
123
  ### Supported legacy paths
123
124
 
@@ -155,6 +156,7 @@ Nao ha paths experimentais confirmados no contrato publico desta revisao.
155
156
  | `metadata.touchUi` | boolean | false | n/a | component-defined | Partial; verify per source_of_truth. |
156
157
  | `metadata.dateFilter` | string | false | n/a | component-defined | Partial; verify per source_of_truth. |
157
158
  | `metadata.dateFormat` | string | false | n/a | component-defined | Partial; verify per source_of_truth. |
159
+ | `metadata.manualInput` | boolean | false | `true` | `false` blocks manual typing without activating readonly field semantics. | Use for locale-sensitive dates where typed strings would be ambiguous. |
158
160
 
159
161
  ### Input bindings (inbound data)
160
162