@praxisui/table-rule-builder 9.0.0-beta.3 → 9.0.0-beta.30

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,280 @@ 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.textBackgroundColor': 'Text background color',
269
+ 'style.bold': 'Bold',
270
+ 'style.italic': 'Italic',
271
+ 'style.underline': 'Underline',
272
+ 'style.transform': 'Transform',
273
+ 'style.transformAria': 'Text transform',
274
+ 'style.transform.none': 'None',
275
+ 'style.transform.uppercase': 'UPPERCASE',
276
+ 'style.transform.lowercase': 'lowercase',
277
+ 'style.transform.capitalize': 'Capitalize',
278
+ 'style.opacity': 'Opacity',
279
+ 'style.size': 'Size',
280
+ 'layout.group': 'Layout editor',
281
+ 'layout.border': 'Border',
282
+ 'layout.borderColor': 'Border color',
283
+ 'layout.borderWidth': 'Width',
284
+ 'layout.padding': 'Padding',
285
+ 'layout.align': 'Alignment',
286
+ 'layout.elevation': 'Elevation (shadow)',
287
+ 'icon.group': 'Icon and badge editor',
288
+ 'icon.label': 'Icon (mat-icon)',
289
+ 'icon.color': 'Icon color',
290
+ 'icon.position': 'Icon position',
291
+ 'icon.position.before': 'Before',
292
+ 'icon.position.after': 'After',
293
+ 'icon.position.overlay': 'Overlay',
294
+ 'badge.text': 'Badge text',
295
+ 'badge.color': 'Badge color',
296
+ 'badge.style': 'Style',
297
+ 'badge.style.aria': 'Badge style',
298
+ 'badge.style.solid': 'Solid',
299
+ 'badge.style.soft': 'Soft',
300
+ 'badge.style.outline': 'Outline',
301
+ 'background.group': 'Background editor',
302
+ 'background.color': 'Color',
303
+ 'background.gradient': 'CSS gradient',
304
+ 'background.alpha': 'Transparency',
305
+ 'background.blur': 'Blur (px)',
306
+ 'animation.group': 'Animation editor',
307
+ 'animation.enabled': 'Enable animation',
308
+ 'animation.preset': 'Preset',
309
+ 'animation.preset.aria': 'Animation preset',
310
+ 'animation.preset.none': 'No preset',
311
+ 'animation.type': 'Type',
312
+ 'animation.type.aria': 'Animation type',
313
+ 'animation.defaultFromPreset': 'Preset default',
314
+ 'animation.duration': 'Duration (ms)',
315
+ 'animation.duration.placeholder': 'Preset/default',
316
+ 'animation.delay': 'Delay (ms)',
317
+ 'animation.delay.placeholder': 'Optional',
318
+ 'animation.trigger': 'Trigger',
319
+ 'animation.trigger.aria': 'Animation trigger',
320
+ 'animation.trigger.onChange': 'On change',
321
+ 'animation.trigger.onAppear': 'On appear',
322
+ 'animation.trigger.onHover': 'On hover',
323
+ 'animation.trigger.onConditionEnter': 'On condition enter',
324
+ 'animation.trigger.onConditionExit': 'On condition exit',
325
+ 'animation.trigger.onDataRefresh': 'On data refresh',
326
+ 'animation.repeat': 'Repeat',
327
+ 'animation.repeat.aria': 'Animation repeat',
328
+ 'animation.repeat.once': 'Once',
329
+ 'animation.repeat.loop': 'Loop',
330
+ 'animation.repeat.infinite': 'Infinite',
331
+ 'animation.intensity': 'Intensity',
332
+ 'animation.intensity.aria': 'Animation intensity',
333
+ 'animation.intensity.subtle': 'Subtle',
334
+ 'animation.intensity.normal': 'Normal',
335
+ 'animation.intensity.strong': 'Strong',
336
+ 'tooltip.group': 'Tooltip editor',
337
+ 'tooltip.text': 'Text',
338
+ 'tooltip.text.placeholder': 'Cell details',
339
+ 'tooltip.position': 'Position',
340
+ 'tooltip.position.aria': 'Tooltip position',
341
+ 'tooltip.position.top': 'Top',
342
+ 'tooltip.position.right': 'Right',
343
+ 'tooltip.position.bottom': 'Bottom',
344
+ 'tooltip.position.left': 'Left',
345
+ 'tooltip.backgroundColor': 'Background color',
346
+ 'tooltip.delay': 'Delay (ms)',
347
+ };
348
+
349
+ const PRAXIS_TABLE_RULE_BUILDER_PT_BR = {
350
+ 'panel.title': 'C. Efeitos',
351
+ 'panel.subtitle': 'Configure estilos e elementos visuais quando a regra for verdadeira',
352
+ 'tabs.estilo': 'Estilo',
353
+ 'tabs.layout': 'Layout',
354
+ 'tabs.icone': 'Ícone / Badge',
355
+ 'tabs.fundo': 'Fundo',
356
+ 'tabs.animacao': 'Animação',
357
+ 'tabs.tooltip': 'Tooltip',
358
+ 'preview.title': 'Pré-visualização',
359
+ 'preview.hint': 'As mudanças acima refletem o estilo aplicado quando a condição é verdadeira.',
360
+ 'advanced.title': 'Avançado',
361
+ 'advanced.description': 'Descrição',
362
+ 'actions.apply': 'Aplicar',
363
+ 'actions.reset': 'Redefinir',
364
+ 'presets.label': 'Presets',
365
+ 'presets.aprovado': 'Aprovado',
366
+ 'presets.alerta': 'Alerta',
367
+ 'presets.erro': 'Erro',
368
+ 'presets.info': 'Info',
369
+ 'tabs.ariaLabel': 'Categorias de efeitos',
370
+ 'preview.sampleText': 'Valor da célula',
371
+ 'advanced.cssClass': 'Classe CSS',
372
+ 'advanced.inlineStyle': 'Estilo inline',
373
+ 'advanced.descriptionPlaceholder': 'ex.: destacar resultado crítico',
374
+ 'advanced.cssClassPlaceholder': 'ex.: praxis-cell--alert',
375
+ 'advanced.inlineStylePlaceholder': 'ex.: font-weight: 600;',
376
+ 'style.group': 'Editor de estilo',
377
+ 'style.textColor': 'Cor do texto',
378
+ 'style.textBackgroundColor': 'Cor de fundo do texto',
379
+ 'style.bold': 'Negrito',
380
+ 'style.italic': 'Itálico',
381
+ 'style.underline': 'Sublinhado',
382
+ 'style.transform': 'Transformação',
383
+ 'style.transformAria': 'Transformação do texto',
384
+ 'style.transform.none': 'Nenhuma',
385
+ 'style.transform.uppercase': 'MAIÚSCULAS',
386
+ 'style.transform.lowercase': 'minúsculas',
387
+ 'style.transform.capitalize': 'Capitalizar',
388
+ 'style.opacity': 'Opacidade',
389
+ 'style.size': 'Tamanho',
390
+ 'layout.group': 'Editor de layout',
391
+ 'layout.border': 'Borda',
392
+ 'layout.borderColor': 'Cor da borda',
393
+ 'layout.borderWidth': 'Espessura',
394
+ 'layout.padding': 'Padding',
395
+ 'layout.align': 'Alinhamento',
396
+ 'layout.elevation': 'Elevação (sombra)',
397
+ 'icon.group': 'Editor de ícone e badge',
398
+ 'icon.label': 'Ícone (mat-icon)',
399
+ 'icon.color': 'Cor do ícone',
400
+ 'icon.position': 'Posição do ícone',
401
+ 'icon.position.before': 'Antes',
402
+ 'icon.position.after': 'Depois',
403
+ 'icon.position.overlay': 'Sobreposto',
404
+ 'badge.text': 'Texto do badge',
405
+ 'badge.color': 'Cor do badge',
406
+ 'badge.style': 'Estilo',
407
+ 'badge.style.aria': 'Estilo do badge',
408
+ 'badge.style.solid': 'Sólido',
409
+ 'badge.style.soft': 'Suave',
410
+ 'badge.style.outline': 'Contorno',
411
+ 'background.group': 'Editor de fundo',
412
+ 'background.color': 'Cor',
413
+ 'background.gradient': 'Gradient CSS',
414
+ 'background.alpha': 'Transparência',
415
+ 'background.blur': 'Desfoque (px)',
416
+ 'animation.group': 'Editor de animação',
417
+ 'animation.enabled': 'Ativar animação',
418
+ 'animation.preset': 'Preset',
419
+ 'animation.preset.aria': 'Preset de animação',
420
+ 'animation.preset.none': 'Sem preset',
421
+ 'animation.type': 'Tipo',
422
+ 'animation.type.aria': 'Tipo de animação',
423
+ 'animation.defaultFromPreset': 'Padrão do preset',
424
+ 'animation.duration': 'Duração (ms)',
425
+ 'animation.duration.placeholder': 'Preset/default',
426
+ 'animation.delay': 'Delay (ms)',
427
+ 'animation.delay.placeholder': 'Opcional',
428
+ 'animation.trigger': 'Disparo',
429
+ 'animation.trigger.aria': 'Disparo da animação',
430
+ 'animation.trigger.onChange': 'Ao mudar',
431
+ 'animation.trigger.onAppear': 'Ao aparecer',
432
+ 'animation.trigger.onHover': 'Ao passar o mouse',
433
+ 'animation.trigger.onConditionEnter': 'Ao entrar na condição',
434
+ 'animation.trigger.onConditionExit': 'Ao sair da condição',
435
+ 'animation.trigger.onDataRefresh': 'Ao atualizar dados',
436
+ 'animation.repeat': 'Repetição',
437
+ 'animation.repeat.aria': 'Repetição da animação',
438
+ 'animation.repeat.once': 'Uma vez',
439
+ 'animation.repeat.loop': 'Loop',
440
+ 'animation.repeat.infinite': 'Infinito',
441
+ 'animation.intensity': 'Intensidade',
442
+ 'animation.intensity.aria': 'Intensidade da animação',
443
+ 'animation.intensity.subtle': 'Sutil',
444
+ 'animation.intensity.normal': 'Normal',
445
+ 'animation.intensity.strong': 'Forte',
446
+ 'tooltip.group': 'Editor de tooltip',
447
+ 'tooltip.text': 'Texto',
448
+ 'tooltip.text.placeholder': 'Detalhes da célula',
449
+ 'tooltip.position': 'Posição',
450
+ 'tooltip.position.aria': 'Posição do tooltip',
451
+ 'tooltip.position.top': 'Topo',
452
+ 'tooltip.position.right': 'Direita',
453
+ 'tooltip.position.bottom': 'Baixo',
454
+ 'tooltip.position.left': 'Esquerda',
455
+ 'tooltip.backgroundColor': 'Cor do fundo',
456
+ 'tooltip.delay': 'Delay (ms)',
457
+ };
458
+
459
+ const PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE = 'praxisTableRuleBuilder';
460
+ const PRAXIS_TABLE_RULE_BUILDER_LABEL_KEYS = [
461
+ 'panel.title',
462
+ 'panel.subtitle',
463
+ 'tabs.estilo',
464
+ 'tabs.layout',
465
+ 'tabs.icone',
466
+ 'tabs.fundo',
467
+ 'tabs.animacao',
468
+ 'tabs.tooltip',
469
+ 'preview.title',
470
+ 'preview.hint',
471
+ 'advanced.title',
472
+ 'advanced.description',
473
+ 'actions.apply',
474
+ 'actions.reset',
475
+ 'presets.label',
476
+ 'presets.aprovado',
477
+ 'presets.alerta',
478
+ 'presets.erro',
479
+ 'presets.info',
480
+ 'tabs.ariaLabel',
481
+ 'preview.sampleText',
482
+ 'advanced.cssClass',
483
+ 'advanced.inlineStyle',
484
+ 'advanced.descriptionPlaceholder',
485
+ 'advanced.cssClassPlaceholder',
486
+ 'advanced.inlineStylePlaceholder',
487
+ ];
488
+ const PRAXIS_TABLE_RULE_BUILDER_I18N_CONFIG = {
489
+ namespaces: {
490
+ [PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE]: {
491
+ 'pt-BR': PRAXIS_TABLE_RULE_BUILDER_PT_BR,
492
+ 'en-US': PRAXIS_TABLE_RULE_BUILDER_EN_US,
493
+ },
494
+ },
495
+ };
496
+
237
497
  class EstiloEditorComponent {
498
+ i18n;
238
499
  group;
239
- // Public for template (strictTemplates): used by mat-slider
500
+ constructor(i18n) {
501
+ this.i18n = i18n;
502
+ }
503
+ tx(key, fallback) {
504
+ return this.i18n.t(key, undefined, fallback, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE);
505
+ }
506
+ // Public for template (strictTemplates): used by mat-slider.
240
507
  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 });
