@praxisui/table-rule-builder 9.0.0-beta.9 → 9.0.0-beta.90

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.
@@ -1,26 +1,28 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Input, ChangeDetectionStrategy, Component, Injectable, EventEmitter, Output } from '@angular/core';
3
- import * as i3$1 from '@angular/common';
2
+ import { Input, ChangeDetectionStrategy, Component, Injectable, EventEmitter, Output, ENVIRONMENT_INITIALIZER } from '@angular/core';
3
+ import * as i4$1 from '@angular/common';
4
4
  import { CommonModule } from '@angular/common';
5
- import * as i1 from '@angular/forms';
5
+ import * as i2 from '@angular/forms';
6
6
  import { ReactiveFormsModule } from '@angular/forms';
7
+ import * as i1 from '@praxisui/core';
8
+ import { providePraxisI18nConfig, ComponentMetadataRegistry } from '@praxisui/core';
7
9
  import { Subject } from 'rxjs';
8
10
  import { auditTime, takeUntil } from 'rxjs/operators';
9
- import * as i2 from '@angular/material/form-field';
11
+ import * as i3 from '@angular/material/form-field';
10
12
  import { MatFormFieldModule } from '@angular/material/form-field';
11
- import * as i3 from '@angular/material/input';
13
+ import * as i4 from '@angular/material/input';
12
14
  import { MatInputModule } from '@angular/material/input';
13
- import * as i4$1 from '@angular/material/button';
15
+ import * as i5$1 from '@angular/material/button';
14
16
  import { MatButtonModule } from '@angular/material/button';
15
- import * as i5 from '@angular/material/icon';
17
+ import * as i6 from '@angular/material/icon';
16
18
  import { MatIconModule } from '@angular/material/icon';
17
- import * as i6$1 from '@angular/material/tooltip';
19
+ import * as i7$1 from '@angular/material/tooltip';
18
20
  import { MatTooltipModule } from '@angular/material/tooltip';
19
- import * as i7 from '@angular/material/menu';
21
+ import * as i8 from '@angular/material/menu';
20
22
  import { MatMenuModule } from '@angular/material/menu';
21
- import * as i4 from '@angular/material/button-toggle';
23
+ import * as i5 from '@angular/material/button-toggle';
22
24
  import { MatButtonToggleModule } from '@angular/material/button-toggle';
23
- import * as i6 from '@angular/material/slider';
25
+ import * as i7 from '@angular/material/slider';
24
26
  import { MatSliderModule } from '@angular/material/slider';
25
27
  import { PdxColorPickerComponent } from '@praxisui/dynamic-fields';
26
28
 
@@ -234,15 +236,284 @@ const DEFAULT_EFFECT_PRESETS = {
234
236
  },
235
237
  };
236
238
 
239
+ const PRAXIS_TABLE_RULE_BUILDER_EN_US = {
240
+ 'panel.title': 'C. Effects',
241
+ 'panel.subtitle': 'Configure visual styles and elements when the rule is true',
242
+ 'tabs.estilo': 'Style',
243
+ 'tabs.layout': 'Layout',
244
+ 'tabs.icone': 'Icon / Badge',
245
+ 'tabs.fundo': 'Background',
246
+ 'tabs.animacao': 'Animation',
247
+ 'tabs.tooltip': 'Tooltip',
248
+ 'preview.title': 'Preview',
249
+ 'preview.hint': 'The changes above reflect the style applied when the condition is true.',
250
+ 'advanced.title': 'Advanced',
251
+ 'advanced.description': 'Description',
252
+ 'actions.apply': 'Apply',
253
+ 'actions.reset': 'Reset',
254
+ 'presets.label': 'Presets',
255
+ 'presets.aprovado': 'Approved',
256
+ 'presets.alerta': 'Warning',
257
+ 'presets.erro': 'Error',
258
+ 'presets.info': 'Info',
259
+ 'tabs.ariaLabel': 'Effect categories',
260
+ 'preview.sampleText': 'Sample cell value',
261
+ 'advanced.cssClass': 'CSS class',
262
+ 'advanced.inlineStyle': 'Inline style',
263
+ 'advanced.descriptionPlaceholder': 'e.g. highlight critical result',
264
+ 'advanced.cssClassPlaceholder': 'e.g. praxis-cell--alert',
265
+ 'advanced.inlineStylePlaceholder': 'e.g. font-weight: 600;',
266
+ 'style.group': 'Style editor',
267
+ 'style.textColor': 'Text color',
268
+ 'style.textColorAutomaticHint': 'Automatic when unchanged; the runtime derives accessible contrast for solid backgrounds.',
269
+ 'preview.contrastUnresolved': 'Contrast is not proven in this context yet. Transparency, gradients, CSS variables, or external styles require runtime preview validation.',
270
+ 'style.textBackgroundColor': 'Text background color',
271
+ 'style.bold': 'Bold',
272
+ 'style.italic': 'Italic',
273
+ 'style.underline': 'Underline',
274
+ 'style.transform': 'Transform',
275
+ 'style.transformAria': 'Text transform',
276
+ 'style.transform.none': 'None',
277
+ 'style.transform.uppercase': 'UPPERCASE',
278
+ 'style.transform.lowercase': 'lowercase',
279
+ 'style.transform.capitalize': 'Capitalize',
280
+ 'style.opacity': 'Opacity',
281
+ 'style.size': 'Size',
282
+ 'layout.group': 'Layout editor',
283
+ 'layout.border': 'Border',
284
+ 'layout.borderColor': 'Border color',
285
+ 'layout.borderWidth': 'Width',
286
+ 'layout.padding': 'Padding',
287
+ 'layout.align': 'Alignment',
288
+ 'layout.elevation': 'Elevation (shadow)',
289
+ 'icon.group': 'Icon and badge editor',
290
+ 'icon.label': 'Icon (mat-icon)',
291
+ 'icon.color': 'Icon color',
292
+ 'icon.position': 'Icon position',
293
+ 'icon.position.before': 'Before',
294
+ 'icon.position.after': 'After',
295
+ 'icon.position.overlay': 'Overlay',
296
+ 'badge.text': 'Badge text',
297
+ 'badge.color': 'Badge color',
298
+ 'badge.style': 'Style',
299
+ 'badge.style.aria': 'Badge style',
300
+ 'badge.style.solid': 'Solid',
301
+ 'badge.style.soft': 'Soft',
302
+ 'badge.style.outline': 'Outline',
303
+ 'background.group': 'Background editor',
304
+ 'background.color': 'Color',
305
+ 'background.gradient': 'CSS gradient',
306
+ 'background.alpha': 'Transparency',
307
+ 'background.blur': 'Blur (px)',
308
+ 'animation.group': 'Animation editor',
309
+ 'animation.enabled': 'Enable animation',
310
+ 'animation.preset': 'Preset',
311
+ 'animation.preset.aria': 'Animation preset',
312
+ 'animation.preset.none': 'No preset',
313
+ 'animation.type': 'Type',
314
+ 'animation.type.aria': 'Animation type',
315
+ 'animation.defaultFromPreset': 'Preset default',
316
+ 'animation.duration': 'Duration (ms)',
317
+ 'animation.duration.placeholder': 'Preset/default',
318
+ 'animation.delay': 'Delay (ms)',
319
+ 'animation.delay.placeholder': 'Optional',
320
+ 'animation.trigger': 'Trigger',
321
+ 'animation.trigger.aria': 'Animation trigger',
322
+ 'animation.trigger.onChange': 'On change',
323
+ 'animation.trigger.onAppear': 'On appear',
324
+ 'animation.trigger.onHover': 'On hover',
325
+ 'animation.trigger.onConditionEnter': 'On condition enter',
326
+ 'animation.trigger.onConditionExit': 'On condition exit',
327
+ 'animation.trigger.onDataRefresh': 'On data refresh',
328
+ 'animation.repeat': 'Repeat',
329
+ 'animation.repeat.aria': 'Animation repeat',
330
+ 'animation.repeat.once': 'Once',
331
+ 'animation.repeat.loop': 'Loop',
332
+ 'animation.repeat.infinite': 'Infinite',
333
+ 'animation.intensity': 'Intensity',
334
+ 'animation.intensity.aria': 'Animation intensity',
335
+ 'animation.intensity.subtle': 'Subtle',
336
+ 'animation.intensity.normal': 'Normal',
337
+ 'animation.intensity.strong': 'Strong',
338
+ 'tooltip.group': 'Tooltip editor',
339
+ 'tooltip.text': 'Text',
340
+ 'tooltip.text.placeholder': 'Cell details',
341
+ 'tooltip.position': 'Position',
342
+ 'tooltip.position.aria': 'Tooltip position',
343
+ 'tooltip.position.top': 'Top',
344
+ 'tooltip.position.right': 'Right',
345
+ 'tooltip.position.bottom': 'Bottom',
346
+ 'tooltip.position.left': 'Left',
347
+ 'tooltip.backgroundColor': 'Background color',
348
+ 'tooltip.delay': 'Delay (ms)',
349
+ };
350
+
351
+ const PRAXIS_TABLE_RULE_BUILDER_PT_BR = {
352
+ 'panel.title': 'C. Efeitos',
353
+ 'panel.subtitle': 'Configure estilos e elementos visuais quando a regra for verdadeira',
354
+ 'tabs.estilo': 'Estilo',
355
+ 'tabs.layout': 'Layout',
356
+ 'tabs.icone': 'Ícone / Badge',
357
+ 'tabs.fundo': 'Fundo',
358
+ 'tabs.animacao': 'Animação',
359
+ 'tabs.tooltip': 'Tooltip',
360
+ 'preview.title': 'Pré-visualização',
361
+ 'preview.hint': 'As mudanças acima refletem o estilo aplicado quando a condição é verdadeira.',
362
+ 'advanced.title': 'Avançado',
363
+ 'advanced.description': 'Descrição',
364
+ 'actions.apply': 'Aplicar',
365
+ 'actions.reset': 'Redefinir',
366
+ 'presets.label': 'Presets',
367
+ 'presets.aprovado': 'Aprovado',
368
+ 'presets.alerta': 'Alerta',
369
+ 'presets.erro': 'Erro',
370
+ 'presets.info': 'Info',
371
+ 'tabs.ariaLabel': 'Categorias de efeitos',
372
+ 'preview.sampleText': 'Valor da célula',
373
+ 'advanced.cssClass': 'Classe CSS',
374
+ 'advanced.inlineStyle': 'Estilo inline',
375
+ 'advanced.descriptionPlaceholder': 'ex.: destacar resultado crítico',
376
+ 'advanced.cssClassPlaceholder': 'ex.: praxis-cell--alert',
377
+ 'advanced.inlineStylePlaceholder': 'ex.: font-weight: 600;',
378
+ 'style.group': 'Editor de estilo',
379
+ 'style.textColor': 'Cor do texto',
380
+ 'style.textColorAutomaticHint': 'Automática quando não alterada; o runtime deriva contraste acessível para fundos sólidos.',
381
+ 'preview.contrastUnresolved': 'Contraste ainda não comprovado neste contexto. Transparência, gradiente, variável CSS ou estilo externo exige validação no preview do runtime.',
382
+ 'style.textBackgroundColor': 'Cor de fundo do texto',
383
+ 'style.bold': 'Negrito',
384
+ 'style.italic': 'Itálico',
385
+ 'style.underline': 'Sublinhado',
386
+ 'style.transform': 'Transformação',
387
+ 'style.transformAria': 'Transformação do texto',
388
+ 'style.transform.none': 'Nenhuma',
389
+ 'style.transform.uppercase': 'MAIÚSCULAS',
390
+ 'style.transform.lowercase': 'minúsculas',
391
+ 'style.transform.capitalize': 'Capitalizar',
392
+ 'style.opacity': 'Opacidade',
393
+ 'style.size': 'Tamanho',
394
+ 'layout.group': 'Editor de layout',
395
+ 'layout.border': 'Borda',
396
+ 'layout.borderColor': 'Cor da borda',
397
+ 'layout.borderWidth': 'Espessura',
398
+ 'layout.padding': 'Padding',
399
+ 'layout.align': 'Alinhamento',
400
+ 'layout.elevation': 'Elevação (sombra)',
401
+ 'icon.group': 'Editor de ícone e badge',
402
+ 'icon.label': 'Ícone (mat-icon)',
403
+ 'icon.color': 'Cor do ícone',
404
+ 'icon.position': 'Posição do ícone',
405
+ 'icon.position.before': 'Antes',
406
+ 'icon.position.after': 'Depois',
407
+ 'icon.position.overlay': 'Sobreposto',
408
+ 'badge.text': 'Texto do badge',
409
+ 'badge.color': 'Cor do badge',
410
+ 'badge.style': 'Estilo',
411
+ 'badge.style.aria': 'Estilo do badge',
412
+ 'badge.style.solid': 'Sólido',
413
+ 'badge.style.soft': 'Suave',
414
+ 'badge.style.outline': 'Contorno',
415
+ 'background.group': 'Editor de fundo',
416
+ 'background.color': 'Cor',
417
+ 'background.gradient': 'Gradient CSS',
418
+ 'background.alpha': 'Transparência',
419
+ 'background.blur': 'Desfoque (px)',
420
+ 'animation.group': 'Editor de animação',
421
+ 'animation.enabled': 'Ativar animação',
422
+ 'animation.preset': 'Preset',
423
+ 'animation.preset.aria': 'Preset de animação',
424
+ 'animation.preset.none': 'Sem preset',
425
+ 'animation.type': 'Tipo',
426
+ 'animation.type.aria': 'Tipo de animação',
427
+ 'animation.defaultFromPreset': 'Padrão do preset',
428
+ 'animation.duration': 'Duração (ms)',
429
+ 'animation.duration.placeholder': 'Preset/default',
430
+ 'animation.delay': 'Delay (ms)',
431
+ 'animation.delay.placeholder': 'Opcional',
432
+ 'animation.trigger': 'Disparo',
433
+ 'animation.trigger.aria': 'Disparo da animação',
434
+ 'animation.trigger.onChange': 'Ao mudar',
435
+ 'animation.trigger.onAppear': 'Ao aparecer',
436
+ 'animation.trigger.onHover': 'Ao passar o mouse',
437
+ 'animation.trigger.onConditionEnter': 'Ao entrar na condição',
438
+ 'animation.trigger.onConditionExit': 'Ao sair da condição',
439
+ 'animation.trigger.onDataRefresh': 'Ao atualizar dados',
440
+ 'animation.repeat': 'Repetição',
441
+ 'animation.repeat.aria': 'Repetição da animação',
442
+ 'animation.repeat.once': 'Uma vez',
443
+ 'animation.repeat.loop': 'Loop',
444
+ 'animation.repeat.infinite': 'Infinito',
445
+ 'animation.intensity': 'Intensidade',
446
+ 'animation.intensity.aria': 'Intensidade da animação',
447
+ 'animation.intensity.subtle': 'Sutil',
448
+ 'animation.intensity.normal': 'Normal',
449
+ 'animation.intensity.strong': 'Forte',
450
+ 'tooltip.group': 'Editor de tooltip',
451
+ 'tooltip.text': 'Texto',
452
+ 'tooltip.text.placeholder': 'Detalhes da célula',
453
+ 'tooltip.position': 'Posição',
454
+ 'tooltip.position.aria': 'Posição do tooltip',
455
+ 'tooltip.position.top': 'Topo',
456
+ 'tooltip.position.right': 'Direita',
457
+ 'tooltip.position.bottom': 'Baixo',
458
+ 'tooltip.position.left': 'Esquerda',
459
+ 'tooltip.backgroundColor': 'Cor do fundo',
460
+ 'tooltip.delay': 'Delay (ms)',
461
+ };
462
+
463
+ const PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE = 'praxisTableRuleBuilder';
464
+ const PRAXIS_TABLE_RULE_BUILDER_LABEL_KEYS = [
465
+ 'panel.title',
466
+ 'panel.subtitle',
467
+ 'tabs.estilo',
468
+ 'tabs.layout',
469
+ 'tabs.icone',
470
+ 'tabs.fundo',
471
+ 'tabs.animacao',
472
+ 'tabs.tooltip',
473
+ 'preview.title',
474
+ 'preview.hint',
475
+ 'advanced.title',
476
+ 'advanced.description',
477
+ 'actions.apply',
478
+ 'actions.reset',
479
+ 'presets.label',
480
+ 'presets.aprovado',
481
+ 'presets.alerta',
482
+ 'presets.erro',
483
+ 'presets.info',
484
+ 'tabs.ariaLabel',
485
+ 'preview.sampleText',
486
+ 'advanced.cssClass',
487
+ 'advanced.inlineStyle',
488
+ 'advanced.descriptionPlaceholder',
489
+ 'advanced.cssClassPlaceholder',
490
+ 'advanced.inlineStylePlaceholder',
491
+ ];
492
+ const PRAXIS_TABLE_RULE_BUILDER_I18N_CONFIG = {
493
+ namespaces: {
494
+ [PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE]: {
495
+ 'pt-BR': PRAXIS_TABLE_RULE_BUILDER_PT_BR,
496
+ 'en-US': PRAXIS_TABLE_RULE_BUILDER_EN_US,
497
+ },
498
+ },
499
+ };
500
+
237
501
  class EstiloEditorComponent {
502
+ i18n;
238
503
  group;
239
- // Public for template (strictTemplates): used by mat-slider
504
+ constructor(i18n) {
505
+ this.i18n = i18n;
506
+ }
507
+ tx(key, fallback) {
508
+ return this.i18n.t(key, undefined, fallback, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE);
509
+ }
510
+ // Public for template (strictTemplates): used by mat-slider.
240
511
  formatOpacity(v) { return (v ?? 0).toFixed(2); }
241
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EstiloEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
512
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EstiloEditorComponent, deps: [{ token: i1.PraxisI18nService }], target: i0.ɵɵFactoryTarget.Component });
242
513
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: EstiloEditorComponent, isStandalone: true, selector: "praxis-effects-estilo-editor", inputs: { group: "group" }, ngImport: i0, template: `
243
- <div class="estilo-grid" role="group" aria-label="Editor de estilo" [formGroup]="group">
514
+ <div class="estilo-grid" role="group" [attr.aria-label]="tx('style.group', 'Editor de estilo')" [formGroup]="group">
244
515
  <pdx-color-picker
245
- label="Cor do texto"
516
+ [label]="tx('style.textColor', 'Cor do texto')"
246
517
  formControlName="color"
247
518
  [format]="'hex'"
248
519
  [preview]="true"
@@ -251,9 +522,13 @@ class EstiloEditorComponent {
251
522
  [gradientSettings]="{ showOpacity: false, channel: 'hsv' }"
252
523
  [popupSettings]="{ width: 340 }"
253
524
  ></pdx-color-picker>
525
+ <p class="accessible-surface-hint">
526
+ <mat-icon aria-hidden="true">contrast</mat-icon>
527
+ {{ tx('style.textColorAutomaticHint', 'Automática quando não alterada; o runtime deriva contraste acessível para fundos sólidos.') }}
528
+ </p>
254
529
 
255
530
  <pdx-color-picker
256
- label="Cor de fundo do texto"
531
+ [label]="tx('style.textBackgroundColor', 'Cor de fundo do texto')"
257
532
  formControlName="bgColor"
258
533
  [format]="'hex'"
259
534
  [preview]="true"
@@ -265,44 +540,44 @@ class EstiloEditorComponent {
265
540
 
266
541
  <div class="toggles">
267
542
  <mat-button-toggle-group multiple>
268
- <mat-button-toggle [checked]="group.get('bold')?.value" (change)="group.get('bold')?.setValue($event.source.checked)" aria-label="Negrito">
543
+ <mat-button-toggle [checked]="group.get('bold')?.value" (change)="group.get('bold')?.setValue($event.source.checked)" [attr.aria-label]="tx('style.bold', 'Negrito')">
269
544
  <mat-icon>format_bold</mat-icon>
270
545
  </mat-button-toggle>
271
- <mat-button-toggle [checked]="group.get('italic')?.value" (change)="group.get('italic')?.setValue($event.source.checked)" aria-label="Itálico">
546
+ <mat-button-toggle [checked]="group.get('italic')?.value" (change)="group.get('italic')?.setValue($event.source.checked)" [attr.aria-label]="tx('style.italic', 'Italico')">
272
547
  <mat-icon>format_italic</mat-icon>
273
548
  </mat-button-toggle>
274
- <mat-button-toggle [checked]="group.get('underline')?.value" (change)="group.get('underline')?.setValue($event.source.checked)" aria-label="Sublinhado">
549
+ <mat-button-toggle [checked]="group.get('underline')?.value" (change)="group.get('underline')?.setValue($event.source.checked)" [attr.aria-label]="tx('style.underline', 'Sublinhado')">
275
550
  <mat-icon>format_underlined</mat-icon>
276
551
  </mat-button-toggle>
277
552
  </mat-button-toggle-group>
278
553
  </div>
279
554
 
280
555
  <mat-form-field appearance="outline">
281
- <mat-label>Transformação</mat-label>
282
- <select matNativeControl formControlName="transform" aria-label="Transformação do texto">
283
- <option [ngValue]="null">Nenhuma</option>
284
- <option value="uppercase">MAIÚSCULAS</option>
285
- <option value="lowercase">minúsculas</option>
286
- <option value="capitalize">Capitalizar</option>
556
+ <mat-label>{{ tx('style.transform', 'Transformacao') }}</mat-label>
557
+ <select matNativeControl formControlName="transform" [attr.aria-label]="tx('style.transformAria', 'Transformacao do texto')">
558
+ <option [ngValue]="null">{{ tx('style.transform.none', 'Nenhuma') }}</option>
559
+ <option value="uppercase">{{ tx('style.transform.uppercase', 'MAIUSCULAS') }}</option>
560
+ <option value="lowercase">{{ tx('style.transform.lowercase', 'minusculas') }}</option>
561
+ <option value="capitalize">{{ tx('style.transform.capitalize', 'Capitalizar') }}</option>
287
562
  </select>
288
563
  </mat-form-field>
289
564
 
290
565
  <div class="sliders">
291
566
  <label class="slider">
292
- <span>Opacidade</span>
567
+ <span>{{ tx('style.opacity', 'Opacidade') }}</span>
293
568
  <mat-slider min="0" max="1" step="0.05" [displayWith]="formatOpacity">
294
569
  <input matSliderThumb formControlName="opacity" />
295
570
  </mat-slider>
296
571
  </label>
297
572
  <label class="slider">
298
- <span>Tamanho</span>
573
+ <span>{{ tx('style.size', 'Tamanho') }}</span>
299
574
  <mat-slider min="-2" max="2" step="1">
300
575
  <input matSliderThumb formControlName="fontScale" />
301
576
  </mat-slider>
302
577
  </label>
303
578
  </div>
304
579
  </div>
305
- `, isInline: true, styles: [".estilo-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:start}.toggles{display:flex;align-items:center;gap:8px}.sliders{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.slider{display:flex;flex-direction:column;gap:6px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.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.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { 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.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.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: MatButtonToggleModule }, { kind: "directive", type: i4.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i4.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatSliderModule }, { kind: "component", type: i6.MatSlider, selector: "mat-slider", inputs: ["disabled", "discrete", "showTickMarks", "min", "color", "disableRipple", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "directive", type: i6.MatSliderThumb, selector: "input[matSliderThumb]", inputs: ["value"], outputs: ["valueChange", "dragStart", "dragEnd"], exportAs: ["matSliderThumb"] }, { kind: "component", type: PdxColorPickerComponent, selector: "pdx-color-picker", inputs: ["actionsLayout", "activeView", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "clearButton", "disabledMode", "readonlyMode", "visible", "presentationMode", "fillMode", "format", "gradientSettings", "icon", "iconClass", "svgIcon", "paletteSettings", "popupSettings", "preview", "rounded", "size", "tabindex", "views", "maxRecent", "showRecent"], outputs: ["valueChange", "open", "close", "cancel", "activeViewChange", "activeColorClick", "focusEvent", "blurEvent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
580
+ `, isInline: true, styles: [".estilo-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;align-items:start;min-width:0}pdx-color-picker,mat-form-field{min-width:0}.accessible-surface-hint{display:flex;align-items:flex-start;gap:6px;margin:-6px 0 0;color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.35}.accessible-surface-hint mat-icon{flex:0 0 auto;width:16px;height:16px;font-size:16px}.toggles{display:flex;align-items:center;gap:8px;min-width:0}.toggles mat-button-toggle-group{flex-wrap:wrap}.sliders{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;min-width:0}.slider{display:flex;flex-direction:column;gap:6px;min-width:0}.slider span{white-space:nowrap}mat-slider{width:100%;min-width:0}@media(max-width:520px){.estilo-grid,.sliders{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.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: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.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: MatButtonToggleModule }, { kind: "directive", type: i5.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i5.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatSliderModule }, { kind: "component", type: i7.MatSlider, selector: "mat-slider", inputs: ["disabled", "discrete", "showTickMarks", "min", "color", "disableRipple", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "directive", type: i7.MatSliderThumb, selector: "input[matSliderThumb]", inputs: ["value"], outputs: ["valueChange", "dragStart", "dragEnd"], exportAs: ["matSliderThumb"] }, { kind: "component", type: PdxColorPickerComponent, selector: "pdx-color-picker", inputs: ["actionsLayout", "activeView", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "clearButton", "disabledMode", "readonlyMode", "visible", "presentationMode", "fillMode", "format", "gradientSettings", "icon", "iconClass", "svgIcon", "paletteSettings", "popupSettings", "preview", "rounded", "size", "tabindex", "views", "maxRecent", "showRecent"], outputs: ["valueChange", "open", "close", "cancel", "activeViewChange", "activeColorClick", "focusEvent", "blurEvent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
306
581
  }
307
582
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EstiloEditorComponent, decorators: [{
308
583
  type: Component,
@@ -313,11 +588,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
313
588
  MatButtonToggleModule,
314
589
  MatIconModule,
315
590
  MatSliderModule,
316
- PdxColorPickerComponent
591
+ PdxColorPickerComponent,
317
592
  ], template: `
318
- <div class="estilo-grid" role="group" aria-label="Editor de estilo" [formGroup]="group">
593
+ <div class="estilo-grid" role="group" [attr.aria-label]="tx('style.group', 'Editor de estilo')" [formGroup]="group">
319
594
  <pdx-color-picker
320
- label="Cor do texto"
595
+ [label]="tx('style.textColor', 'Cor do texto')"
321
596
  formControlName="color"
322
597
  [format]="'hex'"
323
598
  [preview]="true"
@@ -326,9 +601,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
326
601
  [gradientSettings]="{ showOpacity: false, channel: 'hsv' }"
327
602
  [popupSettings]="{ width: 340 }"
328
603
  ></pdx-color-picker>
604
+ <p class="accessible-surface-hint">
605
+ <mat-icon aria-hidden="true">contrast</mat-icon>
606
+ {{ tx('style.textColorAutomaticHint', 'Automática quando não alterada; o runtime deriva contraste acessível para fundos sólidos.') }}
607
+ </p>
329
608
 
330
609
  <pdx-color-picker
331
- label="Cor de fundo do texto"
610
+ [label]="tx('style.textBackgroundColor', 'Cor de fundo do texto')"
332
611
  formControlName="bgColor"
333
612
  [format]="'hex'"
334
613
  [preview]="true"
@@ -340,56 +619,63 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
340
619
 
341
620
  <div class="toggles">
342
621
  <mat-button-toggle-group multiple>
343
- <mat-button-toggle [checked]="group.get('bold')?.value" (change)="group.get('bold')?.setValue($event.source.checked)" aria-label="Negrito">
622
+ <mat-button-toggle [checked]="group.get('bold')?.value" (change)="group.get('bold')?.setValue($event.source.checked)" [attr.aria-label]="tx('style.bold', 'Negrito')">
344
623
  <mat-icon>format_bold</mat-icon>
345
624
  </mat-button-toggle>
346
- <mat-button-toggle [checked]="group.get('italic')?.value" (change)="group.get('italic')?.setValue($event.source.checked)" aria-label="Itálico">
625
+ <mat-button-toggle [checked]="group.get('italic')?.value" (change)="group.get('italic')?.setValue($event.source.checked)" [attr.aria-label]="tx('style.italic', 'Italico')">
347
626
  <mat-icon>format_italic</mat-icon>
348
627
  </mat-button-toggle>
349
- <mat-button-toggle [checked]="group.get('underline')?.value" (change)="group.get('underline')?.setValue($event.source.checked)" aria-label="Sublinhado">
628
+ <mat-button-toggle [checked]="group.get('underline')?.value" (change)="group.get('underline')?.setValue($event.source.checked)" [attr.aria-label]="tx('style.underline', 'Sublinhado')">
350
629
  <mat-icon>format_underlined</mat-icon>
351
630
  </mat-button-toggle>
352
631
  </mat-button-toggle-group>
353
632
  </div>
354
633
 
355
634
  <mat-form-field appearance="outline">
356
- <mat-label>Transformação</mat-label>
357
- <select matNativeControl formControlName="transform" aria-label="Transformação do texto">
358
- <option [ngValue]="null">Nenhuma</option>
359
- <option value="uppercase">MAIÚSCULAS</option>
360
- <option value="lowercase">minúsculas</option>
361
- <option value="capitalize">Capitalizar</option>
635
+ <mat-label>{{ tx('style.transform', 'Transformacao') }}</mat-label>
636
+ <select matNativeControl formControlName="transform" [attr.aria-label]="tx('style.transformAria', 'Transformacao do texto')">
637
+ <option [ngValue]="null">{{ tx('style.transform.none', 'Nenhuma') }}</option>
638
+ <option value="uppercase">{{ tx('style.transform.uppercase', 'MAIUSCULAS') }}</option>
639
+ <option value="lowercase">{{ tx('style.transform.lowercase', 'minusculas') }}</option>
640
+ <option value="capitalize">{{ tx('style.transform.capitalize', 'Capitalizar') }}</option>
362
641
  </select>
363
642
  </mat-form-field>
364
643
 
365
644
  <div class="sliders">
366
645
  <label class="slider">
367
- <span>Opacidade</span>
646
+ <span>{{ tx('style.opacity', 'Opacidade') }}</span>
368
647
  <mat-slider min="0" max="1" step="0.05" [displayWith]="formatOpacity">
369
648
  <input matSliderThumb formControlName="opacity" />
370
649
  </mat-slider>
371
650
  </label>
372
651
  <label class="slider">
373
- <span>Tamanho</span>
652
+ <span>{{ tx('style.size', 'Tamanho') }}</span>
374
653
  <mat-slider min="-2" max="2" step="1">
375
654
  <input matSliderThumb formControlName="fontScale" />
376
655
  </mat-slider>
377
656
  </label>
378
657
  </div>
379
658
  </div>
380
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".estilo-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:start}.toggles{display:flex;align-items:center;gap:8px}.sliders{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.slider{display:flex;flex-direction:column;gap:6px}\n"] }]
381
- }], propDecorators: { group: [{
659
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".estilo-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;align-items:start;min-width:0}pdx-color-picker,mat-form-field{min-width:0}.accessible-surface-hint{display:flex;align-items:flex-start;gap:6px;margin:-6px 0 0;color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.35}.accessible-surface-hint mat-icon{flex:0 0 auto;width:16px;height:16px;font-size:16px}.toggles{display:flex;align-items:center;gap:8px;min-width:0}.toggles mat-button-toggle-group{flex-wrap:wrap}.sliders{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;min-width:0}.slider{display:flex;flex-direction:column;gap:6px;min-width:0}.slider span{white-space:nowrap}mat-slider{width:100%;min-width:0}@media(max-width:520px){.estilo-grid,.sliders{grid-template-columns:1fr}}\n"] }]
660
+ }], ctorParameters: () => [{ type: i1.PraxisI18nService }], propDecorators: { group: [{
382
661
  type: Input
383
662
  }] } });
