@praxisui/metadata-editor 9.0.59 → 9.0.60

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.
@@ -4,7 +4,7 @@ import * as i1 from '@angular/forms';
4
4
  import { FormControl, FormGroup, FormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS, ReactiveFormsModule, FormArray, FormBuilder } from '@angular/forms';
5
5
  import * as i3$1 from '@angular/common';
6
6
  import { CommonModule } from '@angular/common';
7
- import { DynamicFieldLoaderDirective } from '@praxisui/dynamic-fields';
7
+ import { isValidCssColor, DynamicFieldLoaderDirective, normalizeCssColorToRgb, providePraxisDynamicFieldsI18n } from '@praxisui/dynamic-fields';
8
8
  import * as i2$2 from '@praxisui/core';
9
9
  import { providePraxisI18n, PraxisI18nService, PraxisIconDirective, FieldControlType, INLINE_FILTER_CONTROL_TYPES, resolveInlineFilterControlType, normalizeControlTypeToken, normalizeReactiveDeterminations, ComponentMetadataRegistry } from '@praxisui/core';
10
10
  import * as i5$1 from '@angular/material/expansion';
@@ -442,6 +442,65 @@ const METADATA_EDITOR_EN_US = {
442
442
  'praxis.metadataEditor.fieldResource.hint': 'Select from the host governed catalog. The saved value remains resourcePath.',
443
443
  'praxis.metadataEditor.common.help': 'Help',
444
444
  'praxis.metadataEditor.common.iconMaterialSymbolsHint': 'Use the icon name (Material Symbols)',
445
+ 'praxis.metadataEditor.priceRange.discrete.label': 'Show value while adjusting',
446
+ 'praxis.metadataEditor.priceRange.discrete.hint': 'Shows the monetary value next to the thumb while it is adjusted.',
447
+ 'praxis.metadataEditor.inlineRating.gradient.group': 'Star gradient',
448
+ 'praxis.metadataEditor.inlineRating.gradient.low.label': 'Start',
449
+ 'praxis.metadataEditor.inlineRating.gradient.low.hint': 'Color for lower ratings, on the left side of the scale.',
450
+ 'praxis.metadataEditor.inlineRating.gradient.mid.label': 'Middle',
451
+ 'praxis.metadataEditor.inlineRating.gradient.mid.hint': 'Transition color applied at the center of the scale.',
452
+ 'praxis.metadataEditor.inlineRating.gradient.high.label': 'End',
453
+ 'praxis.metadataEditor.inlineRating.gradient.high.hint': 'Color for higher ratings, on the right side of the scale.',
454
+ 'praxis.metadataEditor.inlineRating.gradient.preview.title': 'Live preview',
455
+ 'praxis.metadataEditor.inlineRating.gradient.preview.description': 'The stars show how the three colors will be distributed across the scale.',
456
+ 'praxis.metadataEditor.inlineRating.gradient.preview.ariaLabel': 'Gradient preview: start {{low}}, middle {{mid}}, end {{high}}.',
457
+ 'praxis.metadataEditor.groups.appearance': 'Appearance',
458
+ 'praxis.metadataEditor.inlineDistance.icon.label': 'Chip icon (legacy)',
459
+ 'praxis.metadataEditor.inlineDistance.icon.hint': 'Legacy prefixIcon alias for the chip icon.',
460
+ 'praxis.metadataEditor.inlineDistance.subtitle.label': 'Panel subtitle',
461
+ 'praxis.metadataEditor.inlineDistance.subtitle.hint': 'Subtitle displayed below the panel title.',
462
+ 'praxis.metadataEditor.inlineDistance.unit.label': 'Initial unit',
463
+ 'praxis.metadataEditor.inlineDistance.unit.hint': 'Initial visual unit for the control.',
464
+ 'praxis.metadataEditor.inlineDistance.baseUnit.label': 'Base unit',
465
+ 'praxis.metadataEditor.inlineDistance.baseUnit.hint': 'Canonical unit used to persist the field value.',
466
+ 'praxis.metadataEditor.inlineDistance.allowUnitToggle.label': 'Allow KM/MI switching',
467
+ 'praxis.metadataEditor.inlineDistance.allowUnitToggle.hint': 'Shows unit switching buttons in the panel.',
468
+ 'praxis.metadataEditor.inlineDistance.units.label': 'Available units',
469
+ 'praxis.metadataEditor.inlineDistance.units.hint': 'Choose the units available in the panel selector.',
470
+ 'praxis.metadataEditor.inlineDistance.unitLabelKm.label': 'KM unit label',
471
+ 'praxis.metadataEditor.inlineDistance.unitLabelKm.hint': 'Visible and announced text for kilometres.',
472
+ 'praxis.metadataEditor.inlineDistance.unitLabelMi.label': 'MI unit label',
473
+ 'praxis.metadataEditor.inlineDistance.unitLabelMi.hint': 'Visible and announced text for miles.',
474
+ 'praxis.metadataEditor.inlineDistance.decimals.label': 'Decimal places',
475
+ 'praxis.metadataEditor.inlineDistance.decimals.hint': 'Sets display decimals; empty uses automatic precision.',
476
+ 'praxis.metadataEditor.inlineDistance.presets.label': 'Distance shortcuts',
477
+ 'praxis.metadataEditor.inlineDistance.presets.hint': 'Add numeric values such as 5, 10, 25, and 50. Advanced presets remain available in the JSON editor.',
478
+ 'praxis.metadataEditor.inlineDistance.rings.label': 'Radial rings',
479
+ 'praxis.metadataEditor.inlineDistance.rings.hint': 'Number of rings in the radial view, from 3 to 8.',
480
+ 'praxis.metadataEditor.inlineDistance.accent.label': 'Accent color',
481
+ 'praxis.metadataEditor.inlineDistance.accent.hint': 'Accent applied to the central value and active states.',
482
+ 'praxis.metadataEditor.inlineDistance.ringColor.label': 'Ring color',
483
+ 'praxis.metadataEditor.inlineDistance.ringColor.hint': 'Base color for the radial rings.',
484
+ 'praxis.metadataEditor.inlineDistance.trackColor.label': 'Track color',
485
+ 'praxis.metadataEditor.inlineDistance.trackColor.hint': 'Color of the inactive slider track.',
486
+ 'praxis.metadataEditor.inlineDistance.glowColor.label': 'Radial glow color',
487
+ 'praxis.metadataEditor.inlineDistance.glowColor.hint': 'Color of the glow around the radial center.',
488
+ 'praxis.metadataEditor.inlineDistance.gradient.group': 'Radius gradient',
489
+ 'praxis.metadataEditor.inlineDistance.gradient.low.label': 'Start',
490
+ 'praxis.metadataEditor.inlineDistance.gradient.low.hint': 'Color for smaller radii, at the center of the visualization.',
491
+ 'praxis.metadataEditor.inlineDistance.gradient.mid.label': 'Middle',
492
+ 'praxis.metadataEditor.inlineDistance.gradient.mid.hint': 'Transition color for the middle region of the radius.',
493
+ 'praxis.metadataEditor.inlineDistance.gradient.high.label': 'End',
494
+ 'praxis.metadataEditor.inlineDistance.gradient.high.hint': 'Color for larger radii, at the outer edge of the visualization.',
495
+ 'praxis.metadataEditor.inlineDistance.gradient.preview.title': 'Radial preview',
496
+ 'praxis.metadataEditor.inlineDistance.gradient.preview.description': 'The radar shows how the three colors evolve from the smallest to the largest radius.',
497
+ 'praxis.metadataEditor.inlineDistance.gradient.preview.ariaLabel': 'Radial gradient preview: center {{low}}, transition {{mid}}, edge {{high}}.',
498
+ 'praxis.metadataEditor.inlineDistance.rangeOpacity.label': 'Range opacity (0\u20131)',
499
+ 'praxis.metadataEditor.inlineDistance.rangeOpacity.hint': 'Overrides the automatic opacity of the radial range.',
500
+ 'praxis.metadataEditor.inlineDistance.density.label': 'Density',
501
+ 'praxis.metadataEditor.inlineDistance.density.hint': 'Adjusts the base dimensions of the inline chip and panel.',
502
+ 'praxis.metadataEditor.validation.invalidCssColor': 'Enter a valid CSS color (for example, {{example}}).',
503
+ 'praxis.metadataEditor.validation.gradientContrast': 'The visual difference between the colors is {{ratio}}:1. Use at least {{minimum}}:1.',
445
504
  'praxis.metadataEditor.presentationFields.group': 'Presentation',
446
505
  'praxis.metadataEditor.presentationFields.valuePresentation.label': 'Value format',
447
506
  'praxis.metadataEditor.presentationFields.valuePresentation.hint': 'Canonical formatter used on readonly/presentation surfaces. Use a JSON object.',
@@ -602,6 +661,65 @@ const METADATA_EDITOR_PT_BR = {
602
661
  'praxis.metadataEditor.fieldResource.hint': 'Selecione no cat\u00e1logo governado do host. O valor gravado continua sendo resourcePath.',
603
662
  'praxis.metadataEditor.common.help': 'Ajuda',
604
663
  'praxis.metadataEditor.common.iconMaterialSymbolsHint': 'Use o nome do \u00edcone (Material Symbols)',
664
+ 'praxis.metadataEditor.priceRange.discrete.label': 'Exibir valor ao ajustar',
665
+ 'praxis.metadataEditor.priceRange.discrete.hint': 'Mostra o valor monet\u00e1rio junto ao manipulador durante o ajuste.',
666
+ 'praxis.metadataEditor.inlineRating.gradient.group': 'Gradiente das estrelas',
667
+ 'praxis.metadataEditor.inlineRating.gradient.low.label': 'In\u00edcio',
668
+ 'praxis.metadataEditor.inlineRating.gradient.low.hint': 'Cor das avalia\u00e7\u00f5es mais baixas, no lado esquerdo da escala.',
669
+ 'praxis.metadataEditor.inlineRating.gradient.mid.label': 'Meio',
670
+ 'praxis.metadataEditor.inlineRating.gradient.mid.hint': 'Cor de transi\u00e7\u00e3o aplicada ao centro da escala.',
671
+ 'praxis.metadataEditor.inlineRating.gradient.high.label': 'Fim',
672
+ 'praxis.metadataEditor.inlineRating.gradient.high.hint': 'Cor das avalia\u00e7\u00f5es mais altas, no lado direito da escala.',
673
+ 'praxis.metadataEditor.inlineRating.gradient.preview.title': 'Pr\u00e9via ao vivo',
674
+ 'praxis.metadataEditor.inlineRating.gradient.preview.description': 'As estrelas mostram como as tr\u00eas cores ser\u00e3o distribu\u00eddas na escala.',
675
+ 'praxis.metadataEditor.inlineRating.gradient.preview.ariaLabel': 'Pr\u00e9via do gradiente: in\u00edcio {{low}}, meio {{mid}}, fim {{high}}.',
676
+ 'praxis.metadataEditor.groups.appearance': 'Apar\u00eancia',
677
+ 'praxis.metadataEditor.inlineDistance.icon.label': '\u00cdcone do chip (legado)',
678
+ 'praxis.metadataEditor.inlineDistance.icon.hint': 'Alias legado de prefixIcon para o \u00edcone do chip.',
679
+ 'praxis.metadataEditor.inlineDistance.subtitle.label': 'Subt\u00edtulo do painel',
680
+ 'praxis.metadataEditor.inlineDistance.subtitle.hint': 'Subt\u00edtulo exibido abaixo do t\u00edtulo no painel.',
681
+ 'praxis.metadataEditor.inlineDistance.unit.label': 'Unidade inicial',
682
+ 'praxis.metadataEditor.inlineDistance.unit.hint': 'Unidade visual inicial do controle.',
683
+ 'praxis.metadataEditor.inlineDistance.baseUnit.label': 'Unidade base',
684
+ 'praxis.metadataEditor.inlineDistance.baseUnit.hint': 'Unidade can\u00f4nica persistida no valor do campo.',
685
+ 'praxis.metadataEditor.inlineDistance.allowUnitToggle.label': 'Permitir alternar KM/MI',
686
+ 'praxis.metadataEditor.inlineDistance.allowUnitToggle.hint': 'Mostra os bot\u00f5es para alternar a unidade no painel.',
687
+ 'praxis.metadataEditor.inlineDistance.units.label': 'Unidades dispon\u00edveis',
688
+ 'praxis.metadataEditor.inlineDistance.units.hint': 'Escolha as unidades dispon\u00edveis no seletor do painel.',
689
+ 'praxis.metadataEditor.inlineDistance.unitLabelKm.label': 'R\u00f3tulo da unidade KM',
690
+ 'praxis.metadataEditor.inlineDistance.unitLabelKm.hint': 'Texto vis\u00edvel e anunciado para quil\u00f4metros.',
691
+ 'praxis.metadataEditor.inlineDistance.unitLabelMi.label': 'R\u00f3tulo da unidade MI',
692
+ 'praxis.metadataEditor.inlineDistance.unitLabelMi.hint': 'Texto vis\u00edvel e anunciado para milhas.',
693
+ 'praxis.metadataEditor.inlineDistance.decimals.label': 'Casas decimais',
694
+ 'praxis.metadataEditor.inlineDistance.decimals.hint': 'Define as casas decimais da exibi\u00e7\u00e3o; vazio usa precis\u00e3o autom\u00e1tica.',
695
+ 'praxis.metadataEditor.inlineDistance.presets.label': 'Atalhos de dist\u00e2ncia',
696
+ 'praxis.metadataEditor.inlineDistance.presets.hint': 'Adicione valores num\u00e9ricos como 5, 10, 25 e 50. Presets avan\u00e7ados permanecem no editor JSON.',
697
+ 'praxis.metadataEditor.inlineDistance.rings.label': 'An\u00e9is radiais',
698
+ 'praxis.metadataEditor.inlineDistance.rings.hint': 'Quantidade de an\u00e9is no radar visual, entre 3 e 8.',
699
+ 'praxis.metadataEditor.inlineDistance.accent.label': 'Cor principal',
700
+ 'praxis.metadataEditor.inlineDistance.accent.hint': 'Cor principal aplicada ao valor central e aos estados ativos.',
701
+ 'praxis.metadataEditor.inlineDistance.ringColor.label': 'Cor dos an\u00e9is',
702
+ 'praxis.metadataEditor.inlineDistance.ringColor.hint': 'Cor base dos an\u00e9is circulares do radar.',
703
+ 'praxis.metadataEditor.inlineDistance.trackColor.label': 'Cor da trilha',
704
+ 'praxis.metadataEditor.inlineDistance.trackColor.hint': 'Cor da trilha inativa do controle deslizante.',
705
+ 'praxis.metadataEditor.inlineDistance.glowColor.label': 'Cor do brilho radial',
706
+ 'praxis.metadataEditor.inlineDistance.glowColor.hint': 'Cor do brilho ao redor do centro radial.',
707
+ 'praxis.metadataEditor.inlineDistance.gradient.group': 'Gradiente do raio',
708
+ 'praxis.metadataEditor.inlineDistance.gradient.low.label': 'In\u00edcio',
709
+ 'praxis.metadataEditor.inlineDistance.gradient.low.hint': 'Cor dos raios menores, no centro da visualiza\u00e7\u00e3o.',
710
+ 'praxis.metadataEditor.inlineDistance.gradient.mid.label': 'Meio',
711
+ 'praxis.metadataEditor.inlineDistance.gradient.mid.hint': 'Cor de transi\u00e7\u00e3o aplicada \u00e0 regi\u00e3o intermedi\u00e1ria do raio.',
712
+ 'praxis.metadataEditor.inlineDistance.gradient.high.label': 'Fim',
713
+ 'praxis.metadataEditor.inlineDistance.gradient.high.hint': 'Cor dos maiores raios, na borda externa da visualiza\u00e7\u00e3o.',
714
+ 'praxis.metadataEditor.inlineDistance.gradient.preview.title': 'Pr\u00e9via radial',
715
+ 'praxis.metadataEditor.inlineDistance.gradient.preview.description': 'O radar mostra como as tr\u00eas cores evoluem do menor para o maior raio.',
716
+ 'praxis.metadataEditor.inlineDistance.gradient.preview.ariaLabel': 'Pr\u00e9via radial do gradiente: centro {{low}}, transi\u00e7\u00e3o {{mid}}, borda {{high}}.',
717
+ 'praxis.metadataEditor.inlineDistance.rangeOpacity.label': 'Opacidade da faixa (0\u20131)',
718
+ 'praxis.metadataEditor.inlineDistance.rangeOpacity.hint': 'Sobrescreve a opacidade autom\u00e1tica da faixa radial.',
719
+ 'praxis.metadataEditor.inlineDistance.density.label': 'Densidade',
720
+ 'praxis.metadataEditor.inlineDistance.density.hint': 'Ajusta as dimens\u00f5es base do chip e do painel inline.',
721
+ 'praxis.metadataEditor.validation.invalidCssColor': 'Informe uma cor CSS v\u00e1lida (ex.: {{example}}).',
722
+ 'praxis.metadataEditor.validation.gradientContrast': 'A diferen\u00e7a visual entre as cores \u00e9 {{ratio}}:1. Use ao menos {{minimum}}:1.',
605
723
  'praxis.metadataEditor.presentationFields.group': 'Apresenta\u00e7\u00e3o',
606
724
  'praxis.metadataEditor.presentationFields.valuePresentation.label': 'Formato do valor',
607
725
  'praxis.metadataEditor.presentationFields.valuePresentation.hint': 'Formatador can\u00f4nico usado em superf\u00edcies readonly/presentation. Use um objeto JSON.',
@@ -1957,6 +2075,8 @@ class DynamicEditorRendererComponent {
1957
2075
  _inline: p.inline || false,
1958
2076
  _row: p.row || undefined,
1959
2077
  _editorType: p.editorType,
2078
+ _gradientPreviewKind: p.gradientPreviewKind,
2079
+ _gradientPreviewI18nPrefix: p.gradientPreviewI18nPrefix,
1960
2080
  // validators do EditorProperty já foram aplicados ao FormControl pela fábrica,
1961
2081
  // mas manter aqui não prejudica e habilita exibição de mensagens padrão.
1962
2082
  validators: undefined,
@@ -1966,11 +2086,7 @@ class DynamicEditorRendererComponent {
1966
2086
  if (coreNames.has(p.name) && !meta._row)
1967
2087
  meta._row = '__core';
1968
2088
  // Campos menores e de baixa relevância visual (agrupados inline)
1969
- const smallNames = new Set([
1970
- 'prefix',
1971
- 'suffix',
1972
- 'icon',
1973
- ]);
2089
+ const smallNames = new Set(['prefix', 'suffix', 'icon']);
1974
2090
  if (smallNames.has(p.name)) {
1975
2091
  meta._inline = true;
1976
2092
  if (!meta._row)
@@ -2016,6 +2132,8 @@ class DynamicEditorRendererComponent {
2016
2132
  'geral',
2017
2133
  'apresent',
2018
2134
  'display',
2135
+ 'gradiente',
2136
+ 'gradient',
2019
2137
  'valida',
2020
2138
  'formato',
2021
2139
  'comport',
@@ -2036,6 +2154,8 @@ class DynamicEditorRendererComponent {
2036
2154
  return 'row-presentation-rules';
2037
2155
  if (this.isPresentationChoiceRow(row))
2038
2156
  return 'row-presentation-choice';
2157
+ if (this.isGradientStopsRow(row))
2158
+ return 'row-gradient-stops';
2039
2159
  // Linha compacta (toggles) quando todos são inline
2040
2160
  if (row.every((f) => !!f._inline))
2041
2161
  return 'row-inline';
@@ -2048,16 +2168,64 @@ class DynamicEditorRendererComponent {
2048
2168
  return '';
2049
2169
  }
2050
2170
  isPresentationRulesRow(row) {
2051
- return row.length > 0 && row.every((field) => field._editorType === 'presentation-rules-builder');
2171
+ return (row.length > 0 &&
2172
+ row.every((field) => field._editorType === 'presentation-rules-builder'));
2052
2173
  }
2053
2174
  isPresentationChoiceRow(row) {
2054
- return row.length > 0 && row.every((field) => field._editorType === 'presentation-choice');
2175
+ return (row.length > 0 &&
2176
+ row.every((field) => field._editorType === 'presentation-choice'));
2177
+ }
2178
+ isGradientStopsRow(row) {
2179
+ return (row.length === 3 &&
2180
+ row.every((field) => field._editorType === 'gradient-stop'));
2181
+ }
2182
+ gradientPreviewKind(row = []) {
2183
+ const kind = String(row[0]?._gradientPreviewKind ?? '').trim();
2184
+ return kind === 'radial' ? 'radial' : 'stars';
2185
+ }
2186
+ gradientPreviewTitle(row = []) {
2187
+ const prefix = this.gradientPreviewI18nPrefix(row);
2188
+ return (this.resolveEditorText(`${prefix}.preview.title`, 'Prévia ao vivo') ?? 'Prévia ao vivo');
2189
+ }
2190
+ gradientPreviewDescription(row = []) {
2191
+ const prefix = this.gradientPreviewI18nPrefix(row);
2192
+ return (this.resolveEditorText(`${prefix}.preview.description`, 'As estrelas mostram como as três cores serão distribuídas na escala.') ??
2193
+ 'As estrelas mostram como as três cores serão distribuídas na escala.');
2194
+ }
2195
+ gradientPreviewBackground(row) {
2196
+ const colors = row.map((field) => this.previewColor(field.name));
2197
+ const [low, mid, high] = colors;
2198
+ if (this.gradientPreviewKind(row) === 'radial') {
2199
+ return `radial-gradient(circle, ${low} 0%, ${mid} 56%, ${high} 100%)`;
2200
+ }
2201
+ return `linear-gradient(90deg, ${low} 0%, ${mid} 50%, ${high} 100%)`;
2202
+ }
2203
+ gradientPreviewAriaLabel(row) {
2204
+ const [low, mid, high] = row.map((field) => this.previewColor(field.name));
2205
+ const prefix = this.gradientPreviewI18nPrefix(row);
2206
+ const template = this.resolveEditorText(`${prefix}.preview.ariaLabel`, 'Prévia do gradiente: início {{low}}, meio {{mid}}, fim {{high}}.') ?? 'Prévia do gradiente: início {{low}}, meio {{mid}}, fim {{high}}.';
2207
+ return template
2208
+ .replace('{{low}}', low)
2209
+ .replace('{{mid}}', mid)
2210
+ .replace('{{high}}', high);
2211
+ }
2212
+ gradientPreviewI18nPrefix(row = []) {
2213
+ return String(row[0]?._gradientPreviewI18nPrefix ?? 'inlineRating.gradient');
2214
+ }
2215
+ previewColor(path) {
2216
+ const fallback = 'var(--md-sys-color-tertiary)';
2217
+ const value = String(this.form?.get(path)?.value ?? '').trim();
2218
+ return value && isValidCssColor(value) ? value : fallback;
2055
2219
  }
2056
2220
  canRenderPresentationRulesRow(row) {
2057
- return this.ready && this.isPresentationRulesRow(row) && this.hasControlsForRow(row);
2221
+ return (this.ready &&
2222
+ this.isPresentationRulesRow(row) &&
2223
+ this.hasControlsForRow(row));
2058
2224
  }
2059
2225
  canRenderPresentationChoiceRow(row) {
2060
- return this.ready && this.isPresentationChoiceRow(row) && this.hasControlsForRow(row);
2226
+ return (this.ready &&
2227
+ this.isPresentationChoiceRow(row) &&
2228
+ this.hasControlsForRow(row));
2061
2229
  }
2062
2230
  hasControlsForRow(row) {
2063
2231
  return row.every((field) => !!this.form?.get(field.name));
@@ -2079,6 +2247,10 @@ class DynamicEditorRendererComponent {
2079
2247
  return FieldControlType.TEXTAREA;
2080
2248
  case 'select':
2081
2249
  return FieldControlType.SELECT;
2250
+ case 'multi-select':
2251
+ return FieldControlType.MULTI_SELECT;
2252
+ case 'chip-input':
2253
+ return FieldControlType.CHIP_INPUT;
2082
2254
  case 'checkbox':
2083
2255
  // Para booleano simples, usamos o toggle
2084
2256
  return FieldControlType.TOGGLE;
@@ -2087,6 +2259,7 @@ class DynamicEditorRendererComponent {
2087
2259
  case 'datetime-local':
2088
2260
  return FieldControlType.DATETIME_LOCAL_INPUT;
2089
2261
  case 'color':
2262
+ case 'gradient-stop':
2090
2263
  return FieldControlType.COLOR_INPUT;
2091
2264
  case 'colorPicker':
2092
2265
  return FieldControlType.COLOR_PICKER;
@@ -2153,11 +2326,11 @@ class DynamicEditorRendererComponent {
2153
2326
  if (!path)
2154
2327
  return false;
2155
2328
  // Supports: prefixIcon, suffixIcon, icon, clearButton.icon, any *.icon
2156
- return path === 'prefixIcon'
2157
- || path === 'suffixIcon'
2158
- || path === 'icon'
2159
- || path === 'emptyIcon'
2160
- || /(^|\.)icon$/.test(path);
2329
+ return (path === 'prefixIcon' ||
2330
+ path === 'suffixIcon' ||
2331
+ path === 'icon' ||
2332
+ path === 'emptyIcon' ||
2333
+ /(^|\.)icon$/.test(path));
2161
2334
  }
2162
2335
  useHelpSuffix(field) {
2163
2336
  const editorType = field._editorType;
@@ -2213,10 +2386,15 @@ class DynamicEditorRendererComponent {
2213
2386
  }
2214
2387
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicEditorRendererComponent, deps: [{ token: i1$1.MatDialog }, { token: i2$2.IconPickerService }, { token: i2$2.PraxisI18nService, optional: true }], target: i0.ɵɵFactoryTarget.Component });
2215
2388
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicEditorRendererComponent, isStandalone: true, selector: "praxis-dynamic-editor-renderer", inputs: { properties: "properties", form: "form" }, usesOnChanges: true, ngImport: i0, template: `
2216
- <ng-template #item let-field="field" let-index="index" let-content="content">
2389
+ <ng-template
2390
+ #item
2391
+ let-field="field"
2392
+ let-index="index"
2393
+ let-content="content"
2394
+ >
2217
2395
  <div class="editor-item" [attr.data-control-type]="field.controlType">
2218
2396
  <ng-container [ngTemplateOutlet]="content"></ng-container>
2219
-
2397
+
2220
2398
  <div class="actions-container">
2221
2399
  <!-- Botão de ajuda para regex -->
2222
2400
  @if (field.name === 'pattern') {
@@ -2227,7 +2405,7 @@ class DynamicEditorRendererComponent {
2227
2405
  (click)="openRegexHelp()"
2228
2406
  aria-label="Exemplos de regex"
2229
2407
  matTooltip="Exemplos de regex"
2230
- >
2408
+ >
2231
2409
  <mat-icon [praxisIcon]="'search'"></mat-icon>
2232
2410
  </button>
2233
2411
  }
@@ -2240,7 +2418,7 @@ class DynamicEditorRendererComponent {
2240
2418
  (click)="openIconPicker(field.name)"
2241
2419
  aria-label="Escolher ícone"
2242
2420
  matTooltip="Escolher ícone"
2243
- >
2421
+ >
2244
2422
  <mat-icon [praxisIcon]="'apps'"></mat-icon>
2245
2423
  </button>
2246
2424
  }
@@ -2252,15 +2430,15 @@ class DynamicEditorRendererComponent {
2252
2430
  class="hint-btn decorator-btn"
2253
2431
  [class.has-icon-picker]="isIconField(field.name)"
2254
2432
  [matTooltip]="field.hint"
2255
- aria-label="Ajuda"
2256
- >
2433
+ [attr.aria-label]="field.hint"
2434
+ >
2257
2435
  <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2258
2436
  </button>
2259
2437
  }
2260
2438
  </div>
2261
2439
  </div>
2262
2440
  </ng-template>
2263
-
2441
+
2264
2442
  <div class="editor-surface">
2265
2443
  <mat-accordion class="section-accordion" multi>
2266
2444
  @for (g of groupOrder; track g) {
@@ -2268,7 +2446,10 @@ class DynamicEditorRendererComponent {
2268
2446
  <mat-expansion-panel-header class="section-header">
2269
2447
  <mat-panel-title>
2270
2448
  <span class="section-title">
2271
- <mat-icon class="section-icon" [praxisIcon]="groupIcon(g)"></mat-icon>
2449
+ <mat-icon
2450
+ class="section-icon"
2451
+ [praxisIcon]="groupIcon(g)"
2452
+ ></mat-icon>
2272
2453
  {{ g }}
2273
2454
  </span>
2274
2455
  </mat-panel-title>
@@ -2279,7 +2460,8 @@ class DynamicEditorRendererComponent {
2279
2460
  @for (field of row; track field.name) {
2280
2461
  <praxis-presentation-rules-builder
2281
2462
  class="presentation-rules-field"
2282
- [formControl]="controlFor(field.name)">
2463
+ [formControl]="controlFor(field.name)"
2464
+ >
2283
2465
  </praxis-presentation-rules-builder>
2284
2466
  }
2285
2467
  } @else if (canRenderPresentationChoiceRow(row)) {
@@ -2287,15 +2469,53 @@ class DynamicEditorRendererComponent {
2287
2469
  <praxis-presentation-choice-control
2288
2470
  class="presentation-choice-field"
2289
2471
  [field]="field"
2290
- [formControl]="controlFor(field.name)">
2472
+ [formControl]="controlFor(field.name)"
2473
+ >
2291
2474
  </praxis-presentation-choice-control>
2292
2475
  }
2476
+ } @else if (isGradientStopsRow(row)) {
2477
+ <div
2478
+ class="gradient-stops-preview"
2479
+ role="img"
2480
+ [attr.aria-label]="gradientPreviewAriaLabel(row)"
2481
+ >
2482
+ <div class="gradient-stops-preview__copy">
2483
+ <strong>{{ gradientPreviewTitle(row) }}</strong>
2484
+ <span>{{ gradientPreviewDescription(row) }}</span>
2485
+ </div>
2486
+ @if (gradientPreviewKind(row) === 'radial') {
2487
+ <span
2488
+ class="gradient-stops-preview__radial"
2489
+ aria-hidden="true"
2490
+ [style.background-image]="gradientPreviewBackground(row)"
2491
+ >
2492
+ <span></span>
2493
+ </span>
2494
+ } @else {
2495
+ <span
2496
+ class="gradient-stops-preview__stars"
2497
+ aria-hidden="true"
2498
+ [style.background-image]="gradientPreviewBackground(row)"
2499
+ >★★★★★</span
2500
+ >
2501
+ }
2502
+ </div>
2503
+ @if (ready && hasControlsForRow(row)) {
2504
+ <ng-container
2505
+ dynamicFieldLoader
2506
+ [fields]="row"
2507
+ [formGroup]="form"
2508
+ [itemTemplate]="item"
2509
+ >
2510
+ </ng-container>
2511
+ }
2293
2512
  } @else if (ready && hasControlsForRow(row)) {
2294
2513
  <ng-container
2295
2514
  dynamicFieldLoader
2296
2515
  [fields]="row"
2297
2516
  [formGroup]="form"
2298
- [itemTemplate]="item">
2517
+ [itemTemplate]="item"
2518
+ >
2299
2519
  </ng-container>
2300
2520
  }
2301
2521
  </div>
@@ -2304,7 +2524,7 @@ class DynamicEditorRendererComponent {
2304
2524
  }
2305
2525
  </mat-accordion>
2306
2526
  </div>
2307
- `, isInline: true, styles: [":host{display:block}.editor-surface{padding:8px 0 2px;border-radius:12px;background:transparent}.section-accordion{display:block}.section-card{margin:6px 0 8px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);overflow:hidden}.section-card.mat-expanded{border-color:var(--md-sys-color-primary);box-shadow:0 2px 10px #0000000d}.section-card .mat-expansion-panel-body{background:var(--md-sys-color-surface-container-low)}.section-header{background:var(--md-sys-color-surface-container-low);border-bottom:1px solid var(--md-sys-color-outline-variant, var(--sicoob-stroke-medium));padding:2px 8px;min-height:32px;display:flex;align-items:center;color:var(--md-sys-color-on-surface)}.section-header .mat-expansion-panel-header-title,.section-header .mat-expansion-panel-header-description{display:flex;align-items:center;color:var(--md-sys-color-on-surface)}.section-title{display:inline-flex;align-items:center;gap:6px;font-weight:600;letter-spacing:.2px;color:var(--md-sys-color-on-surface);font-size:.9rem;line-height:1.2}.section-icon{color:var(--md-sys-color-primary, var(--md-sys-color-primary, #3f51b5));opacity:.9}.editor-row{display:flex;gap:12px;align-items:flex-start;flex-wrap:wrap;margin-bottom:8px}.editor-row>praxis-field-shell{flex:1 1 100%;min-width:280px}.editor-row praxis-field-shell .mat-mdc-form-field{width:100%;margin-bottom:8px}.editor-row.row-inline>praxis-field-shell{flex:0 0 auto}.editor-row.row-2>praxis-field-shell{flex:1 1 calc(50% - 12px);min-width:260px}.editor-row.row-3>praxis-field-shell{flex:1 1 calc(33.333% - 12px);min-width:220px}.editor-row>praxis-field-shell[data-field-name=controlType],.editor-row>praxis-field-shell[data-field-name=label],.editor-row>praxis-field-shell[data-field-name=placeholder]{flex:1 1 calc(50% - 12px);min-width:300px}.editor-row>praxis-presentation-rules-builder.presentation-rules-field{flex:1 1 100%;min-width:0}.editor-row>praxis-presentation-choice-control.presentation-choice-field{flex:1 1 100%;min-width:0}praxis-field-shell[data-field-name=label] .mdc-floating-label,praxis-field-shell[data-field-name=placeholder] .mdc-floating-label{font-weight:600}.editor-row>praxis-field-shell[data-field-name=prefix],.editor-row>praxis-field-shell[data-field-name=suffix]{flex:0 0 200px;min-width:160px}.editor-row>praxis-field-shell[data-field-name=prefixIcon],.editor-row>praxis-field-shell[data-field-name=suffixIcon],.editor-row>praxis-field-shell[data-field-name=prefixIconColor],.editor-row>praxis-field-shell[data-field-name=suffixIconColor]{flex:1 1 auto;min-width:160px}.editor-item{display:flex;align-items:flex-start;gap:4px;min-width:0;width:100%}.editor-item>ng-container,.editor-item>praxis-field-shell{flex:1;min-width:0}.actions-container{display:flex;align-items:center;gap:0;margin-top:12px;flex-shrink:0}.decorator-btn{position:static;color:var(--md-sys-color-primary, #3f51b5);opacity:.6;transform:scale(.8);width:32px;height:32px;line-height:32px;padding:0}.decorator-btn:hover{opacity:1}.icon-picker-btn,.hint-btn,.hint-btn.has-icon-picker{right:auto}.editor-row .mat-mdc-form-field-subscript-wrapper mat-hint{display:none!important}.editor-row .mat-mdc-form-field-subscript-wrapper mat-error{display:block!important}praxis-field-shell[data-field-name=showCharCount] .mdc-switch{transform:scale(1.05)}praxis-field-shell[data-field-name=showCharCount] .mat-mdc-slide-toggle{font-weight:600}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-hint{display:flex;align-items:center;gap:8px;background:var(--md-sys-color-tertiary-container);border:1px solid var(--md-sys-color-tertiary);color:var(--md-sys-color-on-tertiary-container);padding:8px 10px;border-radius:6px;line-height:1.3;white-space:normal}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-hint:before{content:\"\\26a0\\fe0f\";display:inline-block}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-subscript-wrapper{margin-top:6px;margin-bottom:10px;min-height:auto}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field{margin-bottom:16px}@media(max-width:520px){.editor-row,.editor-row.row-inline{gap:8px}.editor-item{flex-direction:column;gap:2px}.editor-row.row-inline>praxis-field-shell,.editor-row.row-2>praxis-field-shell,.editor-row.row-3>praxis-field-shell{flex:1 1 100%;min-width:0}.actions-container{width:100%;justify-content:flex-end;margin-top:0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: DynamicFieldLoaderDirective, selector: "[dynamicFieldLoader]", inputs: ["fields", "formGroup", "enableExternalControlBinding", "itemTemplate", "debugTrace", "debugTraceLabel", "readonlyMode", "disabledMode", "presentationMode", "visible", "canvasMode"], outputs: ["componentsCreated", "fieldCreated", "fieldDestroyed", "renderError", "canvasMouseEnter", "canvasMouseLeave", "canvasClick", "canvasFocus"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "directive", type: i5$1.MatAccordion, selector: "mat-accordion", inputs: ["hideToggle", "displayMode", "togglePosition"], exportAs: ["matAccordion"] }, { kind: "component", type: i5$1.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i5$1.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i5$1.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PresentationRulesBuilderComponent, selector: "praxis-presentation-rules-builder" }, { kind: "component", type: PresentationChoiceControlComponent, selector: "praxis-presentation-choice-control", inputs: ["field"] }], encapsulation: i0.ViewEncapsulation.None });
2527
+ `, isInline: true, styles: [":host{display:block}.editor-surface{padding:8px 0 2px;border-radius:12px;background:transparent}.section-accordion{display:block}.section-card{margin:6px 0 8px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);overflow:hidden}.section-card.mat-expanded{border-color:var(--md-sys-color-primary);box-shadow:0 2px 10px #0000000d}.section-card .mat-expansion-panel-body{background:var(--md-sys-color-surface-container-low)}.section-header{background:var(--md-sys-color-surface-container-low);border-bottom:1px solid var(--md-sys-color-outline-variant, var(--sicoob-stroke-medium));padding:2px 8px;min-height:32px;display:flex;align-items:center;color:var(--md-sys-color-on-surface)}.section-header .mat-expansion-panel-header-title,.section-header .mat-expansion-panel-header-description{display:flex;align-items:center;color:var(--md-sys-color-on-surface)}.section-title{display:inline-flex;align-items:center;gap:6px;font-weight:600;letter-spacing:.2px;color:var(--md-sys-color-on-surface);font-size:.9rem;line-height:1.2}.section-icon{color:var( --md-sys-color-primary, var(--md-sys-color-primary, #3f51b5) );opacity:.9}.editor-row{display:flex;gap:12px;align-items:flex-start;flex-wrap:wrap;margin-bottom:8px}.editor-row>praxis-field-shell{flex:1 1 100%;min-width:280px}.editor-row praxis-field-shell .mat-mdc-form-field{width:100%;margin-bottom:8px}.editor-row.row-inline>praxis-field-shell{flex:0 0 auto}.editor-row.row-2>praxis-field-shell{flex:1 1 calc(50% - 12px);min-width:260px}.editor-row.row-3>praxis-field-shell{flex:1 1 calc(33.333% - 12px);min-width:220px}.editor-row.row-gradient-stops>praxis-field-shell{flex:1 1 100%;min-width:0;width:100%}.editor-row.row-gradient-stops .editor-item>pdx-color-input{flex:1 1 auto;min-width:0}.gradient-stops-preview{display:flex;flex:1 1 100%;align-items:center;justify-content:space-between;gap:16px;min-width:0;padding:14px 16px;border:1px solid var(--md-sys-color-outline-variant);border-radius:12px;background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface)}.gradient-stops-preview__copy{display:grid;gap:3px;min-width:0}.gradient-stops-preview__copy strong{font:var(--md-sys-typescale-label-large-font, inherit);font-weight:650}.gradient-stops-preview__copy span{color:var(--md-sys-color-on-surface-variant);font:var(--md-sys-typescale-body-small-font, inherit);line-height:1.35}.gradient-stops-preview__stars{flex:0 0 auto;color:transparent;background-clip:text;-webkit-background-clip:text;font-size:30px;line-height:1;letter-spacing:2px}.gradient-stops-preview__radial{position:relative;flex:0 0 auto;width:76px;height:76px;border-radius:50%;box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent)}.gradient-stops-preview__radial:before,.gradient-stops-preview__radial:after,.gradient-stops-preview__radial>span{content:\"\";position:absolute;inset:12px;border:1px dashed color-mix(in srgb,var(--md-sys-color-on-surface) 35%,transparent);border-radius:50%}.gradient-stops-preview__radial:after{inset:25px}.gradient-stops-preview__radial>span{inset:35px;border:0;background:var(--md-sys-color-on-surface)}@media(forced-colors:active){.gradient-stops-preview{border-color:CanvasText}.gradient-stops-preview__stars,.gradient-stops-preview__radial{color:CanvasText;background:none}}.editor-row>praxis-field-shell[data-field-name=controlType],.editor-row>praxis-field-shell[data-field-name=label],.editor-row>praxis-field-shell[data-field-name=placeholder]{flex:1 1 calc(50% - 12px);min-width:300px}.editor-row>praxis-presentation-rules-builder.presentation-rules-field{flex:1 1 100%;min-width:0}.editor-row>praxis-presentation-choice-control.presentation-choice-field{flex:1 1 100%;min-width:0}praxis-field-shell[data-field-name=label] .mdc-floating-label,praxis-field-shell[data-field-name=placeholder] .mdc-floating-label{font-weight:600}.editor-row>praxis-field-shell[data-field-name=prefix],.editor-row>praxis-field-shell[data-field-name=suffix]{flex:0 0 200px;min-width:160px}.editor-row>praxis-field-shell[data-field-name=prefixIcon],.editor-row>praxis-field-shell[data-field-name=suffixIcon],.editor-row>praxis-field-shell[data-field-name=prefixIconColor],.editor-row>praxis-field-shell[data-field-name=suffixIconColor]{flex:1 1 auto;min-width:160px}.editor-item{display:flex;align-items:flex-start;gap:4px;min-width:0;width:100%}.editor-item>ng-container,.editor-item>praxis-field-shell{flex:1;min-width:0}.actions-container{display:flex;align-items:center;gap:0;margin-top:12px;flex-shrink:0}.decorator-btn{position:static;color:var(--md-sys-color-primary, #3f51b5);opacity:.6;transform:scale(.8);width:32px;height:32px;line-height:32px;padding:0}.decorator-btn:hover{opacity:1}.icon-picker-btn,.hint-btn,.hint-btn.has-icon-picker{right:auto}.editor-row .mat-mdc-form-field-subscript-wrapper mat-hint{display:none!important}.editor-row .mat-mdc-form-field-subscript-wrapper mat-error{display:block!important}praxis-field-shell[data-field-name=showCharCount] .mdc-switch{transform:scale(1.05)}praxis-field-shell[data-field-name=showCharCount] .mat-mdc-slide-toggle{font-weight:600}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-hint{display:flex;align-items:center;gap:8px;background:var(--md-sys-color-tertiary-container);border:1px solid var(--md-sys-color-tertiary);color:var(--md-sys-color-on-tertiary-container);padding:8px 10px;border-radius:6px;line-height:1.3;white-space:normal}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-hint:before{content:\"\\26a0\\fe0f\";display:inline-block}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-subscript-wrapper{margin-top:6px;margin-bottom:10px;min-height:auto}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field{margin-bottom:16px}@media(max-width:520px){.editor-row,.editor-row.row-inline{gap:8px}.editor-item{flex-direction:column;gap:2px}.editor-row.row-inline>praxis-field-shell,.editor-row.row-2>praxis-field-shell,.editor-row.row-3>praxis-field-shell{flex:1 1 100%;min-width:0}.gradient-stops-preview{align-items:flex-start;flex-direction:column}.gradient-stops-preview__stars{font-size:27px}.actions-container{width:100%;justify-content:flex-end;margin-top:0}.editor-row.row-gradient-stops .editor-item{align-items:flex-start;flex-direction:row;gap:4px}.editor-row.row-gradient-stops .actions-container{width:auto;margin-top:12px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: DynamicFieldLoaderDirective, selector: "[dynamicFieldLoader]", inputs: ["fields", "formGroup", "enableExternalControlBinding", "itemTemplate", "debugTrace", "debugTraceLabel", "readonlyMode", "disabledMode", "presentationMode", "visible", "canvasMode"], outputs: ["componentsCreated", "fieldCreated", "fieldDestroyed", "renderError", "canvasMouseEnter", "canvasMouseLeave", "canvasClick", "canvasFocus"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "directive", type: i5$1.MatAccordion, selector: "mat-accordion", inputs: ["hideToggle", "displayMode", "togglePosition"], exportAs: ["matAccordion"] }, { kind: "component", type: i5$1.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i5$1.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i5$1.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PresentationRulesBuilderComponent, selector: "praxis-presentation-rules-builder" }, { kind: "component", type: PresentationChoiceControlComponent, selector: "praxis-presentation-choice-control", inputs: ["field"] }], encapsulation: i0.ViewEncapsulation.None });
2308
2528
  }
2309
2529
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicEditorRendererComponent, decorators: [{
2310
2530
  type: Component,
@@ -2321,10 +2541,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
2321
2541
  PresentationRulesBuilderComponent,
2322
2542
  PresentationChoiceControlComponent,
2323
2543
  ], encapsulation: ViewEncapsulation.None, template: `
2324
- <ng-template #item let-field="field" let-index="index" let-content="content">
2544
+ <ng-template
2545
+ #item
2546
+ let-field="field"
2547
+ let-index="index"
2548
+ let-content="content"
2549
+ >
2325
2550
  <div class="editor-item" [attr.data-control-type]="field.controlType">
2326
2551
  <ng-container [ngTemplateOutlet]="content"></ng-container>
2327
-
2552
+
2328
2553
  <div class="actions-container">
2329
2554
  <!-- Botão de ajuda para regex -->
2330
2555
  @if (field.name === 'pattern') {
@@ -2335,7 +2560,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
2335
2560
  (click)="openRegexHelp()"
2336
2561
  aria-label="Exemplos de regex"
2337
2562
  matTooltip="Exemplos de regex"
2338
- >
2563
+ >
2339
2564
  <mat-icon [praxisIcon]="'search'"></mat-icon>
2340
2565
  </button>
2341
2566
  }
@@ -2348,7 +2573,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
2348
2573
  (click)="openIconPicker(field.name)"
2349
2574
  aria-label="Escolher ícone"
2350
2575
  matTooltip="Escolher ícone"
2351
- >
2576
+ >
2352
2577
  <mat-icon [praxisIcon]="'apps'"></mat-icon>
2353
2578
  </button>
2354
2579
  }
@@ -2360,15 +2585,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
2360
2585
  class="hint-btn decorator-btn"
2361
2586
  [class.has-icon-picker]="isIconField(field.name)"
2362
2587
  [matTooltip]="field.hint"
2363
- aria-label="Ajuda"
2364
- >
2588
+ [attr.aria-label]="field.hint"
2589
+ >
2365
2590
  <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2366
2591
  </button>
2367
2592
  }
2368
2593
  </div>
2369
2594
  </div>
2370
2595
  </ng-template>
2371
-
2596
+
2372
2597
  <div class="editor-surface">
2373
2598
  <mat-accordion class="section-accordion" multi>
2374
2599
  @for (g of groupOrder; track g) {
@@ -2376,7 +2601,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
2376
2601
  <mat-expansion-panel-header class="section-header">
2377
2602
  <mat-panel-title>
2378
2603
  <span class="section-title">
2379
- <mat-icon class="section-icon" [praxisIcon]="groupIcon(g)"></mat-icon>
2604
+ <mat-icon
2605
+ class="section-icon"
2606
+ [praxisIcon]="groupIcon(g)"
2607
+ ></mat-icon>
2380
2608
  {{ g }}
2381
2609
  </span>
2382
2610
  </mat-panel-title>
@@ -2387,7 +2615,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
2387
2615
  @for (field of row; track field.name) {
2388
2616
  <praxis-presentation-rules-builder
2389
2617
  class="presentation-rules-field"
2390
- [formControl]="controlFor(field.name)">
2618
+ [formControl]="controlFor(field.name)"
2619
+ >
2391
2620
  </praxis-presentation-rules-builder>
2392
2621
  }
2393
2622
  } @else if (canRenderPresentationChoiceRow(row)) {
@@ -2395,15 +2624,53 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
2395
2624
  <praxis-presentation-choice-control
2396
2625
  class="presentation-choice-field"
2397
2626
  [field]="field"
2398
- [formControl]="controlFor(field.name)">
2627
+ [formControl]="controlFor(field.name)"
2628
+ >
2399
2629
  </praxis-presentation-choice-control>
2400
2630
  }
2631
+ } @else if (isGradientStopsRow(row)) {
2632
+ <div
2633
+ class="gradient-stops-preview"
2634
+ role="img"
2635
+ [attr.aria-label]="gradientPreviewAriaLabel(row)"
2636
+ >
2637
+ <div class="gradient-stops-preview__copy">
2638
+ <strong>{{ gradientPreviewTitle(row) }}</strong>
2639
+ <span>{{ gradientPreviewDescription(row) }}</span>
2640
+ </div>
2641
+ @if (gradientPreviewKind(row) === 'radial') {
2642
+ <span
2643
+ class="gradient-stops-preview__radial"
2644
+ aria-hidden="true"
2645
+ [style.background-image]="gradientPreviewBackground(row)"
2646
+ >
2647
+ <span></span>
2648
+ </span>
2649
+ } @else {
2650
+ <span
2651
+ class="gradient-stops-preview__stars"
2652
+ aria-hidden="true"
2653
+ [style.background-image]="gradientPreviewBackground(row)"
2654
+ >★★★★★</span
2655
+ >
2656
+ }
2657
+ </div>
2658
+ @if (ready && hasControlsForRow(row)) {
2659
+ <ng-container
2660
+ dynamicFieldLoader
2661
+ [fields]="row"
2662
+ [formGroup]="form"
2663
+ [itemTemplate]="item"
2664
+ >
2665
+ </ng-container>
2666
+ }
2401
2667
  } @else if (ready && hasControlsForRow(row)) {
2402
2668
  <ng-container
2403
2669
  dynamicFieldLoader
2404
2670
  [fields]="row"
2405
2671
  [formGroup]="form"
2406
- [itemTemplate]="item">
2672
+ [itemTemplate]="item"
2673
+ >
2407
2674
  </ng-container>
2408
2675
  }
2409
2676
  </div>
@@ -2412,7 +2679,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
2412
2679
  }
2413
2680
  </mat-accordion>
2414
2681
  </div>
2415
- `, styles: [":host{display:block}.editor-surface{padding:8px 0 2px;border-radius:12px;background:transparent}.section-accordion{display:block}.section-card{margin:6px 0 8px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);overflow:hidden}.section-card.mat-expanded{border-color:var(--md-sys-color-primary);box-shadow:0 2px 10px #0000000d}.section-card .mat-expansion-panel-body{background:var(--md-sys-color-surface-container-low)}.section-header{background:var(--md-sys-color-surface-container-low);border-bottom:1px solid var(--md-sys-color-outline-variant, var(--sicoob-stroke-medium));padding:2px 8px;min-height:32px;display:flex;align-items:center;color:var(--md-sys-color-on-surface)}.section-header .mat-expansion-panel-header-title,.section-header .mat-expansion-panel-header-description{display:flex;align-items:center;color:var(--md-sys-color-on-surface)}.section-title{display:inline-flex;align-items:center;gap:6px;font-weight:600;letter-spacing:.2px;color:var(--md-sys-color-on-surface);font-size:.9rem;line-height:1.2}.section-icon{color:var(--md-sys-color-primary, var(--md-sys-color-primary, #3f51b5));opacity:.9}.editor-row{display:flex;gap:12px;align-items:flex-start;flex-wrap:wrap;margin-bottom:8px}.editor-row>praxis-field-shell{flex:1 1 100%;min-width:280px}.editor-row praxis-field-shell .mat-mdc-form-field{width:100%;margin-bottom:8px}.editor-row.row-inline>praxis-field-shell{flex:0 0 auto}.editor-row.row-2>praxis-field-shell{flex:1 1 calc(50% - 12px);min-width:260px}.editor-row.row-3>praxis-field-shell{flex:1 1 calc(33.333% - 12px);min-width:220px}.editor-row>praxis-field-shell[data-field-name=controlType],.editor-row>praxis-field-shell[data-field-name=label],.editor-row>praxis-field-shell[data-field-name=placeholder]{flex:1 1 calc(50% - 12px);min-width:300px}.editor-row>praxis-presentation-rules-builder.presentation-rules-field{flex:1 1 100%;min-width:0}.editor-row>praxis-presentation-choice-control.presentation-choice-field{flex:1 1 100%;min-width:0}praxis-field-shell[data-field-name=label] .mdc-floating-label,praxis-field-shell[data-field-name=placeholder] .mdc-floating-label{font-weight:600}.editor-row>praxis-field-shell[data-field-name=prefix],.editor-row>praxis-field-shell[data-field-name=suffix]{flex:0 0 200px;min-width:160px}.editor-row>praxis-field-shell[data-field-name=prefixIcon],.editor-row>praxis-field-shell[data-field-name=suffixIcon],.editor-row>praxis-field-shell[data-field-name=prefixIconColor],.editor-row>praxis-field-shell[data-field-name=suffixIconColor]{flex:1 1 auto;min-width:160px}.editor-item{display:flex;align-items:flex-start;gap:4px;min-width:0;width:100%}.editor-item>ng-container,.editor-item>praxis-field-shell{flex:1;min-width:0}.actions-container{display:flex;align-items:center;gap:0;margin-top:12px;flex-shrink:0}.decorator-btn{position:static;color:var(--md-sys-color-primary, #3f51b5);opacity:.6;transform:scale(.8);width:32px;height:32px;line-height:32px;padding:0}.decorator-btn:hover{opacity:1}.icon-picker-btn,.hint-btn,.hint-btn.has-icon-picker{right:auto}.editor-row .mat-mdc-form-field-subscript-wrapper mat-hint{display:none!important}.editor-row .mat-mdc-form-field-subscript-wrapper mat-error{display:block!important}praxis-field-shell[data-field-name=showCharCount] .mdc-switch{transform:scale(1.05)}praxis-field-shell[data-field-name=showCharCount] .mat-mdc-slide-toggle{font-weight:600}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-hint{display:flex;align-items:center;gap:8px;background:var(--md-sys-color-tertiary-container);border:1px solid var(--md-sys-color-tertiary);color:var(--md-sys-color-on-tertiary-container);padding:8px 10px;border-radius:6px;line-height:1.3;white-space:normal}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-hint:before{content:\"\\26a0\\fe0f\";display:inline-block}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-subscript-wrapper{margin-top:6px;margin-bottom:10px;min-height:auto}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field{margin-bottom:16px}@media(max-width:520px){.editor-row,.editor-row.row-inline{gap:8px}.editor-item{flex-direction:column;gap:2px}.editor-row.row-inline>praxis-field-shell,.editor-row.row-2>praxis-field-shell,.editor-row.row-3>praxis-field-shell{flex:1 1 100%;min-width:0}.actions-container{width:100%;justify-content:flex-end;margin-top:0}}\n"] }]
2682
+ `, styles: [":host{display:block}.editor-surface{padding:8px 0 2px;border-radius:12px;background:transparent}.section-accordion{display:block}.section-card{margin:6px 0 8px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);overflow:hidden}.section-card.mat-expanded{border-color:var(--md-sys-color-primary);box-shadow:0 2px 10px #0000000d}.section-card .mat-expansion-panel-body{background:var(--md-sys-color-surface-container-low)}.section-header{background:var(--md-sys-color-surface-container-low);border-bottom:1px solid var(--md-sys-color-outline-variant, var(--sicoob-stroke-medium));padding:2px 8px;min-height:32px;display:flex;align-items:center;color:var(--md-sys-color-on-surface)}.section-header .mat-expansion-panel-header-title,.section-header .mat-expansion-panel-header-description{display:flex;align-items:center;color:var(--md-sys-color-on-surface)}.section-title{display:inline-flex;align-items:center;gap:6px;font-weight:600;letter-spacing:.2px;color:var(--md-sys-color-on-surface);font-size:.9rem;line-height:1.2}.section-icon{color:var( --md-sys-color-primary, var(--md-sys-color-primary, #3f51b5) );opacity:.9}.editor-row{display:flex;gap:12px;align-items:flex-start;flex-wrap:wrap;margin-bottom:8px}.editor-row>praxis-field-shell{flex:1 1 100%;min-width:280px}.editor-row praxis-field-shell .mat-mdc-form-field{width:100%;margin-bottom:8px}.editor-row.row-inline>praxis-field-shell{flex:0 0 auto}.editor-row.row-2>praxis-field-shell{flex:1 1 calc(50% - 12px);min-width:260px}.editor-row.row-3>praxis-field-shell{flex:1 1 calc(33.333% - 12px);min-width:220px}.editor-row.row-gradient-stops>praxis-field-shell{flex:1 1 100%;min-width:0;width:100%}.editor-row.row-gradient-stops .editor-item>pdx-color-input{flex:1 1 auto;min-width:0}.gradient-stops-preview{display:flex;flex:1 1 100%;align-items:center;justify-content:space-between;gap:16px;min-width:0;padding:14px 16px;border:1px solid var(--md-sys-color-outline-variant);border-radius:12px;background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface)}.gradient-stops-preview__copy{display:grid;gap:3px;min-width:0}.gradient-stops-preview__copy strong{font:var(--md-sys-typescale-label-large-font, inherit);font-weight:650}.gradient-stops-preview__copy span{color:var(--md-sys-color-on-surface-variant);font:var(--md-sys-typescale-body-small-font, inherit);line-height:1.35}.gradient-stops-preview__stars{flex:0 0 auto;color:transparent;background-clip:text;-webkit-background-clip:text;font-size:30px;line-height:1;letter-spacing:2px}.gradient-stops-preview__radial{position:relative;flex:0 0 auto;width:76px;height:76px;border-radius:50%;box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent)}.gradient-stops-preview__radial:before,.gradient-stops-preview__radial:after,.gradient-stops-preview__radial>span{content:\"\";position:absolute;inset:12px;border:1px dashed color-mix(in srgb,var(--md-sys-color-on-surface) 35%,transparent);border-radius:50%}.gradient-stops-preview__radial:after{inset:25px}.gradient-stops-preview__radial>span{inset:35px;border:0;background:var(--md-sys-color-on-surface)}@media(forced-colors:active){.gradient-stops-preview{border-color:CanvasText}.gradient-stops-preview__stars,.gradient-stops-preview__radial{color:CanvasText;background:none}}.editor-row>praxis-field-shell[data-field-name=controlType],.editor-row>praxis-field-shell[data-field-name=label],.editor-row>praxis-field-shell[data-field-name=placeholder]{flex:1 1 calc(50% - 12px);min-width:300px}.editor-row>praxis-presentation-rules-builder.presentation-rules-field{flex:1 1 100%;min-width:0}.editor-row>praxis-presentation-choice-control.presentation-choice-field{flex:1 1 100%;min-width:0}praxis-field-shell[data-field-name=label] .mdc-floating-label,praxis-field-shell[data-field-name=placeholder] .mdc-floating-label{font-weight:600}.editor-row>praxis-field-shell[data-field-name=prefix],.editor-row>praxis-field-shell[data-field-name=suffix]{flex:0 0 200px;min-width:160px}.editor-row>praxis-field-shell[data-field-name=prefixIcon],.editor-row>praxis-field-shell[data-field-name=suffixIcon],.editor-row>praxis-field-shell[data-field-name=prefixIconColor],.editor-row>praxis-field-shell[data-field-name=suffixIconColor]{flex:1 1 auto;min-width:160px}.editor-item{display:flex;align-items:flex-start;gap:4px;min-width:0;width:100%}.editor-item>ng-container,.editor-item>praxis-field-shell{flex:1;min-width:0}.actions-container{display:flex;align-items:center;gap:0;margin-top:12px;flex-shrink:0}.decorator-btn{position:static;color:var(--md-sys-color-primary, #3f51b5);opacity:.6;transform:scale(.8);width:32px;height:32px;line-height:32px;padding:0}.decorator-btn:hover{opacity:1}.icon-picker-btn,.hint-btn,.hint-btn.has-icon-picker{right:auto}.editor-row .mat-mdc-form-field-subscript-wrapper mat-hint{display:none!important}.editor-row .mat-mdc-form-field-subscript-wrapper mat-error{display:block!important}praxis-field-shell[data-field-name=showCharCount] .mdc-switch{transform:scale(1.05)}praxis-field-shell[data-field-name=showCharCount] .mat-mdc-slide-toggle{font-weight:600}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-hint{display:flex;align-items:center;gap:8px;background:var(--md-sys-color-tertiary-container);border:1px solid var(--md-sys-color-tertiary);color:var(--md-sys-color-on-tertiary-container);padding:8px 10px;border-radius:6px;line-height:1.3;white-space:normal}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-hint:before{content:\"\\26a0\\fe0f\";display:inline-block}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-subscript-wrapper{margin-top:6px;margin-bottom:10px;min-height:auto}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field{margin-bottom:16px}@media(max-width:520px){.editor-row,.editor-row.row-inline{gap:8px}.editor-item{flex-direction:column;gap:2px}.editor-row.row-inline>praxis-field-shell,.editor-row.row-2>praxis-field-shell,.editor-row.row-3>praxis-field-shell{flex:1 1 100%;min-width:0}.gradient-stops-preview{align-items:flex-start;flex-direction:column}.gradient-stops-preview__stars{font-size:27px}.actions-container{width:100%;justify-content:flex-end;margin-top:0}.editor-row.row-gradient-stops .editor-item{align-items:flex-start;flex-direction:row;gap:4px}.editor-row.row-gradient-stops .actions-container{width:auto;margin-top:12px}}\n"] }]
2416
2683
  }], ctorParameters: () => [{ type: i1$1.MatDialog }, { type: i2$2.IconPickerService }, { type: i2$2.PraxisI18nService, decorators: [{
2417
2684
  type: Optional
2418
2685
  }] }], propDecorators: { properties: [{
@@ -7068,6 +7335,15 @@ const priceRangeProperties = [
7068
7335
  ],
7069
7336
  hint: 'Controla a exibição das marcações no slider inline.',
7070
7337
  },
7338
+ {
7339
+ name: 'discrete',
7340
+ label: 'Exibir valor ao ajustar',
7341
+ labelKey: 'priceRange.discrete.label',
7342
+ editorType: 'checkbox',
7343
+ group: 'Formato/Comportamento',
7344
+ hint: 'Mostra o valor monetário junto ao manipulador durante o ajuste.',
7345
+ hintKey: 'priceRange.discrete.hint',
7346
+ },
7071
7347
  {
7072
7348
  name: 'marks',
7073
7349
  label: 'Marcadores (JSON)',
@@ -7639,95 +7915,6 @@ function minLenLeMaxLen(group) {
7639
7915
  return null;
7640
7916
  }
7641
7917
 
7642
- const HEX_PATTERN = /^#([\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/i;
7643
- function clampChannel(value) {
7644
- return Math.max(0, Math.min(255, Math.round(value)));
7645
- }
7646
- function parseHexColor(raw) {
7647
- const normalized = raw.trim();
7648
- if (!HEX_PATTERN.test(normalized)) {
7649
- return null;
7650
- }
7651
- const hex = normalized.slice(1);
7652
- if (hex.length === 3 || hex.length === 4) {
7653
- return {
7654
- r: Number.parseInt(hex[0] + hex[0], 16),
7655
- g: Number.parseInt(hex[1] + hex[1], 16),
7656
- b: Number.parseInt(hex[2] + hex[2], 16),
7657
- };
7658
- }
7659
- return {
7660
- r: Number.parseInt(hex.slice(0, 2), 16),
7661
- g: Number.parseInt(hex.slice(2, 4), 16),
7662
- b: Number.parseInt(hex.slice(4, 6), 16),
7663
- };
7664
- }
7665
- function parseRgbChannel(token) {
7666
- const value = token.trim();
7667
- if (!value.length)
7668
- return null;
7669
- if (value.endsWith('%')) {
7670
- const pct = Number.parseFloat(value.slice(0, -1));
7671
- if (!Number.isFinite(pct))
7672
- return null;
7673
- return clampChannel((pct / 100) * 255);
7674
- }
7675
- const numeric = Number.parseFloat(value);
7676
- if (!Number.isFinite(numeric))
7677
- return null;
7678
- return clampChannel(numeric);
7679
- }
7680
- function parseRgbColor(raw) {
7681
- const normalized = raw.trim().toLowerCase();
7682
- if (!normalized.startsWith('rgb')) {
7683
- return null;
7684
- }
7685
- const parts = normalized.match(/[\d.]+%?/g) ?? [];
7686
- if (parts.length < 3) {
7687
- return null;
7688
- }
7689
- const [rRaw, gRaw, bRaw] = parts;
7690
- if (rRaw === undefined || gRaw === undefined || bRaw === undefined) {
7691
- return null;
7692
- }
7693
- const r = parseRgbChannel(rRaw);
7694
- const g = parseRgbChannel(gRaw);
7695
- const b = parseRgbChannel(bRaw);
7696
- if (r === null || g === null || b === null) {
7697
- return null;
7698
- }
7699
- return { r, g, b };
7700
- }
7701
- function parseComputedRgbColor(raw) {
7702
- if (typeof document === 'undefined') {
7703
- return null;
7704
- }
7705
- const probe = document.createElement('span');
7706
- probe.style.color = '';
7707
- probe.style.color = raw;
7708
- if (!probe.style.color) {
7709
- return null;
7710
- }
7711
- const host = document.body ?? document.documentElement;
7712
- let computed = probe.style.color;
7713
- if (host) {
7714
- host.appendChild(probe);
7715
- try {
7716
- computed = getComputedStyle(probe).color || computed;
7717
- }
7718
- finally {
7719
- probe.remove();
7720
- }
7721
- }
7722
- return parseRgbColor(computed) ?? parseHexColor(computed);
7723
- }
7724
- function normalizeCssColorToRgb(value) {
7725
- const raw = String(value ?? '').trim();
7726
- if (!raw.length) {
7727
- return null;
7728
- }
7729
- return parseHexColor(raw) ?? parseRgbColor(raw) ?? parseComputedRgbColor(raw);
7730
- }
7731
7918
  function relativeLuminance({ r, g, b }) {
7732
7919
  const normalize = (channel) => {
7733
7920
  const value = channel / 255;
@@ -7743,22 +7930,30 @@ function contrastRatio(a, b) {
7743
7930
  return (lighter + 0.05) / (darker + 0.05);
7744
7931
  }
7745
7932
  function gradientColorStopValidator(options) {
7746
- const label = String(options.label || 'Cor').trim() || 'Cor';
7747
7933
  const compareWith = options.compareWith ?? [];
7748
- const minContrastRatio = Math.max(1, Number(options.minContrastRatio ?? 1.4));
7934
+ // Adjacent gradient stops are allowed to be subtle or even equal. Contrast
7935
+ // is only a blocking rule when a consumer explicitly opts into a threshold.
7936
+ const minContrastRatio = Math.max(1, Number(options.minContrastRatio ?? 1));
7749
7937
  return (control) => {
7750
7938
  const rawValue = String(control.value ?? '').trim();
7751
7939
  if (!rawValue.length) {
7752
7940
  return null;
7753
7941
  }
7754
- const currentColor = normalizeCssColorToRgb(rawValue);
7755
- if (!currentColor) {
7942
+ if (!isValidCssColor(rawValue)) {
7756
7943
  return {
7757
7944
  invalidColor: {
7758
- message: `${label}: informe uma cor CSS valida (ex.: #22c55e).`,
7945
+ messageKey: 'praxis.metadataEditor.validation.invalidCssColor',
7946
+ params: { example: '#22c55e' },
7947
+ fallback: 'Informe uma cor CSS válida (ex.: #22c55e).',
7759
7948
  },
7760
7949
  };
7761
7950
  }
7951
+ const currentColor = normalizeCssColorToRgb(rawValue);
7952
+ if (!currentColor) {
7953
+ // A valid host token can remain unresolved inside the editor theme.
7954
+ // Runtime and preview still consume the same syntactically valid value.
7955
+ return null;
7956
+ }
7762
7957
  const parent = control.parent;
7763
7958
  if (!parent || !compareWith.length) {
7764
7959
  return null;
@@ -7776,8 +7971,13 @@ function gradientColorStopValidator(options) {
7776
7971
  if (ratio < minContrastRatio) {
7777
7972
  return {
7778
7973
  gradientContrast: {
7779
- message: `${label}: contraste baixo com ${target.label} ` +
7780
- `(${ratio.toFixed(2)}:1). Use ao menos ${minContrastRatio.toFixed(1)}:1.`,
7974
+ messageKey: 'praxis.metadataEditor.validation.gradientContrast',
7975
+ params: {
7976
+ ratio: ratio.toFixed(2),
7977
+ minimum: minContrastRatio.toFixed(1),
7978
+ },
7979
+ fallback: `A diferença visual entre as cores é ${ratio.toFixed(2)}:1. ` +
7980
+ `Use ao menos ${minContrastRatio.toFixed(1)}:1.`,
7781
7981
  ratio,
7782
7982
  minContrastRatio,
7783
7983
  comparedField: target.field,
@@ -7797,25 +7997,70 @@ function cloneProperty$6(prop) {
7797
7997
  : prop.options,
7798
7998
  };
7799
7999
  }
8000
+ const DISTANCE_RADIUS_INHERITED_PROPERTY_NAMES = new Set([
8001
+ 'label',
8002
+ 'hint',
8003
+ 'prefixIcon',
8004
+ 'prefixIconColor',
8005
+ 'suffixIcon',
8006
+ 'suffixIconColor',
8007
+ 'mode',
8008
+ 'step',
8009
+ 'thumbLabel',
8010
+ 'valueLabelDisplay',
8011
+ 'showTicks',
8012
+ 'marks',
8013
+ 'discrete',
8014
+ 'readonly',
8015
+ 'disabled',
8016
+ 'min',
8017
+ 'max',
8018
+ 'minDistance',
8019
+ 'maxDistance',
8020
+ 'validators.minMessage',
8021
+ 'validators.maxMessage',
8022
+ 'validators.rangeMessage',
8023
+ 'validators.distanceMessage',
8024
+ 'required',
8025
+ 'validators.requiredMessage',
8026
+ 'color',
8027
+ 'ariaLabel',
8028
+ 'ariaDescribedby',
8029
+ 'ariaLabelledby',
8030
+ 'tabIndex',
8031
+ ]);
8032
+ function isDistanceRadiusInheritedProperty(prop) {
8033
+ return (DISTANCE_RADIUS_INHERITED_PROPERTY_NAMES.has(prop.name) ||
8034
+ prop.name.startsWith('inlineOverlay.') ||
8035
+ prop.name.startsWith('clearButton.') ||
8036
+ prop.name.startsWith('inlineAutoSize.'));
8037
+ }
7800
8038
  const inlineDistanceRadiusProperties = [
7801
- ...rangeSliderProperties.map((prop) => cloneProperty$6(prop)),
8039
+ ...rangeSliderProperties
8040
+ .filter((prop) => isDistanceRadiusInheritedProperty(prop))
8041
+ .map((prop) => cloneProperty$6(prop)),
7802
8042
  {
7803
8043
  name: 'distanceIcon',
7804
- label: 'Icone do chip (legado)',
8044
+ label: 'Ícone do chip (legado)',
8045
+ labelKey: 'inlineDistance.icon.label',
7805
8046
  editorType: 'text',
7806
8047
  group: 'Compatibilidade',
7807
- hint: 'Alias legado de prefixIcon para o icone do chip (ex.: place, my_location).',
8048
+ hint: 'Alias legado de prefixIcon para o ícone do chip (ex.: place, my_location).',
8049
+ hintKey: 'inlineDistance.icon.hint',
7808
8050
  },
7809
8051
  {
7810
8052
  name: 'distanceSubtitle',
7811
- label: 'Subtitulo do painel',
8053
+ label: 'Subtítulo do painel',
8054
+ labelKey: 'inlineDistance.subtitle.label',
7812
8055
  editorType: 'text',
7813
8056
  group: 'Geral',
7814
- hint: 'Subtitulo exibido abaixo do titulo no popover.',
8057
+ hint: 'Subtítulo exibido abaixo do título no painel.',
8058
+ hintKey: 'inlineDistance.subtitle.hint',
7815
8059
  },
7816
8060
  {
7817
8061
  name: 'distanceUnit',
7818
8062
  label: 'Unidade inicial',
8063
+ labelKey: 'inlineDistance.unit.label',
7819
8064
  editorType: 'select',
7820
8065
  group: 'Formato/Comportamento',
7821
8066
  options: [
@@ -7823,163 +8068,217 @@ const inlineDistanceRadiusProperties = [
7823
8068
  { value: 'mi', text: 'MI' },
7824
8069
  ],
7825
8070
  hint: 'Unidade visual inicial do controle.',
8071
+ hintKey: 'inlineDistance.unit.hint',
7826
8072
  },
7827
8073
  {
7828
8074
  name: 'distanceBaseUnit',
7829
8075
  label: 'Unidade base',
8076
+ labelKey: 'inlineDistance.baseUnit.label',
7830
8077
  editorType: 'select',
7831
8078
  group: 'Formato/Comportamento',
7832
8079
  options: [
7833
8080
  { value: 'km', text: 'KM' },
7834
8081
  { value: 'mi', text: 'MI' },
7835
8082
  ],
7836
- hint: 'Unidade canonica persistida no valor do campo.',
8083
+ hint: 'Unidade canônica persistida no valor do campo.',
8084
+ hintKey: 'inlineDistance.baseUnit.hint',
7837
8085
  },
7838
8086
  {
7839
8087
  name: 'distanceAllowUnitToggle',
7840
8088
  label: 'Permitir alternar KM/MI',
8089
+ labelKey: 'inlineDistance.allowUnitToggle.label',
7841
8090
  editorType: 'checkbox',
7842
8091
  group: 'Formato/Comportamento',
7843
- hint: 'Quando ativo, mostra os botoes para alternar unidade no popover.',
8092
+ hint: 'Quando ativo, mostra os botões para alternar unidade no painel.',
8093
+ hintKey: 'inlineDistance.allowUnitToggle.hint',
7844
8094
  },
7845
8095
  {
7846
8096
  name: 'distanceUnits',
7847
- label: 'Unidades disponiveis (JSON)',
7848
- editorType: 'textarea',
8097
+ label: 'Unidades disponíveis',
8098
+ labelKey: 'inlineDistance.units.label',
8099
+ editorType: 'multi-select',
7849
8100
  group: 'Formato/Comportamento',
7850
- hint: 'Array JSON opcional. Ex.: ["km","mi"].',
8101
+ options: [
8102
+ { value: 'km', text: 'KM' },
8103
+ { value: 'mi', text: 'MI' },
8104
+ ],
8105
+ hint: 'Escolha as unidades disponíveis no seletor do painel.',
8106
+ hintKey: 'inlineDistance.units.hint',
7851
8107
  },
7852
8108
  {
7853
8109
  name: 'distanceUnitLabels.km',
7854
- label: 'Label unidade KM',
8110
+ label: 'Rótulo da unidade KM',
8111
+ labelKey: 'inlineDistance.unitLabelKm.label',
7855
8112
  editorType: 'text',
7856
8113
  group: 'Formato/Comportamento',
7857
8114
  row: 'distance-unit-labels',
7858
8115
  inline: true,
8116
+ hint: 'Texto visível e anunciado para quilômetros.',
8117
+ hintKey: 'inlineDistance.unitLabelKm.hint',
7859
8118
  },
7860
8119
  {
7861
8120
  name: 'distanceUnitLabels.mi',
7862
- label: 'Label unidade MI',
8121
+ label: 'Rótulo da unidade MI',
8122
+ labelKey: 'inlineDistance.unitLabelMi.label',
7863
8123
  editorType: 'text',
7864
8124
  group: 'Formato/Comportamento',
7865
8125
  row: 'distance-unit-labels',
7866
8126
  inline: true,
8127
+ hint: 'Texto visível e anunciado para milhas.',
8128
+ hintKey: 'inlineDistance.unitLabelMi.hint',
7867
8129
  },
7868
8130
  {
7869
8131
  name: 'distanceDisplayDecimals',
7870
- label: 'Casas decimais (display)',
8132
+ label: 'Casas decimais',
8133
+ labelKey: 'inlineDistance.decimals.label',
7871
8134
  editorType: 'number',
7872
8135
  group: 'Formato/Comportamento',
7873
- hint: 'Define casas decimais para exibicao visual (valor vazio usa automatico).',
8136
+ hint: 'Define as casas decimais da exibição; vazio usa precisão automática.',
8137
+ hintKey: 'inlineDistance.decimals.hint',
7874
8138
  },
7875
8139
  {
7876
8140
  name: 'distancePresets',
7877
- label: 'Presets de distancia (JSON)',
7878
- editorType: 'textarea',
8141
+ label: 'Atalhos de distância',
8142
+ labelKey: 'inlineDistance.presets.label',
8143
+ editorType: 'chip-input',
7879
8144
  group: 'Formato/Comportamento',
7880
- hint: 'Array JSON. Ex.: [5,10,25,50], [{"label":"25 km","value":25}] ou [{"label":"10-30 km","start":10,"end":30}] para modo faixa.',
8145
+ hint: 'Adicione valores numéricos como 5, 10, 25 e 50. Presets avançados continuam disponíveis no editor JSON.',
8146
+ hintKey: 'inlineDistance.presets.hint',
7881
8147
  },
7882
8148
  {
7883
8149
  name: 'distanceRadialRings',
7884
- label: 'Qtd. aneis radiais',
8150
+ label: 'Anéis radiais',
8151
+ labelKey: 'inlineDistance.rings.label',
7885
8152
  editorType: 'number',
7886
- group: 'Aparencia',
7887
- hint: 'Quantidade de aneis no radar visual (3 a 8).',
8153
+ group: 'Aparência',
8154
+ groupKey: 'groups.appearance',
8155
+ hint: 'Quantidade de anéis no radar visual, entre 3 e 8.',
8156
+ hintKey: 'inlineDistance.rings.hint',
7888
8157
  },
7889
8158
  {
7890
8159
  name: 'distanceAccentColor',
7891
8160
  label: 'Cor principal',
8161
+ labelKey: 'inlineDistance.accent.label',
7892
8162
  editorType: 'color',
7893
- group: 'Aparencia',
8163
+ group: 'Aparência',
8164
+ groupKey: 'groups.appearance',
7894
8165
  hint: 'Cor principal aplicada ao valor central e estados ativos.',
8166
+ hintKey: 'inlineDistance.accent.hint',
7895
8167
  },
7896
8168
  {
7897
8169
  name: 'distanceRingColor',
7898
- label: 'Cor dos aneis',
8170
+ label: 'Cor dos anéis',
8171
+ labelKey: 'inlineDistance.ringColor.label',
7899
8172
  editorType: 'color',
7900
- group: 'Aparencia',
7901
- hint: 'Cor base dos aneis circulares do radar.',
8173
+ group: 'Aparência',
8174
+ groupKey: 'groups.appearance',
8175
+ hint: 'Cor base dos anéis circulares do radar.',
8176
+ hintKey: 'inlineDistance.ringColor.hint',
7902
8177
  },
7903
8178
  {
7904
8179
  name: 'distanceTrackColor',
7905
- label: 'Cor trilha slider',
8180
+ label: 'Cor da trilha',
8181
+ labelKey: 'inlineDistance.trackColor.label',
7906
8182
  editorType: 'color',
7907
- group: 'Aparencia',
8183
+ group: 'Aparência',
8184
+ groupKey: 'groups.appearance',
7908
8185
  hint: 'Cor da trilha inativa do slider.',
8186
+ hintKey: 'inlineDistance.trackColor.hint',
7909
8187
  },
7910
8188
  {
7911
8189
  name: 'distanceGlowColor',
7912
- label: 'Cor brilho radial',
8190
+ label: 'Cor do brilho radial',
8191
+ labelKey: 'inlineDistance.glowColor.label',
7913
8192
  editorType: 'color',
7914
- group: 'Aparencia',
8193
+ group: 'Aparência',
8194
+ groupKey: 'groups.appearance',
7915
8195
  hint: 'Cor do glow ao redor do centro radial.',
8196
+ hintKey: 'inlineDistance.glowColor.hint',
7916
8197
  },
7917
8198
  {
7918
8199
  name: 'distanceGradientLowColor',
7919
- label: 'Gradiente baixo',
7920
- editorType: 'color',
7921
- group: 'Aparencia',
8200
+ label: 'Início',
8201
+ labelKey: 'inlineDistance.gradient.low.label',
8202
+ editorType: 'gradient-stop',
8203
+ group: 'Gradiente do raio',
8204
+ groupKey: 'inlineDistance.gradient.group',
7922
8205
  row: 'distance-gradient-colors',
7923
- inline: true,
7924
- hint: 'Cor para valores baixos (fallback padrao: verde).',
8206
+ hint: 'Cor dos raios menores, no centro da visualização.',
8207
+ hintKey: 'inlineDistance.gradient.low.hint',
8208
+ gradientPreviewKind: 'radial',
8209
+ gradientPreviewI18nPrefix: 'inlineDistance.gradient',
7925
8210
  validators: [
7926
8211
  gradientColorStopValidator({
7927
- label: 'Gradiente baixo',
7928
- compareWith: [{ field: 'distanceGradientMidColor', label: 'Gradiente medio' }],
8212
+ label: 'Início',
8213
+ compareWith: [{ field: 'distanceGradientMidColor', label: 'Meio' }],
7929
8214
  }),
7930
8215
  ],
7931
8216
  },
7932
8217
  {
7933
8218
  name: 'distanceGradientMidColor',
7934
- label: 'Gradiente medio',
7935
- editorType: 'color',
7936
- group: 'Aparencia',
8219
+ label: 'Meio',
8220
+ labelKey: 'inlineDistance.gradient.mid.label',
8221
+ editorType: 'gradient-stop',
8222
+ group: 'Gradiente do raio',
8223
+ groupKey: 'inlineDistance.gradient.group',
7937
8224
  row: 'distance-gradient-colors',
7938
- inline: true,
7939
- hint: 'Cor para valores medios (fallback padrao: amarelo/ambar).',
8225
+ hint: 'Cor de transição aplicada à região intermediária do raio.',
8226
+ hintKey: 'inlineDistance.gradient.mid.hint',
8227
+ gradientPreviewKind: 'radial',
8228
+ gradientPreviewI18nPrefix: 'inlineDistance.gradient',
7940
8229
  validators: [
7941
8230
  gradientColorStopValidator({
7942
- label: 'Gradiente medio',
8231
+ label: 'Meio',
7943
8232
  compareWith: [
7944
- { field: 'distanceGradientLowColor', label: 'Gradiente baixo' },
7945
- { field: 'distanceGradientHighColor', label: 'Gradiente alto' },
8233
+ { field: 'distanceGradientLowColor', label: 'Início' },
8234
+ { field: 'distanceGradientHighColor', label: 'Fim' },
7946
8235
  ],
7947
8236
  }),
7948
8237
  ],
7949
8238
  },
7950
8239
  {
7951
8240
  name: 'distanceGradientHighColor',
7952
- label: 'Gradiente alto',
7953
- editorType: 'color',
7954
- group: 'Aparencia',
8241
+ label: 'Fim',
8242
+ labelKey: 'inlineDistance.gradient.high.label',
8243
+ editorType: 'gradient-stop',
8244
+ group: 'Gradiente do raio',
8245
+ groupKey: 'inlineDistance.gradient.group',
7955
8246
  row: 'distance-gradient-colors',
7956
- inline: true,
7957
- hint: 'Cor para valores altos (fallback padrao: vermelho).',
8247
+ hint: 'Cor dos maiores raios, na borda externa da visualização.',
8248
+ hintKey: 'inlineDistance.gradient.high.hint',
8249
+ gradientPreviewKind: 'radial',
8250
+ gradientPreviewI18nPrefix: 'inlineDistance.gradient',
7958
8251
  validators: [
7959
8252
  gradientColorStopValidator({
7960
- label: 'Gradiente alto',
7961
- compareWith: [{ field: 'distanceGradientMidColor', label: 'Gradiente medio' }],
8253
+ label: 'Fim',
8254
+ compareWith: [{ field: 'distanceGradientMidColor', label: 'Meio' }],
7962
8255
  }),
7963
8256
  ],
7964
8257
  },
7965
8258
  {
7966
8259
  name: 'distanceRangeBandOpacity',
7967
8260
  label: 'Opacidade da faixa (0-1)',
8261
+ labelKey: 'inlineDistance.rangeOpacity.label',
7968
8262
  editorType: 'number',
7969
- group: 'Aparencia',
7970
- hint: 'Opcional. Sobrescreve a opacidade automatica da faixa radial no modo range.',
8263
+ group: 'Aparência',
8264
+ groupKey: 'groups.appearance',
8265
+ hint: 'Opcional. Sobrescreve a opacidade automática da faixa radial.',
8266
+ hintKey: 'inlineDistance.rangeOpacity.hint',
7971
8267
  },
7972
8268
  {
7973
8269
  name: 'materialDesign.density',
7974
8270
  label: 'Densidade',
8271
+ labelKey: 'inlineDistance.density.label',
7975
8272
  editorType: 'select',
7976
- group: 'Aparencia',
8273
+ group: 'Aparência',
8274
+ groupKey: 'groups.appearance',
7977
8275
  options: [
7978
8276
  { value: 'compact', text: 'Compacta' },
7979
- { value: 'default', text: 'Padrao' },
8277
+ { value: 'default', text: 'Padrão' },
7980
8278
  { value: 'dense', text: 'Densa' },
7981
8279
  ],
7982
- hint: 'Ajusta dimensoes base do chip e painel inline.',
8280
+ hint: 'Ajusta as dimensões base do chip e do painel inline.',
8281
+ hintKey: 'inlineDistance.density.hint',
7983
8282
  },
7984
8283
  ];
7985
8284
 
@@ -9187,62 +9486,74 @@ const inlineRatingProperties = [
9187
9486
  name: 'ratingToneLowColor',
9188
9487
  label: 'Cor estrelas (baixo)',
9189
9488
  editorType: 'color',
9190
- group: 'Aparência',
9191
- hint: 'Cor para estrelas de notas baixas (fallback: vermelho).',
9489
+ group: 'Cores alternativas',
9490
+ hint: 'Fallback por faixa, usado apenas quando o gradiente não estiver configurado.',
9192
9491
  },
9193
9492
  {
9194
9493
  name: 'ratingToneMidColor',
9195
9494
  label: 'Cor estrelas (médio)',
9196
9495
  editorType: 'color',
9197
- group: 'Aparência',
9198
- hint: 'Cor para estrelas de notas médias (fallback: âmbar).',
9496
+ group: 'Cores alternativas',
9497
+ hint: 'Fallback por faixa, usado apenas quando o gradiente não estiver configurado.',
9199
9498
  },
9200
9499
  {
9201
9500
  name: 'ratingToneHighColor',
9202
9501
  label: 'Cor estrelas (alto)',
9203
9502
  editorType: 'color',
9204
- group: 'Aparência',
9205
- hint: 'Cor para estrelas de notas altas (fallback: verde).',
9503
+ group: 'Cores alternativas',
9504
+ hint: 'Fallback por faixa, usado apenas quando o gradiente não estiver configurado.',
9206
9505
  },
9207
9506
  {
9208
9507
  name: 'ratingGradientLowColor',
9209
- label: 'Gradiente estrelas (inicio)',
9210
- editorType: 'color',
9211
- group: 'Aparência',
9212
- hint: 'Cor inicial do gradiente aplicado na escala de estrelas.',
9508
+ label: 'Início',
9509
+ labelKey: 'inlineRating.gradient.low.label',
9510
+ editorType: 'gradient-stop',
9511
+ group: 'Gradiente das estrelas',
9512
+ groupKey: 'inlineRating.gradient.group',
9513
+ row: 'rating.gradient.stops',
9514
+ hint: 'Cor das avaliações mais baixas, no lado esquerdo da escala.',
9515
+ hintKey: 'inlineRating.gradient.low.hint',
9213
9516
  validators: [
9214
9517
  gradientColorStopValidator({
9215
- label: 'Gradiente estrelas (inicio)',
9216
- compareWith: [{ field: 'ratingGradientMidColor', label: 'Gradiente estrelas (meio)' }],
9518
+ label: 'Início',
9519
+ compareWith: [{ field: 'ratingGradientMidColor', label: 'Meio' }],
9217
9520
  }),
9218
9521
  ],
9219
9522
  },
9220
9523
  {
9221
9524
  name: 'ratingGradientMidColor',
9222
- label: 'Gradiente estrelas (meio)',
9223
- editorType: 'color',
9224
- group: 'Aparência',
9225
- hint: 'Cor intermediaria do gradiente aplicado na escala de estrelas.',
9525
+ label: 'Meio',
9526
+ labelKey: 'inlineRating.gradient.mid.label',
9527
+ editorType: 'gradient-stop',
9528
+ group: 'Gradiente das estrelas',
9529
+ groupKey: 'inlineRating.gradient.group',
9530
+ row: 'rating.gradient.stops',
9531
+ hint: 'Cor de transição aplicada ao centro da escala.',
9532
+ hintKey: 'inlineRating.gradient.mid.hint',
9226
9533
  validators: [
9227
9534
  gradientColorStopValidator({
9228
- label: 'Gradiente estrelas (meio)',
9535
+ label: 'Meio',
9229
9536
  compareWith: [
9230
- { field: 'ratingGradientLowColor', label: 'Gradiente estrelas (inicio)' },
9231
- { field: 'ratingGradientHighColor', label: 'Gradiente estrelas (fim)' },
9537
+ { field: 'ratingGradientLowColor', label: 'Início' },
9538
+ { field: 'ratingGradientHighColor', label: 'Fim' },
9232
9539
  ],
9233
9540
  }),
9234
9541
  ],
9235
9542
  },
9236
9543
  {
9237
9544
  name: 'ratingGradientHighColor',
9238
- label: 'Gradiente estrelas (fim)',
9239
- editorType: 'color',
9240
- group: 'Aparência',
9241
- hint: 'Cor final do gradiente aplicado na escala de estrelas.',
9545
+ label: 'Fim',
9546
+ labelKey: 'inlineRating.gradient.high.label',
9547
+ editorType: 'gradient-stop',
9548
+ group: 'Gradiente das estrelas',
9549
+ groupKey: 'inlineRating.gradient.group',
9550
+ row: 'rating.gradient.stops',
9551
+ hint: 'Cor das avaliações mais altas, no lado direito da escala.',
9552
+ hintKey: 'inlineRating.gradient.high.hint',
9242
9553
  validators: [
9243
9554
  gradientColorStopValidator({
9244
- label: 'Gradiente estrelas (fim)',
9245
- compareWith: [{ field: 'ratingGradientMidColor', label: 'Gradiente estrelas (meio)' }],
9555
+ label: 'Fim',
9556
+ compareWith: [{ field: 'ratingGradientMidColor', label: 'Meio' }],
9246
9557
  }),
9247
9558
  ],
9248
9559
  },
@@ -9285,8 +9596,8 @@ const inlineRatingProperties = [
9285
9596
  name: 'ratingToneColors',
9286
9597
  label: 'Paleta por tom (JSON)',
9287
9598
  editorType: 'textarea',
9288
- group: 'Aparência',
9289
- hint: 'JSON opcional. Ex.: {"low":"#ef4444","mid":"#f59e0b","high":"#22a45d","badge":"#f59e0b"}',
9599
+ group: 'Compatibilidade',
9600
+ hint: 'Formato avançado anterior. Prefira os três seletores do grupo Gradiente das estrelas.',
9290
9601
  },
9291
9602
  {
9292
9603
  name: 'ratingColors',
@@ -10187,9 +10498,14 @@ class FieldMetadataEditorComponent {
10187
10498
  }
10188
10499
  // track validity/dirty with snapshot-based detection (avoid false dirty on init)
10189
10500
  this.isValid$.next(this.form.valid);
10190
- this.form.statusChanges.subscribe(() => this.isValid$.next(this.form.valid));
10501
+ this.form.statusChanges
10502
+ .pipe(takeUntilDestroyed(this.destroyRef))
10503
+ .subscribe(() => this.isValid$.next(this.form.valid));
10504
+ this.setupGradientStopValidationSync();
10191
10505
  this.setupCurrencyPresetSync();
10192
- this.form.valueChanges.subscribe((val) => {
10506
+ this.form.valueChanges
10507
+ .pipe(takeUntilDestroyed(this.destroyRef))
10508
+ .subscribe((val) => {
10193
10509
  if (!this.baselineReady) {
10194
10510
  // Ignore initial churn until baseline is captured
10195
10511
  return;
@@ -10221,6 +10537,32 @@ class FieldMetadataEditorComponent {
10221
10537
  }
10222
10538
  });
10223
10539
  }
10540
+ setupGradientStopValidationSync() {
10541
+ const rows = new Map();
10542
+ for (const property of this.normalizedProps) {
10543
+ if (property?.editorType !== 'gradient-stop' || !property?.name)
10544
+ continue;
10545
+ const row = String(property.row || 'gradient-stops');
10546
+ rows.set(row, [...(rows.get(row) ?? []), property.name]);
10547
+ }
10548
+ for (const fieldNames of rows.values()) {
10549
+ for (const sourceField of fieldNames) {
10550
+ const source = this.form.get(sourceField);
10551
+ if (!source)
10552
+ continue;
10553
+ source.valueChanges
10554
+ .pipe(takeUntilDestroyed(this.destroyRef))
10555
+ .subscribe(() => {
10556
+ for (const targetField of fieldNames) {
10557
+ if (targetField === sourceField)
10558
+ continue;
10559
+ this.form.get(targetField)?.updateValueAndValidity({ emitEvent: false });
10560
+ }
10561
+ this.isValid$.next(this.form.valid);
10562
+ });
10563
+ }
10564
+ }
10565
+ }
10224
10566
  setupCurrencyPresetSync() {
10225
10567
  const ctU = String(this.controlType || '').toUpperCase();
10226
10568
  if (ctU !== String(FieldControlType.CURRENCY_INPUT) && ctU !== 'CURRENCY' && ctU !== String(FieldControlType.PRICE_RANGE) && ctU !== 'PRICERANGE') {
@@ -10436,6 +10778,14 @@ class FieldMetadataEditorComponent {
10436
10778
  patch.shortcuts = parsedShortcuts;
10437
10779
  }
10438
10780
  }
10781
+ if (Array.isArray(patch.distancePresets)) {
10782
+ patch.distancePresets = patch.distancePresets.map((preset) => {
10783
+ if (typeof preset !== 'string' || !preset.trim().length)
10784
+ return preset;
10785
+ const numeric = Number(preset);
10786
+ return Number.isFinite(numeric) ? numeric : preset;
10787
+ });
10788
+ }
10439
10789
  this.normalizeEntityLookupPatchValues(patch);
10440
10790
  this.normalizeArrayPatchValues(patch);
10441
10791
  this.normalizePresentationPatchValues(patch);
@@ -10757,7 +11107,10 @@ class FieldMetadataEditorComponent {
10757
11107
  control.setErrors(Object.keys(errors).length ? errors : null);
10758
11108
  }
10759
11109
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FieldMetadataEditorComponent, deps: [{ token: ConfigRegistryService }, { token: SchemaNormalizerService }, { token: DynamicFormFactoryService }, { token: ContextValidatorRegistryService }], target: i0.ɵɵFactoryTarget.Component });
10760
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: FieldMetadataEditorComponent, isStandalone: true, selector: "praxis-field-metadata-editor", inputs: { controlType: "controlType", seed: "seed" }, outputs: { applied: "applied", cancel: "cancel" }, ngImport: i0, template: `
11110
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: FieldMetadataEditorComponent, isStandalone: true, selector: "praxis-field-metadata-editor", inputs: { controlType: "controlType", seed: "seed" }, outputs: { applied: "applied", cancel: "cancel" }, providers: [
11111
+ providePraxisMetadataEditorI18n(),
11112
+ ...providePraxisDynamicFieldsI18n(),
11113
+ ], ngImport: i0, template: `
10761
11114
  @if (form) {
10762
11115
  <div class="p-3">
10763
11116
  <praxis-dynamic-editor-renderer
@@ -10784,6 +11137,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
10784
11137
  DynamicEditorRendererComponent,
10785
11138
  ArrayItemSchemaFieldsEditorComponent
10786
11139
  ],
11140
+ providers: [
11141
+ providePraxisMetadataEditorI18n(),
11142
+ ...providePraxisDynamicFieldsI18n(),
11143
+ ],
10787
11144
  template: `
10788
11145
  @if (form) {
10789
11146
  <div class="p-3">