508
+ 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
509
  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">
510
+ <div class="estilo-grid" role="group" [attr.aria-label]="tx('style.group', 'Editor de estilo')" [formGroup]="group">
244
511
  <pdx-color-picker
245
- label="Cor do texto"
512
+ [label]="tx('style.textColor', 'Cor do texto')"
246
513
  formControlName="color"
247
514
  [format]="'hex'"
248
515
  [preview]="true"
@@ -253,7 +520,7 @@ class EstiloEditorComponent {
253
520
  ></pdx-color-picker>
254
521
 
255
522
  <pdx-color-picker
256
- label="Cor de fundo do texto"
523
+ [label]="tx('style.textBackgroundColor', 'Cor de fundo do texto')"
257
524
  formControlName="bgColor"
258
525
  [format]="'hex'"
259
526
  [preview]="true"
@@ -265,44 +532,44 @@ class EstiloEditorComponent {
265
532
 
266
533
  <div class="toggles">
267
534
  <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">
535
+ <mat-button-toggle [checked]="group.get('bold')?.value" (change)="group.get('bold')?.setValue($event.source.checked)" [attr.aria-label]="tx('style.bold', 'Negrito')">
269
536
  <mat-icon>format_bold</mat-icon>
270
537
  </mat-button-toggle>
271
- <mat-button-toggle [checked]="group.get('italic')?.value" (change)="group.get('italic')?.setValue($event.source.checked)" aria-label="Itálico">
538
+ <mat-button-toggle [checked]="group.get('italic')?.value" (change)="group.get('italic')?.setValue($event.source.checked)" [attr.aria-label]="tx('style.italic', 'Italico')">
272
539
  <mat-icon>format_italic</mat-icon>
273
540
  </mat-button-toggle>
274
- <mat-button-toggle [checked]="group.get('underline')?.value" (change)="group.get('underline')?.setValue($event.source.checked)" aria-label="Sublinhado">
541
+ <mat-button-toggle [checked]="group.get('underline')?.value" (change)="group.get('underline')?.setValue($event.source.checked)" [attr.aria-label]="tx('style.underline', 'Sublinhado')">
275
542
  <mat-icon>format_underlined</mat-icon>
276
543
  </mat-button-toggle>
277
544
  </mat-button-toggle-group>
278
545
  </div>
279
546
 
280
547
  <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>
548
+ <mat-label>{{ tx('style.transform', 'Transformacao') }}</mat-label>
549
+ <select matNativeControl formControlName="transform" [attr.aria-label]="tx('style.transformAria', 'Transformacao do texto')">
550
+ <option [ngValue]="null">{{ tx('style.transform.none', 'Nenhuma') }}</option>
551
+ <option value="uppercase">{{ tx('style.transform.uppercase', 'MAIUSCULAS') }}</option>
552
+ <option value="lowercase">{{ tx('style.transform.lowercase', 'minusculas') }}</option>
553
+ <option value="capitalize">{{ tx('style.transform.capitalize', 'Capitalizar') }}</option>
287
554
  </select>
288
555
  </mat-form-field>
289
556
 
290
557
  <div class="sliders">
291
558
  <label class="slider">
292
- <span>Opacidade</span>
559
+ <span>{{ tx('style.opacity', 'Opacidade') }}</span>
293
560
  <mat-slider min="0" max="1" step="0.05" [displayWith]="formatOpacity">
294
561
  <input matSliderThumb formControlName="opacity" />
295
562
  </mat-slider>
296
563
  </label>
297
564
  <label class="slider">
298
- <span>Tamanho</span>
565
+ <span>{{ tx('style.size', 'Tamanho') }}</span>
299
566
  <mat-slider min="-2" max="2" step="1">
300
567
  <input matSliderThumb formControlName="fontScale" />
301
568
  </mat-slider>
302
569
  </label>
303
570
  </div>
304
571
  </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 });
572
+ `, 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}.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
573
  }
307
574
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EstiloEditorComponent, decorators: [{
308
575
  type: Component,
@@ -313,11 +580,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
313
580
  MatButtonToggleModule,
314
581
  MatIconModule,
315
582
  MatSliderModule,
316
- PdxColorPickerComponent
583
+ PdxColorPickerComponent,
317
584
  ], template: `
318
- <div class="estilo-grid" role="group" aria-label="Editor de estilo" [formGroup]="group">
585
+ <div class="estilo-grid" role="group" [attr.aria-label]="tx('style.group', 'Editor de estilo')" [formGroup]="group">
319
586
  <pdx-color-picker
320
- label="Cor do texto"
587
+ [label]="tx('style.textColor', 'Cor do texto')"
321
588
  formControlName="color"
322
589
  [format]="'hex'"
323
590
  [preview]="true"
@@ -328,7 +595,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
328
595
  ></pdx-color-picker>
329
596
 
330
597
  <pdx-color-picker
331
- label="Cor de fundo do texto"
598
+ [label]="tx('style.textBackgroundColor', 'Cor de fundo do texto')"
332
599
  formControlName="bgColor"
333
600
  [format]="'hex'"
334
601
  [preview]="true"
@@ -340,56 +607,63 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
340
607
 
341
608
  <div class="toggles">
342
609
  <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">
610
+ <mat-button-toggle [checked]="group.get('bold')?.value" (change)="group.get('bold')?.setValue($event.source.checked)" [attr.aria-label]="tx('style.bold', 'Negrito')">
344
611
  <mat-icon>format_bold</mat-icon>
345
612
  </mat-button-toggle>
346
- <mat-button-toggle [checked]="group.get('italic')?.value" (change)="group.get('italic')?.setValue($event.source.checked)" aria-label="Itálico">
613
+ <mat-button-toggle [checked]="group.get('italic')?.value" (change)="group.get('italic')?.setValue($event.source.checked)" [attr.aria-label]="tx('style.italic', 'Italico')">
347
614
  <mat-icon>format_italic</mat-icon>
348
615
  </mat-button-toggle>
349
- <mat-button-toggle [checked]="group.get('underline')?.value" (change)="group.get('underline')?.setValue($event.source.checked)" aria-label="Sublinhado">
616
+ <mat-button-toggle [checked]="group.get('underline')?.value" (change)="group.get('underline')?.setValue($event.source.checked)" [attr.aria-label]="tx('style.underline', 'Sublinhado')">
350
617
  <mat-icon>format_underlined</mat-icon>