384
663
 
385
664
  class LayoutEditorComponent {
665
+ i18n;
386
666
  group;
387
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: LayoutEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
667
+ constructor(i18n) {
668
+ this.i18n = i18n;
669
+ }
670
+ tx(key, fallback) {
671
+ return this.i18n.t(key, undefined, fallback, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE);
672
+ }
673
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: LayoutEditorComponent, deps: [{ token: i1.PraxisI18nService }], target: i0.ɵɵFactoryTarget.Component });
388
674
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: LayoutEditorComponent, isStandalone: true, selector: "praxis-effects-layout-editor", inputs: { group: "group" }, ngImport: i0, template: `
389
- <div class="layout-grid" role="group" aria-label="Editor de layout" [formGroup]="group">
675
+ <div class="layout-grid" role="group" [attr.aria-label]="tx('layout.group', 'Editor de layout')" [formGroup]="group">
390
676
  <div class="borders">
391
- <span class="lbl">Borda</span>
392
- <mat-button-toggle-group [value]="group.get('border')?.value" (change)="group.get('border')?.setValue($event.value)" aria-label="Borda">
677
+ <span class="lbl">{{ tx('layout.border', 'Borda') }}</span>
678
+ <mat-button-toggle-group [value]="group.get('border')?.value" (change)="group.get('border')?.setValue($event.value)" [attr.aria-label]="tx('layout.border', 'Borda')">
393
679
  <mat-button-toggle value="none"><mat-icon>crop_free</mat-icon></mat-button-toggle>
394
680
  <mat-button-toggle value="left"><mat-icon>border_left</mat-icon></mat-button-toggle>
395
681
  <mat-button-toggle value="right"><mat-icon>border_right</mat-icon></mat-button-toggle>
@@ -400,21 +686,21 @@ class LayoutEditorComponent {
400
686
  </div>
401
687
 
402
688
  <mat-form-field appearance="outline">
403
- <mat-label>Cor da borda</mat-label>
689
+ <mat-label>{{ tx('layout.borderColor', 'Cor da borda') }}</mat-label>
404
690
  <input matInput type="text" formControlName="borderColor" placeholder="#487BFF" />
405
691
  </mat-form-field>
406
692
  <mat-form-field appearance="outline">
407
- <mat-label>Espessura</mat-label>
693
+ <mat-label>{{ tx('layout.borderWidth', 'Espessura') }}</mat-label>
408
694
  <input matInput type="number" formControlName="borderWidth" placeholder="2" />
409
695
  </mat-form-field>
410
696
  <mat-form-field appearance="outline">
411
- <mat-label>Padding</mat-label>
697
+ <mat-label>{{ tx('layout.padding', 'Padding') }}</mat-label>
412
698
  <input matInput type="number" formControlName="padding" placeholder="6" />
413
699
  </mat-form-field>
414
700
 
415
701
  <div class="align">
416
- <span class="lbl">Alinhamento</span>
417
- <mat-button-toggle-group [value]="group.get('align')?.value" (change)="group.get('align')?.setValue($event.value)" aria-label="Alinhamento">
702
+ <span class="lbl">{{ tx('layout.align', 'Alinhamento') }}</span>
703
+ <mat-button-toggle-group [value]="group.get('align')?.value" (change)="group.get('align')?.setValue($event.value)" [attr.aria-label]="tx('layout.align', 'Alinhamento')">
418
704
  <mat-button-toggle value="start"><mat-icon>format_align_left</mat-icon></mat-button-toggle>
419
705
  <mat-button-toggle value="center"><mat-icon>format_align_center</mat-icon></mat-button-toggle>
420
706
  <mat-button-toggle value="end"><mat-icon>format_align_right</mat-icon></mat-button-toggle>
@@ -422,19 +708,19 @@ class LayoutEditorComponent {
422
708
  </div>
423
709
 
424
710
  <mat-form-field appearance="outline">
425
- <mat-label>Elevação (sombra)</mat-label>
711
+ <mat-label>{{ tx('layout.elevation', 'Elevacao (sombra)') }}</mat-label>
426
712
  <input matInput type="number" formControlName="elevation" placeholder="6" />
427
713
  </mat-form-field>
428
714
  </div>
429
- `, isInline: true, styles: [".layout-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:center}.borders,.align{display:flex;align-items:center;gap:8px}.lbl{font-size:.85rem;opacity:.8}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.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.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { 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.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.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: MatButtonToggleModule }, { kind: "directive", type: i4.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i4.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
715
+ `, isInline: true, styles: [".layout-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;align-items:center;min-width:0}mat-form-field{min-width:0}.borders,.align{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.borders mat-button-toggle-group,.align mat-button-toggle-group{flex-wrap:wrap}.lbl{font-size:.85rem;opacity:.8}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.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: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.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: MatButtonToggleModule }, { kind: "directive", type: i5.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i5.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
430
716
  }
431
717
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: LayoutEditorComponent, decorators: [{
432
718
  type: Component,
433
719
  args: [{ selector: 'praxis-effects-layout-editor', standalone: true, imports: [ReactiveFormsModule, MatFormFieldModule, MatInputModule, MatButtonToggleModule, MatIconModule], template: `
434
- <div class="layout-grid" role="group" aria-label="Editor de layout" [formGroup]="group">
720
+ <div class="layout-grid" role="group" [attr.aria-label]="tx('layout.group', 'Editor de layout')" [formGroup]="group">
435
721
  <div class="borders">
436
- <span class="lbl">Borda</span>
437
- <mat-button-toggle-group [value]="group.get('border')?.value" (change)="group.get('border')?.setValue($event.value)" aria-label="Borda">
722
+ <span class="lbl">{{ tx('layout.border', 'Borda') }}</span>
723
+ <mat-button-toggle-group [value]="group.get('border')?.value" (change)="group.get('border')?.setValue($event.value)" [attr.aria-label]="tx('layout.border', 'Borda')">
438
724
  <mat-button-toggle value="none"><mat-icon>crop_free</mat-icon></mat-button-toggle>
439
725
  <mat-button-toggle value="left"><mat-icon>border_left</mat-icon></mat-button-toggle>
440
726
  <mat-button-toggle value="right"><mat-icon>border_right</mat-icon></mat-button-toggle>
@@ -445,21 +731,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
445
731
  </div>
446
732
 
447
733
  <mat-form-field appearance="outline">
448
- <mat-label>Cor da borda</mat-label>
734
+ <mat-label>{{ tx('layout.borderColor', 'Cor da borda') }}</mat-label>
449
735
  <input matInput type="text" formControlName="borderColor" placeholder="#487BFF" />
450
736
  </mat-form-field>
451
737
  <mat-form-field appearance="outline">
452
- <mat-label>Espessura</mat-label>
738
+ <mat-label>{{ tx('layout.borderWidth', 'Espessura') }}</mat-label>
453
739
  <input matInput type="number" formControlName="borderWidth" placeholder="2" />
454
740
  </mat-form-field>
455
741
  <mat-form-field appearance="outline">
456
- <mat-label>Padding</mat-label>
742
+ <mat-label>{{ tx('layout.padding', 'Padding') }}</mat-label>
457
743
  <input matInput type="number" formControlName="padding" placeholder="6" />
458
744
  </mat-form-field>
459
745
 
460
746
  <div class="align">
461
- <span class="lbl">Alinhamento</span>
462
- <mat-button-toggle-group [value]="group.get('align')?.value" (change)="group.get('align')?.setValue($event.value)" aria-label="Alinhamento">
747
+ <span class="lbl">{{ tx('layout.align', 'Alinhamento') }}</span>
748
+ <mat-button-toggle-group [value]="group.get('align')?.value" (change)="group.get('align')?.setValue($event.value)" [attr.aria-label]="tx('layout.align', 'Alinhamento')">
463
749
  <mat-button-toggle value="start"><mat-icon>format_align_left</mat-icon></mat-button-toggle>
464
750
  <mat-button-toggle value="center"><mat-icon>format_align_center</mat-icon></mat-button-toggle>
465
751
  <mat-button-toggle value="end"><mat-icon>format_align_right</mat-icon></mat-button-toggle>
@@ -467,176 +753,197 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
467
753
  </div>
468
754
 
469
755
  <mat-form-field appearance="outline">
470
- <mat-label>Elevação (sombra)</mat-label>
756
+ <mat-label>{{ tx('layout.elevation', 'Elevacao (sombra)') }}</mat-label>
471
757
  <input matInput type="number" formControlName="elevation" placeholder="6" />
472
758
  </mat-form-field>
473
759
  </div>
474
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".layout-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:center}.borders,.align{display:flex;align-items:center;gap:8px}.lbl{font-size:.85rem;opacity:.8}\n"] }]
475
- }], propDecorators: { group: [{
760
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".layout-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;align-items:center;min-width:0}mat-form-field{min-width:0}.borders,.align{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.borders mat-button-toggle-group,.align mat-button-toggle-group{flex-wrap:wrap}.lbl{font-size:.85rem;opacity:.8}\n"] }]
761
+ }], ctorParameters: () => [{ type: i1.PraxisI18nService }], propDecorators: { group: [{
476
762
  type: Input
477
763
  }] } });
478
764
 
479
765
  class IconeBadgeEditorComponent {
766
+ i18n;
480
767
  group;
481
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: IconeBadgeEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
768
+ constructor(i18n) {
769
+ this.i18n = i18n;
770
+ }
771
+ tx(key, fallback) {
772
+ return this.i18n.t(key, undefined, fallback, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE);
773
+ }
774
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: IconeBadgeEditorComponent, deps: [{ token: i1.PraxisI18nService }], target: i0.ɵɵFactoryTarget.Component });
482
775
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: IconeBadgeEditorComponent, isStandalone: true, selector: "praxis-effects-icone-badge-editor", inputs: { group: "group" }, ngImport: i0, template: `
483
- <div class="icone-grid" role="group" aria-label="Editor de ícone e badge" [formGroup]="group">
776
+ <div class="icone-grid" role="group" [attr.aria-label]="tx('icon.group', 'Editor de icone e badge')" [formGroup]="group">
484
777
  <mat-form-field appearance="outline">
485
- <mat-label>Ícone (mat-icon)</mat-label>
778
+ <mat-label>{{ tx('icon.label', 'Icone (mat-icon)') }}</mat-label>
486
779
  <input matInput type="text" formControlName="icon" placeholder="check_circle" />
487
780
  </mat-form-field>
488
781
  <mat-form-field appearance="outline">
489
- <mat-label>Cor do ícone</mat-label>
782
+ <mat-label>{{ tx('icon.color', 'Cor do icone') }}</mat-label>
490
783
  <input matInput type="text" formControlName="iconColor" placeholder="#35D07F" />
491
784
  </mat-form-field>
492
785
 
493
786
  <div class="pos">
494
- <span class="lbl">Posição do ícone</span>
495
- <mat-button-toggle-group [value]="group.get('iconPos')?.value" (change)="group.get('iconPos')?.setValue($event.value)" aria-label="Posição do ícone">
496
- <mat-button-toggle value="before">Antes</mat-button-toggle>
497
- <mat-button-toggle value="after">Depois</mat-button-toggle>
498
- <mat-button-toggle value="overlay">Sobreposto</mat-button-toggle>
787
+ <span class="lbl">{{ tx('icon.position', 'Posicao do icone') }}</span>
788
+ <mat-button-toggle-group [value]="group.get('iconPos')?.value" (change)="group.get('iconPos')?.setValue($event.value)" [attr.aria-label]="tx('icon.position', 'Posicao do icone')">
789
+ <mat-button-toggle value="before">{{ tx('icon.position.before', 'Antes') }}</mat-button-toggle>
790
+ <mat-button-toggle value="after">{{ tx('icon.position.after', 'Depois') }}</mat-button-toggle>
791
+ <mat-button-toggle value="overlay">{{ tx('icon.position.overlay', 'Sobreposto') }}</mat-button-toggle>
499
792
  </mat-button-toggle-group>
500
793
  </div>
501
794
 
502
795
  <mat-form-field appearance="outline">
503
- <mat-label>Texto do badge</mat-label>
796
+ <mat-label>{{ tx('badge.text', 'Texto do badge') }}</mat-label>
504
797
  <input matInput type="text" formControlName="badgeText" placeholder="Aprovado" />
505
798
  </mat-form-field>
506
799
  <mat-form-field appearance="outline">
507
- <mat-label>Cor do badge</mat-label>
800
+ <mat-label>{{ tx('badge.color', 'Cor do badge') }}</mat-label>
508
801
  <input matInput type="text" formControlName="badgeColor" placeholder="#2a8455" />
509
802
  </mat-form-field>
510
803
 
511
804
  <div class="variant">
512
- <span class="lbl">Estilo</span>
513
- <mat-button-toggle-group [value]="group.get('badgeStyle')?.value" (change)="group.get('badgeStyle')?.setValue($event.value)" aria-label="Estilo do badge">
514
- <mat-button-toggle value="solid">Sólido</mat-button-toggle>
515
- <mat-button-toggle value="soft">Suave</mat-button-toggle>
516
- <mat-button-toggle value="outline">Contorno</mat-button-toggle>
805
+ <span class="lbl">{{ tx('badge.style', 'Estilo') }}</span>
806
+ <mat-button-toggle-group [value]="group.get('badgeStyle')?.value" (change)="group.get('badgeStyle')?.setValue($event.value)" [attr.aria-label]="tx('badge.style.aria', 'Estilo do badge')">
807
+ <mat-button-toggle value="solid">{{ tx('badge.style.solid', 'Solido') }}</mat-button-toggle>
808
+ <mat-button-toggle value="soft">{{ tx('badge.style.soft', 'Suave') }}</mat-button-toggle>
809
+ <mat-button-toggle value="outline">{{ tx('badge.style.outline', 'Contorno') }}</mat-button-toggle>
517
810
  </mat-button-toggle-group>
518
811
  </div>
519
812
  </div>
520
- `, isInline: true, styles: [".icone-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:center}.pos,.variant{display:flex;align-items:center;gap:8px}.lbl{font-size:.85rem;opacity:.8}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.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: MatButtonToggleModule }, { kind: "directive", type: i4.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i4.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatIconModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
813
+ `, isInline: true, styles: [".icone-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;align-items:center;min-width:0}mat-form-field{min-width:0}.pos,.variant{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.pos mat-button-toggle-group,.variant mat-button-toggle-group{flex-wrap:wrap}.lbl{font-size:.85rem;opacity:.8}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.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: MatButtonToggleModule }, { kind: "directive", type: i5.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i5.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatIconModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
521
814
  }
522
815
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: IconeBadgeEditorComponent, decorators: [{
523
816
  type: Component,
524
817
  args: [{ selector: 'praxis-effects-icone-badge-editor', standalone: true, imports: [ReactiveFormsModule, MatFormFieldModule, MatInputModule, MatButtonToggleModule, MatIconModule], template: `
525
- <div class="icone-grid" role="group" aria-label="Editor de ícone e badge" [formGroup]="group">
818
+ <div class="icone-grid" role="group" [attr.aria-label]="tx('icon.group', 'Editor de icone e badge')" [formGroup]="group">
526
819
  <mat-form-field appearance="outline">
527
- <mat-label>Ícone (mat-icon)</mat-label>
820
+ <mat-label>{{ tx('icon.label', 'Icone (mat-icon)') }}</mat-label>
528
821
  <input matInput type="text" formControlName="icon" placeholder="check_circle" />
529
822
  </mat-form-field>
530
823
  <mat-form-field appearance="outline">
531
- <mat-label>Cor do ícone</mat-label>
824
+ <mat-label>{{ tx('icon.color', 'Cor do icone') }}</mat-label>
532
825
  <input matInput type="text" formControlName="iconColor" placeholder="#35D07F" />
533
826
  </mat-form-field>
534
827
 
535
828
  <div class="pos">
536
- <span class="lbl">Posição do ícone</span>
537
- <mat-button-toggle-group [value]="group.get('iconPos')?.value" (change)="group.get('iconPos')?.setValue($event.value)" aria-label="Posição do ícone">
538
- <mat-button-toggle value="before">Antes</mat-button-toggle>
539
- <mat-button-toggle value="after">Depois</mat-button-toggle>
540
- <mat-button-toggle value="overlay">Sobreposto</mat-button-toggle>
829
+ <span class="lbl">{{ tx('icon.position', 'Posicao do icone') }}</span>
830
+ <mat-button-toggle-group [value]="group.get('iconPos')?.value" (change)="group.get('iconPos')?.setValue($event.value)" [attr.aria-label]="tx('icon.position', 'Posicao do icone')">
831
+ <mat-button-toggle value="before">{{ tx('icon.position.before', 'Antes') }}</mat-button-toggle>
832
+ <mat-button-toggle value="after">{{ tx('icon.position.after', 'Depois') }}</mat-button-toggle>
833
+ <mat-button-toggle value="overlay">{{ tx('icon.position.overlay', 'Sobreposto') }}</mat-button-toggle>
541
834
  </mat-button-toggle-group>
542
835
  </div>
543
836
 
544
837
  <mat-form-field appearance="outline">
545
- <mat-label>Texto do badge</mat-label>
838
+ <mat-label>{{ tx('badge.text', 'Texto do badge') }}</mat-label>
546
839
  <input matInput type="text" formControlName="badgeText" placeholder="Aprovado" />
547
840
  </mat-form-field>
548
841
  <mat-form-field appearance="outline">
549
- <mat-label>Cor do badge</mat-label>
842
+ <mat-label>{{ tx('badge.color', 'Cor do badge') }}</mat-label>
550
843
  <input matInput type="text" formControlName="badgeColor" placeholder="#2a8455" />
551
844
  </mat-form-field>
552
845
 
553
846
  <div class="variant">
554
- <span class="lbl">Estilo</span>
555
- <mat-button-toggle-group [value]="group.get('badgeStyle')?.value" (change)="group.get('badgeStyle')?.setValue($event.value)" aria-label="Estilo do badge">
556
- <mat-button-toggle value="solid">Sólido</mat-button-toggle>
557
- <mat-button-toggle value="soft">Suave</mat-button-toggle>
558
- <mat-button-toggle value="outline">Contorno</mat-button-toggle>
847
+ <span class="lbl">{{ tx('badge.style', 'Estilo') }}</span>
848
+ <mat-button-toggle-group [value]="group.get('badgeStyle')?.value" (change)="group.get('badgeStyle')?.setValue($event.value)" [attr.aria-label]="tx('badge.style.aria', 'Estilo do badge')">
849
+ <mat-button-toggle value="solid">{{ tx('badge.style.solid', 'Solido') }}</mat-button-toggle>
850
+ <mat-button-toggle value="soft">{{ tx('badge.style.soft', 'Suave') }}</mat-button-toggle>
851
+ <mat-button-toggle value="outline">{{ tx('badge.style.outline', 'Contorno') }}</mat-button-toggle>
559
852
  </mat-button-toggle-group>
560
853
  </div>
561
854
  </div>
562
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".icone-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:center}.pos,.variant{display:flex;align-items:center;gap:8px}.lbl{font-size:.85rem;opacity:.8}\n"] }]
563
- }], propDecorators: { group: [{
855
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".icone-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;align-items:center;min-width:0}mat-form-field{min-width:0}.pos,.variant{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.pos mat-button-toggle-group,.variant mat-button-toggle-group{flex-wrap:wrap}.lbl{font-size:.85rem;opacity:.8}\n"] }]
856
+ }], ctorParameters: () => [{ type: i1.PraxisI18nService }], propDecorators: { group: [{
564
857
  type: Input
565
858
  }] } });
566
859
 
567
860
  class FundoEditorComponent {
861
+ i18n;
568
862
  group;
569
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FundoEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
863
+ constructor(i18n) {
864
+ this.i18n = i18n;
865
+ }
866
+ tx(key, fallback) {
867
+ return this.i18n.t(key, undefined, fallback, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE);
868
+ }
869
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FundoEditorComponent, deps: [{ token: i1.PraxisI18nService }], target: i0.ɵɵFactoryTarget.Component });
570
870
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: FundoEditorComponent, isStandalone: true, selector: "praxis-effects-fundo-editor", inputs: { group: "group" }, ngImport: i0, template: `
571
- <div class="fundo-grid" role="group" aria-label="Editor de fundo" [formGroup]="group">
871
+ <div class="fundo-grid" role="group" [attr.aria-label]="tx('background.group', 'Editor de fundo')" [formGroup]="group">
572
872
  <mat-form-field appearance="outline">
573
- <mat-label>Cor</mat-label>
873
+ <mat-label>{{ tx('background.color', 'Cor') }}</mat-label>
574
874
  <input matInput type="text" formControlName="color" placeholder="#122033" />
575
875
  </mat-form-field>
576
876
  <mat-form-field appearance="outline" class="full">
577
- <mat-label>Gradient CSS</mat-label>
877
+ <mat-label>{{ tx('background.gradient', 'Gradient CSS') }}</mat-label>
578
878
  <input matInput type="text" formControlName="gradient" placeholder="linear-gradient(180deg, #202637, #1c2230)" />
579
879
  </mat-form-field>
580
880
 
581
881
  <label class="slider">
582
- <span>Transparência</span>
882
+ <span>{{ tx('background.alpha', 'Transparencia') }}</span>
583
883
  <mat-slider min="0" max="100" step="5">
584
884
  <input matSliderThumb formControlName="alpha" />
585
885
  </mat-slider>
586
886
  </label>
587
887
  <label class="slider">
588
- <span>Desfoque (px)</span>
888
+ <span>{{ tx('background.blur', 'Desfoque (px)') }}</span>
589
889
  <mat-slider min="0" max="20" step="1">
590
890
  <input matSliderThumb formControlName="blur" />
591
891
  </mat-slider>
592
892
  </label>
593
893
  </div>
594
- `, isInline: true, styles: [".fundo-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:center}.full{grid-column:1 / -1}.slider{display:flex;flex-direction:column;gap:6px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.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: MatSliderModule }, { kind: "component", type: i6.MatSlider, selector: "mat-slider", inputs: ["disabled", "discrete", "showTickMarks", "min", "color", "disableRipple", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "directive", type: i6.MatSliderThumb, selector: "input[matSliderThumb]", inputs: ["value"], outputs: ["valueChange", "dragStart", "dragEnd"], exportAs: ["matSliderThumb"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
894
+ `, isInline: true, styles: [".fundo-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;align-items:center;min-width:0}.full{grid-column:1 / -1}mat-form-field,.slider{min-width:0}.slider{display:flex;flex-direction:column;gap:6px}.slider span{white-space:nowrap}mat-slider{width:100%;min-width:0}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.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: MatSliderModule }, { kind: "component", type: i7.MatSlider, selector: "mat-slider", inputs: ["disabled", "discrete", "showTickMarks", "min", "color", "disableRipple", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "directive", type: i7.MatSliderThumb, selector: "input[matSliderThumb]", inputs: ["value"], outputs: ["valueChange", "dragStart", "dragEnd"], exportAs: ["matSliderThumb"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
595
895
  }
596
896
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FundoEditorComponent, decorators: [{
597
897
  type: Component,
598
898
  args: [{ selector: 'praxis-effects-fundo-editor', standalone: true, imports: [ReactiveFormsModule, MatFormFieldModule, MatInputModule, MatSliderModule], template: `
599
- <div class="fundo-grid" role="group" aria-label="Editor de fundo" [formGroup]="group">
899
+ <div class="fundo-grid" role="group" [attr.aria-label]="tx('background.group', 'Editor de fundo')" [formGroup]="group">
600
900
  <mat-form-field appearance="outline">
601
- <mat-label>Cor</mat-label>
901
+ <mat-label>{{ tx('background.color', 'Cor') }}</mat-label>
602
902
  <input matInput type="text" formControlName="color" placeholder="#122033" />
603
903
  </mat-form-field>
604
904
  <mat-form-field appearance="outline" class="full">
605
- <mat-label>Gradient CSS</mat-label>
905
+ <mat-label>{{ tx('background.gradient', 'Gradient CSS') }}</mat-label>
606
906
  <input matInput type="text" formControlName="gradient" placeholder="linear-gradient(180deg, #202637, #1c2230)" />
607
907
  </mat-form-field>
608
908
 
609
909
  <label class="slider">
610
- <span>Transparência</span>
910
+ <span>{{ tx('background.alpha', 'Transparencia') }}</span>
611
911
  <mat-slider min="0" max="100" step="5">
612
912
  <input matSliderThumb formControlName="alpha" />
613
913
  </mat-slider>
614
914
  </label>
615
915
  <label class="slider">
616
- <span>Desfoque (px)</span>
916
+ <span>{{ tx('background.blur', 'Desfoque (px)') }}</span>
617
917
  <mat-slider min="0" max="20" step="1">
618
918
  <input matSliderThumb formControlName="blur" />
619
919
  </mat-slider>
620
920
  </label>
621
921
  </div>
622
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".fundo-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:center}.full{grid-column:1 / -1}.slider{display:flex;flex-direction:column;gap:6px}\n"] }]
623
- }], propDecorators: { group: [{
922
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".fundo-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;align-items:center;min-width:0}.full{grid-column:1 / -1}mat-form-field,.slider{min-width:0}.slider{display:flex;flex-direction:column;gap:6px}.slider span{white-space:nowrap}mat-slider{width:100%;min-width:0}\n"] }]
923
+ }], ctorParameters: () => [{ type: i1.PraxisI18nService }], propDecorators: { group: [{
624
924
  type: Input
625
925
  }] } });
626
926
 