351
618
  </mat-button-toggle>
352
619
  </mat-button-toggle-group>
353
620
  </div>
354
621
 
355
622
  <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>
623
+ <mat-label>{{ tx('style.transform', 'Transformacao') }}</mat-label>
624
+ <select matNativeControl formControlName="transform" [attr.aria-label]="tx('style.transformAria', 'Transformacao do texto')">
625
+ <option [ngValue]="null">{{ tx('style.transform.none', 'Nenhuma') }}</option>
626
+ <option value="uppercase">{{ tx('style.transform.uppercase', 'MAIUSCULAS') }}</option>
627
+ <option value="lowercase">{{ tx('style.transform.lowercase', 'minusculas') }}</option>
628
+ <option value="capitalize">{{ tx('style.transform.capitalize', 'Capitalizar') }}</option>
362
629
  </select>
363
630
  </mat-form-field>
364
631
 
365
632
  <div class="sliders">
366
633
  <label class="slider">
367
- <span>Opacidade</span>
634
+ <span>{{ tx('style.opacity', 'Opacidade') }}</span>
368
635
  <mat-slider min="0" max="1" step="0.05" [displayWith]="formatOpacity">
369
636
  <input matSliderThumb formControlName="opacity" />
370
637
  </mat-slider>
371
638
  </label>
372
639
  <label class="slider">
373
- <span>Tamanho</span>
640
+ <span>{{ tx('style.size', 'Tamanho') }}</span>
374
641
  <mat-slider min="-2" max="2" step="1">
375
642
  <input matSliderThumb formControlName="fontScale" />
376
643
  </mat-slider>
377
644
  </label>
378
645
  </div>
379
646
  </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: [{
647
+ `, 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}.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"] }]
648
+ }], ctorParameters: () => [{ type: i1.PraxisI18nService }], propDecorators: { group: [{
382
649
  type: Input
383
650
  }] } });
384
651
 
385
652
  class LayoutEditorComponent {
653
+ i18n;
386
654
  group;
387
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: LayoutEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
655
+ constructor(i18n) {
656
+ this.i18n = i18n;
657
+ }
658
+ tx(key, fallback) {
659
+ return this.i18n.t(key, undefined, fallback, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE);
660
+ }
661
+ 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
662
  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">
663
+ <div class="layout-grid" role="group" [attr.aria-label]="tx('layout.group', 'Editor de layout')" [formGroup]="group">
390
664
  <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">
665
+ <span class="lbl">{{ tx('layout.border', 'Borda') }}</span>
666
+ <mat-button-toggle-group [value]="group.get('border')?.value" (change)="group.get('border')?.setValue($event.value)" [attr.aria-label]="tx('layout.border', 'Borda')">
393
667
  <mat-button-toggle value="none"><mat-icon>crop_free</mat-icon></mat-button-toggle>
394
668
  <mat-button-toggle value="left"><mat-icon>border_left</mat-icon></mat-button-toggle>
395
669
  <mat-button-toggle value="right"><mat-icon>border_right</mat-icon></mat-button-toggle>
@@ -400,21 +674,21 @@ class LayoutEditorComponent {
400
674
  </div>
401
675
 
402
676
  <mat-form-field appearance="outline">
403
- <mat-label>Cor da borda</mat-label>
677
+ <mat-label>{{ tx('layout.borderColor', 'Cor da borda') }}</mat-label>
404
678
  <input matInput type="text" formControlName="borderColor" placeholder="#487BFF" />
405
679
  </mat-form-field>
406
680
  <mat-form-field appearance="outline">
407
- <mat-label>Espessura</mat-label>
681
+ <mat-label>{{ tx('layout.borderWidth', 'Espessura') }}</mat-label>
408
682
  <input matInput type="number" formControlName="borderWidth" placeholder="2" />
409
683
  </mat-form-field>
410
684
  <mat-form-field appearance="outline">
411
- <mat-label>Padding</mat-label>
685
+ <mat-label>{{ tx('layout.padding', 'Padding') }}</mat-label>
412
686
  <input matInput type="number" formControlName="padding" placeholder="6" />
413
687
  </mat-form-field>
414
688
 
415
689
  <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">
690
+ <span class="lbl">{{ tx('layout.align', 'Alinhamento') }}</span>
691
+ <mat-button-toggle-group [value]="group.get('align')?.value" (change)="group.get('align')?.setValue($event.value)" [attr.aria-label]="tx('layout.align', 'Alinhamento')">
418
692
  <mat-button-toggle value="start"><mat-icon>format_align_left</mat-icon></mat-button-toggle>
419
693
  <mat-button-toggle value="center"><mat-icon>format_align_center</mat-icon></mat-button-toggle>
420
694
  <mat-button-toggle value="end"><mat-icon>format_align_right</mat-icon></mat-button-toggle>
@@ -422,19 +696,19 @@ class LayoutEditorComponent {
422
696
  </div>
423
697
 
424
698
  <mat-form-field appearance="outline">
425
- <mat-label>Elevação (sombra)</mat-label>
699
+ <mat-label>{{ tx('layout.elevation', 'Elevacao (sombra)') }}</mat-label>
426
700
  <input matInput type="number" formControlName="elevation" placeholder="6" />
427
701
  </mat-form-field>
428
702
  </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 });
703
+ `, 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
704
  }
431
705
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: LayoutEditorComponent, decorators: [{
432
706
  type: Component,
433
707
  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">
708
+ <div class="layout-grid" role="group" [attr.aria-label]="tx('layout.group', 'Editor de layout')" [formGroup]="group">
435
709
  <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">
710
+ <span class="lbl">{{ tx('layout.border', 'Borda') }}</span>
711
+ <mat-button-toggle-group [value]="group.get('border')?.value" (change)="group.get('border')?.setValue($event.value)" [attr.aria-label]="tx('layout.border', 'Borda')">
438
712
  <mat-button-toggle value="none"><mat-icon>crop_free</mat-icon></mat-button-toggle>
439
713
  <mat-button-toggle value="left"><mat-icon>border_left</mat-icon></mat-button-toggle>
440
714
  <mat-button-toggle value="right"><mat-icon>border_right</mat-icon></mat-button-toggle>
@@ -445,21 +719,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
445
719
  </div>
446
720
 
447
721
  <mat-form-field appearance="outline">
448
- <mat-label>Cor da borda</mat-label>
722
+ <mat-label>{{ tx('layout.borderColor', 'Cor da borda') }}</mat-label>
449
723
  <input matInput type="text" formControlName="borderColor" placeholder="#487BFF" />
450
724
  </mat-form-field>
451
725
  <mat-form-field appearance="outline">
452
- <mat-label>Espessura</mat-label>
726
+ <mat-label>{{ tx('layout.borderWidth', 'Espessura') }}</mat-label>
453
727
  <input matInput type="number" formControlName="borderWidth" placeholder="2" />
454
728
  </mat-form-field>
455
729
  <mat-form-field appearance="outline">
456
- <mat-label>Padding</mat-label>
730
+ <mat-label>{{ tx('layout.padding', 'Padding') }}</mat-label>
457
731
  <input matInput type="number" formControlName="padding" placeholder="6" />
458
732
  </mat-form-field>
459
733
 
460
734
  <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">
735
+ <span class="lbl">{{ tx('layout.align', 'Alinhamento') }}</span>
736
+ <mat-button-toggle-group [value]="group.get('align')?.value" (change)="group.get('align')?.setValue($event.value)" [attr.aria-label]="tx('layout.align', 'Alinhamento')">
463
737
  <mat-button-toggle value="start"><mat-icon>format_align_left</mat-icon></mat-button-toggle>
464
738
  <mat-button-toggle value="center"><mat-icon>format_align_center</mat-icon></mat-button-toggle>
465
739
  <mat-button-toggle value="end"><mat-icon>format_align_right</mat-icon></mat-button-toggle>
@@ -467,176 +741,197 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
467
741
  </div>
468
742
 
469
743
  <mat-form-field appearance="outline">
470
- <mat-label>Elevação (sombra)</mat-label>
744
+ <mat-label>{{ tx('layout.elevation', 'Elevacao (sombra)') }}</mat-label>
471
745
  <input matInput type="number" formControlName="elevation" placeholder="6" />
472
746
  </mat-form-field>
473
747
  </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: [{
748
+ `, 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"] }]
749
+ }], ctorParameters: () => [{ type: i1.PraxisI18nService }], propDecorators: { group: [{
476
750
  type: Input
477
751
  }] } });
478
752
 
479
753
  class IconeBadgeEditorComponent {
754
+ i18n;
480
755
  group;
481
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: IconeBadgeEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
756
+ constructor(i18n) {
757
+ this.i18n = i18n;
758
+ }
759
+ tx(key, fallback) {
760
+ return this.i18n.t(key, undefined, fallback, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE);
761
+ }
762
+ 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
763
  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">
764
+ <div class="icone-grid" role="group" [attr.aria-label]="tx('icon.group', 'Editor de icone e badge')" [formGroup]="group">
484
765
  <mat-form-field appearance="outline">
485
- <mat-label>Ícone (mat-icon)</mat-label>
766
+ <mat-label>{{ tx('icon.label', 'Icone (mat-icon)') }}</mat-label>
486
767
  <input matInput type="text" formControlName="icon" placeholder="check_circle" />
487
768
  </mat-form-field>
488
769
  <mat-form-field appearance="outline">
489
- <mat-label>Cor do ícone</mat-label>
770
+ <mat-label>{{ tx('icon.color', 'Cor do icone') }}</mat-label>
490
771
  <input matInput type="text" formControlName="iconColor" placeholder="#35D07F" />
491
772
  </mat-form-field>
492
773
 
493
774
  <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>
775
+ <span class="lbl">{{ tx('icon.position', 'Posicao do icone') }}</span>
776
+ <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')">
777
+ <mat-button-toggle value="before">{{ tx('icon.position.before', 'Antes') }}</mat-button-toggle>
778
+ <mat-button-toggle value="after">{{ tx('icon.position.after', 'Depois') }}</mat-button-toggle>
779
+ <mat-button-toggle value="overlay">{{ tx('icon.position.overlay', 'Sobreposto') }}</mat-button-toggle>
499
780
  </mat-button-toggle-group>
500
781
  </div>
501
782
 
502
783
  <mat-form-field appearance="outline">
503
- <mat-label>Texto do badge</mat-label>
784
+ <mat-label>{{ tx('badge.text', 'Texto do badge') }}</mat-label>
504
785
  <input matInput type="text" formControlName="badgeText" placeholder="Aprovado" />
505
786
  </mat-form-field>
506
787
  <mat-form-field appearance="outline">
507
- <mat-label>Cor do badge</mat-label>
788
+ <mat-label>{{ tx('badge.color', 'Cor do badge') }}</mat-label>
508
789
  <input matInput type="text" formControlName="badgeColor" placeholder="#2a8455" />
509
790
  </mat-form-field>
510
791
 
511
792
  <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>
793
+ <span class="lbl">{{ tx('badge.style', 'Estilo') }}</span>
794
+ <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')">
795
+ <mat-button-toggle value="solid">{{ tx('badge.style.solid', 'Solido') }}</mat-button-toggle>
796
+ <mat-button-toggle value="soft">{{ tx('badge.style.soft', 'Suave') }}</mat-button-toggle>
797
+ <mat-button-toggle value="outline">{{ tx('badge.style.outline', 'Contorno') }}</mat-button-toggle>
517
798
  </mat-button-toggle-group>
518
799
  </div>
519
800
  </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 });
801
+ `, 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
802
  }
522
803
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: IconeBadgeEditorComponent, decorators: [{
523
804
  type: Component,
524
805
  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">
806
+ <div class="icone-grid" role="group" [attr.aria-label]="tx('icon.group', 'Editor de icone e badge')" [formGroup]="group">
526
807
  <mat-form-field appearance="outline">
527
- <mat-label>Ícone (mat-icon)</mat-label>
808
+ <mat-label>{{ tx('icon.label', 'Icone (mat-icon)') }}</mat-label>
528
809
  <input matInput type="text" formControlName="icon" placeholder="check_circle" />
529
810
  </mat-form-field>
530
811
  <mat-form-field appearance="outline">
531
- <mat-label>Cor do ícone</mat-label>
812
+ <mat-label>{{ tx('icon.color', 'Cor do icone') }}</mat-label>
532
813
  <input matInput type="text" formControlName="iconColor" placeholder="#35D07F" />
533
814
  </mat-form-field>
534
815
 
535
816
  <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>
817
+ <span class="lbl">{{ tx('icon.position', 'Posicao do icone') }}</span>
818
+ <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')">
819
+ <mat-button-toggle value="before">{{ tx('icon.position.before', 'Antes') }}</mat-button-toggle>
820
+ <mat-button-toggle value="after">{{ tx('icon.position.after', 'Depois') }}</mat-button-toggle>
821
+ <mat-button-toggle value="overlay">{{ tx('icon.position.overlay', 'Sobreposto') }}</mat-button-toggle>
541
822
  </mat-button-toggle-group>
542
823
  </div>
543
824
 
544
825
  <mat-form-field appearance="outline">
545
- <mat-label>Texto do badge</mat-label>
826
+ <mat-label>{{ tx('badge.text', 'Texto do badge') }}</mat-label>
546
827
  <input matInput type="text" formControlName="badgeText" placeholder="Aprovado" />
547
828
  </mat-form-field>
548
829
  <mat-form-field appearance="outline">
549
- <mat-label>Cor do badge</mat-label>
830
+ <mat-label>{{ tx('badge.color', 'Cor do badge') }}</mat-label>
550
831
  <input matInput type="text" formControlName="badgeColor" placeholder="#2a8455" />
551
832
  </mat-form-field>
552
833
 
553
834
  <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>
835
+ <span class="lbl">{{ tx('badge.style', 'Estilo') }}</span>
836
+ <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')">
837
+ <mat-button-toggle value="solid">{{ tx('badge.style.solid', 'Solido') }}</mat-button-toggle>
838
+ <mat-button-toggle value="soft">{{ tx('badge.style.soft', 'Suave') }}</mat-button-toggle>
839
+ <mat-button-toggle value="outline">{{ tx('badge.style.outline', 'Contorno') }}</mat-button-toggle>
559
840
  </mat-button-toggle-group>
560
841
  </div>
561
842
  </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: [{
843
+ `, 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"] }]
844
+ }], ctorParameters: () => [{ type: i1.PraxisI18nService }], propDecorators: { group: [{
564
845
  type: Input
565
846
  }] } });
566
847
 
567
848
  class FundoEditorComponent {
849
+ i18n;
568
850
  group;
569
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FundoEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
851
+ constructor(i18n) {
852
+ this.i18n = i18n;
853
+ }
854
+ tx(key, fallback) {
855
+ return this.i18n.t(key, undefined, fallback, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE);
856
+ }
857
+ 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
858
  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">
859
+ <div class="fundo-grid" role="group" [attr.aria-label]="tx('background.group', 'Editor de fundo')" [formGroup]="group">
572
860
  <mat-form-field appearance="outline">
573
- <mat-label>Cor</mat-label>
861
+ <mat-label>{{ tx('background.color', 'Cor') }}</mat-label>
574
862
  <input matInput type="text" formControlName="color" placeholder="#122033" />
575
863
  </mat-form-field>
576
864
  <mat-form-field appearance="outline" class="full">
577
- <mat-label>Gradient CSS</mat-label>
865
+ <mat-label>{{ tx('background.gradient', 'Gradient CSS') }}</mat-label>
578
866
  <input matInput type="text" formControlName="gradient" placeholder="linear-gradient(180deg, #202637, #1c2230)" />
579
867
  </mat-form-field>
580
868
 
581
869
  <label class="slider">
582
- <span>Transparência</span>
870
+ <span>{{ tx('background.alpha', 'Transparencia') }}</span>
583
871
  <mat-slider min="0" max="100" step="5">
584
872
  <input matSliderThumb formControlName="alpha" />
585
873
  </mat-slider>
586
874
  </label>
587
875
  <label class="slider">
588
- <span>Desfoque (px)</span>
876
+ <span>{{ tx('background.blur', 'Desfoque (px)') }}</span>
589
877
  <mat-slider min="0" max="20" step="1">
590
878
  <input matSliderThumb formControlName="blur" />
591
879
  </mat-slider>
592
880
  </label>
593
881
  </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 });
882
+ `, 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
883
  }
596
884
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FundoEditorComponent, decorators: [{
597
885
  type: Component,
598
886
  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">
887
+ <div class="fundo-grid" role="group" [attr.aria-label]="tx('background.group', 'Editor de fundo')" [formGroup]="group">
600
888
  <mat-form-field appearance="outline">
601
- <mat-label>Cor</mat-label>
889
+ <mat-label>{{ tx('background.color', 'Cor') }}</mat-label>
602
890
  <input matInput type="text" formControlName="color" placeholder="#122033" />
603
891
  </mat-form-field>
604
892
  <mat-form-field appearance="outline" class="full">
605
- <mat-label>Gradient CSS</mat-label>
893
+ <mat-label>{{ tx('background.gradient', 'Gradient CSS') }}</mat-label>
606
894
  <input matInput type="text" formControlName="gradient" placeholder="linear-gradient(180deg, #202637, #1c2230)" />
607
895
  </mat-form-field>
608
896
 
609
897
  <label class="slider">
610
- <span>Transparência</span>
898
+ <span>{{ tx('background.alpha', 'Transparencia') }}</span>
611
899
  <mat-slider min="0" max="100" step="5">
612
900
  <input matSliderThumb formControlName="alpha" />
613
901
  </mat-slider>
614
902
  </label>
615
903
  <label class="slider">
616
- <span>Desfoque (px)</span>
904
+ <span>{{ tx('background.blur', 'Desfoque (px)') }}</span>
617
905
  <mat-slider min="0" max="20" step="1">
618
906
  <input matSliderThumb formControlName="blur" />
619
907
  </mat-slider>
620
908
  </label>
621
909
  </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: [{
910
+ `, 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"] }]
911
+ }], ctorParameters: () => [{ type: i1.PraxisI18nService }], propDecorators: { group: [{
624
912
  type: Input
625
913
  }] } });
626
914
 
627
915
  class AnimacaoEditorComponent {
916
+ i18n;
628
917
  group;
629
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AnimacaoEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
918
+ constructor(i18n) {
919
+ this.i18n = i18n;
920
+ }
921
+ tx(key, fallback) {
922
+ return this.i18n.t(key, undefined, fallback, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE);
923
+ }
924
+ 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
925
  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">
926
+ <div class="anim-grid" role="group" [attr.aria-label]="tx('animation.group', 'Editor de animacao')" [formGroup]="group">
632
927
  <label class="anim-toggle">
633
928
  <input type="checkbox" formControlName="enabled" />
634
- <span>Ativar animação</span>
929
+ <span>{{ tx('animation.enabled', 'Ativar animacao') }}</span>
635
930
  </label>
636
931
  <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>
932
+ <mat-label>{{ tx('animation.preset', 'Preset') }}</mat-label>
933
+ <select matNativeControl formControlName="preset" [attr.aria-label]="tx('animation.preset.aria', 'Preset de animacao')">
934
+ <option value="">{{ tx('animation.preset.none', 'Sem preset') }}</option>
640
935
  <option value="info-soft">Info Soft</option>
641
936
  <option value="success-confirm">Success Confirm</option>
642
937
  <option value="warning-attention">Warning Attention</option>
@@ -652,9 +947,9 @@ class AnimacaoEditorComponent {
652
947
  </select>
653
948
  </mat-form-field>
654
949
  <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>
950
+ <mat-label>{{ tx('animation.type', 'Tipo') }}</mat-label>
951
+ <select matNativeControl formControlName="type" [attr.aria-label]="tx('animation.type.aria', 'Tipo de animacao')">
952
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
658
953
  <option value="pulse">Pulse</option>
659
954
  <option value="blink">Blink</option>
660
955
  <option value="grow">Grow</option>
@@ -664,58 +959,58 @@ class AnimacaoEditorComponent {
664
959
  </select>
665
960
  </mat-form-field>
666
961
  <mat-form-field appearance="outline">
667
- <mat-label>Duração (ms)</mat-label>
668
- <input matInput type="number" formControlName="durationMs" placeholder="Preset/default" />
962
+ <mat-label>{{ tx('animation.duration', 'Duracao (ms)') }}</mat-label>
963
+ <input matInput type="number" formControlName="durationMs" [placeholder]="tx('animation.duration.placeholder', 'Preset/default')" />
669
964
  </mat-form-field>
670
965
  <mat-form-field appearance="outline">
671
- <mat-label>Delay (ms)</mat-label>
672
- <input matInput type="number" formControlName="delayMs" placeholder="Opcional" />
966
+ <mat-label>{{ tx('animation.delay', 'Delay (ms)') }}</mat-label>
967
+ <input matInput type="number" formControlName="delayMs" [placeholder]="tx('animation.delay.placeholder', 'Opcional')" />
673
968
  </mat-form-field>
674
969
  <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>
970
+ <mat-label>{{ tx('animation.trigger', 'Disparo') }}</mat-label>
971
+ <select matNativeControl formControlName="trigger" [attr.aria-label]="tx('animation.trigger.aria', 'Disparo da animacao')">
972
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
973
+ <option value="onChange">{{ tx('animation.trigger.onChange', 'Ao mudar') }}</option>
974
+ <option value="onAppear">{{ tx('animation.trigger.onAppear', 'Ao aparecer') }}</option>
975
+ <option value="onHover">{{ tx('animation.trigger.onHover', 'Ao passar o mouse') }}</option>
976
+ <option value="onConditionEnter">{{ tx('animation.trigger.onConditionEnter', 'Ao entrar na condicao') }}</option>
977
+ <option value="onConditionExit">{{ tx('animation.trigger.onConditionExit', 'Ao sair da condicao') }}</option>
978
+ <option value="onDataRefresh">{{ tx('animation.trigger.onDataRefresh', 'Ao atualizar dados') }}</option>
684
979
  </select>
685
980
  </mat-form-field>
686
981
  <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>
982
+ <mat-label>{{ tx('animation.repeat', 'Repeticao') }}</mat-label>
983
+ <select matNativeControl formControlName="repeat" [attr.aria-label]="tx('animation.repeat.aria', 'Repeticao da animacao')">
984
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
985
+ <option value="once">{{ tx('animation.repeat.once', 'Uma vez') }}</option>
986
+ <option value="loop">{{ tx('animation.repeat.loop', 'Loop') }}</option>
987
+ <option value="infinite">{{ tx('animation.repeat.infinite', 'Infinito') }}</option>
693
988
  </select>
694
989
  </mat-form-field>
695
990
  <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>
991
+ <mat-label>{{ tx('animation.intensity', 'Intensidade') }}</mat-label>
992
+ <select matNativeControl formControlName="intensity" [attr.aria-label]="tx('animation.intensity.aria', 'Intensidade da animacao')">
993
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
994
+ <option value="subtle">{{ tx('animation.intensity.subtle', 'Sutil') }}</option>
995
+ <option value="normal">{{ tx('animation.intensity.normal', 'Normal') }}</option>
996
+ <option value="strong">{{ tx('animation.intensity.strong', 'Forte') }}</option>
702
997
  </select>
703
998
  </mat-form-field>
704
999
  </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 });
1000
+ `, 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
1001
  }
707
1002
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AnimacaoEditorComponent, decorators: [{
708
1003
  type: Component,
709
1004
  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">
1005
+ <div class="anim-grid" role="group" [attr.aria-label]="tx('animation.group', 'Editor de animacao')" [formGroup]="group">
711
1006
  <label class="anim-toggle">
712
1007
  <input type="checkbox" formControlName="enabled" />
713
- <span>Ativar animação</span>
1008
+ <span>{{ tx('animation.enabled', 'Ativar animacao') }}</span>
714
1009
  </label>
715
1010
  <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>
1011
+ <mat-label>{{ tx('animation.preset', 'Preset') }}</mat-label>
1012
+ <select matNativeControl formControlName="preset" [attr.aria-label]="tx('animation.preset.aria', 'Preset de animacao')">
1013
+ <option value="">{{ tx('animation.preset.none', 'Sem preset') }}</option>
719
1014
  <option value="info-soft">Info Soft</option>
720
1015
  <option value="success-confirm">Success Confirm</option>
721
1016
  <option value="warning-attention">Warning Attention</option>
@@ -731,9 +1026,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
731
1026
  </select>
732
1027
  </mat-form-field>
733
1028
  <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>
1029
+ <mat-label>{{ tx('animation.type', 'Tipo') }}</mat-label>
1030
+ <select matNativeControl formControlName="type" [attr.aria-label]="tx('animation.type.aria', 'Tipo de animacao')">
1031
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
737
1032
  <option value="pulse">Pulse</option>
738
1033
  <option value="blink">Blink</option>
739
1034
  <option value="grow">Grow</option>
@@ -743,106 +1038,113 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
743
1038
  </select>
744
1039
  </mat-form-field>
745
1040
  <mat-form-field appearance="outline">
746
- <mat-label>Duração (ms)</mat-label>
747
- <input matInput type="number" formControlName="durationMs" placeholder="Preset/default" />
1041
+ <mat-label>{{ tx('animation.duration', 'Duracao (ms)') }}</mat-label>
1042
+ <input matInput type="number" formControlName="durationMs" [placeholder]="tx('animation.duration.placeholder', 'Preset/default')" />
748
1043
  </mat-form-field>
749
1044
  <mat-form-field appearance="outline">
750
- <mat-label>Delay (ms)</mat-label>
751
- <input matInput type="number" formControlName="delayMs" placeholder="Opcional" />
1045
+ <mat-label>{{ tx('animation.delay', 'Delay (ms)') }}</mat-label>
1046
+ <input matInput type="number" formControlName="delayMs" [placeholder]="tx('animation.delay.placeholder', 'Opcional')" />
752
1047
  </mat-form-field>
753
1048
  <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>
1049
+ <mat-label>{{ tx('animation.trigger', 'Disparo') }}</mat-label>
1050
+ <select matNativeControl formControlName="trigger" [attr.aria-label]="tx('animation.trigger.aria', 'Disparo da animacao')">
1051
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
1052
+ <option value="onChange">{{ tx('animation.trigger.onChange', 'Ao mudar') }}</option>
1053
+ <option value="onAppear">{{ tx('animation.trigger.onAppear', 'Ao aparecer') }}</option>
1054
+ <option value="onHover">{{ tx('animation.trigger.onHover', 'Ao passar o mouse') }}</option>
1055
+ <option value="onConditionEnter">{{ tx('animation.trigger.onConditionEnter', 'Ao entrar na condicao') }}</option>
1056
+ <option value="onConditionExit">{{ tx('animation.trigger.onConditionExit', 'Ao sair da condicao') }}</option>
1057
+ <option value="onDataRefresh">{{ tx('animation.trigger.onDataRefresh', 'Ao atualizar dados') }}</option>
763
1058
  </select>
764
1059
  </mat-form-field>
765
1060
  <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>
1061
+ <mat-label>{{ tx('animation.repeat', 'Repeticao') }}</mat-label>
1062
+ <select matNativeControl formControlName="repeat" [attr.aria-label]="tx('animation.repeat.aria', 'Repeticao da animacao')">
1063
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
1064
+ <option value="once">{{ tx('animation.repeat.once', 'Uma vez') }}</option>
1065
+ <option value="loop">{{ tx('animation.repeat.loop', 'Loop') }}</option>
1066
+ <option value="infinite">{{ tx('animation.repeat.infinite', 'Infinito') }}</option>
772
1067
  </select>
773
1068
  </mat-form-field>
774
1069
  <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>
1070
+ <mat-label>{{ tx('animation.intensity', 'Intensidade') }}</mat-label>
1071
+ <select matNativeControl formControlName="intensity" [attr.aria-label]="tx('animation.intensity.aria', 'Intensidade da animacao')">
1072
+ <option value="">{{ tx('animation.defaultFromPreset', 'Padrao do preset') }}</option>
1073
+ <option value="subtle">{{ tx('animation.intensity.subtle', 'Sutil') }}</option>
1074
+ <option value="normal">{{ tx('animation.intensity.normal', 'Normal') }}</option>
1075
+ <option value="strong">{{ tx('animation.intensity.strong', 'Forte') }}</option>
781
1076
  </select>
782
1077
  </mat-form-field>
783
1078
  </div>
784
1079
  `, 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: [{
1080
+ }], ctorParameters: () => [{ type: i1.PraxisI18nService }], propDecorators: { group: [{
786
1081
  type: Input
787
1082
  }] } });
788
1083
 
789
1084
  class TooltipEditorComponent {
1085
+ i18n;
790
1086
  group;
791
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TooltipEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1087
+ constructor(i18n) {
1088
+ this.i18n = i18n;
1089
+ }
1090
+ tx(key, fallback) {
1091
+ return this.i18n.t(key, undefined, fallback, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE);
1092
+ }
1093
+ 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
1094
  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">
1095
+ <div class="tooltip-grid" role="group" [attr.aria-label]="tx('tooltip.group', 'Editor de tooltip')" [formGroup]="group">
794
1096
  <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" />
1097
+ <mat-label>{{ tx('tooltip.text', 'Texto') }}</mat-label>
1098
+ <input matInput type="text" formControlName="text" [placeholder]="tx('tooltip.text.placeholder', 'Detalhes da celula')" />
797
1099
  </mat-form-field>
798
1100
  <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>
1101
+ <mat-label>{{ tx('tooltip.position', 'Posicao') }}</mat-label>
1102
+ <select matNativeControl formControlName="position" [attr.aria-label]="tx('tooltip.position.aria', 'Posicao do tooltip')">
1103
+ <option value="top">{{ tx('tooltip.position.top', 'Topo') }}</option>
1104
+ <option value="right">{{ tx('tooltip.position.right', 'Direita') }}</option>
1105
+ <option value="bottom">{{ tx('tooltip.position.bottom', 'Baixo') }}</option>
1106
+ <option value="left">{{ tx('tooltip.position.left', 'Esquerda') }}</option>
805
1107
  </select>
806
1108
  </mat-form-field>
807
1109
  <mat-form-field appearance="outline">
808
- <mat-label>Cor do fundo</mat-label>
1110
+ <mat-label>{{ tx('tooltip.backgroundColor', 'Cor do fundo') }}</mat-label>
809
1111
  <input matInput type="text" formControlName="bgColor" placeholder="#2E3142" />
810
1112
  </mat-form-field>
811
1113
  <mat-form-field appearance="outline">
812
- <mat-label>Delay (ms)</mat-label>
1114
+ <mat-label>{{ tx('tooltip.delay', 'Delay (ms)') }}</mat-label>
813
1115
  <input matInput type="number" formControlName="delayMs" placeholder="300" />
814
1116
  </mat-form-field>
815
1117
  </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 });
1118
+ `, 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
1119
  }
818
1120
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TooltipEditorComponent, decorators: [{
819
1121
  type: Component,
820
1122
  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">
1123
+ <div class="tooltip-grid" role="group" [attr.aria-label]="tx('tooltip.group', 'Editor de tooltip')" [formGroup]="group">
822
1124
  <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" />
1125
+ <mat-label>{{ tx('tooltip.text', 'Texto') }}</mat-label>
1126
+ <input matInput type="text" formControlName="text" [placeholder]="tx('tooltip.text.placeholder', 'Detalhes da celula')" />
825
1127
  </mat-form-field>
826
1128
  <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>
1129
+ <mat-label>{{ tx('tooltip.position', 'Posicao') }}</mat-label>
1130
+ <select matNativeControl formControlName="position" [attr.aria-label]="tx('tooltip.position.aria', 'Posicao do tooltip')">
1131
+ <option value="top">{{ tx('tooltip.position.top', 'Topo') }}</option>
1132
+ <option value="right">{{ tx('tooltip.position.right', 'Direita') }}</option>
1133
+ <option value="bottom">{{ tx('tooltip.position.bottom', 'Baixo') }}</option>
1134
+ <option value="left">{{ tx('tooltip.position.left', 'Esquerda') }}</option>
833
1135
  </select>
834
1136
  </mat-form-field>
835
1137
  <mat-form-field appearance="outline">
836
- <mat-label>Cor do fundo</mat-label>
1138
+ <mat-label>{{ tx('tooltip.backgroundColor', 'Cor do fundo') }}</mat-label>
837
1139
  <input matInput type="text" formControlName="bgColor" placeholder="#2E3142" />
838
1140
  </mat-form-field>
839
1141
  <mat-form-field appearance="outline">
840
- <mat-label>Delay (ms)</mat-label>
1142
+ <mat-label>{{ tx('tooltip.delay', 'Delay (ms)') }}</mat-label>
841
1143
  <input matInput type="number" formControlName="delayMs" placeholder="300" />
842
1144
  </mat-form-field>
843
1145
  </div>
844
1146
  `, 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: [{
1147
+ }], ctorParameters: () => [{ type: i1.PraxisI18nService }], propDecorators: { group: [{
846
1148
  type: Input
847
1149
  }] } });
848
1150
 
@@ -868,6 +1170,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
868
1170
  class RuleEffectsPanelComponent {
869
1171
  fb;
870
1172
  registry;
1173
+ i18n;
1174
+ static DEFAULT_ESTILO_FORM_VALUE = {
1175
+ color: '#ffffff',
1176
+ bgColor: '',
1177
+ bold: false,
1178
+ italic: false,
1179
+ underline: false,
1180
+ transform: null,
1181
+ opacity: 1,
1182
+ fontScale: 0,
1183
+ };
1184
+ static DEFAULT_LAYOUT_FORM_VALUE = {
1185
+ border: 'none',
1186
+ borderColor: '#487BFF',
1187
+ borderWidth: 2,
1188
+ padding: 6,
1189
+ align: 'start',
1190
+ elevation: 6,
1191
+ };
1192
+ static DEFAULT_ICON_BADGE_FORM_VALUE = {
1193
+ icon: 'check_circle',
1194
+ iconColor: '#35D07F',
1195
+ iconPos: 'before',
1196
+ badgeText: '',
1197
+ badgeStyle: 'soft',
1198
+ badgeColor: '#2a8455',
1199
+ };
1200
+ static DEFAULT_BACKGROUND_FORM_VALUE = {
1201
+ color: '#122033',
1202
+ gradient: '',
1203
+ alpha: 0,
1204
+ blur: 0,
1205
+ };
871
1206
  static DEFAULT_ANIMATION_FORM_VALUE = {
872
1207
  enabled: true,
873
1208
  preset: '',
@@ -878,25 +1213,27 @@ class RuleEffectsPanelComponent {
878
1213
  delayMs: null,
879
1214
  intensity: '',
880
1215
  };
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',
1216
+ static DEFAULT_TOOLTIP_FORM_VALUE = {
1217
+ text: '',
1218
+ position: 'bottom',
1219
+ bgColor: '#2E3142',
1220
+ delayMs: 300,
898
1221
  };
899
- t(key) { return this.labels[key] ?? key; }
1222
+ _labelOverrides = {};
1223
+ // Host-specific overrides take precedence over the component i18n catalog.
1224
+ set labels(value) {
1225
+ this._labelOverrides = { ...(value ?? {}) };
1226
+ }
1227
+ get labels() {
1228
+ return PRAXIS_TABLE_RULE_BUILDER_LABEL_KEYS.reduce((acc, key) => {
1229
+ acc[key] = this.t(key);
1230
+ return acc;
1231
+ }, {});
1232
+ }
1233
+ t(key) {
1234
+ return this._labelOverrides[key]
1235
+ ?? this.i18n.t(key, undefined, key, PRAXIS_TABLE_RULE_BUILDER_I18N_NAMESPACE);
1236
+ }
900
1237
  scope = 'row';
901
1238
  _value;
902
1239
  set value(v) {
@@ -913,9 +1250,10 @@ class RuleEffectsPanelComponent {
913
1250
  destroy$ = new Subject();
914
1251
  isHovering = false;
915
1252
  tabOrder = ['estilo', 'layout', 'icone', 'fundo', 'animacao', 'tooltip'];
916
- constructor(fb, registry) {
1253
+ constructor(fb, registry, i18n) {
917
1254
  this.fb = fb;
918
1255
  this.registry = registry;
1256
+ this.i18n = i18n;
919
1257
  }
920
1258
  ngOnInit() {
921
1259
  // Register built-in editors for the registry (extensible)
@@ -928,36 +1266,36 @@ class RuleEffectsPanelComponent {
928
1266
  this.effectsForm = this.fb.group({
929
1267
  description: [''],
930
1268
  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],
1269
+ color: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.color],
1270
+ bgColor: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.bgColor],
1271
+ bold: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.bold],
1272
+ italic: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.italic],
1273
+ underline: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.underline],
1274
+ transform: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.transform],
1275
+ opacity: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.opacity],
1276
+ fontScale: [RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.fontScale],
939
1277
  }),
940
1278
  layout: this.fb.group({
941
- border: ['none'],
942
- borderColor: ['#487BFF'],
943
- borderWidth: [2],
944
- padding: [6],
945
- align: ['start'],
946
- elevation: [6],
1279
+ border: [RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.border],
1280
+ borderColor: [RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.borderColor],
1281
+ borderWidth: [RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.borderWidth],
1282
+ padding: [RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.padding],
1283
+ align: [RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.align],
1284
+ elevation: [RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.elevation],
947
1285
  }),
948
1286
  iconBadge: this.fb.group({
949
- icon: ['check_circle'],
950
- iconColor: ['#35D07F'],
951
- iconPos: ['before'],
952
- badgeText: [''],
953
- badgeStyle: ['soft'],
954
- badgeColor: ['#2a8455'],
1287
+ icon: [RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.icon],
1288
+ iconColor: [RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.iconColor],
1289
+ iconPos: [RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.iconPos],
1290
+ badgeText: [RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.badgeText],
1291
+ badgeStyle: [RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.badgeStyle],
1292
+ badgeColor: [RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.badgeColor],
955
1293
  }),
956
1294
  background: this.fb.group({
957
- color: ['#122033'],
958
- gradient: [''],
959
- alpha: [0],
960
- blur: [0],
1295
+ color: [RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.color],
1296
+ gradient: [RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.gradient],
1297
+ alpha: [RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.alpha],
1298
+ blur: [RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.blur],
961
1299
  }),
962
1300
  animation: this.fb.group({
963
1301
  enabled: [RuleEffectsPanelComponent.DEFAULT_ANIMATION_FORM_VALUE.enabled],
@@ -970,10 +1308,10 @@ class RuleEffectsPanelComponent {
970
1308
  intensity: [RuleEffectsPanelComponent.DEFAULT_ANIMATION_FORM_VALUE.intensity],
971
1309
  }),
972
1310
  tooltip: this.fb.group({
973
- text: [''],
974
- position: ['bottom'],
975
- bgColor: ['#2E3142'],
976
- delayMs: [300],
1311
+ text: [RuleEffectsPanelComponent.DEFAULT_TOOLTIP_FORM_VALUE.text],
1312
+ position: [RuleEffectsPanelComponent.DEFAULT_TOOLTIP_FORM_VALUE.position],
1313
+ bgColor: [RuleEffectsPanelComponent.DEFAULT_TOOLTIP_FORM_VALUE.bgColor],
1314
+ delayMs: [RuleEffectsPanelComponent.DEFAULT_TOOLTIP_FORM_VALUE.delayMs],
977
1315
  }),
978
1316
  cssClass: [''],
979
1317
  inlineStyle: [''],
@@ -987,10 +1325,7 @@ class RuleEffectsPanelComponent {
987
1325
  this.patchForm(this._value);
988
1326
  }
989
1327
  patchForm(v) {
990
- const animationGroup = this.effectsForm.get('animation');
991
- if (animationGroup) {
992
- animationGroup.reset(RuleEffectsPanelComponent.DEFAULT_ANIMATION_FORM_VALUE, { emitEvent: false });
993
- }
1328
+ this.effectsForm.reset(this.createDefaultFormValue(), { emitEvent: false });
994
1329
  this.effectsForm.patchValue(v, { emitEvent: false });
995
1330
  }
996
1331
  setTab(tab) {
@@ -1008,7 +1343,7 @@ class RuleEffectsPanelComponent {
1008
1343
  this.apply.emit();
1009
1344
  }
1010
1345
  onReset() {
1011
- this.effectsForm.reset();
1346
+ this.effectsForm.reset(this.createDefaultFormValue());
1012
1347
  this.reset.emit();
1013
1348
  }
1014
1349
  ngOnDestroy() {
@@ -1063,9 +1398,17 @@ class RuleEffectsPanelComponent {
1063
1398
  computeCellStyle(v) {
1064
1399
  const b = v?.background || {};
1065
1400
  const ly = v?.layout || {};
1066
- const bg = b.gradient ? b.gradient : (b.color || 'transparent');
1401
+ const estilo = v?.estilo || {};
1402
+ const backgroundColor = this.nonEmptyString(b.color);
1403
+ const gradient = this.nonEmptyString(b.gradient);
1404
+ const textBackgroundColor = this.nonEmptyString(estilo.bgColor);
1405
+ const hasDeliberateBackgroundColor = backgroundColor
1406
+ && backgroundColor !== RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.color;
1407
+ const bg = gradient || (hasDeliberateBackgroundColor ? backgroundColor : textBackgroundColor) || 'transparent';
1067
1408
  const alpha = (b.alpha ?? 0) / 100;
1068
- const bgWithAlpha = b.color ? `color-mix(in srgb, ${b.color} ${100 - alpha * 100}%, transparent)` : bg;
1409
+ const bgWithAlpha = hasDeliberateBackgroundColor
1410
+ ? `color-mix(in srgb, ${backgroundColor} ${100 - alpha * 100}%, transparent)`
1411
+ : bg;
1069
1412
  const borderColor = ly.borderColor || 'transparent';
1070
1413
  const borderWidth = (ly.borderWidth ?? 0) + 'px';
1071
1414
  const borderStyle = ly.border === 'none' ? 'none' : `${borderWidth} solid ${borderColor}`;
@@ -1157,16 +1500,156 @@ class RuleEffectsPanelComponent {
1157
1500
  return s?.badgeStyle === 'outline' ? s.badgeColor || '#777' : '#0000';
1158
1501
  }
1159
1502
  toEffectDefinitionForEmit(formValue) {
1160
- const value = { scope: this.scope, ...(formValue || {}) };
1503
+ const value = { scope: this.scope };
1504
+ const raw = formValue || {};
1505
+ const description = this.nonEmptyString(raw.description);
1506
+ if (description)
1507
+ value.description = description;
1508
+ const estilo = raw.estilo || {};
1509
+ const normalizedEstilo = {};
1510
+ const color = this.nonEmptyString(estilo.color);
1511
+ const bgColor = this.nonEmptyString(estilo.bgColor);
1512
+ const transform = this.nonEmptyString(estilo.transform);
1513
+ if (color && color !== RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE.color)
1514
+ normalizedEstilo.color = color;
1515
+ if (bgColor)
1516
+ normalizedEstilo.bgColor = bgColor;
1517
+ if (estilo.bold === true)
1518
+ normalizedEstilo.bold = true;
1519
+ if (estilo.italic === true)
1520
+ normalizedEstilo.italic = true;
1521
+ if (estilo.underline === true)
1522
+ normalizedEstilo.underline = true;
1523
+ if (transform)
1524
+ normalizedEstilo.transform = transform;
1525
+ const opacity = this.toFiniteNumber(estilo.opacity);
1526
+ if (opacity !== undefined && opacity !== 1)
1527
+ normalizedEstilo.opacity = opacity;
1528
+ const fontScale = this.toFiniteNumber(estilo.fontScale);
1529
+ if (fontScale !== undefined && fontScale !== 0)
1530
+ normalizedEstilo.fontScale = fontScale;
1531
+ if (Object.keys(normalizedEstilo).length)
1532
+ value.estilo = normalizedEstilo;
1533
+ const layout = raw.layout || {};
1534
+ const normalizedLayout = {};
1535
+ const border = this.nonEmptyString(layout.border);
1536
+ const borderColor = this.nonEmptyString(layout.borderColor);
1537
+ const align = this.nonEmptyString(layout.align);
1538
+ if (border && border !== RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.border) {
1539
+ normalizedLayout.border = border;
1540
+ if (borderColor)
1541
+ normalizedLayout.borderColor = borderColor;
1542
+ const borderWidth = this.toFiniteNumber(layout.borderWidth);
1543
+ if (borderWidth !== undefined)
1544
+ normalizedLayout.borderWidth = borderWidth;
1545
+ }
1546
+ const padding = this.toFiniteNumber(layout.padding);
1547
+ if (padding !== undefined && padding !== RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.padding)
1548
+ normalizedLayout.padding = padding;
1549
+ if (align && align !== RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.align)
1550
+ normalizedLayout.align = align;
1551
+ const elevation = this.toFiniteNumber(layout.elevation);
1552
+ if (elevation !== undefined && elevation !== RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE.elevation)
1553
+ normalizedLayout.elevation = elevation;
1554
+ if (Object.keys(normalizedLayout).length)
1555
+ value.layout = normalizedLayout;
1556
+ const iconBadge = raw.iconBadge || {};
1557
+ const normalizedIconBadge = {};
1558
+ const icon = this.nonEmptyString(iconBadge.icon);
1559
+ const badgeText = this.nonEmptyString(iconBadge.badgeText);
1560
+ const iconChanged = icon && icon !== RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.icon;
1561
+ const iconColor = this.nonEmptyString(iconBadge.iconColor);
1562
+ const iconColorChanged = iconColor && iconColor !== RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.iconColor;
1563
+ const iconPos = this.nonEmptyString(iconBadge.iconPos);
1564
+ const iconPosChanged = iconPos && iconPos !== RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.iconPos;
1565
+ if (iconChanged || iconColorChanged || iconPosChanged) {
1566
+ normalizedIconBadge.icon = icon || RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.icon;
1567
+ if (iconColor)
1568
+ normalizedIconBadge.iconColor = iconColor;
1569
+ if (iconPos)
1570
+ normalizedIconBadge.iconPos = iconPos;
1571
+ }
1572
+ if (badgeText) {
1573
+ normalizedIconBadge.badgeText = badgeText;
1574
+ const badgeStyle = this.nonEmptyString(iconBadge.badgeStyle);
1575
+ const badgeColor = this.nonEmptyString(iconBadge.badgeColor);
1576
+ if (badgeStyle && badgeStyle !== RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.badgeStyle)
1577
+ normalizedIconBadge.badgeStyle = badgeStyle;
1578
+ if (badgeColor && badgeColor !== RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE.badgeColor)
1579
+ normalizedIconBadge.badgeColor = badgeColor;
1580
+ }
1581
+ if (Object.keys(normalizedIconBadge).length)
1582
+ value.iconBadge = normalizedIconBadge;
1583
+ const background = raw.background || {};
1584
+ const normalizedBackground = {};
1585
+ const backgroundColor = this.nonEmptyString(background.color);
1586
+ const gradient = this.nonEmptyString(background.gradient);
1587
+ if (gradient)
1588
+ normalizedBackground.gradient = gradient;
1589
+ const alpha = this.toFiniteNumber(background.alpha);
1590
+ const blur = this.toFiniteNumber(background.blur);
1591
+ const hasBackgroundAdjustment = (alpha !== undefined && alpha !== RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.alpha)
1592
+ || (blur !== undefined && blur !== RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.blur);
1593
+ if (backgroundColor && (backgroundColor !== RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.color || hasBackgroundAdjustment)) {
1594
+ normalizedBackground.color = backgroundColor;
1595
+ }
1596
+ if (alpha !== undefined && alpha !== RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.alpha && (normalizedBackground.color || normalizedBackground.gradient))
1597
+ normalizedBackground.alpha = alpha;
1598
+ if (blur !== undefined && blur !== RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE.blur && (normalizedBackground.color || normalizedBackground.gradient))
1599
+ normalizedBackground.blur = blur;
1600
+ if (Object.keys(normalizedBackground).length)
1601
+ value.background = normalizedBackground;
1602
+ const tooltip = raw.tooltip || {};
1603
+ const tooltipText = this.nonEmptyString(tooltip.text);
1604
+ if (tooltipText) {
1605
+ const normalizedTooltip = { text: tooltipText };
1606
+ const position = this.nonEmptyString(tooltip.position);
1607
+ const bgColor = this.nonEmptyString(tooltip.bgColor);
1608
+ const delayMs = this.toNonNegativeMs(tooltip.delayMs);
1609
+ if (position)
1610
+ normalizedTooltip.position = position;
1611
+ if (bgColor)
1612
+ normalizedTooltip.bgColor = bgColor;
1613
+ if (delayMs !== undefined)
1614
+ normalizedTooltip.delayMs = delayMs;
1615
+ value.tooltip = normalizedTooltip;
1616
+ }
1617
+ const cssClass = this.nonEmptyString(raw.cssClass);
1618
+ const inlineStyle = this.nonEmptyString(raw.inlineStyle);
1619
+ if (cssClass)
1620
+ value.cssClass = cssClass;
1621
+ if (inlineStyle)
1622
+ value.inlineStyle = inlineStyle;
1161
1623
  const normalizedAnimation = this.normalizeAnimationForEmit((formValue || {}).animation);
1162
1624
  if (normalizedAnimation) {
1163
1625
  value.animation = normalizedAnimation;
1164
1626
  }
1165
- else {
1166
- delete value.animation;
1167
- }
1168
1627
  return value;
1169
1628
  }
1629
+ nonEmptyString(value) {
1630
+ return typeof value === 'string' ? value.trim() : '';
1631
+ }
1632
+ toFiniteNumber(value) {
1633
+ if (value === null || value === undefined)
1634
+ return undefined;
1635
+ if (typeof value === 'string' && !value.trim())
1636
+ return undefined;
1637
+ const parsed = Number(value);
1638
+ return Number.isFinite(parsed) ? parsed : undefined;
1639
+ }
1640
+ createDefaultFormValue() {
1641
+ return {
1642
+ description: '',
1643
+ estilo: { ...RuleEffectsPanelComponent.DEFAULT_ESTILO_FORM_VALUE },
1644
+ layout: { ...RuleEffectsPanelComponent.DEFAULT_LAYOUT_FORM_VALUE },
1645
+ iconBadge: { ...RuleEffectsPanelComponent.DEFAULT_ICON_BADGE_FORM_VALUE },
1646
+ background: { ...RuleEffectsPanelComponent.DEFAULT_BACKGROUND_FORM_VALUE },
1647
+ animation: { ...RuleEffectsPanelComponent.DEFAULT_ANIMATION_FORM_VALUE },
1648
+ tooltip: { ...RuleEffectsPanelComponent.DEFAULT_TOOLTIP_FORM_VALUE },
1649
+ cssClass: '',
1650
+ inlineStyle: '',
1651
+ };
1652
+ }
1170
1653
  normalizeAnimationForEmit(animation) {
1171
1654
  if (!animation)
1172
1655
  return undefined;
@@ -1208,8 +1691,8 @@ class RuleEffectsPanelComponent {
1208
1691
  const parsed = Number(value);
1209
1692
  return Number.isFinite(parsed) && parsed >= 0 ? Math.round(parsed) : undefined;
1210
1693
  }
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 });
1694
+ 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 });
1695
+ 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 </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}.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
1696
  }
1214
1697
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: RuleEffectsPanelComponent, decorators: [{
1215
1698
  type: Component,
@@ -1229,8 +1712,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
1229
1712
  FundoEditorComponent,
1230
1713
  AnimacaoEditorComponent,
1231
1714
  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: [{
1715
+ ], 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 </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}.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"] }]
1716
+ }], ctorParameters: () => [{ type: i2.FormBuilder }, { type: EffectRegistryService }, { type: i1.PraxisI18nService }], propDecorators: { labels: [{
1717
+ type: Input
1718
+ }], scope: [{
1234
1719
  type: Input
1235
1720
  }], value: [{
1236
1721
  type: Input
@@ -1468,9 +1953,10 @@ const PRAXIS_TABLE_RULE_BUILDER_AUTHORING_MANIFEST = {
1468
1953
  runtimeInputs: [
1469
1954
  { name: 'scope', type: 'RuleScope', description: 'Effect scope: cell, row, column or table.' },
1470
1955
  { name: 'value', type: 'RuleEffectDefinition | undefined', description: 'Initial effect definition hydrated into the panel form.' },
1956
+ { 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
1957
  { name: 'valueChange', type: 'RuleEffectDefinition', description: 'Debounced normalized effect payload emitted by the editor.' },
1472
1958
  { 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.' },
1959
+ { name: 'reset', type: 'void', description: 'Emitted when the user resets the panel form back to canonical defaults.' },
1474
1960
  ],
1475
1961
  editableTargets: [
1476
1962
  { 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 +2217,70 @@ const PRAXIS_TABLE_RULE_BUILDER_AUTHORING_MANIFEST = {
1731
2217
  ],
1732
2218
  };
1733
2219
 
2220
+ /** Metadata for Praxis Table Rule Builder component */
2221
+ const PRAXIS_TABLE_RULE_BUILDER_COMPONENT_METADATA = {
2222
+ id: 'praxis-table-rule-builder',
2223
+ selector: 'praxis-rule-effects-panel',
2224
+ component: RuleEffectsPanelComponent,
2225
+ friendlyName: 'Praxis Table Rule Builder',
2226
+ description: 'Editor for table rule effects and conditional styling.',
2227
+ inputs: [
2228
+ {
2229
+ name: 'scope',
2230
+ type: 'RuleScope',
2231
+ label: 'Escopo',
2232
+ description: 'Escopo do efeito (cell, row, column, table).',
2233
+ },
2234
+ {
2235
+ name: 'value',
2236
+ type: 'RuleEffectDefinition | undefined',
2237
+ label: 'Valor',
2238
+ description: 'Valor inicial para hidratar o formulário.',
2239
+ },
2240
+ {
2241
+ name: 'labels',
2242
+ type: 'Record<string, string>',
2243
+ label: 'Rótulos',
2244
+ description: 'Overrides parciais de texto do painel, aplicados acima do catálogo i18n da lib sem alterar o payload de regras.',
2245
+ },
2246
+ ],
2247
+ outputs: [
2248
+ {
2249
+ name: 'valueChange',
2250
+ type: 'RuleEffectDefinition',
2251
+ label: 'Mudança de valor',
2252
+ description: 'Disparado quando o valor consolidado é atualizado.',
2253
+ },
2254
+ {
2255
+ name: 'apply',
2256
+ type: 'void',
2257
+ label: 'Aplicar',
2258
+ description: 'Disparado quando o usuário aplica as mudanças.',
2259
+ },
2260
+ {
2261
+ name: 'reset',
2262
+ type: 'void',
2263
+ label: 'Resetar',
2264
+ description: 'Disparado quando o usuário redefine o formulário para os defaults canônicos.',
2265
+ },
2266
+ ],
2267
+ tags: ['widget', 'rules', 'table', 'configurable'],
2268
+ lib: '@praxisui/table-rule-builder',
2269
+ };
2270
+ /** Provider para auto-registrar metadados do componente Table Rule Builder. */
2271
+ function providePraxisTableRuleBuilderMetadata() {
2272
+ return {
2273
+ provide: ENVIRONMENT_INITIALIZER,
2274
+ multi: true,
2275
+ useFactory: (registry) => () => {
2276
+ registry.register(PRAXIS_TABLE_RULE_BUILDER_COMPONENT_METADATA);
2277
+ },
2278
+ deps: [ComponentMetadataRegistry],
2279
+ };
2280
+ }
2281
+
1734
2282
  /**
1735
2283
  * Generated bundle index. Do not edit.
1736
2284
  */
1737
2285
 
1738
- export { AnimacaoEditorComponent, DEFAULT_EFFECT_PRESETS, EffectRegistryService, EstiloEditorComponent, FundoEditorComponent, IconeBadgeEditorComponent, LayoutEditorComponent, PRAXIS_TABLE_RULE_BUILDER_AUTHORING_MANIFEST, RuleEffectsPanelComponent, TooltipEditorComponent, toCellClassAndStyle };
2286
+ 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 };