627
927
  class AnimacaoEditorComponent {
928
+ i18n;
628
929
  group;
629
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AnimacaoEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
930
+ constructor(i18n) {
931
+ this.i18n = i18n;
932
+ }
933
+ tx(key, fallback) {
934
+ return this.i18n.t(key, undefined, fallback, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE);
935
+ }
936
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AnimacaoEditorComponent, deps: [{ token: i1.PraxisI18nService }], target: i0.ɵɵFactoryTarget.Component });
630
937
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: AnimacaoEditorComponent, isStandalone: true, selector: "praxis-effects-animacao-editor", inputs: { group: "group" }, ngImport: i0, template: `
631
- <div class="anim-grid" role="group" aria-label="Editor de animação" [formGroup]="group">
938
+ <div class="anim-grid" role="group" [attr.aria-label]="tx('animation.group', 'Editor de animacao')" [formGroup]="group">
632
939
  <label class="anim-toggle">
633
940
  <input type="checkbox" formControlName="enabled" />
634
- <span>Ativar animação</span>
941
+ <span>{{ tx('animation.enabled', 'Ativar animacao') }}</span>
635
942
  </label>
636
943
  <mat-form-field appearance="outline">
637
- <mat-label>Preset</mat-label>
638
- <select matNativeControl formControlName="preset" aria-label="Preset de animação">
639
- <option value="">Sem preset</option>
944
+ <mat-label>{{ tx('animation.preset', 'Preset') }}</mat-label>
945
+ <select matNativeControl formControlName="preset" [attr.aria-label]="tx('animation.preset.aria', 'Preset de animacao')">
946
+ <option value="">{{ tx('animation.preset.none', 'Sem preset') }}</option>
640
947
  <option value="info-soft">Info Soft</option>
641
948
  <option value="success-confirm">Success Confirm</option>
642
949
  <option value="warning-attention">Warning Attention</option>
@@ -652,9 +959,9 @@ class AnimacaoEditorComponent {
652
959
  </select>
653
960
  </mat-form-field>
654
961
  <mat-form-field appearance="outline">
655
- <mat-label>Tipo</mat-label>
656
- <select matNativeControl formControlName="type" aria-label="Tipo de animação">
657
- <option value="">Padrão do preset</option>
962
+ <mat-label>{{ tx('animation.type', 'Tipo') }}</mat-label>
963
+ <select matNativeControl formControlName="type" [attr.aria-label]="tx('animation.type.aria', 'Tipo de animacao')">
964
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
658
965
  <option value="pulse">Pulse</option>
659
966
  <option value="blink">Blink</option>
660
967
  <option value="grow">Grow</option>
@@ -664,58 +971,58 @@ class AnimacaoEditorComponent {
664
971
  </select>
665
972
  </mat-form-field>
666
973
  <mat-form-field appearance="outline">
667
- <mat-label>Duração (ms)</mat-label>
668
- <input matInput type="number" formControlName="durationMs" placeholder="Preset/default" />
974
+ <mat-label>{{ tx('animation.duration', 'Duracao (ms)') }}</mat-label>
975
+ <input matInput type="number" formControlName="durationMs" [placeholder]="tx('animation.duration.placeholder', 'Preset/default')" />
669
976
  </mat-form-field>
670
977
  <mat-form-field appearance="outline">
671
- <mat-label>Delay (ms)</mat-label>
672
- <input matInput type="number" formControlName="delayMs" placeholder="Opcional" />
978
+ <mat-label>{{ tx('animation.delay', 'Delay (ms)') }}</mat-label>
979
+ <input matInput type="number" formControlName="delayMs" [placeholder]="tx('animation.delay.placeholder', 'Opcional')" />
673
980
  </mat-form-field>
674
981
  <mat-form-field appearance="outline">
675
- <mat-label>Disparo</mat-label>
676
- <select matNativeControl formControlName="trigger" aria-label="Disparo da animação">
677
- <option value="">Padrão do preset</option>
678
- <option value="onChange">Ao mudar</option>
679
- <option value="onAppear">Ao aparecer</option>
680
- <option value="onHover">Ao passar o mouse</option>
681
- <option value="onConditionEnter">Ao entrar na condição</option>
682
- <option value="onConditionExit">Ao sair da condição</option>
683
- <option value="onDataRefresh">Ao atualizar dados</option>
982
+ <mat-label>{{ tx('animation.trigger', 'Disparo') }}</mat-label>
983
+ <select matNativeControl formControlName="trigger" [attr.aria-label]="tx('animation.trigger.aria', 'Disparo da animacao')">
984
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
985
+ <option value="onChange">{{ tx('animation.trigger.onChange', 'Ao mudar') }}</option>
986
+ <option value="onAppear">{{ tx('animation.trigger.onAppear', 'Ao aparecer') }}</option>
987
+ <option value="onHover">{{ tx('animation.trigger.onHover', 'Ao passar o mouse') }}</option>
988
+ <option value="onConditionEnter">{{ tx('animation.trigger.onConditionEnter', 'Ao entrar na condicao') }}</option>
989
+ <option value="onConditionExit">{{ tx('animation.trigger.onConditionExit', 'Ao sair da condicao') }}</option>
990
+ <option value="onDataRefresh">{{ tx('animation.trigger.onDataRefresh', 'Ao atualizar dados') }}</option>
684
991
  </select>
685
992
  </mat-form-field>
686
993
  <mat-form-field appearance="outline">
687
- <mat-label>Repetição</mat-label>
688
- <select matNativeControl formControlName="repeat" aria-label="Repetição da animação">
689
- <option value="">Padrão do preset</option>
690
- <option value="once">Uma vez</option>
691
- <option value="loop">Loop</option>
692
- <option value="infinite">Infinito</option>
994
+ <mat-label>{{ tx('animation.repeat', 'Repeticao') }}</mat-label>
995
+ <select matNativeControl formControlName="repeat" [attr.aria-label]="tx('animation.repeat.aria', 'Repeticao da animacao')">
996
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
997
+ <option value="once">{{ tx('animation.repeat.once', 'Uma vez') }}</option>
998
+ <option value="loop">{{ tx('animation.repeat.loop', 'Loop') }}</option>
999
+ <option value="infinite">{{ tx('animation.repeat.infinite', 'Infinito') }}</option>
693
1000
  </select>
694
1001
  </mat-form-field>
695
1002
  <mat-form-field appearance="outline">
696
- <mat-label>Intensidade</mat-label>
697
- <select matNativeControl formControlName="intensity" aria-label="Intensidade da animação">
698
- <option value="">Padrão do preset</option>
699
- <option value="subtle">Sutil</option>
700
- <option value="normal">Normal</option>
701
- <option value="strong">Forte</option>
1003
+ <mat-label>{{ tx('animation.intensity', 'Intensidade') }}</mat-label>
1004
+ <select matNativeControl formControlName="intensity" [attr.aria-label]="tx('animation.intensity.aria', 'Intensidade da animacao')">
1005
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
1006
+ <option value="subtle">{{ tx('animation.intensity.subtle', 'Sutil') }}</option>
1007
+ <option value="normal">{{ tx('animation.intensity.normal', 'Normal') }}</option>
1008
+ <option value="strong">{{ tx('animation.intensity.strong', 'Forte') }}</option>
702
1009
  </select>
703
1010
  </mat-form-field>
704
1011
  </div>
705
- `, isInline: true, styles: [".anim-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:center}.anim-toggle{grid-column:1 / -1;display:inline-flex;align-items:center;gap:8px;color:inherit;font-size:.9rem}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.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.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { 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.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1012
+ `, isInline: true, styles: [".anim-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:center}.anim-toggle{grid-column:1 / -1;display:inline-flex;align-items:center;gap:8px;color:inherit;font-size:.9rem}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.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: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
706
1013
  }
707
1014
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AnimacaoEditorComponent, decorators: [{
708
1015
  type: Component,
709
1016
  args: [{ selector: 'praxis-effects-animacao-editor', standalone: true, imports: [ReactiveFormsModule, MatFormFieldModule, MatInputModule], template: `
710
- <div class="anim-grid" role="group" aria-label="Editor de animação" [formGroup]="group">
1017
+ <div class="anim-grid" role="group" [attr.aria-label]="tx('animation.group', 'Editor de animacao')" [formGroup]="group">
711
1018
  <label class="anim-toggle">
712
1019
  <input type="checkbox" formControlName="enabled" />
713
- <span>Ativar animação</span>
1020
+ <span>{{ tx('animation.enabled', 'Ativar animacao') }}</span>
714
1021
  </label>
715
1022
  <mat-form-field appearance="outline">
716
- <mat-label>Preset</mat-label>
717
- <select matNativeControl formControlName="preset" aria-label="Preset de animação">
718
- <option value="">Sem preset</option>
1023
+ <mat-label>{{ tx('animation.preset', 'Preset') }}</mat-label>
1024
+ <select matNativeControl formControlName="preset" [attr.aria-label]="tx('animation.preset.aria', 'Preset de animacao')">
1025
+ <option value="">{{ tx('animation.preset.none', 'Sem preset') }}</option>
719
1026
  <option value="info-soft">Info Soft</option>
720
1027
  <option value="success-confirm">Success Confirm</option>
721
1028
  <option value="warning-attention">Warning Attention</option>
@@ -731,9 +1038,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
731
1038
  </select>
732
1039
  </mat-form-field>
733
1040
  <mat-form-field appearance="outline">
734
- <mat-label>Tipo</mat-label>
735
- <select matNativeControl formControlName="type" aria-label="Tipo de animação">
736
- <option value="">Padrão do preset</option>
1041
+ <mat-label>{{ tx('animation.type', 'Tipo') }}</mat-label>
1042
+ <select matNativeControl formControlName="type" [attr.aria-label]="tx('animation.type.aria', 'Tipo de animacao')">
1043
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
737
1044
  <option value="pulse">Pulse</option>
738
1045
  <option value="blink">Blink</option>
739
1046
  <option value="grow">Grow</option>
@@ -743,106 +1050,113 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
743
1050
  </select>
744
1051
  </mat-form-field>
745
1052
  <mat-form-field appearance="outline">
746
- <mat-label>Duração (ms)</mat-label>
747
- <input matInput type="number" formControlName="durationMs" placeholder="Preset/default" />
1053
+ <mat-label>{{ tx('animation.duration', 'Duracao (ms)') }}</mat-label>
1054
+ <input matInput type="number" formControlName="durationMs" [placeholder]="tx('animation.duration.placeholder', 'Preset/default')" />
748
1055
  </mat-form-field>
749
1056
  <mat-form-field appearance="outline">
750
- <mat-label>Delay (ms)</mat-label>
751
- <input matInput type="number" formControlName="delayMs" placeholder="Opcional" />
1057
+ <mat-label>{{ tx('animation.delay', 'Delay (ms)') }}</mat-label>
1058
+ <input matInput type="number" formControlName="delayMs" [placeholder]="tx('animation.delay.placeholder', 'Opcional')" />
752
1059
  </mat-form-field>
753
1060
  <mat-form-field appearance="outline">
754
- <mat-label>Disparo</mat-label>
755
- <select matNativeControl formControlName="trigger" aria-label="Disparo da animação">
756
- <option value="">Padrão do preset</option>
757
- <option value="onChange">Ao mudar</option>
758
- <option value="onAppear">Ao aparecer</option>
759
- <option value="onHover">Ao passar o mouse</option>
760
- <option value="onConditionEnter">Ao entrar na condição</option>
761
- <option value="onConditionExit">Ao sair da condição</option>
762
- <option value="onDataRefresh">Ao atualizar dados</option>
1061
+ <mat-label>{{ tx('animation.trigger', 'Disparo') }}</mat-label>
1062
+ <select matNativeControl formControlName="trigger" [attr.aria-label]="tx('animation.trigger.aria', 'Disparo da animacao')">
1063
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
1064
+ <option value="onChange">{{ tx('animation.trigger.onChange', 'Ao mudar') }}</option>
1065
+ <option value="onAppear">{{ tx('animation.trigger.onAppear', 'Ao aparecer') }}</option>
1066
+ <option value="onHover">{{ tx('animation.trigger.onHover', 'Ao passar o mouse') }}</option>
1067
+ <option value="onConditionEnter">{{ tx('animation.trigger.onConditionEnter', 'Ao entrar na condicao') }}</option>
1068
+ <option value="onConditionExit">{{ tx('animation.trigger.onConditionExit', 'Ao sair da condicao') }}</option>
1069
+ <option value="onDataRefresh">{{ tx('animation.trigger.onDataRefresh', 'Ao atualizar dados') }}</option>
763
1070
  </select>
764
1071
  </mat-form-field>
765
1072
  <mat-form-field appearance="outline">
766
- <mat-label>Repetição</mat-label>
767
- <select matNativeControl formControlName="repeat" aria-label="Repetição da animação">
768
- <option value="">Padrão do preset</option>
769
- <option value="once">Uma vez</option>
770
- <option value="loop">Loop</option>
771
- <option value="infinite">Infinito</option>
1073
+ <mat-label>{{ tx('animation.repeat', 'Repeticao') }}</mat-label>
1074
+ <select matNativeControl formControlName="repeat" [attr.aria-label]="tx('animation.repeat.aria', 'Repeticao da animacao')">
1075
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
1076
+ <option value="once">{{ tx('animation.repeat.once', 'Uma vez') }}</option>
1077
+ <option value="loop">{{ tx('animation.repeat.loop', 'Loop') }}</option>
1078
+ <option value="infinite">{{ tx('animation.repeat.infinite', 'Infinito') }}</option>
772
1079
  </select>
773
1080
  </mat-form-field>
774
1081
  <mat-form-field appearance="outline">
775
- <mat-label>Intensidade</mat-label>
776
- <select matNativeControl formControlName="intensity" aria-label="Intensidade da animação">
777
- <option value="">Padrão do preset</option>
778
- <option value="subtle">Sutil</option>
779
- <option value="normal">Normal</option>
780
- <option value="strong">Forte</option>
1082
+ <mat-label>{{ tx('animation.intensity', 'Intensidade') }}</mat-label>
1083
+ <select matNativeControl formControlName="intensity" [attr.aria-label]="tx('animation.intensity.aria', 'Intensidade da animacao')">
1084
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
1085
+ <option value="subtle">{{ tx('animation.intensity.subtle', 'Sutil') }}</option>
1086
+ <option value="normal">{{ tx('animation.intensity.normal', 'Normal') }}</option>
1087
+ <option value="strong">{{ tx('animation.intensity.strong', 'Forte') }}</option>
781
1088
  </select>
782
1089
  </mat-form-field>
783
1090
  </div>
784
1091
  `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".anim-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:center}.anim-toggle{grid-column:1 / -1;display:inline-flex;align-items:center;gap:8px;color:inherit;font-size:.9rem}\n"] }]
785
- }], propDecorators: { group: [{
1092
+ }], ctorParameters: () => [{ type: i1.PraxisI18nService }], propDecorators: { group: [{
786
1093
  type: Input
787
1094
  }] } });
788
1095
 
789
1096
  class TooltipEditorComponent {
1097
+ i18n;
790
1098
  group;
791
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TooltipEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1099
+ constructor(i18n) {
1100
+ this.i18n = i18n;
1101
+ }
1102
+ tx(key, fallback) {
1103
+ return this.i18n.t(key, undefined, fallback, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE);
1104
+ }
1105
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TooltipEditorComponent, deps: [{ token: i1.PraxisI18nService }], target: i0.ɵɵFactoryTarget.Component });
792
1106
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: TooltipEditorComponent, isStandalone: true, selector: "praxis-effects-tooltip-editor", inputs: { group: "group" }, ngImport: i0, template: `
793
- <div class="tooltip-grid" role="group" aria-label="Editor de tooltip" [formGroup]="group">
1107
+ <div class="tooltip-grid" role="group" [attr.aria-label]="tx('tooltip.group', 'Editor de tooltip')" [formGroup]="group">
794
1108
  <mat-form-field appearance="outline" class="full">
795
- <mat-label>Texto</mat-label>
796
- <input matInput type="text" formControlName="text" placeholder="Detalhes da célula" />
1109
+ <mat-label>{{ tx('tooltip.text', 'Texto') }}</mat-label>
1110
+ <input matInput type="text" formControlName="text" [placeholder]="tx('tooltip.text.placeholder', 'Detalhes da celula')" />
797
1111
  </mat-form-field>
798
1112
  <mat-form-field appearance="outline">
799
- <mat-label>Posição</mat-label>
800
- <select matNativeControl formControlName="position" aria-label="Posição do tooltip">
801
- <option value="top">Topo</option>
802
- <option value="right">Direita</option>
803
- <option value="bottom">Baixo</option>
804
- <option value="left">Esquerda</option>
1113
+ <mat-label>{{ tx('tooltip.position', 'Posicao') }}</mat-label>
1114
+ <select matNativeControl formControlName="position" [attr.aria-label]="tx('tooltip.position.aria', 'Posicao do tooltip')">
1115
+ <option value="top">{{ tx('tooltip.position.top', 'Topo') }}</option>
1116
+ <option value="right">{{ tx('tooltip.position.right', 'Direita') }}</option>
1117
+ <option value="bottom">{{ tx('tooltip.position.bottom', 'Baixo') }}</option>
1118
+ <option value="left">{{ tx('tooltip.position.left', 'Esquerda') }}</option>
805
1119
  </select>
806
1120
  </mat-form-field>
807
1121
  <mat-form-field appearance="outline">
808
- <mat-label>Cor do fundo</mat-label>
1122
+ <mat-label>{{ tx('tooltip.backgroundColor', 'Cor do fundo') }}</mat-label>
809
1123
  <input matInput type="text" formControlName="bgColor" placeholder="#2E3142" />
810
1124
  </mat-form-field>
811
1125
  <mat-form-field appearance="outline">
812
- <mat-label>Delay (ms)</mat-label>
1126
+ <mat-label>{{ tx('tooltip.delay', 'Delay (ms)') }}</mat-label>
813
1127
  <input matInput type="number" formControlName="delayMs" placeholder="300" />
814
1128
  </mat-form-field>
815
1129
  </div>
816
- `, isInline: true, styles: [".tooltip-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:center}.full{grid-column:1 / -1}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.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.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { 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.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1130
+ `, isInline: true, styles: [".tooltip-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:center}.full{grid-column:1 / -1}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.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: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
817
1131
  }
818
1132
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TooltipEditorComponent, decorators: [{
819
1133
  type: Component,
820
1134
  args: [{ selector: 'praxis-effects-tooltip-editor', standalone: true, imports: [ReactiveFormsModule, MatFormFieldModule, MatInputModule], template: `
821
- <div class="tooltip-grid" role="group" aria-label="Editor de tooltip" [formGroup]="group">
1135
+ <div class="tooltip-grid" role="group" [attr.aria-label]="tx('tooltip.group', 'Editor de tooltip')" [formGroup]="group">
822
1136
  <mat-form-field appearance="outline" class="full">
823
- <mat-label>Texto</mat-label>
824
- <input matInput type="text" formControlName="text" placeholder="Detalhes da célula" />
1137
+ <mat-label>{{ tx('tooltip.text', 'Texto') }}</mat-label>
1138
+ <input matInput type="text" formControlName="text" [placeholder]="tx('tooltip.text.placeholder', 'Detalhes da celula')" />
825
1139
  </mat-form-field>
826
1140
  <mat-form-field appearance="outline">
827
- <mat-label>Posição</mat-label>
828
- <select matNativeControl formControlName="position" aria-label="Posição do tooltip">
829
- <option value="top">Topo</option>
830
- <option value="right">Direita</option>
831
- <option value="bottom">Baixo</option>
832
- <option value="left">Esquerda</option>
1141
+ <mat-label>{{ tx('tooltip.position', 'Posicao') }}</mat-label>
1142
+ <select matNativeControl formControlName="position" [attr.aria-label]="tx('tooltip.position.aria', 'Posicao do tooltip')">
1143
+ <option value="top">{{ tx('tooltip.position.top', 'Topo') }}</option>
1144
+ <option value="right">{{ tx('tooltip.position.right', 'Direita') }}</option>
1145
+ <option value="bottom">{{ tx('tooltip.position.bottom', 'Baixo') }}</option>
1146
+ <option value="left">{{ tx('tooltip.position.left', 'Esquerda') }}</option>
833
1147
  </select>
834
1148
  </mat-form-field>
835
1149
  <mat-form-field appearance="outline">
836
- <mat-label>Cor do fundo</mat-label>
1150
+ <mat-label>{{ tx('tooltip.backgroundColor', 'Cor do fundo') }}</mat-label>
837
1151
  <input matInput type="text" formControlName="bgColor" placeholder="#2E3142" />
838
1152
  </mat-form-field>
839
1153
  <mat-form-field appearance="outline">
840
- <mat-label>Delay (ms)</mat-label>
1154
+ <mat-label>{{ tx('tooltip.delay', 'Delay (ms)') }}</mat-label>
841
1155
  <input matInput type="number" formControlName="delayMs" placeholder="300" />
842
1156
  </mat-form-field>
843
1157
  </div>
844
1158
  `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".tooltip-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:center}.full{grid-column:1 / -1}\n"] }]
845
- }], propDecorators: { group: [{
1159
+ }], ctorParameters: () => [{ type: i1.PraxisI18nService }], propDecorators: { group: [{
846
1160
  type: Input
847
1161
  }] } });
848
1162
 
@@ -868,6 +1182,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
868
1182
  class RuleEffectsPanelComponent {
869
1183
  fb;
870
1184
  registry;
1185
+ i18n;
1186
+ static DEFAULT_ESTILO_FORM_VALUE = {
1187
+ color: '#ffffff',
1188
+ bgColor: '',
1189
+ bold: false,
1190
+ italic: false,
1191
+ underline: false,
1192
+ transform: null,
1193
+ opacity: 1,
1194
+ fontScale: 0,
1195
+ };
1196
+ static DEFAULT_LAYOUT_FORM_VALUE = {
1197
+ border: 'none',
1198
+ borderColor: '#487BFF',
1199
+ borderWidth: 2,
1200
+ padding: 6,
1201
+ align: 'start',
1202
+ elevation: 6,
1203
+ };
1204
+ static DEFAULT_ICON_BADGE_FORM_VALUE = {
1205
+ icon: 'check_circle',
1206
+ iconColor: '#35D07F',
1207
+ iconPos: 'before',
1208
+ badgeText: '',
1209
+ badgeStyle: 'soft',
1210
+ badgeColor: '#2a8455',
1211
+ };
1212
+ static DEFAULT_BACKGROUND_FORM_VALUE = {
1213
+ color: '#122033',
1214
+ gradient: '',
1215
+ alpha: 0,
1216
+ blur: 0,
1217
+ };
871
1218
  static DEFAULT_ANIMATION_FORM_VALUE = {
872
1219
  enabled: true,
873
1220
  preset: '',
@@ -878,25 +1225,27 @@ class RuleEffectsPanelComponent {
878
1225
  delayMs: null,
879
1226
  intensity: '',
880
1227
  };
881
- // i18n-friendly labels map
882
- labels = {
883
- 'panel.title': 'C. Efeitos',
884
- 'panel.subtitle': 'Configure estilos e elementos visuais quando a regra for verdadeira',
885
- 'tabs.estilo': 'Estilo',
886
- 'tabs.layout': 'Layout',
887
- 'tabs.icone': 'Ícone / Badge',
888
- 'tabs.fundo': 'Fundo',
889
- 'tabs.animacao': 'Animação',
890
- 'tabs.tooltip': 'Tooltip',
891
- 'preview.title': 'Pré-visualização',
892
- 'preview.hint': 'As mudanças acima refletem o estilo aplicado quando a condição é verdadeira.',
893
- 'advanced.title': 'Avançado',
894
- 'advanced.description': 'Descrição',
895
- 'actions.apply': 'Aplicar',
896
- 'actions.reset': 'Redefinir',
897
- 'presets.label': 'Presets',
1228
+ static DEFAULT_TOOLTIP_FORM_VALUE = {
1229
+ text: '',
1230
+ position: 'bottom',
1231
+ bgColor: '#2E3142',
1232
+ delayMs: 300,
898
1233
  };
899
- t(key) { return this.labels[key] ?? key; }
1234
+ _labelOverrides = {};
1235
+ // Host-specific overrides take precedence over the component i18n catalog.
1236
+ set labels(value) {
1237
+ this._labelOverrides = { ...(value ?? {}) };
1238
+ }
1239
+ get labels() {
1240
+ return PRAXIS_TABLE_RULE_BUILDER_LABEL_KEYS.reduce((acc, key) => {
1241
+ acc[key] = this.t(key);
1242
+ return acc;
1243
+ }, {});
1244
+ }
1245
+ t(key) {
1246
+ return this._labelOverrides[key]
1247
+ ?? this.i18n.t(key, undefined, key, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE);
1248
+ }
900
1249
  scope = 'row';
901
1250
  _value;
902
1251
  set value(v) {
@@ -913,9 +1262,23 @@ class RuleEffectsPanelComponent {
913
1262
  destroy$ = new Subject();
914
1263
  isHovering = false;
915
1264
  tabOrder = ['estilo', 'layout', 'icone', 'fundo', 'animacao', 'tooltip'];
916
- constructor(fb, registry) {
1265
+ get conditionalSurfacePreviewUnresolved() {
1266
+ if (!this.effectsForm)
1267
+ return false;
1268
+ const raw = this.effectsForm.getRawValue();
1269
+ const background = raw?.background ?? {};
1270
+ const color = this.nonEmptyString(background.color);
1271
+ return !!(this.nonEmptyString(background.gradient)
1272
+ || (this.toFiniteNumber(background.alpha) ?? 0) > 0
1273
+ || (this.toFiniteNumber(background.blur) ?? 0) > 0
1274
+ || (color && /(?:var|color-mix)\s*\(/i.test(color))
1275
+ || this.nonEmptyString(raw?.cssClass)
1276
+ || this.nonEmptyString(raw?.inlineStyle));
1277
+ }
1278
+ constructor(fb, registry, i18n) {
917
1279
  this.fb = fb;
918
1280
  this.registry = registry;
1281
+ this.i18n = i18n;
919
1282
  }
920
1283
  ngOnInit() {
921
1284
  // Register built-in editors for the registry (extensible)
@@ -928,36 +1291,36 @@ class RuleEffectsPanelComponent {
928
1291
  this.effectsForm = this.fb.group({
929
1292
  description: [''],
930
1293
  estilo: this.fb.group({
931
- color: ['#ffffff'],
932
- bgColor: [''],
933
- bold: [false],
934
- italic: [false],
935
- underline: [false],
936
- transform: [null],
937
- opacity: [1],
938
- fontScale: [0],
1294
+ color: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.color],
1295
+ bgColor: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.bgColor],
1296
+ bold: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.bold],
1297
+ italic: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.italic],
1298
+ underline: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.underline],
1299
+ transform: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.transform],
1300
+ opacity: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.opacity],
1301
+ fontScale: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.fontScale],
939
1302
  }),
940
1303
  layout: this.fb.group({
941
- border: ['none'],
942
- borderColor: ['#487BFF'],
943
- borderWidth: [2],
944
- padding: [6],
945
- align: ['start'],
946
- elevation: [6],
1304
+ border: [RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.border],
1305
+ borderColor: [RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.borderColor],
1306
+ borderWidth: [RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.borderWidth],
1307
+ padding: [RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.padding],
1308
+ align: [RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.align],
1309
+ elevation: [RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.elevation],
947
1310
  }),
948
1311
  iconBadge: this.fb.group({
949
- icon: ['check_circle'],
950
- iconColor: ['#35D07F'],
951
- iconPos: ['before'],
952
- badgeText: [''],
953
- badgeStyle: ['soft'],
954
- badgeColor: ['#2a8455'],
1312
+ icon: [RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.icon],
1313
+ iconColor: [RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.iconColor],
1314
+ iconPos: [RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.iconPos],
1315
+ badgeText: [RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.badgeText],
1316
+ badgeStyle: [RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.badgeStyle],
1317
+ badgeColor: [RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.badgeColor],
955
1318
  }),
956
1319
  background: this.fb.group({
957
- color: ['#122033'],
958
- gradient: [''],
959
- alpha: [0],
960
- blur: [0],
1320
+ color: [RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.color],
1321
+ gradient: [RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.gradient],
1322
+ alpha: [RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.alpha],
1323
+ blur: [RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.blur],
961
1324
  }),
962
1325
  animation: this.fb.group({
963
1326
  enabled: [RuleEffectsPanelComponent.DEFAULT_ANIMATION_FORM_VALUE.enabled],
@@ -970,10 +1333,10 @@ class RuleEffectsPanelComponent {
970
1333
  intensity: [RuleEffectsPanelComponent.DEFAULT_ANIMATION_FORM_VALUE.intensity],
971
1334
  }),
972
1335
  tooltip: this.fb.group({
973
- text: [''],
974
- position: ['bottom'],
975
- bgColor: ['#2E3142'],
976
- delayMs: [300],
1336
+ text: [RuleEffectsPanelComponent.DEFAULT_TOOLTIP_FORM_VALUE.text],
1337
+ position: [RuleEffectsPanelComponent.DEFAULT_TOOLTIP_FORM_VALUE.position],
1338
+ bgColor: [RuleEffectsPanelComponent.DEFAULT_TOOLTIP_FORM_VALUE.bgColor],
1339
+ delayMs: [RuleEffectsPanelComponent.DEFAULT_TOOLTIP_FORM_VALUE.delayMs],
977
1340
  }),
978
1341
  cssClass: [''],
979
1342
  inlineStyle: [''],
@@ -987,10 +1350,7 @@ class RuleEffectsPanelComponent {
987
1350
  this.patchForm(this._value);
988
1351
  }
989
1352
  patchForm(v) {
990
- const animationGroup = this.effectsForm.get('animation');
991
- if (animationGroup) {
992
- animationGroup.reset(RuleEffectsPanelComponent.DEFAULT_ANIMATION_FORM_VALUE, { emitEvent: false });
993
- }
1353
+ this.effectsForm.reset(this.createDefaultFormValue(), { emitEvent: false });
994
1354
  this.effectsForm.patchValue(v, { emitEvent: false });
995
1355
  }
996
1356
  setTab(tab) {
@@ -1008,7 +1368,7 @@ class RuleEffectsPanelComponent {
1008
1368
  this.apply.emit();
1009
1369
  }
1010
1370
  onReset() {
1011
- this.effectsForm.reset();
1371
+ this.effectsForm.reset(this.createDefaultFormValue());
1012
1372
  this.reset.emit();
1013
1373
  }
1014
1374
  ngOnDestroy() {
@@ -1063,9 +1423,17 @@ class RuleEffectsPanelComponent {
1063
1423
  computeCellStyle(v) {
1064
1424
  const b = v?.background || {};
1065
1425
  const ly = v?.layout || {};
1066
- const bg = b.gradient ? b.gradient : (b.color || 'transparent');
1426
+ const estilo = v?.estilo || {};
1427
+ const backgroundColor = this.nonEmptyString(b.color);
1428
+ const gradient = this.nonEmptyString(b.gradient);
1429
+ const textBackgroundColor = this.nonEmptyString(estilo.bgColor);
1430
+ const hasDeliberateBackgroundColor = backgroundColor
1431
+ && backgroundColor !== RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.color;
1432
+ const bg = gradient || (hasDeliberateBackgroundColor ? backgroundColor : textBackgroundColor) || 'transparent';
1067
1433
  const alpha = (b.alpha ?? 0) / 100;
1068
- const bgWithAlpha = b.color ? `color-mix(in srgb, ${b.color} ${100 - alpha * 100}%, transparent)` : bg;
1434
+ const bgWithAlpha = hasDeliberateBackgroundColor
1435
+ ? `color-mix(in srgb, ${backgroundColor} ${100 - alpha * 100}%, transparent)`
1436
+ : bg;
1069
1437
  const borderColor = ly.borderColor || 'transparent';
1070
1438
  const borderWidth = (ly.borderWidth ?? 0) + 'px';
1071
1439
  const borderStyle = ly.border === 'none' ? 'none' : `${borderWidth} solid ${borderColor}`;
@@ -1157,16 +1525,156 @@ class RuleEffectsPanelComponent {
1157
1525
  return s?.badgeStyle === 'outline' ? s.badgeColor || '#777' : '#0000';
1158
1526
  }
1159
1527
  toEffectDefinitionForEmit(formValue) {
1160
- const value = { scope: this.scope, ...(formValue || {}) };
1528
+ const value = { scope: this.scope };
1529
+ const raw = formValue || {};
1530
+ const description = this.nonEmptyString(raw.description);
1531
+ if (description)
1532
+ value.description = description;
1533
+ const estilo = raw.estilo || {};
1534
+ const normalizedEstilo = {};
1535
+ const color = this.nonEmptyString(estilo.color);
1536
+ const bgColor = this.nonEmptyString(estilo.bgColor);
1537
+ const transform = this.nonEmptyString(estilo.transform);
1538
+ if (color && color !== RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.color)
1539
+ normalizedEstilo.color = color;
1540
+ if (bgColor)
1541
+ normalizedEstilo.bgColor = bgColor;
1542
+ if (estilo.bold === true)
1543
+ normalizedEstilo.bold = true;
1544
+ if (estilo.italic === true)
1545
+ normalizedEstilo.italic = true;
1546
+ if (estilo.underline === true)
1547
+ normalizedEstilo.underline = true;
1548
+ if (transform)
1549
+ normalizedEstilo.transform = transform;
1550
+ const opacity = this.toFiniteNumber(estilo.opacity);
1551
+ if (opacity !== undefined && opacity !== 1)
1552
+ normalizedEstilo.opacity = opacity;
1553
+ const fontScale = this.toFiniteNumber(estilo.fontScale);
1554
+ if (fontScale !== undefined && fontScale !== 0)
1555
+ normalizedEstilo.fontScale = fontScale;
1556
+ if (Object.keys(normalizedEstilo).length)
1557
+ value.estilo = normalizedEstilo;
1558
+ const layout = raw.layout || {};
1559
+ const normalizedLayout = {};
1560
+ const border = this.nonEmptyString(layout.border);
1561
+ const borderColor = this.nonEmptyString(layout.borderColor);
1562
+ const align = this.nonEmptyString(layout.align);
1563
+ if (border && border !== RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.border) {
1564
+ normalizedLayout.border = border;
1565
+ if (borderColor)
1566
+ normalizedLayout.borderColor = borderColor;
1567
+ const borderWidth = this.toFiniteNumber(layout.borderWidth);
1568
+ if (borderWidth !== undefined)
1569
+ normalizedLayout.borderWidth = borderWidth;
1570
+ }
1571
+ const padding = this.toFiniteNumber(layout.padding);
1572
+ if (padding !== undefined && padding !== RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.padding)
1573
+ normalizedLayout.padding = padding;
1574
+ if (align && align !== RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.align)
1575
+ normalizedLayout.align = align;
1576
+ const elevation = this.toFiniteNumber(layout.elevation);
1577
+ if (elevation !== undefined && elevation !== RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.elevation)
1578
+ normalizedLayout.elevation = elevation;
1579
+ if (Object.keys(normalizedLayout).length)
1580
+ value.layout = normalizedLayout;
1581
+ const iconBadge = raw.iconBadge || {};
1582
+ const normalizedIconBadge = {};
1583
+ const icon = this.nonEmptyString(iconBadge.icon);
1584
+ const badgeText = this.nonEmptyString(iconBadge.badgeText);
1585
+ const iconChanged = icon && icon !== RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.icon;
1586
+ const iconColor = this.nonEmptyString(iconBadge.iconColor);
1587
+ const iconColorChanged = iconColor && iconColor !== RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.iconColor;
1588
+ const iconPos = this.nonEmptyString(iconBadge.iconPos);
1589
+ const iconPosChanged = iconPos && iconPos !== RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.iconPos;
1590
+ if (iconChanged || iconColorChanged || iconPosChanged) {
1591
+ normalizedIconBadge.icon = icon || RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.icon;
1592
+ if (iconColor)
1593
+ normalizedIconBadge.iconColor = iconColor;
1594
+ if (iconPos)
1595
+ normalizedIconBadge.iconPos = iconPos;
1596
+ }
1597
+ if (badgeText) {
1598
+ normalizedIconBadge.badgeText = badgeText;
1599
+ const badgeStyle = this.nonEmptyString(iconBadge.badgeStyle);
1600
+ const badgeColor = this.nonEmptyString(iconBadge.badgeColor);
1601
+ if (badgeStyle && badgeStyle !== RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.badgeStyle)
1602
+ normalizedIconBadge.badgeStyle = badgeStyle;
1603
+ if (badgeColor && badgeColor !== RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.badgeColor)
1604
+ normalizedIconBadge.badgeColor = badgeColor;
1605
+ }
1606
+ if (Object.keys(normalizedIconBadge).length)
1607
+ value.iconBadge = normalizedIconBadge;
1608
+ const background = raw.background || {};
1609
+ const normalizedBackground = {};
1610
+ const backgroundColor = this.nonEmptyString(background.color);
1611
+ const gradient = this.nonEmptyString(background.gradient);
1612
+ if (gradient)
1613
+ normalizedBackground.gradient = gradient;
1614
+ const alpha = this.toFiniteNumber(background.alpha);
1615
+ const blur = this.toFiniteNumber(background.blur);
1616
+ const hasBackgroundAdjustment = (alpha !== undefined && alpha !== RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.alpha)
1617
+ || (blur !== undefined && blur !== RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.blur);
1618
+ if (backgroundColor && (backgroundColor !== RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.color || hasBackgroundAdjustment)) {
1619
+ normalizedBackground.color = backgroundColor;
1620
+ }
1621
+ if (alpha !== undefined && alpha !== RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.alpha && (normalizedBackground.color || normalizedBackground.gradient))
1622
+ normalizedBackground.alpha = alpha;
1623
+ if (blur !== undefined && blur !== RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.blur && (normalizedBackground.color || normalizedBackground.gradient))
1624
+ normalizedBackground.blur = blur;
1625
+ if (Object.keys(normalizedBackground).length)
1626
+ value.background = normalizedBackground;
1627
+ const tooltip = raw.tooltip || {};
1628
+ const tooltipText = this.nonEmptyString(tooltip.text);
1629
+ if (tooltipText) {
1630
+ const normalizedTooltip = { text: tooltipText };
1631
+ const position = this.nonEmptyString(tooltip.position);
1632
+ const bgColor = this.nonEmptyString(tooltip.bgColor);
1633
+ const delayMs = this.toNonNegativeMs(tooltip.delayMs);
1634
+ if (position)
1635
+ normalizedTooltip.position = position;
1636
+ if (bgColor)
1637
+ normalizedTooltip.bgColor = bgColor;
1638
+ if (delayMs !== undefined)
1639
+ normalizedTooltip.delayMs = delayMs;
1640
+ value.tooltip = normalizedTooltip;
1641
+ }
1642
+ const cssClass = this.nonEmptyString(raw.cssClass);
1643
+ const inlineStyle = this.nonEmptyString(raw.inlineStyle);
1644
+ if (cssClass)
1645
+ value.cssClass = cssClass;
1646
+ if (inlineStyle)
1647
+ value.inlineStyle = inlineStyle;
1161
1648
  const normalizedAnimation = this.normalizeAnimationForEmit((formValue || {}).animation);
1162
1649
  if (normalizedAnimation) {
1163
1650
  value.animation = normalizedAnimation;
1164
1651
  }
1165
- else {
1166
- delete value.animation;
1167
- }
1168
1652
  return value;
1169
1653
  }
1654
+ nonEmptyString(value) {
1655
+ return typeof value === 'string' ? value.trim() : '';
1656
+ }
1657
+ toFiniteNumber(value) {
1658
+ if (value === null || value === undefined)
1659
+ return undefined;
1660
+ if (typeof value === 'string' && !value.trim())
1661
+ return undefined;
1662
+ const parsed = Number(value);
1663
+ return Number.isFinite(parsed) ? parsed : undefined;
1664
+ }
1665
+ createDefaultFormValue() {
1666
+ return {
1667
+ description: '',
1668
+ estilo: { ...RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE },
1669
+ layout: { ...RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE },
1670
+ iconBadge: { ...RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE },
1671
+ background: { ...RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE },
1672
+ animation: { ...RuleEffectsPanelComponent.DEFAULT_ANIMATION_FORM_VALUE },
1673
+ tooltip: { ...RuleEffectsPanelComponent.DEFAULT_TOOLTIP_FORM_VALUE },
1674
+ cssClass: '',
1675
+ inlineStyle: '',
1676
+ };
1677
+ }
1170
1678
  normalizeAnimationForEmit(animation) {
1171
1679
  if (!animation)
1172
1680
  return undefined;
@@ -1208,8 +1716,8 @@ class RuleEffectsPanelComponent {
1208
1716
  const parsed = Number(value);
1209
1717
  return Number.isFinite(parsed) && parsed >= 0 ? Math.round(parsed) : undefined;
1210
1718
  }
1211
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: RuleEffectsPanelComponent, deps: [{ token: i1.FormBuilder }, { token: EffectRegistryService }], target: i0.ɵɵFactoryTarget.Component });
1212
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: RuleEffectsPanelComponent, isStandalone: true, selector: "praxis-rule-effects-panel", inputs: { scope: "scope", value: "value" }, outputs: { valueChange: "valueChange", apply: "apply", reset: "reset" }, ngImport: i0, template: "<div class=\"rulefx\">\n <header class=\"rulefx__header\">\n <h3 class=\"rulefx__title\">{{ t('panel.title') }}</h3>\n <p class=\"rulefx__subtitle\">{{ t('panel.subtitle') }}</p>\n <div class=\"rulefx__actions\">\n <button mat-stroked-button type=\"button\" [matMenuTriggerFor]=\"presetsMenu\" [attr.aria-label]=\"t('presets.label')\" (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\n <mat-icon>bookmarks</mat-icon>\n {{ t('presets.label') }}\n </button>\n <mat-menu #presetsMenu=\"matMenu\">\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('aprovado')\"><mat-icon>check_circle</mat-icon> Aprovado</button>\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('alerta')\"><mat-icon>warning</mat-icon> Alerta</button>\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('erro')\"><mat-icon>error</mat-icon> Erro</button>\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('info')\"><mat-icon>info</mat-icon> Info</button>\n </mat-menu>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"$event.stopPropagation(); onApply()\" (mousedown)=\"$event.stopPropagation()\" [attr.aria-label]=\"t('actions.apply')\" [matTooltip]=\"t('actions.apply')\" matTooltipPosition=\"below\">\n <mat-icon>done</mat-icon>\n {{ t('actions.apply') }}\n </button>\n <button mat-stroked-button type=\"button\" (click)=\"$event.stopPropagation(); onReset()\" (mousedown)=\"$event.stopPropagation()\" [attr.aria-label]=\"t('actions.reset')\" [matTooltip]=\"t('actions.reset')\" matTooltipPosition=\"below\">\n <mat-icon>restart_alt</mat-icon>\n {{ t('actions.reset') }}\n </button>\n </div>\n </header>\n\n <!-- Ribbon com seis categorias -->\n <nav\n class=\"rulefx__ribbon\"\n aria-label=\"Categorias de efeitos\"\n role=\"tablist\"\n (keydown)=\"onTabsKeydown($event)\"\n >\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'estilo'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'estilo'\"\n [attr.tabindex]=\"activeTab === 'estilo' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('estilo')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.estilo')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">text_format</span>\n <span>{{ t('tabs.estilo') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'layout'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'layout'\"\n [attr.tabindex]=\"activeTab === 'layout' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('layout')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.layout')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">view_quilt</span>\n <span>{{ t('tabs.layout') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'icone'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'icone'\"\n [attr.tabindex]=\"activeTab === 'icone' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('icone')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.icone')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">verified</span>\n <span>{{ t('tabs.icone') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'fundo'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'fundo'\"\n [attr.tabindex]=\"activeTab === 'fundo' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('fundo')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.fundo')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">gradient</span>\n <span>{{ t('tabs.fundo') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'animacao'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'animacao'\"\n [attr.tabindex]=\"activeTab === 'animacao' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('animacao')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.animacao')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">animation</span>\n <span>{{ t('tabs.animacao') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'tooltip'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'tooltip'\"\n [attr.tabindex]=\"activeTab === 'tooltip' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('tooltip')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.tooltip')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">info</span>\n <span>{{ t('tabs.tooltip') }}</span>\n </button>\n </nav>\n\n <!-- Quickbar contextual -->\n @if (effectsForm) {\n <section class=\"rulefx__quickbar\" aria-live=\"polite\">\n @switch (activeTab) {\n @case ('estilo') {\n <praxis-effects-estilo-editor [group]=\"estiloGroup\"></praxis-effects-estilo-editor>\n }\n @case ('layout') {\n <praxis-effects-layout-editor [group]=\"layoutGroup\"></praxis-effects-layout-editor>\n }\n @case ('icone') {\n <praxis-effects-icone-badge-editor [group]=\"iconBadgeGroup\"></praxis-effects-icone-badge-editor>\n }\n @case ('fundo') {\n <praxis-effects-fundo-editor [group]=\"backgroundGroup\"></praxis-effects-fundo-editor>\n }\n @case ('animacao') {\n <praxis-effects-animacao-editor [group]=\"animationGroup\"></praxis-effects-animacao-editor>\n }\n @case ('tooltip') {\n <praxis-effects-tooltip-editor [group]=\"tooltipGroup\"></praxis-effects-tooltip-editor>\n }\n }\n </section>\n }\n\n <!-- Pr\u00E9-visualiza\u00E7\u00E3o e se\u00E7\u00E3o avan\u00E7ada -->\n <section class=\"rulefx__body\">\n <div class=\"rulefx__preview\">\n <div class=\"preview__title\">{{ t('preview.title') }}</div>\n\n <div\n class=\"preview__cell\"\n [ngStyle]=\"computeCellStyle(formValue)\"\n [ngClass]=\"computeCellClass(formValue)\"\n (mouseenter)=\"onHoverPreview(true)\"\n (mouseleave)=\"onHoverPreview(false)\"\n >\n @if (formValue.iconBadge?.icon && formValue.iconBadge?.iconPos === 'before') {\n <span\n class=\"material-icons preview__icon\"\n [style.color]=\"formValue.iconBadge?.iconColor\"\n >\n {{ formValue.iconBadge?.icon }}\n </span>\n }\n\n <span class=\"preview__text\" [ngStyle]=\"computeTextStyle(formValue)\">\n Joana Silva \u2014 Ativo desde 2019\n </span>\n\n @if (formValue.iconBadge?.badgeText) {\n <span\n class=\"preview__badge\"\n [ngStyle]=\"{ 'background': badgeBackground(formValue), 'border-color': badgeBorder(formValue) }\"\n >\n {{ formValue.iconBadge?.badgeText }}\n </span>\n }\n\n @if (formValue.iconBadge?.icon && formValue.iconBadge?.iconPos === 'after') {\n <span\n class=\"material-icons preview__icon\"\n [style.color]=\"formValue.iconBadge?.iconColor\"\n >\n {{ formValue.iconBadge?.icon }}\n </span>\n }\n </div>\n\n <p class=\"preview__hint\">{{ t('preview.hint') }}</p>\n </div>\n\n <div class=\"rulefx__advanced\">\n <details class=\"advanced__section\">\n <summary (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">{{ t('advanced.title') }}</summary>\n <div class=\"advanced__grid\" [formGroup]=\"effectsForm\">\n <label class=\"textctl\">\n <span>{{ t('advanced.description') }}</span>\n <input type=\"text\" formControlName=\"description\" placeholder=\"ex.: Destacar pre\u00E7os altos\" />\n </label>\n <label class=\"textctl\">\n <span>Classe CSS</span>\n <input type=\"text\" formControlName=\"cssClass\" placeholder=\"ex.: praxis-cell--alert\" />\n </label>\n <label class=\"textctl\">\n <span>Estilo inline</span>\n <input type=\"text\" formControlName=\"inlineStyle\" placeholder=\"ex.: text-shadow: 0 0 8px rgba(0,255,163,.5)\" />\n </label>\n </div>\n </details>\n </div>\n </section>\n</div>\n", styles: [".rulefx{background:linear-gradient(180deg,#171b24,#1e2431);border-radius:14px;color:#e7ecf6;border:1px solid rgba(255,255,255,.08);box-shadow:0 6px 24px #00000047;padding:12px}.rulefx__header{display:grid;grid-template-columns:1fr auto;align-items:center;gap:8px;margin-bottom:8px}.rulefx__title{margin:0;font-size:1.05rem}.rulefx__subtitle{margin:0;opacity:.75;font-size:.9rem}.rulefx__actions{display:inline-flex;gap:8px;align-items:center}.rulefx__ribbon{display:flex;gap:6px;padding:8px;border-radius:10px;background:linear-gradient(180deg,#202636,#1c2230);margin-bottom:8px}.ribbon__tab{display:flex;align-items:center;gap:8px;padding:8px 10px;border-radius:10px;background:transparent;color:#e7ecf6;cursor:pointer;border:none}.ribbon__tab.is-active{background:linear-gradient(180deg,#2a3550,#243149);box-shadow:inset 0 0 0 1px #ffffff0a}.rulefx__quickbar{border:1px solid rgba(255,255,255,.08);border-radius:12px;padding:10px;background:linear-gradient(180deg,#202637,#1c2230);margin-bottom:10px}.rulefx__body{display:grid;grid-template-columns:1fr 320px;gap:12px}.rulefx__preview{border:1px solid rgba(255,255,255,.08);border-radius:12px;padding:12px;background:linear-gradient(180deg,#202637,#1c2230)}.preview__title{font-weight:600;margin-bottom:8px}.preview__cell{display:inline-flex;align-items:center;gap:8px;padding:10px 12px;border-radius:12px;background:#35d07f14;border:1px solid rgba(53,208,127,.25)}.preview__icon{font-size:18px;line-height:1}.preview__badge{font-size:.75rem;border-radius:999px;padding:2px 8px;border:1px solid transparent}.preview__hint{opacity:.7;font-size:.85rem;margin:8px 0 0}.rulefx__advanced .advanced__grid{display:grid;grid-template-columns:1fr;gap:8px}.rulefx__advanced .textctl{display:grid;gap:6px}.rulefx__advanced input[type=text]{background:#151a24;color:#e7ecf6;border:1px solid rgba(255,255,255,.08);border-radius:8px;padding:8px 10px}.anim--once{animation-iteration-count:1}.anim--loop{animation-iteration-count:infinite}.anim--count{animation-iteration-count:3}.anim--subtle{--pfx-preview-scale-peak: 1.01;--pfx-preview-min-opacity: .7;--pfx-preview-slide-distance: 2px;--pfx-preview-border-strength: .18}.anim--normal{--pfx-preview-scale-peak: 1.03;--pfx-preview-min-opacity: .45;--pfx-preview-slide-distance: 6px;--pfx-preview-border-strength: .3}.anim--strong{--pfx-preview-scale-peak: 1.05;--pfx-preview-min-opacity: .25;--pfx-preview-slide-distance: 8px;--pfx-preview-border-strength: .42}.anim--pulse{animation-name:pfxPulse;animation-duration:.8s;animation-timing-function:ease-in-out}.anim--blink{animation-name:pfxBlink;animation-duration:.7s}.anim--grow{animation-name:pfxGrow;animation-duration:.4s}.anim--fade{animation-name:pfxFade;animation-duration:.6s}.anim--slide-in{animation-name:pfxSlideIn;animation-duration:.3s}.anim--border-pulse{animation-name:pfxBorderPulse;animation-duration:.9s}@keyframes pfxPulse{0%{transform:scale(1)}50%{transform:scale(var(--pfx-preview-scale-peak, 1.03))}to{transform:scale(1)}}@keyframes pfxBlink{0%,49%{opacity:1}50%,to{opacity:var(--pfx-preview-min-opacity, .25)}}@keyframes pfxGrow{0%{transform:scale(.96)}to{transform:scale(1)}}@keyframes pfxFade{0%{opacity:0}to{opacity:1}}@keyframes pfxSlideIn{0%{transform:translateY(var(--pfx-preview-slide-distance, 6px));opacity:0}to{transform:translateY(0);opacity:1}}@keyframes pfxBorderPulse{0%,to{box-shadow:inset 0 0 #d32f2f00}50%{box-shadow:inset 0 0 0 2px rgba(211,47,47,var(--pfx-preview-border-strength, .3))}}.icon--overlay{position:relative}.icon--overlay .preview__icon{position:absolute;left:6px;top:6px}@media(prefers-reduced-motion:reduce){.preview__cell{animation:none!important;transition:none!important}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4$1.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: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i6$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "component", type: EstiloEditorComponent, selector: "praxis-effects-estilo-editor", inputs: ["group"] }, { kind: "component", type: LayoutEditorComponent, selector: "praxis-effects-layout-editor", inputs: ["group"] }, { kind: "component", type: IconeBadgeEditorComponent, selector: "praxis-effects-icone-badge-editor", inputs: ["group"] }, { kind: "component", type: FundoEditorComponent, selector: "praxis-effects-fundo-editor", inputs: ["group"] }, { kind: "component", type: AnimacaoEditorComponent, selector: "praxis-effects-animacao-editor", inputs: ["group"] }, { kind: "component", type: TooltipEditorComponent, selector: "praxis-effects-tooltip-editor", inputs: ["group"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1719
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: RuleEffectsPanelComponent, deps: [{ token: i2.FormBuilder }, { token: EffectRegistryService }, { token: i1.PraxisI18nService }], target: i0.ɵɵFactoryTarget.Component });
1720
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: RuleEffectsPanelComponent, isStandalone: true, selector: "praxis-rule-effects-panel", inputs: { labels: "labels", scope: "scope", value: "value" }, outputs: { valueChange: "valueChange", apply: "apply", reset: "reset" }, providers: [providePraxisI18nConfig(PRAXIS_TABLE_RULE_BUILDER_I18N_CONFIG)], ngImport: i0, template: "<div class=\"rulefx\">\n <header class=\"rulefx__header\">\n <h3 class=\"rulefx__title\">{{ t('panel.title') }}</h3>\n <p class=\"rulefx__subtitle\">{{ t('panel.subtitle') }}</p>\n <div class=\"rulefx__actions\">\n <button mat-stroked-button type=\"button\" [matMenuTriggerFor]=\"presetsMenu\" [attr.aria-label]=\"t('presets.label')\" (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\n <mat-icon>bookmarks</mat-icon>\n {{ t('presets.label') }}\n </button>\n <mat-menu #presetsMenu=\"matMenu\">\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('aprovado')\"><mat-icon>check_circle</mat-icon> {{ t('presets.aprovado') }}</button>\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('alerta')\"><mat-icon>warning</mat-icon> {{ t('presets.alerta') }}</button>\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('erro')\"><mat-icon>error</mat-icon> {{ t('presets.erro') }}</button>\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('info')\"><mat-icon>info</mat-icon> {{ t('presets.info') }}</button>\n </mat-menu>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"$event.stopPropagation(); onApply()\" (mousedown)=\"$event.stopPropagation()\" [attr.aria-label]=\"t('actions.apply')\" [matTooltip]=\"t('actions.apply')\" matTooltipPosition=\"below\">\n <mat-icon>done</mat-icon>\n {{ t('actions.apply') }}\n </button>\n <button mat-stroked-button type=\"button\" (click)=\"$event.stopPropagation(); onReset()\" (mousedown)=\"$event.stopPropagation()\" [attr.aria-label]=\"t('actions.reset')\" [matTooltip]=\"t('actions.reset')\" matTooltipPosition=\"below\">\n <mat-icon>restart_alt</mat-icon>\n {{ t('actions.reset') }}\n </button>\n </div>\n </header>\n\n <!-- Ribbon com seis categorias -->\n <nav\n class=\"rulefx__ribbon\"\n [attr.aria-label]=\"t('tabs.ariaLabel')\"\n role=\"tablist\"\n (keydown)=\"onTabsKeydown($event)\"\n >\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'estilo'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'estilo'\"\n [attr.tabindex]=\"activeTab === 'estilo' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('estilo')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.estilo')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">text_format</span>\n <span>{{ t('tabs.estilo') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'layout'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'layout'\"\n [attr.tabindex]=\"activeTab === 'layout' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('layout')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.layout')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">view_quilt</span>\n <span>{{ t('tabs.layout') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'icone'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'icone'\"\n [attr.tabindex]=\"activeTab === 'icone' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('icone')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.icone')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">verified</span>\n <span>{{ t('tabs.icone') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'fundo'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'fundo'\"\n [attr.tabindex]=\"activeTab === 'fundo' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('fundo')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.fundo')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">gradient</span>\n <span>{{ t('tabs.fundo') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'animacao'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'animacao'\"\n [attr.tabindex]=\"activeTab === 'animacao' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('animacao')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.animacao')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">animation</span>\n <span>{{ t('tabs.animacao') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'tooltip'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'tooltip'\"\n [attr.tabindex]=\"activeTab === 'tooltip' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('tooltip')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.tooltip')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">info</span>\n <span>{{ t('tabs.tooltip') }}</span>\n </button>\n </nav>\n\n <!-- Quickbar contextual -->\n @if (effectsForm) {\n <section class=\"rulefx__quickbar\" aria-live=\"polite\">\n @switch (activeTab) {\n @case ('estilo') {\n <praxis-effects-estilo-editor [group]=\"estiloGroup\"></praxis-effects-estilo-editor>\n }\n @case ('layout') {\n <praxis-effects-layout-editor [group]=\"layoutGroup\"></praxis-effects-layout-editor>\n }\n @case ('icone') {\n <praxis-effects-icone-badge-editor [group]=\"iconBadgeGroup\"></praxis-effects-icone-badge-editor>\n }\n @case ('fundo') {\n <praxis-effects-fundo-editor [group]=\"backgroundGroup\"></praxis-effects-fundo-editor>\n }\n @case ('animacao') {\n <praxis-effects-animacao-editor [group]=\"animationGroup\"></praxis-effects-animacao-editor>\n }\n @case ('tooltip') {\n <praxis-effects-tooltip-editor [group]=\"tooltipGroup\"></praxis-effects-tooltip-editor>\n }\n }\n </section>\n }\n\n <!-- Pr\u00E9-visualiza\u00E7\u00E3o e se\u00E7\u00E3o avan\u00E7ada -->\n <section class=\"rulefx__body\">\n <div class=\"rulefx__preview\">\n <div class=\"preview__title\">{{ t('preview.title') }}</div>\n\n <div\n class=\"preview__cell\"\n [ngStyle]=\"computeCellStyle(formValue)\"\n [ngClass]=\"computeCellClass(formValue)\"\n (mouseenter)=\"onHoverPreview(true)\"\n (mouseleave)=\"onHoverPreview(false)\"\n >\n @if (formValue.iconBadge?.icon && formValue.iconBadge?.iconPos === 'before') {\n <span\n class=\"material-icons preview__icon\"\n [style.color]=\"formValue.iconBadge?.iconColor\"\n >\n {{ formValue.iconBadge?.icon }}\n </span>\n }\n\n <span class=\"preview__text\" [ngStyle]=\"computeTextStyle(formValue)\">\n {{ t('preview.sampleText') }}\n </span>\n\n @if (formValue.iconBadge?.badgeText) {\n <span\n class=\"preview__badge\"\n [ngStyle]=\"{ 'background': badgeBackground(formValue), 'border-color': badgeBorder(formValue) }\"\n >\n {{ formValue.iconBadge?.badgeText }}\n </span>\n }\n\n @if (formValue.iconBadge?.icon && formValue.iconBadge?.iconPos === 'after') {\n <span\n class=\"material-icons preview__icon\"\n [style.color]=\"formValue.iconBadge?.iconColor\"\n >\n {{ formValue.iconBadge?.icon }}\n </span>\n }\n </div>\n\n <p class=\"preview__hint\">{{ t('preview.hint') }}</p>\n @if (conditionalSurfacePreviewUnresolved) {\n <p class=\"preview__diagnostic\" role=\"status\">\n <mat-icon aria-hidden=\"true\">warning_amber</mat-icon>\n <span>{{ t('preview.contrastUnresolved') }}</span>\n </p>\n }\n </div>\n\n <div class=\"rulefx__advanced\">\n <details class=\"advanced__section\">\n <summary (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">{{ t('advanced.title') }}</summary>\n <div class=\"advanced__grid\" [formGroup]=\"effectsForm\">\n <label class=\"textctl\">\n <span>{{ t('advanced.description') }}</span>\n <input type=\"text\" formControlName=\"description\" [placeholder]=\"t('advanced.descriptionPlaceholder')\" />\n </label>\n <label class=\"textctl\">\n <span>{{ t('advanced.cssClass') }}</span>\n <input type=\"text\" formControlName=\"cssClass\" [placeholder]=\"t('advanced.cssClassPlaceholder')\" />\n </label>\n <label class=\"textctl\">\n <span>{{ t('advanced.inlineStyle') }}</span>\n <input type=\"text\" formControlName=\"inlineStyle\" [placeholder]=\"t('advanced.inlineStylePlaceholder')\" />\n </label>\n </div>\n </details>\n </div>\n </section>\n</div>\n", styles: [".rulefx{background:var(--md-sys-color-surface-container-low, var(--mat-sys-surface-container-low, #f7f8fa));border-radius:8px;color:var(--md-sys-color-on-surface, var(--mat-sys-on-surface, #1d1b20));border:1px solid var(--md-sys-color-outline-variant, var(--mat-sys-outline-variant, #d9dee6));box-shadow:var(--md-sys-elevation-level1, 0 1px 3px rgba(0, 0, 0, .12));padding:12px;min-width:0;scroll-margin-block:140px 120px}.rulefx__header{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:8px;margin-bottom:8px}.rulefx__title{grid-column:1;margin:0;min-width:0;font-size:1.05rem}.rulefx__subtitle{grid-column:1;margin:0;min-width:0;opacity:.75;font-size:.9rem;overflow-wrap:anywhere}.rulefx__actions{grid-column:2;grid-row:1/span 2;display:inline-flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:flex-end;min-width:0}.rulefx__ribbon{display:flex;flex-wrap:wrap;gap:6px;padding:8px;border-radius:8px;background:var(--md-sys-color-surface-container, var(--mat-sys-surface-container, #eef1f5));margin-bottom:8px}.ribbon__tab{display:flex;align-items:center;justify-content:center;gap:8px;flex:1 1 128px;min-width:0;padding:8px 10px;border-radius:8px;background:transparent;color:var(--md-sys-color-on-surface-variant, var(--mat-sys-on-surface-variant, #49454f));cursor:pointer;border:none}.ribbon__tab .material-icons{flex:0 0 auto;overflow:visible;font-size:18px;line-height:1}.ribbon__tab span:not(.material-icons){min-width:0;overflow:visible;text-overflow:clip;white-space:nowrap;line-height:1.2}.ribbon__tab.is-active{background:var(--md-sys-color-secondary-container, var(--mat-sys-secondary-container, #e8def8));color:var(--md-sys-color-on-secondary-container, var(--mat-sys-on-secondary-container, #1d192b));box-shadow:inset 0 0 0 1px var(--md-sys-color-outline-variant, var(--mat-sys-outline-variant, #d9dee6))}.rulefx__quickbar{border:1px solid var(--md-sys-color-outline-variant, var(--mat-sys-outline-variant, #d9dee6));border-radius:8px;padding:10px;background:var(--md-sys-color-surface, var(--mat-sys-surface, #ffffff));margin-bottom:10px;min-width:0}.rulefx__body{display:grid;grid-template-columns:1fr 320px;gap:12px}.rulefx__preview{border:1px solid var(--md-sys-color-outline-variant, var(--mat-sys-outline-variant, #d9dee6));border-radius:8px;padding:12px;background:var(--md-sys-color-surface, var(--mat-sys-surface, #ffffff));min-width:0}.preview__title{font-weight:600;margin-bottom:8px}.preview__cell{display:inline-flex;align-items:center;flex-wrap:wrap;gap:8px;max-width:100%;padding:10px 12px;border-radius:8px;background:var(--md-sys-color-surface-container-low, var(--mat-sys-surface-container-low, #f7f8fa));border:1px solid var(--md-sys-color-outline-variant, var(--mat-sys-outline-variant, #d9dee6))}.preview__icon{font-size:18px;line-height:1}.preview__text{min-width:0;overflow-wrap:anywhere}.preview__badge{font-size:.75rem;border-radius:999px;padding:2px 8px;border:1px solid transparent}.preview__hint{opacity:.7;font-size:.85rem;margin:8px 0 0}.preview__diagnostic{display:flex;align-items:flex-start;gap:6px;margin:8px 0 0;padding:8px 10px;border-radius:6px;background:var(--md-sys-color-error-container, var(--mat-sys-error-container, #ffdad6));color:var(--md-sys-color-on-error-container, var(--mat-sys-on-error-container, #410002));font-size:.82rem;line-height:1.35}.preview__diagnostic mat-icon{flex:0 0 auto;width:18px;height:18px;font-size:18px}.rulefx__advanced .advanced__grid{display:grid;grid-template-columns:1fr;gap:8px;min-width:0}.rulefx__advanced .textctl{display:grid;gap:6px}.rulefx__advanced input[type=text]{background:var(--md-sys-color-surface, var(--mat-sys-surface, #ffffff));color:var(--md-sys-color-on-surface, var(--mat-sys-on-surface, #1d1b20));border:1px solid var(--md-sys-color-outline-variant, var(--mat-sys-outline-variant, #d9dee6));border-radius:8px;padding:8px 10px;min-width:0}@media(max-width:760px){.rulefx__header{grid-template-columns:1fr}.rulefx__actions{grid-column:1;grid-row:auto;justify-content:flex-start}.rulefx__body{grid-template-columns:1fr}}@media(max-width:420px){.rulefx{padding:10px}.ribbon__tab{flex-basis:calc(50% - 4px)}.ribbon__tab span:not(.material-icons){white-space:normal}}.anim--once{animation-iteration-count:1}.anim--loop{animation-iteration-count:infinite}.anim--count{animation-iteration-count:3}.anim--subtle{--pfx-preview-scale-peak: 1.01;--pfx-preview-min-opacity: .7;--pfx-preview-slide-distance: 2px;--pfx-preview-border-strength: .18}.anim--normal{--pfx-preview-scale-peak: 1.03;--pfx-preview-min-opacity: .45;--pfx-preview-slide-distance: 6px;--pfx-preview-border-strength: .3}.anim--strong{--pfx-preview-scale-peak: 1.05;--pfx-preview-min-opacity: .25;--pfx-preview-slide-distance: 8px;--pfx-preview-border-strength: .42}.anim--pulse{animation-name:pfxPulse;animation-duration:.8s;animation-timing-function:ease-in-out}.anim--blink{animation-name:pfxBlink;animation-duration:.7s}.anim--grow{animation-name:pfxGrow;animation-duration:.4s}.anim--fade{animation-name:pfxFade;animation-duration:.6s}.anim--slide-in{animation-name:pfxSlideIn;animation-duration:.3s}.anim--border-pulse{animation-name:pfxBorderPulse;animation-duration:.9s}@keyframes pfxPulse{0%{transform:scale(1)}50%{transform:scale(var(--pfx-preview-scale-peak, 1.03))}to{transform:scale(1)}}@keyframes pfxBlink{0%,49%{opacity:1}50%,to{opacity:var(--pfx-preview-min-opacity, .25)}}@keyframes pfxGrow{0%{transform:scale(.96)}to{transform:scale(1)}}@keyframes pfxFade{0%{opacity:0}to{opacity:1}}@keyframes pfxSlideIn{0%{transform:translateY(var(--pfx-preview-slide-distance, 6px));opacity:0}to{transform:translateY(0);opacity:1}}@keyframes pfxBorderPulse{0%,to{box-shadow:inset 0 0 #d32f2f00}50%{box-shadow:inset 0 0 0 2px rgba(211,47,47,var(--pfx-preview-border-strength, .3))}}.icon--overlay{position:relative}.icon--overlay .preview__icon{position:absolute;left:6px;top:6px}@media(prefers-reduced-motion:reduce){.preview__cell{animation:none!important;transition:none!important}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i4$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i5$1.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: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i8.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i8.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i8.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "component", type: EstiloEditorComponent, selector: "praxis-effects-estilo-editor", inputs: ["group"] }, { kind: "component", type: LayoutEditorComponent, selector: "praxis-effects-layout-editor", inputs: ["group"] }, { kind: "component", type: IconeBadgeEditorComponent, selector: "praxis-effects-icone-badge-editor", inputs: ["group"] }, { kind: "component", type: FundoEditorComponent, selector: "praxis-effects-fundo-editor", inputs: ["group"] }, { kind: "component", type: AnimacaoEditorComponent, selector: "praxis-effects-animacao-editor", inputs: ["group"] }, { kind: "component", type: TooltipEditorComponent, selector: "praxis-effects-tooltip-editor", inputs: ["group"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1213
1721
  }
1214
1722
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: RuleEffectsPanelComponent, decorators: [{
1215
1723
  type: Component,
@@ -1229,8 +1737,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
1229
1737
  FundoEditorComponent,
1230
1738
  AnimacaoEditorComponent,
1231
1739
  TooltipEditorComponent,
1232
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"rulefx\">\n <header class=\"rulefx__header\">\n <h3 class=\"rulefx__title\">{{ t('panel.title') }}</h3>\n <p class=\"rulefx__subtitle\">{{ t('panel.subtitle') }}</p>\n <div class=\"rulefx__actions\">\n <button mat-stroked-button type=\"button\" [matMenuTriggerFor]=\"presetsMenu\" [attr.aria-label]=\"t('presets.label')\" (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\n <mat-icon>bookmarks</mat-icon>\n {{ t('presets.label') }}\n </button>\n <mat-menu #presetsMenu=\"matMenu\">\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('aprovado')\"><mat-icon>check_circle</mat-icon> Aprovado</button>\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('alerta')\"><mat-icon>warning</mat-icon> Alerta</button>\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('erro')\"><mat-icon>error</mat-icon> Erro</button>\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('info')\"><mat-icon>info</mat-icon> Info</button>\n </mat-menu>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"$event.stopPropagation(); onApply()\" (mousedown)=\"$event.stopPropagation()\" [attr.aria-label]=\"t('actions.apply')\" [matTooltip]=\"t('actions.apply')\" matTooltipPosition=\"below\">\n <mat-icon>done</mat-icon>\n {{ t('actions.apply') }}\n </button>\n <button mat-stroked-button type=\"button\" (click)=\"$event.stopPropagation(); onReset()\" (mousedown)=\"$event.stopPropagation()\" [attr.aria-label]=\"t('actions.reset')\" [matTooltip]=\"t('actions.reset')\" matTooltipPosition=\"below\">\n <mat-icon>restart_alt</mat-icon>\n {{ t('actions.reset') }}\n </button>\n </div>\n </header>\n\n <!-- Ribbon com seis categorias -->\n <nav\n class=\"rulefx__ribbon\"\n aria-label=\"Categorias de efeitos\"\n role=\"tablist\"\n (keydown)=\"onTabsKeydown($event)\"\n >\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'estilo'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'estilo'\"\n [attr.tabindex]=\"activeTab === 'estilo' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('estilo')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.estilo')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">text_format</span>\n <span>{{ t('tabs.estilo') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'layout'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'layout'\"\n [attr.tabindex]=\"activeTab === 'layout' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('layout')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.layout')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">view_quilt</span>\n <span>{{ t('tabs.layout') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'icone'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'icone'\"\n [attr.tabindex]=\"activeTab === 'icone' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('icone')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.icone')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">verified</span>\n <span>{{ t('tabs.icone') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'fundo'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'fundo'\"\n [attr.tabindex]=\"activeTab === 'fundo' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('fundo')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.fundo')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">gradient</span>\n <span>{{ t('tabs.fundo') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'animacao'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'animacao'\"\n [attr.tabindex]=\"activeTab === 'animacao' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('animacao')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.animacao')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">animation</span>\n <span>{{ t('tabs.animacao') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'tooltip'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'tooltip'\"\n [attr.tabindex]=\"activeTab === 'tooltip' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('tooltip')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.tooltip')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">info</span>\n <span>{{ t('tabs.tooltip') }}</span>\n </button>\n </nav>\n\n <!-- Quickbar contextual -->\n @if (effectsForm) {\n <section class=\"rulefx__quickbar\" aria-live=\"polite\">\n @switch (activeTab) {\n @case ('estilo') {\n <praxis-effects-estilo-editor [group]=\"estiloGroup\"></praxis-effects-estilo-editor>\n }\n @case ('layout') {\n <praxis-effects-layout-editor [group]=\"layoutGroup\"></praxis-effects-layout-editor>\n }\n @case ('icone') {\n <praxis-effects-icone-badge-editor [group]=\"iconBadgeGroup\"></praxis-effects-icone-badge-editor>\n }\n @case ('fundo') {\n <praxis-effects-fundo-editor [group]=\"backgroundGroup\"></praxis-effects-fundo-editor>\n }\n @case ('animacao') {\n <praxis-effects-animacao-editor [group]=\"animationGroup\"></praxis-effects-animacao-editor>\n }\n @case ('tooltip') {\n <praxis-effects-tooltip-editor [group]=\"tooltipGroup\"></praxis-effects-tooltip-editor>\n }\n }\n </section>\n }\n\n <!-- Pr\u00E9-visualiza\u00E7\u00E3o e se\u00E7\u00E3o avan\u00E7ada -->\n <section class=\"rulefx__body\">\n <div class=\"rulefx__preview\">\n <div class=\"preview__title\">{{ t('preview.title') }}</div>\n\n <div\n class=\"preview__cell\"\n [ngStyle]=\"computeCellStyle(formValue)\"\n [ngClass]=\"computeCellClass(formValue)\"\n (mouseenter)=\"onHoverPreview(true)\"\n (mouseleave)=\"onHoverPreview(false)\"\n >\n @if (formValue.iconBadge?.icon && formValue.iconBadge?.iconPos === 'before') {\n <span\n class=\"material-icons preview__icon\"\n [style.color]=\"formValue.iconBadge?.iconColor\"\n >\n {{ formValue.iconBadge?.icon }}\n </span>\n }\n\n <span class=\"preview__text\" [ngStyle]=\"computeTextStyle(formValue)\">\n Joana Silva \u2014 Ativo desde 2019\n </span>\n\n @if (formValue.iconBadge?.badgeText) {\n <span\n class=\"preview__badge\"\n [ngStyle]=\"{ 'background': badgeBackground(formValue), 'border-color': badgeBorder(formValue) }\"\n >\n {{ formValue.iconBadge?.badgeText }}\n </span>\n }\n\n @if (formValue.iconBadge?.icon && formValue.iconBadge?.iconPos === 'after') {\n <span\n class=\"material-icons preview__icon\"\n [style.color]=\"formValue.iconBadge?.iconColor\"\n >\n {{ formValue.iconBadge?.icon }}\n </span>\n }\n </div>\n\n <p class=\"preview__hint\">{{ t('preview.hint') }}</p>\n </div>\n\n <div class=\"rulefx__advanced\">\n <details class=\"advanced__section\">\n <summary (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">{{ t('advanced.title') }}</summary>\n <div class=\"advanced__grid\" [formGroup]=\"effectsForm\">\n <label class=\"textctl\">\n <span>{{ t('advanced.description') }}</span>\n <input type=\"text\" formControlName=\"description\" placeholder=\"ex.: Destacar pre\u00E7os altos\" />\n </label>\n <label class=\"textctl\">\n <span>Classe CSS</span>\n <input type=\"text\" formControlName=\"cssClass\" placeholder=\"ex.: praxis-cell--alert\" />\n </label>\n <label class=\"textctl\">\n <span>Estilo inline</span>\n <input type=\"text\" formControlName=\"inlineStyle\" placeholder=\"ex.: text-shadow: 0 0 8px rgba(0,255,163,.5)\" />\n </label>\n </div>\n </details>\n </div>\n </section>\n</div>\n", styles: [".rulefx{background:linear-gradient(180deg,#171b24,#1e2431);border-radius:14px;color:#e7ecf6;border:1px solid rgba(255,255,255,.08);box-shadow:0 6px 24px #00000047;padding:12px}.rulefx__header{display:grid;grid-template-columns:1fr auto;align-items:center;gap:8px;margin-bottom:8px}.rulefx__title{margin:0;font-size:1.05rem}.rulefx__subtitle{margin:0;opacity:.75;font-size:.9rem}.rulefx__actions{display:inline-flex;gap:8px;align-items:center}.rulefx__ribbon{display:flex;gap:6px;padding:8px;border-radius:10px;background:linear-gradient(180deg,#202636,#1c2230);margin-bottom:8px}.ribbon__tab{display:flex;align-items:center;gap:8px;padding:8px 10px;border-radius:10px;background:transparent;color:#e7ecf6;cursor:pointer;border:none}.ribbon__tab.is-active{background:linear-gradient(180deg,#2a3550,#243149);box-shadow:inset 0 0 0 1px #ffffff0a}.rulefx__quickbar{border:1px solid rgba(255,255,255,.08);border-radius:12px;padding:10px;background:linear-gradient(180deg,#202637,#1c2230);margin-bottom:10px}.rulefx__body{display:grid;grid-template-columns:1fr 320px;gap:12px}.rulefx__preview{border:1px solid rgba(255,255,255,.08);border-radius:12px;padding:12px;background:linear-gradient(180deg,#202637,#1c2230)}.preview__title{font-weight:600;margin-bottom:8px}.preview__cell{display:inline-flex;align-items:center;gap:8px;padding:10px 12px;border-radius:12px;background:#35d07f14;border:1px solid rgba(53,208,127,.25)}.preview__icon{font-size:18px;line-height:1}.preview__badge{font-size:.75rem;border-radius:999px;padding:2px 8px;border:1px solid transparent}.preview__hint{opacity:.7;font-size:.85rem;margin:8px 0 0}.rulefx__advanced .advanced__grid{display:grid;grid-template-columns:1fr;gap:8px}.rulefx__advanced .textctl{display:grid;gap:6px}.rulefx__advanced input[type=text]{background:#151a24;color:#e7ecf6;border:1px solid rgba(255,255,255,.08);border-radius:8px;padding:8px 10px}.anim--once{animation-iteration-count:1}.anim--loop{animation-iteration-count:infinite}.anim--count{animation-iteration-count:3}.anim--subtle{--pfx-preview-scale-peak: 1.01;--pfx-preview-min-opacity: .7;--pfx-preview-slide-distance: 2px;--pfx-preview-border-strength: .18}.anim--normal{--pfx-preview-scale-peak: 1.03;--pfx-preview-min-opacity: .45;--pfx-preview-slide-distance: 6px;--pfx-preview-border-strength: .3}.anim--strong{--pfx-preview-scale-peak: 1.05;--pfx-preview-min-opacity: .25;--pfx-preview-slide-distance: 8px;--pfx-preview-border-strength: .42}.anim--pulse{animation-name:pfxPulse;animation-duration:.8s;animation-timing-function:ease-in-out}.anim--blink{animation-name:pfxBlink;animation-duration:.7s}.anim--grow{animation-name:pfxGrow;animation-duration:.4s}.anim--fade{animation-name:pfxFade;animation-duration:.6s}.anim--slide-in{animation-name:pfxSlideIn;animation-duration:.3s}.anim--border-pulse{animation-name:pfxBorderPulse;animation-duration:.9s}@keyframes pfxPulse{0%{transform:scale(1)}50%{transform:scale(var(--pfx-preview-scale-peak, 1.03))}to{transform:scale(1)}}@keyframes pfxBlink{0%,49%{opacity:1}50%,to{opacity:var(--pfx-preview-min-opacity, .25)}}@keyframes pfxGrow{0%{transform:scale(.96)}to{transform:scale(1)}}@keyframes pfxFade{0%{opacity:0}to{opacity:1}}@keyframes pfxSlideIn{0%{transform:translateY(var(--pfx-preview-slide-distance, 6px));opacity:0}to{transform:translateY(0);opacity:1}}@keyframes pfxBorderPulse{0%,to{box-shadow:inset 0 0 #d32f2f00}50%{box-shadow:inset 0 0 0 2px rgba(211,47,47,var(--pfx-preview-border-strength, .3))}}.icon--overlay{position:relative}.icon--overlay .preview__icon{position:absolute;left:6px;top:6px}@media(prefers-reduced-motion:reduce){.preview__cell{animation:none!important;transition:none!important}}\n"] }]
1233
- }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: EffectRegistryService }], propDecorators: { scope: [{
1740
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [providePraxisI18nConfig(PRAXIS_TABLE_RULE_BUILDER_I18N_CONFIG)], template: "<div class=\"rulefx\">\n <header class=\"rulefx__header\">\n <h3 class=\"rulefx__title\">{{ t('panel.title') }}</h3>\n <p class=\"rulefx__subtitle\">{{ t('panel.subtitle') }}</p>\n <div class=\"rulefx__actions\">\n <button mat-stroked-button type=\"button\" [matMenuTriggerFor]=\"presetsMenu\" [attr.aria-label]=\"t('presets.label')\" (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\n <mat-icon>bookmarks</mat-icon>\n {{ t('presets.label') }}\n </button>\n <mat-menu #presetsMenu=\"matMenu\">\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('aprovado')\"><mat-icon>check_circle</mat-icon> {{ t('presets.aprovado') }}</button>\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('alerta')\"><mat-icon>warning</mat-icon> {{ t('presets.alerta') }}</button>\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('erro')\"><mat-icon>error</mat-icon> {{ t('presets.erro') }}</button>\n <button mat-menu-item type=\"button\" (click)=\"applyPreset('info')\"><mat-icon>info</mat-icon> {{ t('presets.info') }}</button>\n </mat-menu>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"$event.stopPropagation(); onApply()\" (mousedown)=\"$event.stopPropagation()\" [attr.aria-label]=\"t('actions.apply')\" [matTooltip]=\"t('actions.apply')\" matTooltipPosition=\"below\">\n <mat-icon>done</mat-icon>\n {{ t('actions.apply') }}\n </button>\n <button mat-stroked-button type=\"button\" (click)=\"$event.stopPropagation(); onReset()\" (mousedown)=\"$event.stopPropagation()\" [attr.aria-label]=\"t('actions.reset')\" [matTooltip]=\"t('actions.reset')\" matTooltipPosition=\"below\">\n <mat-icon>restart_alt</mat-icon>\n {{ t('actions.reset') }}\n </button>\n </div>\n </header>\n\n <!-- Ribbon com seis categorias -->\n <nav\n class=\"rulefx__ribbon\"\n [attr.aria-label]=\"t('tabs.ariaLabel')\"\n role=\"tablist\"\n (keydown)=\"onTabsKeydown($event)\"\n >\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'estilo'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'estilo'\"\n [attr.tabindex]=\"activeTab === 'estilo' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('estilo')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.estilo')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">text_format</span>\n <span>{{ t('tabs.estilo') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'layout'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'layout'\"\n [attr.tabindex]=\"activeTab === 'layout' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('layout')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.layout')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">view_quilt</span>\n <span>{{ t('tabs.layout') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'icone'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'icone'\"\n [attr.tabindex]=\"activeTab === 'icone' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('icone')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.icone')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">verified</span>\n <span>{{ t('tabs.icone') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'fundo'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'fundo'\"\n [attr.tabindex]=\"activeTab === 'fundo' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('fundo')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.fundo')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">gradient</span>\n <span>{{ t('tabs.fundo') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'animacao'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'animacao'\"\n [attr.tabindex]=\"activeTab === 'animacao' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('animacao')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.animacao')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">animation</span>\n <span>{{ t('tabs.animacao') }}</span>\n </button>\n <button\n class=\"ribbon__tab\"\n [class.is-active]=\"activeTab === 'tooltip'\"\n type=\"button\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'tooltip'\"\n [attr.tabindex]=\"activeTab === 'tooltip' ? 0 : -1\"\n (click)=\"$event.stopPropagation(); setTab('tooltip')\"\n (mousedown)=\"$event.stopPropagation()\"\n [matTooltip]=\"t('tabs.tooltip')\"\n matTooltipPosition=\"below\"\n >\n <span class=\"material-icons\">info</span>\n <span>{{ t('tabs.tooltip') }}</span>\n </button>\n </nav>\n\n <!-- Quickbar contextual -->\n @if (effectsForm) {\n <section class=\"rulefx__quickbar\" aria-live=\"polite\">\n @switch (activeTab) {\n @case ('estilo') {\n <praxis-effects-estilo-editor [group]=\"estiloGroup\"></praxis-effects-estilo-editor>\n }\n @case ('layout') {\n <praxis-effects-layout-editor [group]=\"layoutGroup\"></praxis-effects-layout-editor>\n }\n @case ('icone') {\n <praxis-effects-icone-badge-editor [group]=\"iconBadgeGroup\"></praxis-effects-icone-badge-editor>\n }\n @case ('fundo') {\n <praxis-effects-fundo-editor [group]=\"backgroundGroup\"></praxis-effects-fundo-editor>\n }\n @case ('animacao') {\n <praxis-effects-animacao-editor [group]=\"animationGroup\"></praxis-effects-animacao-editor>\n }\n @case ('tooltip') {\n <praxis-effects-tooltip-editor [group]=\"tooltipGroup\"></praxis-effects-tooltip-editor>\n }\n }\n </section>\n }\n\n <!-- Pr\u00E9-visualiza\u00E7\u00E3o e se\u00E7\u00E3o avan\u00E7ada -->\n <section class=\"rulefx__body\">\n <div class=\"rulefx__preview\">\n <div class=\"preview__title\">{{ t('preview.title') }}</div>\n\n <div\n class=\"preview__cell\"\n [ngStyle]=\"computeCellStyle(formValue)\"\n [ngClass]=\"computeCellClass(formValue)\"\n (mouseenter)=\"onHoverPreview(true)\"\n (mouseleave)=\"onHoverPreview(false)\"\n >\n @if (formValue.iconBadge?.icon && formValue.iconBadge?.iconPos === 'before') {\n <span\n class=\"material-icons preview__icon\"\n [style.color]=\"formValue.iconBadge?.iconColor\"\n >\n {{ formValue.iconBadge?.icon }}\n </span>\n }\n\n <span class=\"preview__text\" [ngStyle]=\"computeTextStyle(formValue)\">\n {{ t('preview.sampleText') }}\n </span>\n\n @if (formValue.iconBadge?.badgeText) {\n <span\n class=\"preview__badge\"\n [ngStyle]=\"{ 'background': badgeBackground(formValue), 'border-color': badgeBorder(formValue) }\"\n >\n {{ formValue.iconBadge?.badgeText }}\n </span>\n }\n\n @if (formValue.iconBadge?.icon && formValue.iconBadge?.iconPos === 'after') {\n <span\n class=\"material-icons preview__icon\"\n [style.color]=\"formValue.iconBadge?.iconColor\"\n >\n {{ formValue.iconBadge?.icon }}\n </span>\n }\n </div>\n\n <p class=\"preview__hint\">{{ t('preview.hint') }}</p>\n @if (conditionalSurfacePreviewUnresolved) {\n <p class=\"preview__diagnostic\" role=\"status\">\n <mat-icon aria-hidden=\"true\">warning_amber</mat-icon>\n <span>{{ t('preview.contrastUnresolved') }}</span>\n </p>\n }\n </div>\n\n <div class=\"rulefx__advanced\">\n <details class=\"advanced__section\">\n <summary (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">{{ t('advanced.title') }}</summary>\n <div class=\"advanced__grid\" [formGroup]=\"effectsForm\">\n <label class=\"textctl\">\n <span>{{ t('advanced.description') }}</span>\n <input type=\"text\" formControlName=\"description\" [placeholder]=\"t('advanced.descriptionPlaceholder')\" />\n </label>\n <label class=\"textctl\">\n <span>{{ t('advanced.cssClass') }}</span>\n <input type=\"text\" formControlName=\"cssClass\" [placeholder]=\"t('advanced.cssClassPlaceholder')\" />\n </label>\n <label class=\"textctl\">\n <span>{{ t('advanced.inlineStyle') }}</span>\n <input type=\"text\" formControlName=\"inlineStyle\" [placeholder]=\"t('advanced.inlineStylePlaceholder')\" />\n </label>\n </div>\n </details>\n </div>\n </section>\n</div>\n", styles: [".rulefx{background:var(--md-sys-color-surface-container-low, var(--mat-sys-surface-container-low, #f7f8fa));border-radius:8px;color:var(--md-sys-color-on-surface, var(--mat-sys-on-surface, #1d1b20));border:1px solid var(--md-sys-color-outline-variant, var(--mat-sys-outline-variant, #d9dee6));box-shadow:var(--md-sys-elevation-level1, 0 1px 3px rgba(0, 0, 0, .12));padding:12px;min-width:0;scroll-margin-block:140px 120px}.rulefx__header{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:8px;margin-bottom:8px}.rulefx__title{grid-column:1;margin:0;min-width:0;font-size:1.05rem}.rulefx__subtitle{grid-column:1;margin:0;min-width:0;opacity:.75;font-size:.9rem;overflow-wrap:anywhere}.rulefx__actions{grid-column:2;grid-row:1/span 2;display:inline-flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:flex-end;min-width:0}.rulefx__ribbon{display:flex;flex-wrap:wrap;gap:6px;padding:8px;border-radius:8px;background:var(--md-sys-color-surface-container, var(--mat-sys-surface-container, #eef1f5));margin-bottom:8px}.ribbon__tab{display:flex;align-items:center;justify-content:center;gap:8px;flex:1 1 128px;min-width:0;padding:8px 10px;border-radius:8px;background:transparent;color:var(--md-sys-color-on-surface-variant, var(--mat-sys-on-surface-variant, #49454f));cursor:pointer;border:none}.ribbon__tab .material-icons{flex:0 0 auto;overflow:visible;font-size:18px;line-height:1}.ribbon__tab span:not(.material-icons){min-width:0;overflow:visible;text-overflow:clip;white-space:nowrap;line-height:1.2}.ribbon__tab.is-active{background:var(--md-sys-color-secondary-container, var(--mat-sys-secondary-container, #e8def8));color:var(--md-sys-color-on-secondary-container, var(--mat-sys-on-secondary-container, #1d192b));box-shadow:inset 0 0 0 1px var(--md-sys-color-outline-variant, var(--mat-sys-outline-variant, #d9dee6))}.rulefx__quickbar{border:1px solid var(--md-sys-color-outline-variant, var(--mat-sys-outline-variant, #d9dee6));border-radius:8px;padding:10px;background:var(--md-sys-color-surface, var(--mat-sys-surface, #ffffff));margin-bottom:10px;min-width:0}.rulefx__body{display:grid;grid-template-columns:1fr 320px;gap:12px}.rulefx__preview{border:1px solid var(--md-sys-color-outline-variant, var(--mat-sys-outline-variant, #d9dee6));border-radius:8px;padding:12px;background:var(--md-sys-color-surface, var(--mat-sys-surface, #ffffff));min-width:0}.preview__title{font-weight:600;margin-bottom:8px}.preview__cell{display:inline-flex;align-items:center;flex-wrap:wrap;gap:8px;max-width:100%;padding:10px 12px;border-radius:8px;background:var(--md-sys-color-surface-container-low, var(--mat-sys-surface-container-low, #f7f8fa));border:1px solid var(--md-sys-color-outline-variant, var(--mat-sys-outline-variant, #d9dee6))}.preview__icon{font-size:18px;line-height:1}.preview__text{min-width:0;overflow-wrap:anywhere}.preview__badge{font-size:.75rem;border-radius:999px;padding:2px 8px;border:1px solid transparent}.preview__hint{opacity:.7;font-size:.85rem;margin:8px 0 0}.preview__diagnostic{display:flex;align-items:flex-start;gap:6px;margin:8px 0 0;padding:8px 10px;border-radius:6px;background:var(--md-sys-color-error-container, var(--mat-sys-error-container, #ffdad6));color:var(--md-sys-color-on-error-container, var(--mat-sys-on-error-container, #410002));font-size:.82rem;line-height:1.35}.preview__diagnostic mat-icon{flex:0 0 auto;width:18px;height:18px;font-size:18px}.rulefx__advanced .advanced__grid{display:grid;grid-template-columns:1fr;gap:8px;min-width:0}.rulefx__advanced .textctl{display:grid;gap:6px}.rulefx__advanced input[type=text]{background:var(--md-sys-color-surface, var(--mat-sys-surface, #ffffff));color:var(--md-sys-color-on-surface, var(--mat-sys-on-surface, #1d1b20));border:1px solid var(--md-sys-color-outline-variant, var(--mat-sys-outline-variant, #d9dee6));border-radius:8px;padding:8px 10px;min-width:0}@media(max-width:760px){.rulefx__header{grid-template-columns:1fr}.rulefx__actions{grid-column:1;grid-row:auto;justify-content:flex-start}.rulefx__body{grid-template-columns:1fr}}@media(max-width:420px){.rulefx{padding:10px}.ribbon__tab{flex-basis:calc(50% - 4px)}.ribbon__tab span:not(.material-icons){white-space:normal}}.anim--once{animation-iteration-count:1}.anim--loop{animation-iteration-count:infinite}.anim--count{animation-iteration-count:3}.anim--subtle{--pfx-preview-scale-peak: 1.01;--pfx-preview-min-opacity: .7;--pfx-preview-slide-distance: 2px;--pfx-preview-border-strength: .18}.anim--normal{--pfx-preview-scale-peak: 1.03;--pfx-preview-min-opacity: .45;--pfx-preview-slide-distance: 6px;--pfx-preview-border-strength: .3}.anim--strong{--pfx-preview-scale-peak: 1.05;--pfx-preview-min-opacity: .25;--pfx-preview-slide-distance: 8px;--pfx-preview-border-strength: .42}.anim--pulse{animation-name:pfxPulse;animation-duration:.8s;animation-timing-function:ease-in-out}.anim--blink{animation-name:pfxBlink;animation-duration:.7s}.anim--grow{animation-name:pfxGrow;animation-duration:.4s}.anim--fade{animation-name:pfxFade;animation-duration:.6s}.anim--slide-in{animation-name:pfxSlideIn;animation-duration:.3s}.anim--border-pulse{animation-name:pfxBorderPulse;animation-duration:.9s}@keyframes pfxPulse{0%{transform:scale(1)}50%{transform:scale(var(--pfx-preview-scale-peak, 1.03))}to{transform:scale(1)}}@keyframes pfxBlink{0%,49%{opacity:1}50%,to{opacity:var(--pfx-preview-min-opacity, .25)}}@keyframes pfxGrow{0%{transform:scale(.96)}to{transform:scale(1)}}@keyframes pfxFade{0%{opacity:0}to{opacity:1}}@keyframes pfxSlideIn{0%{transform:translateY(var(--pfx-preview-slide-distance, 6px));opacity:0}to{transform:translateY(0);opacity:1}}@keyframes pfxBorderPulse{0%,to{box-shadow:inset 0 0 #d32f2f00}50%{box-shadow:inset 0 0 0 2px rgba(211,47,47,var(--pfx-preview-border-strength, .3))}}.icon--overlay{position:relative}.icon--overlay .preview__icon{position:absolute;left:6px;top:6px}@media(prefers-reduced-motion:reduce){.preview__cell{animation:none!important;transition:none!important}}\n"] }]
1741
+ }], ctorParameters: () => [{ type: i2.FormBuilder }, { type: EffectRegistryService }, { type: i1.PraxisI18nService }], propDecorators: { labels: [{
1742
+ type: Input
1743
+ }], scope: [{
1234
1744
  type: Input
1235
1745
  }], value: [{
1236
1746
  type: Input
@@ -1331,6 +1841,10 @@ function toCellClassAndStyle(effect, options) {
1331
1841
  return { classList, style };
1332
1842
  }
1333
1843
 
1844
+ const ruleAnimationPresetEnum = [
1845
+ ...Object.keys(RULE_ANIMATION_PRESETS),
1846
+ ...Object.keys(RULE_ANIMATION_PRESET_ALIASES),
1847
+ ];
1334
1848
  const ruleAddSchema = {
1335
1849
  type: 'object',
1336
1850
  required: ['ruleId', 'scope'],
@@ -1415,20 +1929,7 @@ const animationSetSchema = {
1415
1929
  properties: {
1416
1930
  enabled: { type: 'boolean' },
1417
1931
  preset: {
1418
- enum: [
1419
- 'info-soft',
1420
- 'success-confirm',
1421
- 'warning-attention',
1422
- 'critical-alert',
1423
- 'audit-review',
1424
- 'sync-pending',
1425
- 'sla-warning',
1426
- 'sla-breach',
1427
- 'risk-elevated',
1428
- 'risk-critical',
1429
- 'audit-warning',
1430
- 'sync-warning',
1431
- ],
1932
+ enum: ruleAnimationPresetEnum,
1432
1933
  },
1433
1934
  type: { enum: ['pulse', 'blink', 'grow', 'fade', 'slide-in', 'border-pulse'] },
1434
1935
  trigger: {
@@ -1468,9 +1969,10 @@ const PRAXIS_TABLE_RULE_BUILDER_AUTHORING_MANIFEST = {
1468
1969
  runtimeInputs: [
1469
1970
  { name: 'scope', type: 'RuleScope', description: 'Effect scope: cell, row, column or table.' },
1470
1971
  { name: 'value', type: 'RuleEffectDefinition | undefined', description: 'Initial effect definition hydrated into the panel form.' },
1972
+ { name: 'labels', type: 'Record<string, string>', description: 'Host-owned partial panel copy overrides merged with default labels for i18n/theming context; not part of the rule effect payload.' },
1471
1973
  { name: 'valueChange', type: 'RuleEffectDefinition', description: 'Debounced normalized effect payload emitted by the editor.' },
1472
1974
  { name: 'apply', type: 'void', description: 'Emitted when the user applies the current effect payload.' },
1473
- { name: 'reset', type: 'void', description: 'Emitted when the user resets the panel form.' },
1975
+ { name: 'reset', type: 'void', description: 'Emitted when the user resets the panel form back to canonical defaults.' },
1474
1976
  ],
1475
1977
  editableTargets: [
1476
1978
  { kind: 'rule', resolver: 'table-rule-by-stable-id', description: 'Table conditional rule entry keyed by stable rule id before it is passed to praxis-table.' },
@@ -1731,8 +2233,70 @@ const PRAXIS_TABLE_RULE_BUILDER_AUTHORING_MANIFEST = {
1731
2233
  ],
1732
2234
  };
1733
2235
 
2236
+ /** Metadata for Praxis Table Rule Builder component */
2237
+ const PRAXIS_TABLE_RULE_BUILDER_COMPONENT_METADATA = {
2238
+ id: 'praxis-table-rule-builder',
2239
+ selector: 'praxis-rule-effects-panel',
2240
+ component: RuleEffectsPanelComponent,
2241
+ friendlyName: 'Praxis Table Rule Builder',
2242
+ description: 'Editor for table rule effects and conditional styling.',
2243
+ inputs: [
2244
+ {
2245
+ name: 'scope',
2246
+ type: 'RuleScope',
2247
+ label: 'Escopo',
2248
+ description: 'Escopo do efeito (cell, row, column, table).',
2249
+ },
2250
+ {
2251
+ name: 'value',
2252
+ type: 'RuleEffectDefinition | undefined',
2253
+ label: 'Valor',
2254
+ description: 'Valor inicial para hidratar o formulário.',
2255
+ },
2256
+ {
2257
+ name: 'labels',
2258
+ type: 'Record<string, string>',
2259
+ label: 'Rótulos',
2260
+ description: 'Overrides parciais de texto do painel, aplicados acima do catálogo i18n da lib sem alterar o payload de regras.',
2261
+ },
2262
+ ],
2263
+ outputs: [
2264
+ {
2265
+ name: 'valueChange',
2266
+ type: 'RuleEffectDefinition',
2267
+ label: 'Mudança de valor',
2268
+ description: 'Disparado quando o valor consolidado é atualizado.',
2269
+ },
2270
+ {
2271
+ name: 'apply',
2272
+ type: 'void',
2273
+ label: 'Aplicar',
2274
+ description: 'Disparado quando o usuário aplica as mudanças.',
2275
+ },
2276
+ {
2277
+ name: 'reset',
2278
+ type: 'void',
2279
+ label: 'Resetar',
2280
+ description: 'Disparado quando o usuário redefine o formulário para os defaults canônicos.',
2281
+ },
2282
+ ],
2283
+ tags: ['widget', 'rules', 'table', 'configurable'],
2284
+ lib: '@praxisui/table-rule-builder',
2285
+ };
2286
+ /** Provider para auto-registrar metadados do componente Table Rule Builder. */
2287
+ function providePraxisTableRuleBuilderMetadata() {
2288
+ return {
2289
+ provide: ENVIRONMENT_INITIALIZER,
2290
+ multi: true,
2291
+ useFactory: (registry) => () => {
2292
+ registry.register(PRAXIS_TABLE_RULE_BUILDER_COMPONENT_METADATA);
2293
+ },
2294
+ deps: [ComponentMetadataRegistry],
2295
+ };
2296
+ }
2297
+
1734
2298
  /**
1735
2299
  * Generated bundle index. Do not edit.
1736
2300
  */
1737
2301
 
1738
- export { AnimacaoEditorComponent, DEFAULT_EFFECT_PRESETS, EffectRegistryService, EstiloEditorComponent, FundoEditorComponent, IconeBadgeEditorComponent, LayoutEditorComponent, PRAXIS_TABLE_RULE_BUILDER_AUTHORING_MANIFEST, RuleEffectsPanelComponent, TooltipEditorComponent, toCellClassAndStyle };
2302
+ export { AnimacaoEditorComponent, DEFAULT_EFFECT_PRESETS, EffectRegistryService, EstiloEditorComponent, FundoEditorComponent, IconeBadgeEditorComponent, LayoutEditorComponent, PRAXIS_TABLE_RULE_BUILDER_AUTHORING_MANIFEST, PRAXIS_TABLE_RULE_BUILDER_COMPONENT_METADATA, PRAXIS_TABLE_RULE_BUILDER_I18N_CONFIG, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE, PRAXIS_TABLE_RULE_BUILDER_LABEL_KEYS, RuleEffectsPanelComponent, TooltipEditorComponent, providePraxisTableRuleBuilderMetadata, toCellClassAndStyle };