@praxisui/tabs 1.0.0-beta.4 → 1.0.0-beta.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -3
- package/fesm2022/praxisui-tabs.mjs +1225 -497
- package/fesm2022/praxisui-tabs.mjs.map +1 -1
- package/index.d.ts +64 -7
- package/package.json +7 -7
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { Inject, Component, inject, EventEmitter, signal, Output, Input, ChangeDetectionStrategy, ENVIRONMENT_INITIALIZER } from '@angular/core';
|
|
3
|
+
import { ActivatedRoute } from '@angular/router';
|
|
3
4
|
import * as i1$1 from '@angular/common';
|
|
4
5
|
import { CommonModule } from '@angular/common';
|
|
5
6
|
import * as i3$1 from '@angular/material/tabs';
|
|
6
7
|
import { MatTabsModule } from '@angular/material/tabs';
|
|
7
8
|
import * as i7 from '@angular/material/icon';
|
|
8
9
|
import { MatIconModule } from '@angular/material/icon';
|
|
10
|
+
import * as i11 from '@angular/material/tooltip';
|
|
11
|
+
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
9
12
|
import * as i1 from '@praxisui/core';
|
|
10
|
-
import { PraxisIconDirective,
|
|
11
|
-
import * as
|
|
13
|
+
import { PraxisIconDirective, deepMerge, ASYNC_CONFIG_STORAGE, ComponentKeyService, LoggerService, EmptyStateCardComponent, DynamicWidgetLoaderDirective, ComponentMetadataRegistry } from '@praxisui/core';
|
|
14
|
+
import * as i6$1 from '@angular/material/button';
|
|
12
15
|
import { MatButtonModule } from '@angular/material/button';
|
|
13
16
|
import * as i3 from '@angular/forms';
|
|
14
17
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
@@ -22,11 +25,11 @@ import * as i9 from '@angular/material/slide-toggle';
|
|
|
22
25
|
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
|
23
26
|
import * as i10 from '@angular/cdk/drag-drop';
|
|
24
27
|
import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
|
|
25
|
-
import
|
|
26
|
-
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
27
|
-
import { BehaviorSubject } from 'rxjs';
|
|
28
|
+
import { BehaviorSubject, Subject } from 'rxjs';
|
|
28
29
|
import { produce } from 'immer';
|
|
29
30
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
31
|
+
import { take, takeUntil } from 'rxjs/operators';
|
|
32
|
+
import { BaseAiAdapter, PraxisAiAssistantComponent } from '@praxisui/ai';
|
|
30
33
|
|
|
31
34
|
class PraxisTabsConfigEditor {
|
|
32
35
|
registry;
|
|
@@ -57,31 +60,31 @@ class PraxisTabsConfigEditor {
|
|
|
57
60
|
];
|
|
58
61
|
presets = {
|
|
59
62
|
primary: {
|
|
60
|
-
'active-indicator-color': 'var(--
|
|
61
|
-
'active-label-text-color': 'var(--
|
|
62
|
-
'inactive-label-text-color': '
|
|
63
|
-
'inactive-hover-label-text-color': 'var(--
|
|
64
|
-
'divider-color': '
|
|
65
|
-
'background-color': 'var(--
|
|
66
|
-
'pagination-icon-color': 'var(--
|
|
63
|
+
'active-indicator-color': 'var(--md-sys-color-primary)',
|
|
64
|
+
'active-label-text-color': 'var(--md-sys-color-primary)',
|
|
65
|
+
'inactive-label-text-color': 'var(--md-sys-color-on-surface-variant)',
|
|
66
|
+
'inactive-hover-label-text-color': 'var(--md-sys-color-on-surface)',
|
|
67
|
+
'divider-color': 'var(--md-sys-color-outline-variant)',
|
|
68
|
+
'background-color': 'var(--md-sys-color-surface-container)',
|
|
69
|
+
'pagination-icon-color': 'var(--md-sys-color-on-surface)'
|
|
67
70
|
},
|
|
68
71
|
neutral: {
|
|
69
|
-
'active-indicator-color': 'var(--
|
|
70
|
-
'active-label-text-color': 'var(--
|
|
71
|
-
'inactive-label-text-color': '
|
|
72
|
-
'inactive-hover-label-text-color': 'var(--
|
|
73
|
-
'divider-color': '
|
|
74
|
-
'background-color': 'var(--
|
|
75
|
-
'pagination-icon-color': 'var(--
|
|
72
|
+
'active-indicator-color': 'var(--md-sys-color-on-surface)',
|
|
73
|
+
'active-label-text-color': 'var(--md-sys-color-on-surface)',
|
|
74
|
+
'inactive-label-text-color': 'var(--md-sys-color-on-surface-variant)',
|
|
75
|
+
'inactive-hover-label-text-color': 'var(--md-sys-color-on-surface)',
|
|
76
|
+
'divider-color': 'var(--md-sys-color-outline-variant)',
|
|
77
|
+
'background-color': 'var(--md-sys-color-surface-container)',
|
|
78
|
+
'pagination-icon-color': 'var(--md-sys-color-on-surface)'
|
|
76
79
|
},
|
|
77
80
|
'high-contrast': {
|
|
78
|
-
'active-indicator-color': '
|
|
79
|
-
'active-label-text-color': '
|
|
80
|
-
'inactive-label-text-color': '
|
|
81
|
-
'inactive-hover-label-text-color': '
|
|
82
|
-
'divider-color': '
|
|
83
|
-
'background-color': 'var(--
|
|
84
|
-
'pagination-icon-color': '
|
|
81
|
+
'active-indicator-color': 'var(--md-sys-color-primary)',
|
|
82
|
+
'active-label-text-color': 'var(--md-sys-color-on-primary)',
|
|
83
|
+
'inactive-label-text-color': 'var(--md-sys-color-on-surface-variant)',
|
|
84
|
+
'inactive-hover-label-text-color': 'var(--md-sys-color-on-surface)',
|
|
85
|
+
'divider-color': 'var(--md-sys-color-outline)',
|
|
86
|
+
'background-color': 'var(--md-sys-color-surface)',
|
|
87
|
+
'pagination-icon-color': 'var(--md-sys-color-on-surface)'
|
|
85
88
|
}
|
|
86
89
|
};
|
|
87
90
|
isDirty$ = new BehaviorSubject(false);
|
|
@@ -271,10 +274,10 @@ class PraxisTabsConfigEditor {
|
|
|
271
274
|
t.widgets.push({ id: 'praxis-dynamic-form', inputs: { resourcePath: rp } });
|
|
272
275
|
}
|
|
273
276
|
else if (type === 'table') {
|
|
274
|
-
t.widgets.push({ id: 'praxis-table', inputs: { resourcePath: rp } });
|
|
277
|
+
t.widgets.push({ id: 'praxis-table', inputs: { resourcePath: rp, tableId: rp } });
|
|
275
278
|
}
|
|
276
279
|
else {
|
|
277
|
-
t.widgets.push({ id: 'praxis-crud', inputs: { metadata: { resource: { path: rp } } } });
|
|
280
|
+
t.widgets.push({ id: 'praxis-crud', inputs: { crudId: rp, metadata: { resource: { path: rp } } } });
|
|
278
281
|
}
|
|
279
282
|
this.onAppearanceChange();
|
|
280
283
|
}
|
|
@@ -345,10 +348,10 @@ class PraxisTabsConfigEditor {
|
|
|
345
348
|
l.widgets.push({ id: 'praxis-dynamic-form', inputs: { resourcePath: rp } });
|
|
346
349
|
}
|
|
347
350
|
else if (type === 'table') {
|
|
348
|
-
l.widgets.push({ id: 'praxis-table', inputs: { resourcePath: rp } });
|
|
351
|
+
l.widgets.push({ id: 'praxis-table', inputs: { resourcePath: rp, tableId: rp } });
|
|
349
352
|
}
|
|
350
353
|
else {
|
|
351
|
-
l.widgets.push({ id: 'praxis-crud', inputs: { metadata: { resource: { path: rp } } } });
|
|
354
|
+
l.widgets.push({ id: 'praxis-crud', inputs: { crudId: rp, metadata: { resource: { path: rp } } } });
|
|
352
355
|
}
|
|
353
356
|
this.onAppearanceChange();
|
|
354
357
|
}
|
|
@@ -376,58 +379,108 @@ class PraxisTabsConfigEditor {
|
|
|
376
379
|
}
|
|
377
380
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisTabsConfigEditor, deps: [{ token: SETTINGS_PANEL_DATA }, { token: i1.ComponentMetadataRegistry }], target: i0.ɵɵFactoryTarget.Component });
|
|
378
381
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisTabsConfigEditor, isStandalone: true, selector: "praxis-tabs-config-editor", ngImport: i0, template: `
|
|
379
|
-
<mat-tab-group>
|
|
382
|
+
<mat-tab-group class="editor-tabs">
|
|
380
383
|
<mat-tab label="Comportamento">
|
|
381
|
-
<div
|
|
382
|
-
<div
|
|
383
|
-
<mat-slide-toggle [(ngModel)]="behavior.closeable" (ngModelChange)="onAppearanceChange()">
|
|
384
|
-
<mat-slide-toggle [(ngModel)]="behavior.lazyLoad" (ngModelChange)="onAppearanceChange()">
|
|
385
|
-
<mat-slide-toggle [(ngModel)]="behavior.reorderable" (ngModelChange)="onAppearanceChange()">
|
|
384
|
+
<div class="editor-section">
|
|
385
|
+
<div class="editor-row">
|
|
386
|
+
<mat-slide-toggle [(ngModel)]="behavior.closeable" (ngModelChange)="onAppearanceChange()">Fechavel</mat-slide-toggle>
|
|
387
|
+
<mat-slide-toggle [(ngModel)]="behavior.lazyLoad" (ngModelChange)="onAppearanceChange()">Carregar sob demanda (planejado)</mat-slide-toggle>
|
|
388
|
+
<mat-slide-toggle [(ngModel)]="behavior.reorderable" (ngModelChange)="onAppearanceChange()">Reordenavel (planejado)</mat-slide-toggle>
|
|
386
389
|
</div>
|
|
387
390
|
</div>
|
|
388
391
|
</mat-tab>
|
|
389
392
|
<mat-tab label="Grupo">
|
|
390
|
-
<div
|
|
391
|
-
<div
|
|
392
|
-
<mat-form-field appearance="outline"><mat-label>Alinhamento</mat-label>
|
|
393
|
+
<div class="editor-section">
|
|
394
|
+
<div class="editor-grid two">
|
|
395
|
+
<mat-form-field appearance="outline"><mat-label>Alinhamento das abas</mat-label>
|
|
393
396
|
<select matNativeControl [(ngModel)]="group.alignTabs" (ngModelChange)="onAppearanceChange()">
|
|
394
|
-
<option [ngValue]="undefined">
|
|
395
|
-
<option value="start">
|
|
396
|
-
<option value="center">
|
|
397
|
-
<option value="end">
|
|
397
|
+
<option [ngValue]="undefined">Padrao</option>
|
|
398
|
+
<option value="start">Inicio</option>
|
|
399
|
+
<option value="center">Centro</option>
|
|
400
|
+
<option value="end">Fim</option>
|
|
398
401
|
</select>
|
|
399
402
|
</mat-form-field>
|
|
400
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
403
|
+
<mat-form-field appearance="outline"><mat-label>Posicao do header</mat-label>
|
|
401
404
|
<select matNativeControl [(ngModel)]="group.headerPosition" (ngModelChange)="onAppearanceChange()">
|
|
402
|
-
<option [ngValue]="undefined">
|
|
403
|
-
<option value="above">
|
|
404
|
-
<option value="below">
|
|
405
|
+
<option [ngValue]="undefined">Acima (padrao)</option>
|
|
406
|
+
<option value="above">Acima</option>
|
|
407
|
+
<option value="below">Abaixo</option>
|
|
405
408
|
</select>
|
|
406
409
|
</mat-form-field>
|
|
407
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
410
|
+
<mat-form-field appearance="outline"><mat-label>Indice selecionado</mat-label>
|
|
408
411
|
<input matInput type="number" [(ngModel)]="group.selectedIndex" (ngModelChange)="onAppearanceChange()" />
|
|
412
|
+
<button
|
|
413
|
+
mat-icon-button
|
|
414
|
+
matSuffix
|
|
415
|
+
class="help-icon-button"
|
|
416
|
+
type="button"
|
|
417
|
+
[matTooltip]="'selectedIndex'"
|
|
418
|
+
matTooltipPosition="above"
|
|
419
|
+
>
|
|
420
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
421
|
+
</button>
|
|
409
422
|
</mat-form-field>
|
|
410
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
423
|
+
<mat-form-field appearance="outline"><mat-label>Duracao da animacao</mat-label>
|
|
411
424
|
<input matInput [(ngModel)]="group.animationDuration" (ngModelChange)="onAppearanceChange()" placeholder="500ms" />
|
|
425
|
+
<button
|
|
426
|
+
mat-icon-button
|
|
427
|
+
matSuffix
|
|
428
|
+
class="help-icon-button"
|
|
429
|
+
type="button"
|
|
430
|
+
[matTooltip]="'animationDuration'"
|
|
431
|
+
matTooltipPosition="above"
|
|
432
|
+
>
|
|
433
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
434
|
+
</button>
|
|
412
435
|
</mat-form-field>
|
|
413
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
436
|
+
<mat-form-field appearance="outline"><mat-label>TabIndex do conteudo</mat-label>
|
|
414
437
|
<input matInput type="number" [(ngModel)]="group.contentTabIndex" (ngModelChange)="onAppearanceChange()" />
|
|
438
|
+
<button
|
|
439
|
+
mat-icon-button
|
|
440
|
+
matSuffix
|
|
441
|
+
class="help-icon-button"
|
|
442
|
+
type="button"
|
|
443
|
+
[matTooltip]="'contentTabIndex'"
|
|
444
|
+
matTooltipPosition="above"
|
|
445
|
+
>
|
|
446
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
447
|
+
</button>
|
|
415
448
|
</mat-form-field>
|
|
416
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
449
|
+
<mat-form-field appearance="outline"><mat-label>Cor (M2)</mat-label>
|
|
417
450
|
<select matNativeControl [(ngModel)]="group.color" (ngModelChange)="onAppearanceChange()">
|
|
418
|
-
<option [ngValue]="undefined">(
|
|
419
|
-
<option value="primary">
|
|
420
|
-
<option value="accent">
|
|
421
|
-
<option value="warn">
|
|
451
|
+
<option [ngValue]="undefined">(nenhuma)</option>
|
|
452
|
+
<option value="primary">Primary</option>
|
|
453
|
+
<option value="accent">Accent</option>
|
|
454
|
+
<option value="warn">Warn</option>
|
|
422
455
|
</select>
|
|
456
|
+
<button
|
|
457
|
+
mat-icon-button
|
|
458
|
+
matSuffix
|
|
459
|
+
class="help-icon-button"
|
|
460
|
+
type="button"
|
|
461
|
+
[matTooltip]="'Preferir tokens em Estilo.'"
|
|
462
|
+
matTooltipPosition="above"
|
|
463
|
+
>
|
|
464
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
465
|
+
</button>
|
|
423
466
|
</mat-form-field>
|
|
424
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
467
|
+
<mat-form-field appearance="outline"><mat-label>Cor de fundo (M2)</mat-label>
|
|
425
468
|
<select matNativeControl [(ngModel)]="group.backgroundColor" (ngModelChange)="onAppearanceChange()">
|
|
426
|
-
<option [ngValue]="undefined">(
|
|
427
|
-
<option value="primary">
|
|
428
|
-
<option value="accent">
|
|
429
|
-
<option value="warn">
|
|
469
|
+
<option [ngValue]="undefined">(nenhuma)</option>
|
|
470
|
+
<option value="primary">Primary</option>
|
|
471
|
+
<option value="accent">Accent</option>
|
|
472
|
+
<option value="warn">Warn</option>
|
|
430
473
|
</select>
|
|
474
|
+
<button
|
|
475
|
+
mat-icon-button
|
|
476
|
+
matSuffix
|
|
477
|
+
class="help-icon-button"
|
|
478
|
+
type="button"
|
|
479
|
+
[matTooltip]="'Preferir tokens em Estilo.'"
|
|
480
|
+
matTooltipPosition="above"
|
|
481
|
+
>
|
|
482
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
483
|
+
</button>
|
|
431
484
|
</mat-form-field>
|
|
432
485
|
<mat-form-field appearance="outline"><mat-label>aria-label</mat-label>
|
|
433
486
|
<input matInput [(ngModel)]="group.ariaLabel" (ngModelChange)="onAppearanceChange()" />
|
|
@@ -436,54 +489,94 @@ class PraxisTabsConfigEditor {
|
|
|
436
489
|
<input matInput [(ngModel)]="group.ariaLabelledby" (ngModelChange)="onAppearanceChange()" />
|
|
437
490
|
</mat-form-field>
|
|
438
491
|
</div>
|
|
439
|
-
<div
|
|
440
|
-
<mat-slide-toggle [(ngModel)]="group.dynamicHeight" (ngModelChange)="onAppearanceChange()">
|
|
441
|
-
<mat-slide-toggle [(ngModel)]="group.fitInkBarToContent" (ngModelChange)="onAppearanceChange()">
|
|
442
|
-
<mat-slide-toggle [(ngModel)]="group.disablePagination" (ngModelChange)="onAppearanceChange()">
|
|
443
|
-
<mat-slide-toggle [(ngModel)]="group.disableRipple" (ngModelChange)="onAppearanceChange()">
|
|
444
|
-
<mat-slide-toggle [(ngModel)]="group.preserveContent" (ngModelChange)="onAppearanceChange()">
|
|
445
|
-
<mat-slide-toggle [(ngModel)]="group.stretchTabs" (ngModelChange)="onAppearanceChange()">
|
|
492
|
+
<div class="editor-row">
|
|
493
|
+
<mat-slide-toggle [(ngModel)]="group.dynamicHeight" (ngModelChange)="onAppearanceChange()">Altura dinamica</mat-slide-toggle>
|
|
494
|
+
<mat-slide-toggle [(ngModel)]="group.fitInkBarToContent" (ngModelChange)="onAppearanceChange()">Indicador ajustado ao conteudo</mat-slide-toggle>
|
|
495
|
+
<mat-slide-toggle [(ngModel)]="group.disablePagination" (ngModelChange)="onAppearanceChange()">Sem paginacao</mat-slide-toggle>
|
|
496
|
+
<mat-slide-toggle [(ngModel)]="group.disableRipple" (ngModelChange)="onAppearanceChange()">Sem ripple</mat-slide-toggle>
|
|
497
|
+
<mat-slide-toggle [(ngModel)]="group.preserveContent" (ngModelChange)="onAppearanceChange()">Preservar conteudo</mat-slide-toggle>
|
|
498
|
+
<mat-slide-toggle [(ngModel)]="group.stretchTabs" (ngModelChange)="onAppearanceChange()">Esticar abas</mat-slide-toggle>
|
|
446
499
|
</div>
|
|
447
500
|
</div>
|
|
448
501
|
</mat-tab>
|
|
449
502
|
|
|
450
503
|
<mat-tab label="Navegação">
|
|
451
|
-
<div
|
|
452
|
-
<div
|
|
453
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
504
|
+
<div class="editor-section">
|
|
505
|
+
<div class="editor-grid two">
|
|
506
|
+
<mat-form-field appearance="outline"><mat-label>Indice selecionado</mat-label>
|
|
454
507
|
<input matInput type="number" [(ngModel)]="nav.selectedIndex" (ngModelChange)="onAppearanceChange()" />
|
|
508
|
+
<button
|
|
509
|
+
mat-icon-button
|
|
510
|
+
matSuffix
|
|
511
|
+
class="help-icon-button"
|
|
512
|
+
type="button"
|
|
513
|
+
[matTooltip]="'selectedIndex'"
|
|
514
|
+
matTooltipPosition="above"
|
|
515
|
+
>
|
|
516
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
517
|
+
</button>
|
|
455
518
|
</mat-form-field>
|
|
456
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
519
|
+
<mat-form-field appearance="outline"><mat-label>Duracao da animacao</mat-label>
|
|
457
520
|
<input matInput [(ngModel)]="nav.animationDuration" (ngModelChange)="onAppearanceChange()" placeholder="500ms" />
|
|
521
|
+
<button
|
|
522
|
+
mat-icon-button
|
|
523
|
+
matSuffix
|
|
524
|
+
class="help-icon-button"
|
|
525
|
+
type="button"
|
|
526
|
+
[matTooltip]="'animationDuration'"
|
|
527
|
+
matTooltipPosition="above"
|
|
528
|
+
>
|
|
529
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
530
|
+
</button>
|
|
458
531
|
</mat-form-field>
|
|
459
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
532
|
+
<mat-form-field appearance="outline"><mat-label>Cor (M2)</mat-label>
|
|
460
533
|
<select matNativeControl [(ngModel)]="nav.color" (ngModelChange)="onAppearanceChange()">
|
|
461
|
-
<option [ngValue]="undefined">(
|
|
462
|
-
<option value="primary">
|
|
463
|
-
<option value="accent">
|
|
464
|
-
<option value="warn">
|
|
534
|
+
<option [ngValue]="undefined">(nenhuma)</option>
|
|
535
|
+
<option value="primary">Primary</option>
|
|
536
|
+
<option value="accent">Accent</option>
|
|
537
|
+
<option value="warn">Warn</option>
|
|
465
538
|
</select>
|
|
539
|
+
<button
|
|
540
|
+
mat-icon-button
|
|
541
|
+
matSuffix
|
|
542
|
+
class="help-icon-button"
|
|
543
|
+
type="button"
|
|
544
|
+
[matTooltip]="'Preferir tokens em Estilo.'"
|
|
545
|
+
matTooltipPosition="above"
|
|
546
|
+
>
|
|
547
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
548
|
+
</button>
|
|
466
549
|
</mat-form-field>
|
|
467
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
550
|
+
<mat-form-field appearance="outline"><mat-label>Cor de fundo (M2)</mat-label>
|
|
468
551
|
<select matNativeControl [(ngModel)]="nav.backgroundColor" (ngModelChange)="onAppearanceChange()">
|
|
469
|
-
<option [ngValue]="undefined">(
|
|
470
|
-
<option value="primary">
|
|
471
|
-
<option value="accent">
|
|
472
|
-
<option value="warn">
|
|
552
|
+
<option [ngValue]="undefined">(nenhuma)</option>
|
|
553
|
+
<option value="primary">Primary</option>
|
|
554
|
+
<option value="accent">Accent</option>
|
|
555
|
+
<option value="warn">Warn</option>
|
|
473
556
|
</select>
|
|
557
|
+
<button
|
|
558
|
+
mat-icon-button
|
|
559
|
+
matSuffix
|
|
560
|
+
class="help-icon-button"
|
|
561
|
+
type="button"
|
|
562
|
+
[matTooltip]="'Preferir tokens em Estilo.'"
|
|
563
|
+
matTooltipPosition="above"
|
|
564
|
+
>
|
|
565
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
566
|
+
</button>
|
|
474
567
|
</mat-form-field>
|
|
475
568
|
</div>
|
|
476
|
-
<div
|
|
477
|
-
<mat-slide-toggle [(ngModel)]="nav.fitInkBarToContent" (ngModelChange)="onAppearanceChange()">
|
|
478
|
-
<mat-slide-toggle [(ngModel)]="nav.disablePagination" (ngModelChange)="onAppearanceChange()">
|
|
479
|
-
<mat-slide-toggle [(ngModel)]="nav.disableRipple" (ngModelChange)="onAppearanceChange()">
|
|
480
|
-
<mat-slide-toggle [(ngModel)]="nav.stretchTabs" (ngModelChange)="onAppearanceChange()">
|
|
569
|
+
<div class="editor-row">
|
|
570
|
+
<mat-slide-toggle [(ngModel)]="nav.fitInkBarToContent" (ngModelChange)="onAppearanceChange()">Indicador ajustado ao conteudo</mat-slide-toggle>
|
|
571
|
+
<mat-slide-toggle [(ngModel)]="nav.disablePagination" (ngModelChange)="onAppearanceChange()">Sem paginacao</mat-slide-toggle>
|
|
572
|
+
<mat-slide-toggle [(ngModel)]="nav.disableRipple" (ngModelChange)="onAppearanceChange()">Sem ripple</mat-slide-toggle>
|
|
573
|
+
<mat-slide-toggle [(ngModel)]="nav.stretchTabs" (ngModelChange)="onAppearanceChange()">Esticar abas</mat-slide-toggle>
|
|
481
574
|
</div>
|
|
482
575
|
</div>
|
|
483
576
|
</mat-tab>
|
|
484
577
|
<mat-tab label="JSON">
|
|
485
|
-
<div
|
|
486
|
-
<div class="
|
|
578
|
+
<div class="editor-section">
|
|
579
|
+
<div class="editor-toolbar">
|
|
487
580
|
<button mat-button (click)="formatJson()" [disabled]="!isValid">
|
|
488
581
|
<mat-icon [praxisIcon]="'format_align_left'"></mat-icon>Formatar
|
|
489
582
|
</button>
|
|
@@ -492,26 +585,26 @@ class PraxisTabsConfigEditor {
|
|
|
492
585
|
</button>
|
|
493
586
|
</div>
|
|
494
587
|
|
|
495
|
-
<mat-form-field appearance="outline" class="json-textarea-field
|
|
496
|
-
<mat-label>
|
|
588
|
+
<mat-form-field appearance="outline" class="json-textarea-field full">
|
|
589
|
+
<mat-label>Configuracao JSON</mat-label>
|
|
497
590
|
<textarea
|
|
498
591
|
matInput
|
|
499
592
|
[(ngModel)]="jsonText"
|
|
500
593
|
(ngModelChange)="onJsonTextChange($event)"
|
|
501
594
|
rows="22"
|
|
502
595
|
spellcheck="false"
|
|
503
|
-
|
|
596
|
+
class="editor-json"
|
|
504
597
|
></textarea>
|
|
505
|
-
<mat-hint *ngIf="isValid">JSON
|
|
506
|
-
<mat-error *ngIf="!isValid && jsonText">JSON
|
|
598
|
+
<mat-hint *ngIf="isValid">JSON valido</mat-hint>
|
|
599
|
+
<mat-error *ngIf="!isValid && jsonText">JSON invalido: {{ errorMsg }}</mat-error>
|
|
507
600
|
</mat-form-field>
|
|
508
601
|
</div>
|
|
509
602
|
</mat-tab>
|
|
510
603
|
|
|
511
604
|
<mat-tab label="Estilo">
|
|
512
|
-
<div
|
|
513
|
-
<div
|
|
514
|
-
<span
|
|
605
|
+
<div class="editor-section editor-section-lg">
|
|
606
|
+
<div class="editor-row">
|
|
607
|
+
<span class="editor-muted">Presets:</span>
|
|
515
608
|
<button mat-button color="primary" (click)="applyPreset('primary')">
|
|
516
609
|
<mat-icon [praxisIcon]="'palette'"></mat-icon>
|
|
517
610
|
Primário
|
|
@@ -530,7 +623,7 @@ class PraxisTabsConfigEditor {
|
|
|
530
623
|
</button>
|
|
531
624
|
</div>
|
|
532
625
|
|
|
533
|
-
<div
|
|
626
|
+
<div class="editor-grid two tight">
|
|
534
627
|
<mat-form-field appearance="outline">
|
|
535
628
|
<mat-label>Classe de tema (opcional)</mat-label>
|
|
536
629
|
<input matInput [(ngModel)]="appearance.themeClass" (ngModelChange)="onAppearanceChange()" placeholder="ex.: tabs-accented" />
|
|
@@ -539,38 +632,48 @@ class PraxisTabsConfigEditor {
|
|
|
539
632
|
<mat-form-field appearance="outline">
|
|
540
633
|
<mat-label>Densidade</mat-label>
|
|
541
634
|
<select matNativeControl [(ngModel)]="appearance.density" (ngModelChange)="onAppearanceChange()">
|
|
542
|
-
<option [ngValue]="undefined">
|
|
543
|
-
<option value="compact">
|
|
544
|
-
<option value="comfortable">
|
|
545
|
-
<option value="spacious">
|
|
635
|
+
<option [ngValue]="undefined">Padrao</option>
|
|
636
|
+
<option value="compact">Compacta</option>
|
|
637
|
+
<option value="comfortable">Confortavel</option>
|
|
638
|
+
<option value="spacious">Espacosa</option>
|
|
546
639
|
</select>
|
|
547
640
|
</mat-form-field>
|
|
548
641
|
</div>
|
|
549
642
|
|
|
550
643
|
<div>
|
|
551
|
-
<
|
|
552
|
-
|
|
644
|
+
<div class="editor-title-row">
|
|
645
|
+
<h3 class="editor-title">Tokens (Material 3)</h3>
|
|
646
|
+
<button
|
|
647
|
+
mat-icon-button
|
|
648
|
+
class="help-icon-button"
|
|
649
|
+
type="button"
|
|
650
|
+
[matTooltip]="'Valores aceitam CSS vars (ex.: var(--md-sys-color-primary)) ou cores hex/rgb.'"
|
|
651
|
+
matTooltipPosition="above"
|
|
652
|
+
>
|
|
653
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
654
|
+
</button>
|
|
655
|
+
</div>
|
|
656
|
+
<div class="editor-grid two">
|
|
553
657
|
<ng-container *ngFor="let t of tokenList">
|
|
554
658
|
<mat-form-field appearance="outline">
|
|
555
659
|
<mat-label>{{ t.label }}</mat-label>
|
|
556
|
-
<input matInput placeholder="var(--
|
|
660
|
+
<input matInput placeholder="var(--md-sys-color-primary) / #RRGGBB" [ngModel]="appearance.tokens?.[t.key]" (ngModelChange)="onTokenChange(t.key, $event)" />
|
|
557
661
|
</mat-form-field>
|
|
558
662
|
</ng-container>
|
|
559
663
|
</div>
|
|
560
|
-
<p style="margin:8px 0 0; color: var(--mat-sys-on-surface-variant); font-size: 12px;">Dica: valores aceitam CSS vars (ex.: <code>var(--mat-sys-primary)</code>) ou cores hex/rgb.</p>
|
|
561
664
|
</div>
|
|
562
665
|
|
|
563
666
|
<div>
|
|
564
|
-
<h3
|
|
565
|
-
<mat-form-field appearance="outline" class="json-textarea-field
|
|
667
|
+
<h3 class="editor-title">CSS personalizado</h3>
|
|
668
|
+
<mat-form-field appearance="outline" class="json-textarea-field full">
|
|
566
669
|
<mat-label>CSS a ser injetado no componente</mat-label>
|
|
567
670
|
<textarea matInput rows="10" [(ngModel)]="appearance.customCss" (ngModelChange)="onAppearanceChange()" placeholder=".praxis-tabs-root .mdc-tab__text-label { font-weight: 600; }"></textarea>
|
|
568
671
|
</mat-form-field>
|
|
569
672
|
</div>
|
|
570
673
|
|
|
571
674
|
<div>
|
|
572
|
-
<h3
|
|
573
|
-
<pre
|
|
675
|
+
<h3 class="editor-title">Snippet SCSS (para uso em styles.scss)</h3>
|
|
676
|
+
<pre class="editor-code">
|
|
574
677
|
@use '@angular/material' as mat;
|
|
575
678
|
{{ scssSnippet() }}
|
|
576
679
|
</pre>
|
|
@@ -579,27 +682,27 @@ class PraxisTabsConfigEditor {
|
|
|
579
682
|
</mat-tab>
|
|
580
683
|
|
|
581
684
|
<mat-tab label="Abas">
|
|
582
|
-
<div
|
|
685
|
+
<div class="editor-section">
|
|
583
686
|
<button mat-stroked-button color="primary" (click)="addTab()"><mat-icon [praxisIcon]="'add'"></mat-icon>Adicionar aba</button>
|
|
584
|
-
<div *ngIf="editedConfig.tabs?.length; else noTabs"
|
|
585
|
-
<div *ngFor="let t of editedConfig.tabs; let i = index"
|
|
586
|
-
<div
|
|
587
|
-
<strong
|
|
687
|
+
<div *ngIf="editedConfig.tabs?.length; else noTabs" class="editor-grid">
|
|
688
|
+
<div *ngFor="let t of editedConfig.tabs; let i = index" class="editor-card">
|
|
689
|
+
<div class="editor-card-header">
|
|
690
|
+
<strong class="editor-card-title">Aba #{{ i+1 }}</strong>
|
|
588
691
|
<button mat-icon-button (click)="moveTab(i, -1)" [disabled]="i===0"><mat-icon [praxisIcon]="'arrow_upward'"></mat-icon></button>
|
|
589
692
|
<button mat-icon-button (click)="moveTab(i, 1)" [disabled]="i===editedConfig.tabs!.length-1"><mat-icon [praxisIcon]="'arrow_downward'"></mat-icon></button>
|
|
590
693
|
<button mat-icon-button color="warn" (click)="removeTab(i)"><mat-icon [praxisIcon]="'delete'"></mat-icon></button>
|
|
591
694
|
</div>
|
|
592
|
-
<div
|
|
695
|
+
<div class="editor-grid two tight">
|
|
593
696
|
<mat-form-field appearance="outline"><mat-label>ID</mat-label>
|
|
594
697
|
<input matInput [(ngModel)]="t.id" (ngModelChange)="onAppearanceChange()" />
|
|
595
698
|
</mat-form-field>
|
|
596
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
699
|
+
<mat-form-field appearance="outline"><mat-label>Rotulo</mat-label>
|
|
597
700
|
<input matInput [(ngModel)]="t.textLabel" (ngModelChange)="onAppearanceChange()" />
|
|
598
701
|
</mat-form-field>
|
|
599
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
702
|
+
<mat-form-field appearance="outline"><mat-label>Classe do rotulo</mat-label>
|
|
600
703
|
<input matInput [(ngModel)]="t.labelClass" (ngModelChange)="onAppearanceChange()" />
|
|
601
704
|
</mat-form-field>
|
|
602
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
705
|
+
<mat-form-field appearance="outline"><mat-label>Classe do conteudo</mat-label>
|
|
603
706
|
<input matInput [(ngModel)]="t.bodyClass" (ngModelChange)="onAppearanceChange()" />
|
|
604
707
|
</mat-form-field>
|
|
605
708
|
<mat-form-field appearance="outline"><mat-label>aria-label</mat-label>
|
|
@@ -609,22 +712,22 @@ class PraxisTabsConfigEditor {
|
|
|
609
712
|
<input matInput [(ngModel)]="t.ariaLabelledby" (ngModelChange)="onAppearanceChange()" />
|
|
610
713
|
</mat-form-field>
|
|
611
714
|
</div>
|
|
612
|
-
<mat-slide-toggle [(ngModel)]="t.disabled" (ngModelChange)="onAppearanceChange()">
|
|
715
|
+
<mat-slide-toggle [(ngModel)]="t.disabled" (ngModelChange)="onAppearanceChange()">Desativada</mat-slide-toggle>
|
|
613
716
|
|
|
614
717
|
<!-- Widgets (componentes dinâmicos) -->
|
|
615
|
-
<div
|
|
616
|
-
<div
|
|
617
|
-
<mat-form-field appearance="outline"
|
|
718
|
+
<div class="editor-divider editor-grid">
|
|
719
|
+
<div class="editor-row">
|
|
720
|
+
<mat-form-field appearance="outline" class="editor-field-min">
|
|
618
721
|
<mat-label>Adicionar componente</mat-label>
|
|
619
722
|
<select matNativeControl [(ngModel)]="selectedTabWidgetId[i]">
|
|
620
723
|
<option [ngValue]="''">(selecione)</option>
|
|
621
724
|
<option *ngFor="let c of componentOptions" [ngValue]="c.id">{{ c.friendlyName || c.id }}</option>
|
|
622
725
|
</select>
|
|
623
726
|
</mat-form-field>
|
|
624
|
-
|
|
625
|
-
<span
|
|
626
|
-
<mat-form-field appearance="outline"
|
|
627
|
-
<mat-label>resourcePath</mat-label>
|
|
727
|
+
<button mat-stroked-button (click)="addWidgetToTab(i)"><mat-icon [praxisIcon]="'add'"></mat-icon>Adicionar</button>
|
|
728
|
+
<span class="editor-spacer"></span>
|
|
729
|
+
<mat-form-field appearance="outline" class="editor-field-240">
|
|
730
|
+
<mat-label>Recurso (resourcePath)</mat-label>
|
|
628
731
|
<input matInput [(ngModel)]="quickResourcePathTab[i]" placeholder="ex.: usuarios" />
|
|
629
732
|
</mat-form-field>
|
|
630
733
|
<button mat-button (click)="addPresetToTab(i, 'form')"><mat-icon [praxisIcon]="'description'"></mat-icon>Form</button>
|
|
@@ -632,22 +735,22 @@ class PraxisTabsConfigEditor {
|
|
|
632
735
|
<button mat-button (click)="addPresetToTab(i, 'crud')"><mat-icon [praxisIcon]="'dynamic_form'"></mat-icon>CRUD</button>
|
|
633
736
|
</div>
|
|
634
737
|
|
|
635
|
-
<div *ngIf="t.widgets?.length"
|
|
636
|
-
<div *ngFor="let w of t.widgets; let wi = index" cdkDrag
|
|
637
|
-
<div
|
|
738
|
+
<div *ngIf="t.widgets?.length" class="editor-grid" cdkDropList [cdkDropListData]="t.widgets || []" (cdkDropListDropped)="onTabWidgetDrop(i, $event)">
|
|
739
|
+
<div *ngFor="let w of t.widgets; let wi = index" cdkDrag class="editor-card dashed">
|
|
740
|
+
<div class="editor-card-header">
|
|
638
741
|
<button mat-icon-button cdkDragHandle matTooltip="Arrastar para reordenar" aria-label="Arrastar para reordenar">
|
|
639
742
|
<mat-icon [praxisIcon]="'drag_indicator'"></mat-icon>
|
|
640
743
|
</button>
|
|
641
|
-
<strong
|
|
744
|
+
<strong class="editor-card-title">{{ getCompName(w.id) }}</strong>
|
|
642
745
|
<button mat-icon-button color="warn" (click)="removeWidgetFromTab(i, wi)" matTooltip="Remover componente" aria-label="Remover componente"><mat-icon [praxisIcon]="'delete'"></mat-icon></button>
|
|
643
746
|
</div>
|
|
644
|
-
<div
|
|
747
|
+
<div class="editor-grid two tight">
|
|
645
748
|
<mat-form-field appearance="outline">
|
|
646
|
-
<mat-label>
|
|
749
|
+
<mat-label>Inputs (JSON)</mat-label>
|
|
647
750
|
<textarea matInput rows="4" [ngModel]="stringify(w.inputs)" (ngModelChange)="updateWidgetInputsTab(i, wi, $event)"></textarea>
|
|
648
751
|
</mat-form-field>
|
|
649
752
|
<mat-form-field appearance="outline">
|
|
650
|
-
<mat-label>
|
|
753
|
+
<mat-label>Outputs (JSON)</mat-label>
|
|
651
754
|
<textarea matInput rows="4" [ngModel]="stringify(w.outputs)" (ngModelChange)="updateWidgetOutputsTab(i, wi, $event)"></textarea>
|
|
652
755
|
</mat-form-field>
|
|
653
756
|
</div>
|
|
@@ -656,49 +759,49 @@ class PraxisTabsConfigEditor {
|
|
|
656
759
|
</div>
|
|
657
760
|
</div>
|
|
658
761
|
</div>
|
|
659
|
-
<ng-template #noTabs><em>Nenhuma aba definida.</em></ng-template>
|
|
762
|
+
<ng-template #noTabs><em class="editor-muted">Nenhuma aba definida.</em></ng-template>
|
|
660
763
|
</div>
|
|
661
764
|
</mat-tab>
|
|
662
765
|
|
|
663
766
|
<mat-tab label="Acessibilidade">
|
|
664
|
-
<div
|
|
665
|
-
<div
|
|
666
|
-
<mat-slide-toggle [(ngModel)]="accessibility.highContrast" (ngModelChange)="onAppearanceChange()">
|
|
667
|
-
<mat-slide-toggle [(ngModel)]="accessibility.reduceMotion" (ngModelChange)="onAppearanceChange()">
|
|
767
|
+
<div class="editor-section">
|
|
768
|
+
<div class="editor-row">
|
|
769
|
+
<mat-slide-toggle [(ngModel)]="accessibility.highContrast" (ngModelChange)="onAppearanceChange()">Alto contraste</mat-slide-toggle>
|
|
770
|
+
<mat-slide-toggle [(ngModel)]="accessibility.reduceMotion" (ngModelChange)="onAppearanceChange()">Reduzir movimento</mat-slide-toggle>
|
|
668
771
|
</div>
|
|
669
772
|
</div>
|
|
670
773
|
</mat-tab>
|
|
671
774
|
|
|
672
775
|
<mat-tab label="Links">
|
|
673
|
-
<div
|
|
776
|
+
<div class="editor-section">
|
|
674
777
|
<button mat-stroked-button color="primary" (click)="addLink()"><mat-icon [praxisIcon]="'add_link'"></mat-icon>Adicionar link</button>
|
|
675
|
-
<div *ngIf="nav.links?.length; else noLinks"
|
|
676
|
-
<div *ngFor="let l of nav.links; let i = index"
|
|
677
|
-
<div
|
|
678
|
-
<strong
|
|
778
|
+
<div *ngIf="nav.links?.length; else noLinks" class="editor-grid">
|
|
779
|
+
<div *ngFor="let l of nav.links; let i = index" class="editor-card">
|
|
780
|
+
<div class="editor-card-header">
|
|
781
|
+
<strong class="editor-card-title">Link #{{ i+1 }}</strong>
|
|
679
782
|
<button mat-icon-button (click)="moveLink(i, -1)" [disabled]="i===0"><mat-icon [praxisIcon]="'arrow_upward'"></mat-icon></button>
|
|
680
783
|
<button mat-icon-button (click)="moveLink(i, 1)" [disabled]="i===nav.links!.length-1"><mat-icon [praxisIcon]="'arrow_downward'"></mat-icon></button>
|
|
681
784
|
<button mat-icon-button color="warn" (click)="removeLink(i)"><mat-icon [praxisIcon]="'delete'"></mat-icon></button>
|
|
682
785
|
</div>
|
|
683
|
-
<div
|
|
786
|
+
<div class="editor-grid two tight">
|
|
684
787
|
<mat-form-field appearance="outline"><mat-label>ID</mat-label>
|
|
685
788
|
<input matInput [(ngModel)]="l.id" (ngModelChange)="onAppearanceChange()" />
|
|
686
789
|
</mat-form-field>
|
|
687
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
790
|
+
<mat-form-field appearance="outline"><mat-label>Rotulo</mat-label>
|
|
688
791
|
<input matInput [(ngModel)]="l.label" (ngModelChange)="onAppearanceChange()" />
|
|
689
792
|
</mat-form-field>
|
|
690
793
|
</div>
|
|
691
|
-
<div
|
|
692
|
-
<mat-slide-toggle [(ngModel)]="l.active" (ngModelChange)="onAppearanceChange()">
|
|
693
|
-
<mat-slide-toggle [(ngModel)]="l.disabled" (ngModelChange)="onAppearanceChange()">
|
|
694
|
-
<mat-slide-toggle [(ngModel)]="l.disableRipple" (ngModelChange)="onAppearanceChange()">
|
|
695
|
-
<mat-slide-toggle [(ngModel)]="l.fitInkBarToContent" (ngModelChange)="onAppearanceChange()">
|
|
794
|
+
<div class="editor-row">
|
|
795
|
+
<mat-slide-toggle [(ngModel)]="l.active" (ngModelChange)="onAppearanceChange()">Ativo</mat-slide-toggle>
|
|
796
|
+
<mat-slide-toggle [(ngModel)]="l.disabled" (ngModelChange)="onAppearanceChange()">Desativado</mat-slide-toggle>
|
|
797
|
+
<mat-slide-toggle [(ngModel)]="l.disableRipple" (ngModelChange)="onAppearanceChange()">Sem ripple</mat-slide-toggle>
|
|
798
|
+
<mat-slide-toggle [(ngModel)]="l.fitInkBarToContent" (ngModelChange)="onAppearanceChange()">Indicador ajustado ao conteudo</mat-slide-toggle>
|
|
696
799
|
</div>
|
|
697
800
|
|
|
698
801
|
<!-- Widgets para Links -->
|
|
699
|
-
<div
|
|
700
|
-
<div
|
|
701
|
-
<mat-form-field appearance="outline"
|
|
802
|
+
<div class="editor-divider editor-grid">
|
|
803
|
+
<div class="editor-row">
|
|
804
|
+
<mat-form-field appearance="outline" class="editor-field-min">
|
|
702
805
|
<mat-label>Adicionar componente</mat-label>
|
|
703
806
|
<select matNativeControl [(ngModel)]="selectedLinkWidgetId[i]">
|
|
704
807
|
<option [ngValue]="''">(selecione)</option>
|
|
@@ -706,9 +809,9 @@ class PraxisTabsConfigEditor {
|
|
|
706
809
|
</select>
|
|
707
810
|
</mat-form-field>
|
|
708
811
|
<button mat-stroked-button (click)="addWidgetToLink(i)"><mat-icon [praxisIcon]="'add'"></mat-icon>Adicionar</button>
|
|
709
|
-
<span
|
|
710
|
-
<mat-form-field appearance="outline"
|
|
711
|
-
<mat-label>resourcePath</mat-label>
|
|
812
|
+
<span class="editor-spacer"></span>
|
|
813
|
+
<mat-form-field appearance="outline" class="editor-field-240">
|
|
814
|
+
<mat-label>Recurso (resourcePath)</mat-label>
|
|
712
815
|
<input matInput [(ngModel)]="quickResourcePathLink[i]" placeholder="ex.: usuarios" />
|
|
713
816
|
</mat-form-field>
|
|
714
817
|
<button mat-button (click)="addPresetToLink(i, 'form')"><mat-icon [praxisIcon]="'description'"></mat-icon>Form</button>
|
|
@@ -716,22 +819,22 @@ class PraxisTabsConfigEditor {
|
|
|
716
819
|
<button mat-button (click)="addPresetToLink(i, 'crud')"><mat-icon [praxisIcon]="'dynamic_form'"></mat-icon>CRUD</button>
|
|
717
820
|
</div>
|
|
718
821
|
|
|
719
|
-
<div *ngIf="l.widgets?.length"
|
|
720
|
-
<div *ngFor="let w of l.widgets; let wi = index" cdkDrag
|
|
721
|
-
<div
|
|
822
|
+
<div *ngIf="l.widgets?.length" class="editor-grid" cdkDropList [cdkDropListData]="l.widgets || []" (cdkDropListDropped)="onLinkWidgetDrop(i, $event)">
|
|
823
|
+
<div *ngFor="let w of l.widgets; let wi = index" cdkDrag class="editor-card dashed">
|
|
824
|
+
<div class="editor-card-header">
|
|
722
825
|
<button mat-icon-button cdkDragHandle matTooltip="Arrastar para reordenar" aria-label="Arrastar para reordenar">
|
|
723
826
|
<mat-icon [praxisIcon]="'drag_indicator'"></mat-icon>
|
|
724
827
|
</button>
|
|
725
|
-
<strong
|
|
828
|
+
<strong class="editor-card-title">{{ getCompName(w.id) }}</strong>
|
|
726
829
|
<button mat-icon-button color="warn" (click)="removeWidgetFromLink(i, wi)" matTooltip="Remover componente" aria-label="Remover componente"><mat-icon [praxisIcon]="'delete'"></mat-icon></button>
|
|
727
830
|
</div>
|
|
728
|
-
<div
|
|
831
|
+
<div class="editor-grid two tight">
|
|
729
832
|
<mat-form-field appearance="outline">
|
|
730
|
-
<mat-label>
|
|
833
|
+
<mat-label>Inputs (JSON)</mat-label>
|
|
731
834
|
<textarea matInput rows="4" [ngModel]="stringify(w.inputs)" (ngModelChange)="updateWidgetInputsLink(i, wi, $event)"></textarea>
|
|
732
835
|
</mat-form-field>
|
|
733
836
|
<mat-form-field appearance="outline">
|
|
734
|
-
<mat-label>
|
|
837
|
+
<mat-label>Outputs (JSON)</mat-label>
|
|
735
838
|
<textarea matInput rows="4" [ngModel]="stringify(w.outputs)" (ngModelChange)="updateWidgetOutputsLink(i, wi, $event)"></textarea>
|
|
736
839
|
</mat-form-field>
|
|
737
840
|
</div>
|
|
@@ -740,18 +843,15 @@ class PraxisTabsConfigEditor {
|
|
|
740
843
|
</div>
|
|
741
844
|
</div>
|
|
742
845
|
</div>
|
|
743
|
-
<ng-template #noLinks><em>Nenhum link definido.</em></ng-template>
|
|
846
|
+
<ng-template #noLinks><em class="editor-muted">Nenhum link definido.</em></ng-template>
|
|
744
847
|
</div>
|
|
745
848
|
</mat-tab>
|
|
746
849
|
</mat-tab-group>
|
|
747
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.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: i3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i3.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i3$1.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i3$1.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i5.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type:
|
|
850
|
+
`, isInline: true, styles: [":host{display:block;color:var(--md-sys-color-on-surface)}.editor-tabs{--editor-surface: var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface));--editor-border: 1px solid var(--md-sys-color-outline-variant);--editor-radius: 12px;--editor-muted: var(--md-sys-color-on-surface-variant)}.editor-section{padding:12px;display:grid;gap:12px;background:var(--editor-surface);border:var(--editor-border);border-radius:var(--editor-radius)}.editor-section-lg{gap:16px}.editor-row{display:flex;gap:10px;flex-wrap:wrap;align-items:center}.editor-grid{display:grid;gap:12px}.editor-grid.two{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.editor-grid.tight{gap:8px}.editor-toolbar{display:flex;gap:8px;flex-wrap:wrap;align-items:center}.editor-muted{color:var(--editor-muted)}.editor-title{margin:6px 0 8px;font-size:1rem}.editor-title-row{display:flex;align-items:center;gap:8px}.editor-code{white-space:pre-wrap;background:var(--md-sys-color-surface-container);padding:8px;border-radius:6px;border:1px solid var(--md-sys-color-outline-variant)}.editor-card{border:1px solid var(--md-sys-color-outline-variant);padding:10px;border-radius:10px;display:grid;gap:8px;background:var(--md-sys-color-surface)}.editor-card.dashed{border-style:dashed}.editor-card-header{display:flex;align-items:center;gap:8px}.editor-card-title{flex:1;font-weight:600}.editor-divider{border-top:1px solid var(--md-sys-color-outline-variant);padding-top:8px}.editor-spacer{flex:1}.editor-field-min{min-width:260px}.editor-section .editor-field-min{width:260px;max-width:260px}.editor-field-240{width:240px}.editor-section .editor-field-240{width:240px;max-width:240px}.editor-json{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.editor-section .mat-mdc-form-field{width:100%;max-width:520px;--mdc-outlined-text-field-container-height: 48px;--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-outline);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-error-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-focus-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-hover-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-supporting-text-color: var(--md-sys-color-on-surface-variant)}.editor-section .mat-mdc-form-field.full{max-width:none}.help-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 18px;width:28px;height:28px;padding:0;display:inline-flex;align-items:center;justify-content:center;margin-right:-4px}.help-icon-button mat-icon{font-size:18px;width:18px;height:18px}.mat-mdc-form-field-icon-suffix{align-self:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.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: i3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i3.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i3$1.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i3$1.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i5.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i5.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6$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: "component", type: i6$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i9.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i10.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i10.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i10.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i11.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
|
|
748
851
|
}
|
|
749
852
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisTabsConfigEditor, decorators: [{
|
|
750
853
|
type: Component,
|
|
751
|
-
args: [{
|
|
752
|
-
selector: 'praxis-tabs-config-editor',
|
|
753
|
-
standalone: true,
|
|
754
|
-
imports: [
|
|
854
|
+
args: [{ selector: 'praxis-tabs-config-editor', standalone: true, imports: [
|
|
755
855
|
CommonModule,
|
|
756
856
|
FormsModule,
|
|
757
857
|
MatTabsModule,
|
|
@@ -763,60 +863,109 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
763
863
|
MatSlideToggleModule,
|
|
764
864
|
DragDropModule,
|
|
765
865
|
MatTooltipModule,
|
|
766
|
-
],
|
|
767
|
-
|
|
768
|
-
<mat-tab-group>
|
|
866
|
+
], template: `
|
|
867
|
+
<mat-tab-group class="editor-tabs">
|
|
769
868
|
<mat-tab label="Comportamento">
|
|
770
|
-
<div
|
|
771
|
-
<div
|
|
772
|
-
<mat-slide-toggle [(ngModel)]="behavior.closeable" (ngModelChange)="onAppearanceChange()">
|
|
773
|
-
<mat-slide-toggle [(ngModel)]="behavior.lazyLoad" (ngModelChange)="onAppearanceChange()">
|
|
774
|
-
<mat-slide-toggle [(ngModel)]="behavior.reorderable" (ngModelChange)="onAppearanceChange()">
|
|
869
|
+
<div class="editor-section">
|
|
870
|
+
<div class="editor-row">
|
|
871
|
+
<mat-slide-toggle [(ngModel)]="behavior.closeable" (ngModelChange)="onAppearanceChange()">Fechavel</mat-slide-toggle>
|
|
872
|
+
<mat-slide-toggle [(ngModel)]="behavior.lazyLoad" (ngModelChange)="onAppearanceChange()">Carregar sob demanda (planejado)</mat-slide-toggle>
|
|
873
|
+
<mat-slide-toggle [(ngModel)]="behavior.reorderable" (ngModelChange)="onAppearanceChange()">Reordenavel (planejado)</mat-slide-toggle>
|
|
775
874
|
</div>
|
|
776
875
|
</div>
|
|
777
876
|
</mat-tab>
|
|
778
877
|
<mat-tab label="Grupo">
|
|
779
|
-
<div
|
|
780
|
-
<div
|
|
781
|
-
<mat-form-field appearance="outline"><mat-label>Alinhamento</mat-label>
|
|
878
|
+
<div class="editor-section">
|
|
879
|
+
<div class="editor-grid two">
|
|
880
|
+
<mat-form-field appearance="outline"><mat-label>Alinhamento das abas</mat-label>
|
|
782
881
|
<select matNativeControl [(ngModel)]="group.alignTabs" (ngModelChange)="onAppearanceChange()">
|
|
783
|
-
<option [ngValue]="undefined">
|
|
784
|
-
<option value="start">
|
|
785
|
-
<option value="center">
|
|
786
|
-
<option value="end">
|
|
882
|
+
<option [ngValue]="undefined">Padrao</option>
|
|
883
|
+
<option value="start">Inicio</option>
|
|
884
|
+
<option value="center">Centro</option>
|
|
885
|
+
<option value="end">Fim</option>
|
|
787
886
|
</select>
|
|
788
887
|
</mat-form-field>
|
|
789
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
888
|
+
<mat-form-field appearance="outline"><mat-label>Posicao do header</mat-label>
|
|
790
889
|
<select matNativeControl [(ngModel)]="group.headerPosition" (ngModelChange)="onAppearanceChange()">
|
|
791
|
-
<option [ngValue]="undefined">
|
|
792
|
-
<option value="above">
|
|
793
|
-
<option value="below">
|
|
890
|
+
<option [ngValue]="undefined">Acima (padrao)</option>
|
|
891
|
+
<option value="above">Acima</option>
|
|
892
|
+
<option value="below">Abaixo</option>
|
|
794
893
|
</select>
|
|
795
894
|
</mat-form-field>
|
|
796
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
895
|
+
<mat-form-field appearance="outline"><mat-label>Indice selecionado</mat-label>
|
|
797
896
|
<input matInput type="number" [(ngModel)]="group.selectedIndex" (ngModelChange)="onAppearanceChange()" />
|
|
897
|
+
<button
|
|
898
|
+
mat-icon-button
|
|
899
|
+
matSuffix
|
|
900
|
+
class="help-icon-button"
|
|
901
|
+
type="button"
|
|
902
|
+
[matTooltip]="'selectedIndex'"
|
|
903
|
+
matTooltipPosition="above"
|
|
904
|
+
>
|
|
905
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
906
|
+
</button>
|
|
798
907
|
</mat-form-field>
|
|
799
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
908
|
+
<mat-form-field appearance="outline"><mat-label>Duracao da animacao</mat-label>
|
|
800
909
|
<input matInput [(ngModel)]="group.animationDuration" (ngModelChange)="onAppearanceChange()" placeholder="500ms" />
|
|
910
|
+
<button
|
|
911
|
+
mat-icon-button
|
|
912
|
+
matSuffix
|
|
913
|
+
class="help-icon-button"
|
|
914
|
+
type="button"
|
|
915
|
+
[matTooltip]="'animationDuration'"
|
|
916
|
+
matTooltipPosition="above"
|
|
917
|
+
>
|
|
918
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
919
|
+
</button>
|
|
801
920
|
</mat-form-field>
|
|
802
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
921
|
+
<mat-form-field appearance="outline"><mat-label>TabIndex do conteudo</mat-label>
|
|
803
922
|
<input matInput type="number" [(ngModel)]="group.contentTabIndex" (ngModelChange)="onAppearanceChange()" />
|
|
923
|
+
<button
|
|
924
|
+
mat-icon-button
|
|
925
|
+
matSuffix
|
|
926
|
+
class="help-icon-button"
|
|
927
|
+
type="button"
|
|
928
|
+
[matTooltip]="'contentTabIndex'"
|
|
929
|
+
matTooltipPosition="above"
|
|
930
|
+
>
|
|
931
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
932
|
+
</button>
|
|
804
933
|
</mat-form-field>
|
|
805
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
934
|
+
<mat-form-field appearance="outline"><mat-label>Cor (M2)</mat-label>
|
|
806
935
|
<select matNativeControl [(ngModel)]="group.color" (ngModelChange)="onAppearanceChange()">
|
|
807
|
-
<option [ngValue]="undefined">(
|
|
808
|
-
<option value="primary">
|
|
809
|
-
<option value="accent">
|
|
810
|
-
<option value="warn">
|
|
936
|
+
<option [ngValue]="undefined">(nenhuma)</option>
|
|
937
|
+
<option value="primary">Primary</option>
|
|
938
|
+
<option value="accent">Accent</option>
|
|
939
|
+
<option value="warn">Warn</option>
|
|
811
940
|
</select>
|
|
941
|
+
<button
|
|
942
|
+
mat-icon-button
|
|
943
|
+
matSuffix
|
|
944
|
+
class="help-icon-button"
|
|
945
|
+
type="button"
|
|
946
|
+
[matTooltip]="'Preferir tokens em Estilo.'"
|
|
947
|
+
matTooltipPosition="above"
|
|
948
|
+
>
|
|
949
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
950
|
+
</button>
|
|
812
951
|
</mat-form-field>
|
|
813
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
952
|
+
<mat-form-field appearance="outline"><mat-label>Cor de fundo (M2)</mat-label>
|
|
814
953
|
<select matNativeControl [(ngModel)]="group.backgroundColor" (ngModelChange)="onAppearanceChange()">
|
|
815
|
-
<option [ngValue]="undefined">(
|
|
816
|
-
<option value="primary">
|
|
817
|
-
<option value="accent">
|
|
818
|
-
<option value="warn">
|
|
954
|
+
<option [ngValue]="undefined">(nenhuma)</option>
|
|
955
|
+
<option value="primary">Primary</option>
|
|
956
|
+
<option value="accent">Accent</option>
|
|
957
|
+
<option value="warn">Warn</option>
|
|
819
958
|
</select>
|
|
959
|
+
<button
|
|
960
|
+
mat-icon-button
|
|
961
|
+
matSuffix
|
|
962
|
+
class="help-icon-button"
|
|
963
|
+
type="button"
|
|
964
|
+
[matTooltip]="'Preferir tokens em Estilo.'"
|
|
965
|
+
matTooltipPosition="above"
|
|
966
|
+
>
|
|
967
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
968
|
+
</button>
|
|
820
969
|
</mat-form-field>
|
|
821
970
|
<mat-form-field appearance="outline"><mat-label>aria-label</mat-label>
|
|
822
971
|
<input matInput [(ngModel)]="group.ariaLabel" (ngModelChange)="onAppearanceChange()" />
|
|
@@ -825,54 +974,94 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
825
974
|
<input matInput [(ngModel)]="group.ariaLabelledby" (ngModelChange)="onAppearanceChange()" />
|
|
826
975
|
</mat-form-field>
|
|
827
976
|
</div>
|
|
828
|
-
<div
|
|
829
|
-
<mat-slide-toggle [(ngModel)]="group.dynamicHeight" (ngModelChange)="onAppearanceChange()">
|
|
830
|
-
<mat-slide-toggle [(ngModel)]="group.fitInkBarToContent" (ngModelChange)="onAppearanceChange()">
|
|
831
|
-
<mat-slide-toggle [(ngModel)]="group.disablePagination" (ngModelChange)="onAppearanceChange()">
|
|
832
|
-
<mat-slide-toggle [(ngModel)]="group.disableRipple" (ngModelChange)="onAppearanceChange()">
|
|
833
|
-
<mat-slide-toggle [(ngModel)]="group.preserveContent" (ngModelChange)="onAppearanceChange()">
|
|
834
|
-
<mat-slide-toggle [(ngModel)]="group.stretchTabs" (ngModelChange)="onAppearanceChange()">
|
|
977
|
+
<div class="editor-row">
|
|
978
|
+
<mat-slide-toggle [(ngModel)]="group.dynamicHeight" (ngModelChange)="onAppearanceChange()">Altura dinamica</mat-slide-toggle>
|
|
979
|
+
<mat-slide-toggle [(ngModel)]="group.fitInkBarToContent" (ngModelChange)="onAppearanceChange()">Indicador ajustado ao conteudo</mat-slide-toggle>
|
|
980
|
+
<mat-slide-toggle [(ngModel)]="group.disablePagination" (ngModelChange)="onAppearanceChange()">Sem paginacao</mat-slide-toggle>
|
|
981
|
+
<mat-slide-toggle [(ngModel)]="group.disableRipple" (ngModelChange)="onAppearanceChange()">Sem ripple</mat-slide-toggle>
|
|
982
|
+
<mat-slide-toggle [(ngModel)]="group.preserveContent" (ngModelChange)="onAppearanceChange()">Preservar conteudo</mat-slide-toggle>
|
|
983
|
+
<mat-slide-toggle [(ngModel)]="group.stretchTabs" (ngModelChange)="onAppearanceChange()">Esticar abas</mat-slide-toggle>
|
|
835
984
|
</div>
|
|
836
985
|
</div>
|
|
837
986
|
</mat-tab>
|
|
838
987
|
|
|
839
988
|
<mat-tab label="Navegação">
|
|
840
|
-
<div
|
|
841
|
-
<div
|
|
842
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
989
|
+
<div class="editor-section">
|
|
990
|
+
<div class="editor-grid two">
|
|
991
|
+
<mat-form-field appearance="outline"><mat-label>Indice selecionado</mat-label>
|
|
843
992
|
<input matInput type="number" [(ngModel)]="nav.selectedIndex" (ngModelChange)="onAppearanceChange()" />
|
|
993
|
+
<button
|
|
994
|
+
mat-icon-button
|
|
995
|
+
matSuffix
|
|
996
|
+
class="help-icon-button"
|
|
997
|
+
type="button"
|
|
998
|
+
[matTooltip]="'selectedIndex'"
|
|
999
|
+
matTooltipPosition="above"
|
|
1000
|
+
>
|
|
1001
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
1002
|
+
</button>
|
|
844
1003
|
</mat-form-field>
|
|
845
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
1004
|
+
<mat-form-field appearance="outline"><mat-label>Duracao da animacao</mat-label>
|
|
846
1005
|
<input matInput [(ngModel)]="nav.animationDuration" (ngModelChange)="onAppearanceChange()" placeholder="500ms" />
|
|
1006
|
+
<button
|
|
1007
|
+
mat-icon-button
|
|
1008
|
+
matSuffix
|
|
1009
|
+
class="help-icon-button"
|
|
1010
|
+
type="button"
|
|
1011
|
+
[matTooltip]="'animationDuration'"
|
|
1012
|
+
matTooltipPosition="above"
|
|
1013
|
+
>
|
|
1014
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
1015
|
+
</button>
|
|
847
1016
|
</mat-form-field>
|
|
848
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
1017
|
+
<mat-form-field appearance="outline"><mat-label>Cor (M2)</mat-label>
|
|
849
1018
|
<select matNativeControl [(ngModel)]="nav.color" (ngModelChange)="onAppearanceChange()">
|
|
850
|
-
<option [ngValue]="undefined">(
|
|
851
|
-
<option value="primary">
|
|
852
|
-
<option value="accent">
|
|
853
|
-
<option value="warn">
|
|
1019
|
+
<option [ngValue]="undefined">(nenhuma)</option>
|
|
1020
|
+
<option value="primary">Primary</option>
|
|
1021
|
+
<option value="accent">Accent</option>
|
|
1022
|
+
<option value="warn">Warn</option>
|
|
854
1023
|
</select>
|
|
1024
|
+
<button
|
|
1025
|
+
mat-icon-button
|
|
1026
|
+
matSuffix
|
|
1027
|
+
class="help-icon-button"
|
|
1028
|
+
type="button"
|
|
1029
|
+
[matTooltip]="'Preferir tokens em Estilo.'"
|
|
1030
|
+
matTooltipPosition="above"
|
|
1031
|
+
>
|
|
1032
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
1033
|
+
</button>
|
|
855
1034
|
</mat-form-field>
|
|
856
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
1035
|
+
<mat-form-field appearance="outline"><mat-label>Cor de fundo (M2)</mat-label>
|
|
857
1036
|
<select matNativeControl [(ngModel)]="nav.backgroundColor" (ngModelChange)="onAppearanceChange()">
|
|
858
|
-
<option [ngValue]="undefined">(
|
|
859
|
-
<option value="primary">
|
|
860
|
-
<option value="accent">
|
|
861
|
-
<option value="warn">
|
|
1037
|
+
<option [ngValue]="undefined">(nenhuma)</option>
|
|
1038
|
+
<option value="primary">Primary</option>
|
|
1039
|
+
<option value="accent">Accent</option>
|
|
1040
|
+
<option value="warn">Warn</option>
|
|
862
1041
|
</select>
|
|
1042
|
+
<button
|
|
1043
|
+
mat-icon-button
|
|
1044
|
+
matSuffix
|
|
1045
|
+
class="help-icon-button"
|
|
1046
|
+
type="button"
|
|
1047
|
+
[matTooltip]="'Preferir tokens em Estilo.'"
|
|
1048
|
+
matTooltipPosition="above"
|
|
1049
|
+
>
|
|
1050
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
1051
|
+
</button>
|
|
863
1052
|
</mat-form-field>
|
|
864
1053
|
</div>
|
|
865
|
-
<div
|
|
866
|
-
<mat-slide-toggle [(ngModel)]="nav.fitInkBarToContent" (ngModelChange)="onAppearanceChange()">
|
|
867
|
-
<mat-slide-toggle [(ngModel)]="nav.disablePagination" (ngModelChange)="onAppearanceChange()">
|
|
868
|
-
<mat-slide-toggle [(ngModel)]="nav.disableRipple" (ngModelChange)="onAppearanceChange()">
|
|
869
|
-
<mat-slide-toggle [(ngModel)]="nav.stretchTabs" (ngModelChange)="onAppearanceChange()">
|
|
1054
|
+
<div class="editor-row">
|
|
1055
|
+
<mat-slide-toggle [(ngModel)]="nav.fitInkBarToContent" (ngModelChange)="onAppearanceChange()">Indicador ajustado ao conteudo</mat-slide-toggle>
|
|
1056
|
+
<mat-slide-toggle [(ngModel)]="nav.disablePagination" (ngModelChange)="onAppearanceChange()">Sem paginacao</mat-slide-toggle>
|
|
1057
|
+
<mat-slide-toggle [(ngModel)]="nav.disableRipple" (ngModelChange)="onAppearanceChange()">Sem ripple</mat-slide-toggle>
|
|
1058
|
+
<mat-slide-toggle [(ngModel)]="nav.stretchTabs" (ngModelChange)="onAppearanceChange()">Esticar abas</mat-slide-toggle>
|
|
870
1059
|
</div>
|
|
871
1060
|
</div>
|
|
872
1061
|
</mat-tab>
|
|
873
1062
|
<mat-tab label="JSON">
|
|
874
|
-
<div
|
|
875
|
-
<div class="
|
|
1063
|
+
<div class="editor-section">
|
|
1064
|
+
<div class="editor-toolbar">
|
|
876
1065
|
<button mat-button (click)="formatJson()" [disabled]="!isValid">
|
|
877
1066
|
<mat-icon [praxisIcon]="'format_align_left'"></mat-icon>Formatar
|
|
878
1067
|
</button>
|
|
@@ -881,26 +1070,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
881
1070
|
</button>
|
|
882
1071
|
</div>
|
|
883
1072
|
|
|
884
|
-
<mat-form-field appearance="outline" class="json-textarea-field
|
|
885
|
-
<mat-label>
|
|
1073
|
+
<mat-form-field appearance="outline" class="json-textarea-field full">
|
|
1074
|
+
<mat-label>Configuracao JSON</mat-label>
|
|
886
1075
|
<textarea
|
|
887
1076
|
matInput
|
|
888
1077
|
[(ngModel)]="jsonText"
|
|
889
1078
|
(ngModelChange)="onJsonTextChange($event)"
|
|
890
1079
|
rows="22"
|
|
891
1080
|
spellcheck="false"
|
|
892
|
-
|
|
1081
|
+
class="editor-json"
|
|
893
1082
|
></textarea>
|
|
894
|
-
<mat-hint *ngIf="isValid">JSON
|
|
895
|
-
<mat-error *ngIf="!isValid && jsonText">JSON
|
|
1083
|
+
<mat-hint *ngIf="isValid">JSON valido</mat-hint>
|
|
1084
|
+
<mat-error *ngIf="!isValid && jsonText">JSON invalido: {{ errorMsg }}</mat-error>
|
|
896
1085
|
</mat-form-field>
|
|
897
1086
|
</div>
|
|
898
1087
|
</mat-tab>
|
|
899
1088
|
|
|
900
1089
|
<mat-tab label="Estilo">
|
|
901
|
-
<div
|
|
902
|
-
<div
|
|
903
|
-
<span
|
|
1090
|
+
<div class="editor-section editor-section-lg">
|
|
1091
|
+
<div class="editor-row">
|
|
1092
|
+
<span class="editor-muted">Presets:</span>
|
|
904
1093
|
<button mat-button color="primary" (click)="applyPreset('primary')">
|
|
905
1094
|
<mat-icon [praxisIcon]="'palette'"></mat-icon>
|
|
906
1095
|
Primário
|
|
@@ -919,7 +1108,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
919
1108
|
</button>
|
|
920
1109
|
</div>
|
|
921
1110
|
|
|
922
|
-
<div
|
|
1111
|
+
<div class="editor-grid two tight">
|
|
923
1112
|
<mat-form-field appearance="outline">
|
|
924
1113
|
<mat-label>Classe de tema (opcional)</mat-label>
|
|
925
1114
|
<input matInput [(ngModel)]="appearance.themeClass" (ngModelChange)="onAppearanceChange()" placeholder="ex.: tabs-accented" />
|
|
@@ -928,38 +1117,48 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
928
1117
|
<mat-form-field appearance="outline">
|
|
929
1118
|
<mat-label>Densidade</mat-label>
|
|
930
1119
|
<select matNativeControl [(ngModel)]="appearance.density" (ngModelChange)="onAppearanceChange()">
|
|
931
|
-
<option [ngValue]="undefined">
|
|
932
|
-
<option value="compact">
|
|
933
|
-
<option value="comfortable">
|
|
934
|
-
<option value="spacious">
|
|
1120
|
+
<option [ngValue]="undefined">Padrao</option>
|
|
1121
|
+
<option value="compact">Compacta</option>
|
|
1122
|
+
<option value="comfortable">Confortavel</option>
|
|
1123
|
+
<option value="spacious">Espacosa</option>
|
|
935
1124
|
</select>
|
|
936
1125
|
</mat-form-field>
|
|
937
1126
|
</div>
|
|
938
1127
|
|
|
939
1128
|
<div>
|
|
940
|
-
<
|
|
941
|
-
|
|
1129
|
+
<div class="editor-title-row">
|
|
1130
|
+
<h3 class="editor-title">Tokens (Material 3)</h3>
|
|
1131
|
+
<button
|
|
1132
|
+
mat-icon-button
|
|
1133
|
+
class="help-icon-button"
|
|
1134
|
+
type="button"
|
|
1135
|
+
[matTooltip]="'Valores aceitam CSS vars (ex.: var(--md-sys-color-primary)) ou cores hex/rgb.'"
|
|
1136
|
+
matTooltipPosition="above"
|
|
1137
|
+
>
|
|
1138
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
1139
|
+
</button>
|
|
1140
|
+
</div>
|
|
1141
|
+
<div class="editor-grid two">
|
|
942
1142
|
<ng-container *ngFor="let t of tokenList">
|
|
943
1143
|
<mat-form-field appearance="outline">
|
|
944
1144
|
<mat-label>{{ t.label }}</mat-label>
|
|
945
|
-
<input matInput placeholder="var(--
|
|
1145
|
+
<input matInput placeholder="var(--md-sys-color-primary) / #RRGGBB" [ngModel]="appearance.tokens?.[t.key]" (ngModelChange)="onTokenChange(t.key, $event)" />
|
|
946
1146
|
</mat-form-field>
|
|
947
1147
|
</ng-container>
|
|
948
1148
|
</div>
|
|
949
|
-
<p style="margin:8px 0 0; color: var(--mat-sys-on-surface-variant); font-size: 12px;">Dica: valores aceitam CSS vars (ex.: <code>var(--mat-sys-primary)</code>) ou cores hex/rgb.</p>
|
|
950
1149
|
</div>
|
|
951
1150
|
|
|
952
1151
|
<div>
|
|
953
|
-
<h3
|
|
954
|
-
<mat-form-field appearance="outline" class="json-textarea-field
|
|
1152
|
+
<h3 class="editor-title">CSS personalizado</h3>
|
|
1153
|
+
<mat-form-field appearance="outline" class="json-textarea-field full">
|
|
955
1154
|
<mat-label>CSS a ser injetado no componente</mat-label>
|
|
956
1155
|
<textarea matInput rows="10" [(ngModel)]="appearance.customCss" (ngModelChange)="onAppearanceChange()" placeholder=".praxis-tabs-root .mdc-tab__text-label { font-weight: 600; }"></textarea>
|
|
957
1156
|
</mat-form-field>
|
|
958
1157
|
</div>
|
|
959
1158
|
|
|
960
1159
|
<div>
|
|
961
|
-
<h3
|
|
962
|
-
<pre
|
|
1160
|
+
<h3 class="editor-title">Snippet SCSS (para uso em styles.scss)</h3>
|
|
1161
|
+
<pre class="editor-code">
|
|
963
1162
|
@use '@angular/material' as mat;
|
|
964
1163
|
{{ scssSnippet() }}
|
|
965
1164
|
</pre>
|
|
@@ -968,27 +1167,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
968
1167
|
</mat-tab>
|
|
969
1168
|
|
|
970
1169
|
<mat-tab label="Abas">
|
|
971
|
-
<div
|
|
1170
|
+
<div class="editor-section">
|
|
972
1171
|
<button mat-stroked-button color="primary" (click)="addTab()"><mat-icon [praxisIcon]="'add'"></mat-icon>Adicionar aba</button>
|
|
973
|
-
<div *ngIf="editedConfig.tabs?.length; else noTabs"
|
|
974
|
-
<div *ngFor="let t of editedConfig.tabs; let i = index"
|
|
975
|
-
<div
|
|
976
|
-
<strong
|
|
1172
|
+
<div *ngIf="editedConfig.tabs?.length; else noTabs" class="editor-grid">
|
|
1173
|
+
<div *ngFor="let t of editedConfig.tabs; let i = index" class="editor-card">
|
|
1174
|
+
<div class="editor-card-header">
|
|
1175
|
+
<strong class="editor-card-title">Aba #{{ i+1 }}</strong>
|
|
977
1176
|
<button mat-icon-button (click)="moveTab(i, -1)" [disabled]="i===0"><mat-icon [praxisIcon]="'arrow_upward'"></mat-icon></button>
|
|
978
1177
|
<button mat-icon-button (click)="moveTab(i, 1)" [disabled]="i===editedConfig.tabs!.length-1"><mat-icon [praxisIcon]="'arrow_downward'"></mat-icon></button>
|
|
979
1178
|
<button mat-icon-button color="warn" (click)="removeTab(i)"><mat-icon [praxisIcon]="'delete'"></mat-icon></button>
|
|
980
1179
|
</div>
|
|
981
|
-
<div
|
|
1180
|
+
<div class="editor-grid two tight">
|
|
982
1181
|
<mat-form-field appearance="outline"><mat-label>ID</mat-label>
|
|
983
1182
|
<input matInput [(ngModel)]="t.id" (ngModelChange)="onAppearanceChange()" />
|
|
984
1183
|
</mat-form-field>
|
|
985
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
1184
|
+
<mat-form-field appearance="outline"><mat-label>Rotulo</mat-label>
|
|
986
1185
|
<input matInput [(ngModel)]="t.textLabel" (ngModelChange)="onAppearanceChange()" />
|
|
987
1186
|
</mat-form-field>
|
|
988
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
1187
|
+
<mat-form-field appearance="outline"><mat-label>Classe do rotulo</mat-label>
|
|
989
1188
|
<input matInput [(ngModel)]="t.labelClass" (ngModelChange)="onAppearanceChange()" />
|
|
990
1189
|
</mat-form-field>
|
|
991
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
1190
|
+
<mat-form-field appearance="outline"><mat-label>Classe do conteudo</mat-label>
|
|
992
1191
|
<input matInput [(ngModel)]="t.bodyClass" (ngModelChange)="onAppearanceChange()" />
|
|
993
1192
|
</mat-form-field>
|
|
994
1193
|
<mat-form-field appearance="outline"><mat-label>aria-label</mat-label>
|
|
@@ -998,22 +1197,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
998
1197
|
<input matInput [(ngModel)]="t.ariaLabelledby" (ngModelChange)="onAppearanceChange()" />
|
|
999
1198
|
</mat-form-field>
|
|
1000
1199
|
</div>
|
|
1001
|
-
<mat-slide-toggle [(ngModel)]="t.disabled" (ngModelChange)="onAppearanceChange()">
|
|
1200
|
+
<mat-slide-toggle [(ngModel)]="t.disabled" (ngModelChange)="onAppearanceChange()">Desativada</mat-slide-toggle>
|
|
1002
1201
|
|
|
1003
1202
|
<!-- Widgets (componentes dinâmicos) -->
|
|
1004
|
-
<div
|
|
1005
|
-
<div
|
|
1006
|
-
<mat-form-field appearance="outline"
|
|
1203
|
+
<div class="editor-divider editor-grid">
|
|
1204
|
+
<div class="editor-row">
|
|
1205
|
+
<mat-form-field appearance="outline" class="editor-field-min">
|
|
1007
1206
|
<mat-label>Adicionar componente</mat-label>
|
|
1008
1207
|
<select matNativeControl [(ngModel)]="selectedTabWidgetId[i]">
|
|
1009
1208
|
<option [ngValue]="''">(selecione)</option>
|
|
1010
1209
|
<option *ngFor="let c of componentOptions" [ngValue]="c.id">{{ c.friendlyName || c.id }}</option>
|
|
1011
1210
|
</select>
|
|
1012
1211
|
</mat-form-field>
|
|
1013
|
-
|
|
1014
|
-
<span
|
|
1015
|
-
<mat-form-field appearance="outline"
|
|
1016
|
-
<mat-label>resourcePath</mat-label>
|
|
1212
|
+
<button mat-stroked-button (click)="addWidgetToTab(i)"><mat-icon [praxisIcon]="'add'"></mat-icon>Adicionar</button>
|
|
1213
|
+
<span class="editor-spacer"></span>
|
|
1214
|
+
<mat-form-field appearance="outline" class="editor-field-240">
|
|
1215
|
+
<mat-label>Recurso (resourcePath)</mat-label>
|
|
1017
1216
|
<input matInput [(ngModel)]="quickResourcePathTab[i]" placeholder="ex.: usuarios" />
|
|
1018
1217
|
</mat-form-field>
|
|
1019
1218
|
<button mat-button (click)="addPresetToTab(i, 'form')"><mat-icon [praxisIcon]="'description'"></mat-icon>Form</button>
|
|
@@ -1021,22 +1220,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
1021
1220
|
<button mat-button (click)="addPresetToTab(i, 'crud')"><mat-icon [praxisIcon]="'dynamic_form'"></mat-icon>CRUD</button>
|
|
1022
1221
|
</div>
|
|
1023
1222
|
|
|
1024
|
-
<div *ngIf="t.widgets?.length"
|
|
1025
|
-
<div *ngFor="let w of t.widgets; let wi = index" cdkDrag
|
|
1026
|
-
<div
|
|
1223
|
+
<div *ngIf="t.widgets?.length" class="editor-grid" cdkDropList [cdkDropListData]="t.widgets || []" (cdkDropListDropped)="onTabWidgetDrop(i, $event)">
|
|
1224
|
+
<div *ngFor="let w of t.widgets; let wi = index" cdkDrag class="editor-card dashed">
|
|
1225
|
+
<div class="editor-card-header">
|
|
1027
1226
|
<button mat-icon-button cdkDragHandle matTooltip="Arrastar para reordenar" aria-label="Arrastar para reordenar">
|
|
1028
1227
|
<mat-icon [praxisIcon]="'drag_indicator'"></mat-icon>
|
|
1029
1228
|
</button>
|
|
1030
|
-
<strong
|
|
1229
|
+
<strong class="editor-card-title">{{ getCompName(w.id) }}</strong>
|
|
1031
1230
|
<button mat-icon-button color="warn" (click)="removeWidgetFromTab(i, wi)" matTooltip="Remover componente" aria-label="Remover componente"><mat-icon [praxisIcon]="'delete'"></mat-icon></button>
|
|
1032
1231
|
</div>
|
|
1033
|
-
<div
|
|
1232
|
+
<div class="editor-grid two tight">
|
|
1034
1233
|
<mat-form-field appearance="outline">
|
|
1035
|
-
<mat-label>
|
|
1234
|
+
<mat-label>Inputs (JSON)</mat-label>
|
|
1036
1235
|
<textarea matInput rows="4" [ngModel]="stringify(w.inputs)" (ngModelChange)="updateWidgetInputsTab(i, wi, $event)"></textarea>
|
|
1037
1236
|
</mat-form-field>
|
|
1038
1237
|
<mat-form-field appearance="outline">
|
|
1039
|
-
<mat-label>
|
|
1238
|
+
<mat-label>Outputs (JSON)</mat-label>
|
|
1040
1239
|
<textarea matInput rows="4" [ngModel]="stringify(w.outputs)" (ngModelChange)="updateWidgetOutputsTab(i, wi, $event)"></textarea>
|
|
1041
1240
|
</mat-form-field>
|
|
1042
1241
|
</div>
|
|
@@ -1045,49 +1244,49 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
1045
1244
|
</div>
|
|
1046
1245
|
</div>
|
|
1047
1246
|
</div>
|
|
1048
|
-
<ng-template #noTabs><em>Nenhuma aba definida.</em></ng-template>
|
|
1247
|
+
<ng-template #noTabs><em class="editor-muted">Nenhuma aba definida.</em></ng-template>
|
|
1049
1248
|
</div>
|
|
1050
1249
|
</mat-tab>
|
|
1051
1250
|
|
|
1052
1251
|
<mat-tab label="Acessibilidade">
|
|
1053
|
-
<div
|
|
1054
|
-
<div
|
|
1055
|
-
<mat-slide-toggle [(ngModel)]="accessibility.highContrast" (ngModelChange)="onAppearanceChange()">
|
|
1056
|
-
<mat-slide-toggle [(ngModel)]="accessibility.reduceMotion" (ngModelChange)="onAppearanceChange()">
|
|
1252
|
+
<div class="editor-section">
|
|
1253
|
+
<div class="editor-row">
|
|
1254
|
+
<mat-slide-toggle [(ngModel)]="accessibility.highContrast" (ngModelChange)="onAppearanceChange()">Alto contraste</mat-slide-toggle>
|
|
1255
|
+
<mat-slide-toggle [(ngModel)]="accessibility.reduceMotion" (ngModelChange)="onAppearanceChange()">Reduzir movimento</mat-slide-toggle>
|
|
1057
1256
|
</div>
|
|
1058
1257
|
</div>
|
|
1059
1258
|
</mat-tab>
|
|
1060
1259
|
|
|
1061
1260
|
<mat-tab label="Links">
|
|
1062
|
-
<div
|
|
1261
|
+
<div class="editor-section">
|
|
1063
1262
|
<button mat-stroked-button color="primary" (click)="addLink()"><mat-icon [praxisIcon]="'add_link'"></mat-icon>Adicionar link</button>
|
|
1064
|
-
<div *ngIf="nav.links?.length; else noLinks"
|
|
1065
|
-
<div *ngFor="let l of nav.links; let i = index"
|
|
1066
|
-
<div
|
|
1067
|
-
<strong
|
|
1263
|
+
<div *ngIf="nav.links?.length; else noLinks" class="editor-grid">
|
|
1264
|
+
<div *ngFor="let l of nav.links; let i = index" class="editor-card">
|
|
1265
|
+
<div class="editor-card-header">
|
|
1266
|
+
<strong class="editor-card-title">Link #{{ i+1 }}</strong>
|
|
1068
1267
|
<button mat-icon-button (click)="moveLink(i, -1)" [disabled]="i===0"><mat-icon [praxisIcon]="'arrow_upward'"></mat-icon></button>
|
|
1069
1268
|
<button mat-icon-button (click)="moveLink(i, 1)" [disabled]="i===nav.links!.length-1"><mat-icon [praxisIcon]="'arrow_downward'"></mat-icon></button>
|
|
1070
1269
|
<button mat-icon-button color="warn" (click)="removeLink(i)"><mat-icon [praxisIcon]="'delete'"></mat-icon></button>
|
|
1071
1270
|
</div>
|
|
1072
|
-
<div
|
|
1271
|
+
<div class="editor-grid two tight">
|
|
1073
1272
|
<mat-form-field appearance="outline"><mat-label>ID</mat-label>
|
|
1074
1273
|
<input matInput [(ngModel)]="l.id" (ngModelChange)="onAppearanceChange()" />
|
|
1075
1274
|
</mat-form-field>
|
|
1076
|
-
<mat-form-field appearance="outline"><mat-label>
|
|
1275
|
+
<mat-form-field appearance="outline"><mat-label>Rotulo</mat-label>
|
|
1077
1276
|
<input matInput [(ngModel)]="l.label" (ngModelChange)="onAppearanceChange()" />
|
|
1078
1277
|
</mat-form-field>
|
|
1079
1278
|
</div>
|
|
1080
|
-
<div
|
|
1081
|
-
<mat-slide-toggle [(ngModel)]="l.active" (ngModelChange)="onAppearanceChange()">
|
|
1082
|
-
<mat-slide-toggle [(ngModel)]="l.disabled" (ngModelChange)="onAppearanceChange()">
|
|
1083
|
-
<mat-slide-toggle [(ngModel)]="l.disableRipple" (ngModelChange)="onAppearanceChange()">
|
|
1084
|
-
<mat-slide-toggle [(ngModel)]="l.fitInkBarToContent" (ngModelChange)="onAppearanceChange()">
|
|
1279
|
+
<div class="editor-row">
|
|
1280
|
+
<mat-slide-toggle [(ngModel)]="l.active" (ngModelChange)="onAppearanceChange()">Ativo</mat-slide-toggle>
|
|
1281
|
+
<mat-slide-toggle [(ngModel)]="l.disabled" (ngModelChange)="onAppearanceChange()">Desativado</mat-slide-toggle>
|
|
1282
|
+
<mat-slide-toggle [(ngModel)]="l.disableRipple" (ngModelChange)="onAppearanceChange()">Sem ripple</mat-slide-toggle>
|
|
1283
|
+
<mat-slide-toggle [(ngModel)]="l.fitInkBarToContent" (ngModelChange)="onAppearanceChange()">Indicador ajustado ao conteudo</mat-slide-toggle>
|
|
1085
1284
|
</div>
|
|
1086
1285
|
|
|
1087
1286
|
<!-- Widgets para Links -->
|
|
1088
|
-
<div
|
|
1089
|
-
<div
|
|
1090
|
-
<mat-form-field appearance="outline"
|
|
1287
|
+
<div class="editor-divider editor-grid">
|
|
1288
|
+
<div class="editor-row">
|
|
1289
|
+
<mat-form-field appearance="outline" class="editor-field-min">
|
|
1091
1290
|
<mat-label>Adicionar componente</mat-label>
|
|
1092
1291
|
<select matNativeControl [(ngModel)]="selectedLinkWidgetId[i]">
|
|
1093
1292
|
<option [ngValue]="''">(selecione)</option>
|
|
@@ -1095,9 +1294,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
1095
1294
|
</select>
|
|
1096
1295
|
</mat-form-field>
|
|
1097
1296
|
<button mat-stroked-button (click)="addWidgetToLink(i)"><mat-icon [praxisIcon]="'add'"></mat-icon>Adicionar</button>
|
|
1098
|
-
<span
|
|
1099
|
-
<mat-form-field appearance="outline"
|
|
1100
|
-
<mat-label>resourcePath</mat-label>
|
|
1297
|
+
<span class="editor-spacer"></span>
|
|
1298
|
+
<mat-form-field appearance="outline" class="editor-field-240">
|
|
1299
|
+
<mat-label>Recurso (resourcePath)</mat-label>
|
|
1101
1300
|
<input matInput [(ngModel)]="quickResourcePathLink[i]" placeholder="ex.: usuarios" />
|
|
1102
1301
|
</mat-form-field>
|
|
1103
1302
|
<button mat-button (click)="addPresetToLink(i, 'form')"><mat-icon [praxisIcon]="'description'"></mat-icon>Form</button>
|
|
@@ -1105,22 +1304,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
1105
1304
|
<button mat-button (click)="addPresetToLink(i, 'crud')"><mat-icon [praxisIcon]="'dynamic_form'"></mat-icon>CRUD</button>
|
|
1106
1305
|
</div>
|
|
1107
1306
|
|
|
1108
|
-
<div *ngIf="l.widgets?.length"
|
|
1109
|
-
<div *ngFor="let w of l.widgets; let wi = index" cdkDrag
|
|
1110
|
-
<div
|
|
1307
|
+
<div *ngIf="l.widgets?.length" class="editor-grid" cdkDropList [cdkDropListData]="l.widgets || []" (cdkDropListDropped)="onLinkWidgetDrop(i, $event)">
|
|
1308
|
+
<div *ngFor="let w of l.widgets; let wi = index" cdkDrag class="editor-card dashed">
|
|
1309
|
+
<div class="editor-card-header">
|
|
1111
1310
|
<button mat-icon-button cdkDragHandle matTooltip="Arrastar para reordenar" aria-label="Arrastar para reordenar">
|
|
1112
1311
|
<mat-icon [praxisIcon]="'drag_indicator'"></mat-icon>
|
|
1113
1312
|
</button>
|
|
1114
|
-
<strong
|
|
1313
|
+
<strong class="editor-card-title">{{ getCompName(w.id) }}</strong>
|
|
1115
1314
|
<button mat-icon-button color="warn" (click)="removeWidgetFromLink(i, wi)" matTooltip="Remover componente" aria-label="Remover componente"><mat-icon [praxisIcon]="'delete'"></mat-icon></button>
|
|
1116
1315
|
</div>
|
|
1117
|
-
<div
|
|
1316
|
+
<div class="editor-grid two tight">
|
|
1118
1317
|
<mat-form-field appearance="outline">
|
|
1119
|
-
<mat-label>
|
|
1318
|
+
<mat-label>Inputs (JSON)</mat-label>
|
|
1120
1319
|
<textarea matInput rows="4" [ngModel]="stringify(w.inputs)" (ngModelChange)="updateWidgetInputsLink(i, wi, $event)"></textarea>
|
|
1121
1320
|
</mat-form-field>
|
|
1122
1321
|
<mat-form-field appearance="outline">
|
|
1123
|
-
<mat-label>
|
|
1322
|
+
<mat-label>Outputs (JSON)</mat-label>
|
|
1124
1323
|
<textarea matInput rows="4" [ngModel]="stringify(w.outputs)" (ngModelChange)="updateWidgetOutputsLink(i, wi, $event)"></textarea>
|
|
1125
1324
|
</mat-form-field>
|
|
1126
1325
|
</div>
|
|
@@ -1129,12 +1328,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
1129
1328
|
</div>
|
|
1130
1329
|
</div>
|
|
1131
1330
|
</div>
|
|
1132
|
-
<ng-template #noLinks><em>Nenhum link definido.</em></ng-template>
|
|
1331
|
+
<ng-template #noLinks><em class="editor-muted">Nenhum link definido.</em></ng-template>
|
|
1133
1332
|
</div>
|
|
1134
1333
|
</mat-tab>
|
|
1135
1334
|
</mat-tab-group>
|
|
1136
|
-
`,
|
|
1137
|
-
}]
|
|
1335
|
+
`, styles: [":host{display:block;color:var(--md-sys-color-on-surface)}.editor-tabs{--editor-surface: var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface));--editor-border: 1px solid var(--md-sys-color-outline-variant);--editor-radius: 12px;--editor-muted: var(--md-sys-color-on-surface-variant)}.editor-section{padding:12px;display:grid;gap:12px;background:var(--editor-surface);border:var(--editor-border);border-radius:var(--editor-radius)}.editor-section-lg{gap:16px}.editor-row{display:flex;gap:10px;flex-wrap:wrap;align-items:center}.editor-grid{display:grid;gap:12px}.editor-grid.two{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.editor-grid.tight{gap:8px}.editor-toolbar{display:flex;gap:8px;flex-wrap:wrap;align-items:center}.editor-muted{color:var(--editor-muted)}.editor-title{margin:6px 0 8px;font-size:1rem}.editor-title-row{display:flex;align-items:center;gap:8px}.editor-code{white-space:pre-wrap;background:var(--md-sys-color-surface-container);padding:8px;border-radius:6px;border:1px solid var(--md-sys-color-outline-variant)}.editor-card{border:1px solid var(--md-sys-color-outline-variant);padding:10px;border-radius:10px;display:grid;gap:8px;background:var(--md-sys-color-surface)}.editor-card.dashed{border-style:dashed}.editor-card-header{display:flex;align-items:center;gap:8px}.editor-card-title{flex:1;font-weight:600}.editor-divider{border-top:1px solid var(--md-sys-color-outline-variant);padding-top:8px}.editor-spacer{flex:1}.editor-field-min{min-width:260px}.editor-section .editor-field-min{width:260px;max-width:260px}.editor-field-240{width:240px}.editor-section .editor-field-240{width:240px;max-width:240px}.editor-json{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.editor-section .mat-mdc-form-field{width:100%;max-width:520px;--mdc-outlined-text-field-container-height: 48px;--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-outline);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-error-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-focus-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-hover-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-supporting-text-color: var(--md-sys-color-on-surface-variant)}.editor-section .mat-mdc-form-field.full{max-width:none}.help-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 18px;width:28px;height:28px;padding:0;display:inline-flex;align-items:center;justify-content:center;margin-right:-4px}.help-icon-button mat-icon{font-size:18px;width:18px;height:18px}.mat-mdc-form-field-icon-suffix{align-self:center}\n"] }]
|
|
1138
1336
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1139
1337
|
type: Inject,
|
|
1140
1338
|
args: [SETTINGS_PANEL_DATA]
|
|
@@ -1153,23 +1351,32 @@ class TabsQuickSetupComponent {
|
|
|
1153
1351
|
if (cfg) {
|
|
1154
1352
|
if (cfg.tabs?.length) {
|
|
1155
1353
|
this.model.mode = 'group';
|
|
1156
|
-
this.model.labels = cfg.tabs
|
|
1354
|
+
this.model.labels = cfg.tabs
|
|
1355
|
+
.map((t) => String(t.textLabel || '').trim())
|
|
1356
|
+
.filter((label) => label.length > 0);
|
|
1157
1357
|
this.model.dynamicHeight = cfg.group?.dynamicHeight ?? true;
|
|
1158
1358
|
this.model.stretchTabs = cfg.group?.stretchTabs ?? true;
|
|
1159
1359
|
}
|
|
1160
1360
|
else if (cfg.nav?.links?.length) {
|
|
1161
1361
|
this.model.mode = 'nav';
|
|
1162
|
-
this.model.labels = cfg.nav.links
|
|
1362
|
+
this.model.labels = cfg.nav.links
|
|
1363
|
+
.map((l) => String(l.label || '').trim())
|
|
1364
|
+
.filter((label) => label.length > 0);
|
|
1163
1365
|
this.model.stretchTabs = cfg.nav.stretchTabs ?? true;
|
|
1164
1366
|
}
|
|
1165
1367
|
this.initial = { ...this.model, labels: [...this.model.labels] };
|
|
1166
1368
|
}
|
|
1167
1369
|
this.updateState();
|
|
1168
1370
|
}
|
|
1371
|
+
normalizedLabels() {
|
|
1372
|
+
return this.model.labels
|
|
1373
|
+
.map((label) => String(label || '').trim())
|
|
1374
|
+
.filter((label) => label.length > 0);
|
|
1375
|
+
}
|
|
1169
1376
|
updateState() {
|
|
1170
1377
|
const dirty = JSON.stringify(this.model) !== JSON.stringify(this.initial);
|
|
1171
1378
|
this.isDirty$.next(dirty);
|
|
1172
|
-
this.isValid$.next(this.
|
|
1379
|
+
this.isValid$.next(this.normalizedLabels().length > 0);
|
|
1173
1380
|
}
|
|
1174
1381
|
setMode(mode) {
|
|
1175
1382
|
this.model.mode = mode;
|
|
@@ -1188,6 +1395,7 @@ class TabsQuickSetupComponent {
|
|
|
1188
1395
|
this.updateState();
|
|
1189
1396
|
}
|
|
1190
1397
|
buildConfig() {
|
|
1398
|
+
const labels = this.normalizedLabels();
|
|
1191
1399
|
if (this.model.mode === 'group') {
|
|
1192
1400
|
return {
|
|
1193
1401
|
group: {
|
|
@@ -1195,14 +1403,14 @@ class TabsQuickSetupComponent {
|
|
|
1195
1403
|
stretchTabs: !!this.model.stretchTabs,
|
|
1196
1404
|
selectedIndex: 0,
|
|
1197
1405
|
},
|
|
1198
|
-
tabs:
|
|
1406
|
+
tabs: labels.map((label, idx) => ({ id: `tab${idx + 1}`, textLabel: label })),
|
|
1199
1407
|
};
|
|
1200
1408
|
}
|
|
1201
1409
|
return {
|
|
1202
1410
|
nav: {
|
|
1203
1411
|
selectedIndex: 0,
|
|
1204
1412
|
stretchTabs: !!this.model.stretchTabs,
|
|
1205
|
-
links:
|
|
1413
|
+
links: labels.map((label, idx) => ({ id: `link${idx + 1}`, label })),
|
|
1206
1414
|
},
|
|
1207
1415
|
};
|
|
1208
1416
|
}
|
|
@@ -1214,21 +1422,21 @@ class TabsQuickSetupComponent {
|
|
|
1214
1422
|
}
|
|
1215
1423
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: TabsQuickSetupComponent, deps: [{ token: SETTINGS_PANEL_DATA }], target: i0.ɵɵFactoryTarget.Component });
|
|
1216
1424
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: TabsQuickSetupComponent, isStandalone: true, selector: "praxis-tabs-quick-setup", ngImport: i0, template: `
|
|
1217
|
-
<div
|
|
1218
|
-
<div
|
|
1425
|
+
<div class="setup-root">
|
|
1426
|
+
<div class="setup-row">
|
|
1219
1427
|
<button mat-stroked-button [color]="model.mode==='group' ? 'primary' : undefined" (click)="setMode('group')">
|
|
1220
1428
|
<mat-icon [praxisIcon]="'tab'"></mat-icon>
|
|
1221
|
-
|
|
1429
|
+
Grupo de abas
|
|
1222
1430
|
</button>
|
|
1223
1431
|
<button mat-stroked-button [color]="model.mode==='nav' ? 'primary' : undefined" (click)="setMode('nav')">
|
|
1224
1432
|
<mat-icon [praxisIcon]="'segment'"></mat-icon>
|
|
1225
|
-
|
|
1433
|
+
Navegacao por links
|
|
1226
1434
|
</button>
|
|
1227
1435
|
</div>
|
|
1228
1436
|
|
|
1229
|
-
<div
|
|
1437
|
+
<div class="setup-grid">
|
|
1230
1438
|
<mat-form-field appearance="outline">
|
|
1231
|
-
<mat-label>Adicionar
|
|
1439
|
+
<mat-label>Adicionar rotulo</mat-label>
|
|
1232
1440
|
<input matInput [(ngModel)]="newLabel" (keyup.enter)="addLabel()" placeholder="Ex.: Dados Gerais" />
|
|
1233
1441
|
</mat-form-field>
|
|
1234
1442
|
<button mat-flat-button color="primary" (click)="addLabel()">
|
|
@@ -1237,22 +1445,22 @@ class TabsQuickSetupComponent {
|
|
|
1237
1445
|
</button>
|
|
1238
1446
|
</div>
|
|
1239
1447
|
|
|
1240
|
-
<div *ngIf="model.labels.length; else emptyLabels"
|
|
1448
|
+
<div *ngIf="model.labels.length; else emptyLabels" class="setup-row wrap">
|
|
1241
1449
|
<div *ngFor="let l of model.labels; let i = index" class="chip">
|
|
1242
1450
|
<span>{{ l }}</span>
|
|
1243
|
-
<button mat-icon-button (click)="removeLabel(i)"><mat-icon [praxisIcon]="'close'"></mat-icon></button>
|
|
1451
|
+
<button mat-icon-button (click)="removeLabel(i)" aria-label="Remover rotulo"><mat-icon [praxisIcon]="'close'"></mat-icon></button>
|
|
1244
1452
|
</div>
|
|
1245
1453
|
</div>
|
|
1246
1454
|
<ng-template #emptyLabels>
|
|
1247
|
-
<em>Adicione
|
|
1455
|
+
<em class="hint">Adicione um ou mais rotulos para criar as abas.</em>
|
|
1248
1456
|
</ng-template>
|
|
1249
1457
|
|
|
1250
|
-
<div
|
|
1251
|
-
<mat-slide-toggle [(ngModel)]="model.dynamicHeight">
|
|
1252
|
-
<mat-slide-toggle [(ngModel)]="model.stretchTabs">
|
|
1458
|
+
<div class="setup-row">
|
|
1459
|
+
<mat-slide-toggle [(ngModel)]="model.dynamicHeight">Altura dinamica</mat-slide-toggle>
|
|
1460
|
+
<mat-slide-toggle [(ngModel)]="model.stretchTabs">Esticar abas</mat-slide-toggle>
|
|
1253
1461
|
</div>
|
|
1254
1462
|
</div>
|
|
1255
|
-
`, isInline: true, styles: [".chip{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;border:1px solid var(--
|
|
1463
|
+
`, isInline: true, styles: [":host{display:block;color:var(--md-sys-color-on-surface)}.setup-root{display:grid;gap:12px;padding:8px;background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:12px}.setup-row{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.setup-row.wrap{flex-wrap:wrap}.setup-grid{display:grid;grid-template-columns:1fr auto;gap:8px;align-items:start}.setup-root .mat-mdc-form-field{width:100%;max-width:520px;--mdc-outlined-text-field-container-height: 48px;--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-outline);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-error-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-focus-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-hover-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-supporting-text-color: var(--md-sys-color-on-surface-variant)}.chip{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:16px;background:var(--md-sys-color-surface)}.hint{color:var(--md-sys-color-on-surface-variant)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.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: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6$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: "component", type: i6$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i9.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }] });
|
|
1256
1464
|
}
|
|
1257
1465
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: TabsQuickSetupComponent, decorators: [{
|
|
1258
1466
|
type: Component,
|
|
@@ -1266,21 +1474,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
1266
1474
|
MatButtonModule,
|
|
1267
1475
|
MatSlideToggleModule,
|
|
1268
1476
|
], template: `
|
|
1269
|
-
<div
|
|
1270
|
-
<div
|
|
1477
|
+
<div class="setup-root">
|
|
1478
|
+
<div class="setup-row">
|
|
1271
1479
|
<button mat-stroked-button [color]="model.mode==='group' ? 'primary' : undefined" (click)="setMode('group')">
|
|
1272
1480
|
<mat-icon [praxisIcon]="'tab'"></mat-icon>
|
|
1273
|
-
|
|
1481
|
+
Grupo de abas
|
|
1274
1482
|
</button>
|
|
1275
1483
|
<button mat-stroked-button [color]="model.mode==='nav' ? 'primary' : undefined" (click)="setMode('nav')">
|
|
1276
1484
|
<mat-icon [praxisIcon]="'segment'"></mat-icon>
|
|
1277
|
-
|
|
1485
|
+
Navegacao por links
|
|
1278
1486
|
</button>
|
|
1279
1487
|
</div>
|
|
1280
1488
|
|
|
1281
|
-
<div
|
|
1489
|
+
<div class="setup-grid">
|
|
1282
1490
|
<mat-form-field appearance="outline">
|
|
1283
|
-
<mat-label>Adicionar
|
|
1491
|
+
<mat-label>Adicionar rotulo</mat-label>
|
|
1284
1492
|
<input matInput [(ngModel)]="newLabel" (keyup.enter)="addLabel()" placeholder="Ex.: Dados Gerais" />
|
|
1285
1493
|
</mat-form-field>
|
|
1286
1494
|
<button mat-flat-button color="primary" (click)="addLabel()">
|
|
@@ -1289,33 +1497,256 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
1289
1497
|
</button>
|
|
1290
1498
|
</div>
|
|
1291
1499
|
|
|
1292
|
-
<div *ngIf="model.labels.length; else emptyLabels"
|
|
1500
|
+
<div *ngIf="model.labels.length; else emptyLabels" class="setup-row wrap">
|
|
1293
1501
|
<div *ngFor="let l of model.labels; let i = index" class="chip">
|
|
1294
1502
|
<span>{{ l }}</span>
|
|
1295
|
-
<button mat-icon-button (click)="removeLabel(i)"><mat-icon [praxisIcon]="'close'"></mat-icon></button>
|
|
1503
|
+
<button mat-icon-button (click)="removeLabel(i)" aria-label="Remover rotulo"><mat-icon [praxisIcon]="'close'"></mat-icon></button>
|
|
1296
1504
|
</div>
|
|
1297
1505
|
</div>
|
|
1298
1506
|
<ng-template #emptyLabels>
|
|
1299
|
-
<em>Adicione
|
|
1507
|
+
<em class="hint">Adicione um ou mais rotulos para criar as abas.</em>
|
|
1300
1508
|
</ng-template>
|
|
1301
1509
|
|
|
1302
|
-
<div
|
|
1303
|
-
<mat-slide-toggle [(ngModel)]="model.dynamicHeight">
|
|
1304
|
-
<mat-slide-toggle [(ngModel)]="model.stretchTabs">
|
|
1510
|
+
<div class="setup-row">
|
|
1511
|
+
<mat-slide-toggle [(ngModel)]="model.dynamicHeight">Altura dinamica</mat-slide-toggle>
|
|
1512
|
+
<mat-slide-toggle [(ngModel)]="model.stretchTabs">Esticar abas</mat-slide-toggle>
|
|
1305
1513
|
</div>
|
|
1306
1514
|
</div>
|
|
1307
|
-
`, styles: [".chip{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;border:1px solid var(--
|
|
1515
|
+
`, styles: [":host{display:block;color:var(--md-sys-color-on-surface)}.setup-root{display:grid;gap:12px;padding:8px;background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:12px}.setup-row{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.setup-row.wrap{flex-wrap:wrap}.setup-grid{display:grid;grid-template-columns:1fr auto;gap:8px;align-items:start}.setup-root .mat-mdc-form-field{width:100%;max-width:520px;--mdc-outlined-text-field-container-height: 48px;--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-outline);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-error-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-focus-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-hover-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-supporting-text-color: var(--md-sys-color-on-surface-variant)}.chip{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:16px;background:var(--md-sys-color-surface)}.hint{color:var(--md-sys-color-on-surface-variant)}\n"] }]
|
|
1308
1516
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1309
1517
|
type: Inject,
|
|
1310
1518
|
args: [SETTINGS_PANEL_DATA]
|
|
1311
1519
|
}] }] });
|
|
1312
1520
|
|
|
1521
|
+
/**
|
|
1522
|
+
* Capabilities catalog for Praxis Tabs (TabsMetadata).
|
|
1523
|
+
* Paths follow TabsMetadata shape (patches are merged at config root).
|
|
1524
|
+
*/
|
|
1525
|
+
const ENUMS = {
|
|
1526
|
+
appearanceDensity: ['compact', 'comfortable', 'spacious'],
|
|
1527
|
+
alignTabs: ['start', 'center', 'end'],
|
|
1528
|
+
headerPosition: ['above', 'below'],
|
|
1529
|
+
matColor: ['primary', 'accent', 'warn'],
|
|
1530
|
+
};
|
|
1531
|
+
const TOKENS = [
|
|
1532
|
+
'active-indicator-color',
|
|
1533
|
+
'active-label-text-color',
|
|
1534
|
+
'active-hover-indicator-color',
|
|
1535
|
+
'active-hover-label-text-color',
|
|
1536
|
+
'active-focus-indicator-color',
|
|
1537
|
+
'active-focus-label-text-color',
|
|
1538
|
+
'inactive-label-text-color',
|
|
1539
|
+
'inactive-hover-label-text-color',
|
|
1540
|
+
'inactive-focus-label-text-color',
|
|
1541
|
+
'inactive-ripple-color',
|
|
1542
|
+
'pagination-icon-color',
|
|
1543
|
+
'divider-color',
|
|
1544
|
+
'background-color',
|
|
1545
|
+
];
|
|
1546
|
+
const TOKEN_CAPS = TOKENS.map((t) => ({
|
|
1547
|
+
path: `appearance.tokens.${t}`,
|
|
1548
|
+
category: 'appearance',
|
|
1549
|
+
valueKind: 'string',
|
|
1550
|
+
description: `Token ${t} (CSS color or var).`,
|
|
1551
|
+
}));
|
|
1552
|
+
const CAPS = [
|
|
1553
|
+
{ path: 'meta', category: 'meta', valueKind: 'object', description: 'Metadata bag for tabs.' },
|
|
1554
|
+
{ path: 'appearance', category: 'appearance', valueKind: 'object', description: 'Appearance settings.' },
|
|
1555
|
+
{ path: 'appearance.density', category: 'appearance', valueKind: 'enum', allowedValues: ENUMS.appearanceDensity, description: 'Density preset.' },
|
|
1556
|
+
{ path: 'appearance.themeClass', category: 'appearance', valueKind: 'string', description: 'Theme CSS class applied to root.' },
|
|
1557
|
+
{ path: 'appearance.customCss', category: 'appearance', valueKind: 'string', description: 'Custom CSS injected into component.', safetyNotes: 'CSS is injected as raw string.' },
|
|
1558
|
+
{ path: 'appearance.tokens', category: 'appearance', valueKind: 'object', description: 'Style tokens mapped to runtime CSS.' },
|
|
1559
|
+
...TOKEN_CAPS,
|
|
1560
|
+
{ path: 'behavior', category: 'behavior', valueKind: 'object', description: 'Behavior settings.' },
|
|
1561
|
+
{ path: 'behavior.lazyLoad', category: 'behavior', valueKind: 'boolean', description: 'Lazy load tab content.' },
|
|
1562
|
+
{ path: 'behavior.closeable', category: 'behavior', valueKind: 'boolean', description: 'Show close button on tabs.' },
|
|
1563
|
+
{ path: 'behavior.reorderable', category: 'behavior', valueKind: 'boolean', description: 'Allow reorder tabs/links.' },
|
|
1564
|
+
{ path: 'accessibility', category: 'accessibility', valueKind: 'object', description: 'Accessibility settings.' },
|
|
1565
|
+
{ path: 'accessibility.ariaLabels', category: 'accessibility', valueKind: 'object', description: 'aria-labels map.' },
|
|
1566
|
+
{ path: 'accessibility.keyboardNavigation', category: 'accessibility', valueKind: 'boolean', description: 'Enable keyboard navigation.' },
|
|
1567
|
+
{ path: 'accessibility.highContrast', category: 'accessibility', valueKind: 'boolean', description: 'High contrast mode.' },
|
|
1568
|
+
{ path: 'accessibility.reduceMotion', category: 'accessibility', valueKind: 'boolean', description: 'Reduce motion.' },
|
|
1569
|
+
{ path: 'group', category: 'group', valueKind: 'object', description: 'MatTabGroup settings.' },
|
|
1570
|
+
{ path: 'group.alignTabs', category: 'group', valueKind: 'enum', allowedValues: ENUMS.alignTabs, description: 'Align tabs in header.' },
|
|
1571
|
+
{ path: 'group.animationDuration', category: 'group', valueKind: 'string', description: 'Animation duration (e.g., 500ms).' },
|
|
1572
|
+
{ path: 'group.ariaLabel', category: 'group', valueKind: 'string', description: 'aria-label for tab group.' },
|
|
1573
|
+
{ path: 'group.ariaLabelledby', category: 'group', valueKind: 'string', description: 'aria-labelledby for tab group.' },
|
|
1574
|
+
{ path: 'group.color', category: 'group', valueKind: 'enum', allowedValues: ENUMS.matColor, description: 'M2 color.' },
|
|
1575
|
+
{ path: 'group.backgroundColor', category: 'group', valueKind: 'enum', allowedValues: ENUMS.matColor, description: 'M2 background color.' },
|
|
1576
|
+
{ path: 'group.contentTabIndex', category: 'group', valueKind: 'number', description: 'TabIndex for content.' },
|
|
1577
|
+
{ path: 'group.disablePagination', category: 'group', valueKind: 'boolean', description: 'Disable pagination of header.' },
|
|
1578
|
+
{ path: 'group.disableRipple', category: 'group', valueKind: 'boolean', description: 'Disable ripple.' },
|
|
1579
|
+
{ path: 'group.dynamicHeight', category: 'group', valueKind: 'boolean', description: 'Enable dynamic height.' },
|
|
1580
|
+
{ path: 'group.fitInkBarToContent', category: 'group', valueKind: 'boolean', description: 'Fit ink bar to content.' },
|
|
1581
|
+
{ path: 'group.headerPosition', category: 'group', valueKind: 'enum', allowedValues: ENUMS.headerPosition, description: 'Header position.' },
|
|
1582
|
+
{ path: 'group.preserveContent', category: 'group', valueKind: 'boolean', description: 'Preserve content of inactive tabs.' },
|
|
1583
|
+
{ path: 'group.selectedIndex', category: 'group', valueKind: 'number', description: 'Selected tab index.' },
|
|
1584
|
+
{ path: 'group.stretchTabs', category: 'group', valueKind: 'boolean', description: 'Stretch tabs.' },
|
|
1585
|
+
{ path: 'nav', category: 'nav', valueKind: 'object', description: 'Tab nav settings.' },
|
|
1586
|
+
{ path: 'nav.animationDuration', category: 'nav', valueKind: 'string', description: 'Animation duration (e.g., 500ms).' },
|
|
1587
|
+
{ path: 'nav.color', category: 'nav', valueKind: 'enum', allowedValues: ENUMS.matColor, description: 'M2 color.' },
|
|
1588
|
+
{ path: 'nav.backgroundColor', category: 'nav', valueKind: 'enum', allowedValues: ENUMS.matColor, description: 'M2 background color.' },
|
|
1589
|
+
{ path: 'nav.disablePagination', category: 'nav', valueKind: 'boolean', description: 'Disable pagination of nav.' },
|
|
1590
|
+
{ path: 'nav.disableRipple', category: 'nav', valueKind: 'boolean', description: 'Disable ripple.' },
|
|
1591
|
+
{ path: 'nav.fitInkBarToContent', category: 'nav', valueKind: 'boolean', description: 'Fit ink bar to content.' },
|
|
1592
|
+
{ path: 'nav.selectedIndex', category: 'nav', valueKind: 'number', description: 'Selected nav link index.' },
|
|
1593
|
+
{ path: 'nav.stretchTabs', category: 'nav', valueKind: 'boolean', description: 'Stretch nav tabs.' },
|
|
1594
|
+
{ path: 'nav.links', category: 'nav', valueKind: 'array', description: 'Nav links array.' },
|
|
1595
|
+
{ path: 'nav.links[].id', category: 'nav', valueKind: 'string', description: 'Link id.' },
|
|
1596
|
+
{ path: 'nav.links[].label', category: 'nav', valueKind: 'string', description: 'Link label.' },
|
|
1597
|
+
{ path: 'nav.links[].active', category: 'nav', valueKind: 'boolean', description: 'Link active flag.' },
|
|
1598
|
+
{ path: 'nav.links[].disabled', category: 'nav', valueKind: 'boolean', description: 'Disable link.' },
|
|
1599
|
+
{ path: 'nav.links[].disableRipple', category: 'nav', valueKind: 'boolean', description: 'Disable ripple on link.' },
|
|
1600
|
+
{ path: 'nav.links[].fitInkBarToContent', category: 'nav', valueKind: 'boolean', description: 'Fit ink bar to link content.' },
|
|
1601
|
+
{ path: 'nav.links[].content', category: 'nav', valueKind: 'array', description: 'Dynamic field metadata list.' },
|
|
1602
|
+
{ path: 'nav.links[].widgets', category: 'nav', valueKind: 'array', description: 'Widget definitions for link content.' },
|
|
1603
|
+
{ path: 'tabs', category: 'tabs', valueKind: 'array', description: 'Tabs array.' },
|
|
1604
|
+
{ path: 'tabs[].id', category: 'tabs', valueKind: 'string', description: 'Tab id.' },
|
|
1605
|
+
{ path: 'tabs[].textLabel', category: 'tabs', valueKind: 'string', description: 'Tab label.' },
|
|
1606
|
+
{ path: 'tabs[].labelClass', category: 'tabs', valueKind: 'string', description: 'Label class (string or string[]).' },
|
|
1607
|
+
{ path: 'tabs[].bodyClass', category: 'tabs', valueKind: 'string', description: 'Body class (string or string[]).' },
|
|
1608
|
+
{ path: 'tabs[].ariaLabel', category: 'tabs', valueKind: 'string', description: 'aria-label for tab.' },
|
|
1609
|
+
{ path: 'tabs[].ariaLabelledby', category: 'tabs', valueKind: 'string', description: 'aria-labelledby for tab.' },
|
|
1610
|
+
{ path: 'tabs[].disabled', category: 'tabs', valueKind: 'boolean', description: 'Disable tab.' },
|
|
1611
|
+
{ path: 'tabs[].content', category: 'tabs', valueKind: 'array', description: 'Dynamic field metadata list.' },
|
|
1612
|
+
{ path: 'tabs[].widgets', category: 'tabs', valueKind: 'array', description: 'Widget definitions for tab content.' },
|
|
1613
|
+
{ path: 'tabs[].isActive', category: 'tabs', valueKind: 'boolean', description: 'Active flag (metadata only).' },
|
|
1614
|
+
{ path: 'tabs[].origin', category: 'tabs', valueKind: 'number', description: 'Origin index (metadata only).' },
|
|
1615
|
+
{ path: 'tabs[].position', category: 'tabs', valueKind: 'number', description: 'Position index (metadata only).' },
|
|
1616
|
+
{ path: 'events', category: 'events', valueKind: 'object', description: 'Event config (placeholder).' },
|
|
1617
|
+
];
|
|
1618
|
+
const TABS_AI_CAPABILITIES = {
|
|
1619
|
+
version: 'v1.0',
|
|
1620
|
+
enums: ENUMS,
|
|
1621
|
+
targets: [
|
|
1622
|
+
'praxis-tabs',
|
|
1623
|
+
'tab-group',
|
|
1624
|
+
'tab-item',
|
|
1625
|
+
'praxis-tabs-config-editor',
|
|
1626
|
+
'praxis-tabs-quick-setup',
|
|
1627
|
+
],
|
|
1628
|
+
notes: [
|
|
1629
|
+
'TabsMetadata drives both group and nav modes. Use nav.* when links are present.',
|
|
1630
|
+
'appearance.customCss is injected into a <style> tag; avoid unsafe CSS from untrusted sources.',
|
|
1631
|
+
'tabs[].content expects DynamicFieldMetadata[] and widgets[] expects WidgetDefinition[].',
|
|
1632
|
+
],
|
|
1633
|
+
capabilities: CAPS,
|
|
1634
|
+
};
|
|
1635
|
+
|
|
1636
|
+
class TabsAiAdapter extends BaseAiAdapter {
|
|
1637
|
+
tabs;
|
|
1638
|
+
componentName = 'Praxis Tabs';
|
|
1639
|
+
constructor(tabs) {
|
|
1640
|
+
super();
|
|
1641
|
+
this.tabs = tabs;
|
|
1642
|
+
}
|
|
1643
|
+
getCurrentConfig() {
|
|
1644
|
+
return this.cloneConfig(this.tabs.config || {});
|
|
1645
|
+
}
|
|
1646
|
+
getCapabilities() {
|
|
1647
|
+
return TABS_AI_CAPABILITIES.capabilities;
|
|
1648
|
+
}
|
|
1649
|
+
getRuntimeState() {
|
|
1650
|
+
const cfg = this.tabs.config;
|
|
1651
|
+
return {
|
|
1652
|
+
mode: cfg?.nav?.links?.length ? 'nav' : 'group',
|
|
1653
|
+
tabsCount: cfg?.tabs?.length ?? 0,
|
|
1654
|
+
linksCount: cfg?.nav?.links?.length ?? 0,
|
|
1655
|
+
lazyLoad: !!cfg?.behavior?.lazyLoad,
|
|
1656
|
+
selectedIndex: cfg?.group?.selectedIndex ?? 0,
|
|
1657
|
+
navIndex: cfg?.nav?.selectedIndex ?? 0,
|
|
1658
|
+
};
|
|
1659
|
+
}
|
|
1660
|
+
createSnapshot() {
|
|
1661
|
+
return this.cloneConfig(this.tabs.config || {});
|
|
1662
|
+
}
|
|
1663
|
+
async restoreSnapshot(snapshot) {
|
|
1664
|
+
if (!snapshot)
|
|
1665
|
+
return;
|
|
1666
|
+
this.applyConfig(snapshot);
|
|
1667
|
+
}
|
|
1668
|
+
async applyPatch(patch) {
|
|
1669
|
+
try {
|
|
1670
|
+
const current = this.getCurrentConfig();
|
|
1671
|
+
const next = this.smartMergeTabsConfig(current, patch);
|
|
1672
|
+
this.applyConfig(next);
|
|
1673
|
+
return { success: true };
|
|
1674
|
+
}
|
|
1675
|
+
catch (error) {
|
|
1676
|
+
const message = error instanceof Error ? error.message : 'Unknown error applying patch';
|
|
1677
|
+
return { success: false, error: message };
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
applyConfig(config) {
|
|
1681
|
+
const apply = this.tabs.applyConfigFromAdapter;
|
|
1682
|
+
if (typeof apply === 'function') {
|
|
1683
|
+
apply.call(this.tabs, config);
|
|
1684
|
+
return;
|
|
1685
|
+
}
|
|
1686
|
+
const prev = this.tabs.config;
|
|
1687
|
+
this.tabs.config = config;
|
|
1688
|
+
this.tabs.ngOnChanges({
|
|
1689
|
+
config: {
|
|
1690
|
+
previousValue: prev,
|
|
1691
|
+
currentValue: config,
|
|
1692
|
+
firstChange: false,
|
|
1693
|
+
isFirstChange: () => false,
|
|
1694
|
+
},
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
smartMergeTabsConfig(base, patch) {
|
|
1698
|
+
const result = deepMerge(base, patch);
|
|
1699
|
+
if (patch.tabs && Array.isArray(patch.tabs)) {
|
|
1700
|
+
const merged = this.mergeByKey(base.tabs || [], patch.tabs, (t) => t.id || t.textLabel || '');
|
|
1701
|
+
result.tabs = merged;
|
|
1702
|
+
}
|
|
1703
|
+
const patchLinks = patch.nav?.links;
|
|
1704
|
+
if (patchLinks && Array.isArray(patchLinks)) {
|
|
1705
|
+
const merged = this.mergeByKey(base.nav?.links || [], patchLinks, (l) => l.id || l.label || '');
|
|
1706
|
+
result.nav = { ...(result.nav || {}), links: merged };
|
|
1707
|
+
}
|
|
1708
|
+
return result;
|
|
1709
|
+
}
|
|
1710
|
+
mergeByKey(baseArr, patchArr, keyFn) {
|
|
1711
|
+
const merged = baseArr.map((orig) => {
|
|
1712
|
+
const key = keyFn(orig);
|
|
1713
|
+
const match = key ? patchArr.find((p) => keyFn(p) === key) : undefined;
|
|
1714
|
+
return match ? deepMerge(orig, match) : orig;
|
|
1715
|
+
});
|
|
1716
|
+
patchArr.forEach((item) => {
|
|
1717
|
+
const key = keyFn(item);
|
|
1718
|
+
if (!key || !baseArr.find((o) => keyFn(o) === key)) {
|
|
1719
|
+
merged.push(item);
|
|
1720
|
+
}
|
|
1721
|
+
});
|
|
1722
|
+
return merged;
|
|
1723
|
+
}
|
|
1724
|
+
cloneConfig(config) {
|
|
1725
|
+
try {
|
|
1726
|
+
return structuredClone(config);
|
|
1727
|
+
}
|
|
1728
|
+
catch {
|
|
1729
|
+
return JSON.parse(JSON.stringify(config));
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1313
1734
|
class PraxisTabs {
|
|
1314
1735
|
settings = inject(SettingsPanelService);
|
|
1315
|
-
storage = inject(
|
|
1736
|
+
storage = inject(ASYNC_CONFIG_STORAGE);
|
|
1316
1737
|
snack = inject(MatSnackBar);
|
|
1738
|
+
componentKeys = inject(ComponentKeyService);
|
|
1739
|
+
logger = inject(LoggerService);
|
|
1740
|
+
route = (() => { try {
|
|
1741
|
+
return inject(ActivatedRoute);
|
|
1742
|
+
}
|
|
1743
|
+
catch {
|
|
1744
|
+
return undefined;
|
|
1745
|
+
} })();
|
|
1746
|
+
warnedMissingId = false;
|
|
1317
1747
|
config = null;
|
|
1318
1748
|
tabsId;
|
|
1749
|
+
componentInstanceId;
|
|
1319
1750
|
editModeEnabled = false;
|
|
1320
1751
|
form = null;
|
|
1321
1752
|
context = null;
|
|
@@ -1326,42 +1757,38 @@ class PraxisTabs {
|
|
|
1326
1757
|
indexFocused = new EventEmitter();
|
|
1327
1758
|
selectFocusedIndex = new EventEmitter();
|
|
1328
1759
|
widgetEvent = new EventEmitter();
|
|
1760
|
+
aiAdapter = new TabsAiAdapter(this);
|
|
1329
1761
|
// Signals to manage local state for selection in Nav mode and Group mode
|
|
1330
1762
|
currentNavIndex = signal(0, ...(ngDevMode ? [{ debugName: "currentNavIndex" }] : []));
|
|
1331
1763
|
selectedIndexSignal = signal(0, ...(ngDevMode ? [{ debugName: "selectedIndexSignal" }] : []));
|
|
1332
1764
|
groupLoaded = new Set();
|
|
1333
1765
|
navLoaded = new Set();
|
|
1766
|
+
destroy$ = new Subject();
|
|
1334
1767
|
ngOnInit() {
|
|
1768
|
+
this.syncSelectionFromConfig();
|
|
1335
1769
|
// Load stored config if tabsId provided
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1770
|
+
const key = this.storageKey();
|
|
1771
|
+
if (key) {
|
|
1772
|
+
this.storage.loadConfig(key).pipe(take(1)).subscribe((stored) => {
|
|
1773
|
+
if (stored) {
|
|
1774
|
+
this.config = stored;
|
|
1775
|
+
}
|
|
1776
|
+
this.syncSelectionFromConfig();
|
|
1777
|
+
});
|
|
1341
1778
|
}
|
|
1342
|
-
// Initialize selected indices from config
|
|
1343
|
-
this.selectedIndexSignal.set(this.config?.group?.selectedIndex ?? 0);
|
|
1344
|
-
this.currentNavIndex.set(this.config?.nav?.selectedIndex ?? 0);
|
|
1345
|
-
// Mark initial selections as loaded for lazy mode
|
|
1346
|
-
this.groupLoaded.add(this.selectedIndexSignal() ?? 0);
|
|
1347
|
-
this.navLoaded.add(this.currentNavIndex() ?? 0);
|
|
1348
1779
|
}
|
|
1349
1780
|
ngOnChanges(changes) {
|
|
1350
1781
|
if (changes['config'] && this.config) {
|
|
1351
1782
|
// Reset loaded caches on config change and seed with current selections
|
|
1352
|
-
this.
|
|
1353
|
-
this.navLoaded.clear();
|
|
1354
|
-
// Keep indices in sync when config input changes
|
|
1355
|
-
this.selectedIndexSignal.set(this.config?.group?.selectedIndex ?? 0);
|
|
1356
|
-
this.currentNavIndex.set(this.config?.nav?.selectedIndex ?? 0);
|
|
1357
|
-
this.groupLoaded.add(this.selectedIndexSignal() ?? 0);
|
|
1358
|
-
this.navLoaded.add(this.currentNavIndex() ?? 0);
|
|
1783
|
+
this.syncSelectionFromConfig();
|
|
1359
1784
|
// Persist when tabsId provided
|
|
1360
|
-
|
|
1361
|
-
this.storage.saveConfig(this.storageKey(), this.config);
|
|
1362
|
-
}
|
|
1785
|
+
this.persistConfig(this.config);
|
|
1363
1786
|
}
|
|
1364
1787
|
}
|
|
1788
|
+
ngOnDestroy() {
|
|
1789
|
+
this.destroy$.next();
|
|
1790
|
+
this.destroy$.complete();
|
|
1791
|
+
}
|
|
1365
1792
|
isNavMode() {
|
|
1366
1793
|
return !!this.config?.nav && !!this.config?.nav?.links?.length;
|
|
1367
1794
|
}
|
|
@@ -1375,9 +1802,18 @@ class PraxisTabs {
|
|
|
1375
1802
|
return this.currentNavIndex() === i;
|
|
1376
1803
|
}
|
|
1377
1804
|
onNavClick(i) {
|
|
1378
|
-
if (!this.config?.nav)
|
|
1805
|
+
if (!this.config?.nav?.links?.length)
|
|
1806
|
+
return;
|
|
1807
|
+
const linksCount = this.config.nav.links.length;
|
|
1808
|
+
if (i < 0 || i >= linksCount)
|
|
1379
1809
|
return;
|
|
1380
1810
|
this.currentNavIndex.set(i);
|
|
1811
|
+
this.config = produce(this.config, (draft) => {
|
|
1812
|
+
if (!draft.nav)
|
|
1813
|
+
return;
|
|
1814
|
+
draft.nav.selectedIndex = i;
|
|
1815
|
+
});
|
|
1816
|
+
this.persistConfig(this.config);
|
|
1381
1817
|
// Lazy: mark as loaded
|
|
1382
1818
|
this.navLoaded.add(i);
|
|
1383
1819
|
// Emit as index change for consumers to track
|
|
@@ -1388,6 +1824,9 @@ class PraxisTabs {
|
|
|
1388
1824
|
return;
|
|
1389
1825
|
const prev = event.previousIndex;
|
|
1390
1826
|
const curr = event.currentIndex;
|
|
1827
|
+
const linksLength = this.config.nav.links.length;
|
|
1828
|
+
if (prev < 0 || curr < 0 || prev >= linksLength || curr >= linksLength)
|
|
1829
|
+
return;
|
|
1391
1830
|
if (prev === curr)
|
|
1392
1831
|
return;
|
|
1393
1832
|
const selectedId = this.config.nav.links[this.currentNavIndex()]?.id;
|
|
@@ -1403,43 +1842,74 @@ class PraxisTabs {
|
|
|
1403
1842
|
this.currentNavIndex.set(idx);
|
|
1404
1843
|
}
|
|
1405
1844
|
else {
|
|
1406
|
-
// If no id,
|
|
1407
|
-
|
|
1845
|
+
// If no id, preserve selected index around move.
|
|
1846
|
+
const selected = this.currentNavIndex();
|
|
1847
|
+
if (selected === prev) {
|
|
1408
1848
|
this.currentNavIndex.set(curr);
|
|
1849
|
+
}
|
|
1850
|
+
else if (prev < selected && curr >= selected) {
|
|
1851
|
+
this.currentNavIndex.set(selected - 1);
|
|
1852
|
+
}
|
|
1853
|
+
else if (prev > selected && curr <= selected) {
|
|
1854
|
+
this.currentNavIndex.set(selected + 1);
|
|
1855
|
+
}
|
|
1409
1856
|
}
|
|
1410
1857
|
// Reset lazy cache for nav except current
|
|
1411
1858
|
const currIdx = this.currentNavIndex();
|
|
1412
1859
|
this.navLoaded.clear();
|
|
1413
1860
|
this.navLoaded.add(currIdx);
|
|
1861
|
+
this.config = produce(this.config, (draft) => {
|
|
1862
|
+
if (!draft.nav)
|
|
1863
|
+
return;
|
|
1864
|
+
draft.nav.selectedIndex = currIdx;
|
|
1865
|
+
});
|
|
1866
|
+
this.persistConfig(this.config);
|
|
1414
1867
|
}
|
|
1415
1868
|
onSelectedIndexChange(index) {
|
|
1416
|
-
this.
|
|
1869
|
+
const selected = this.clampIndex(index, this.config?.tabs?.length ?? 0);
|
|
1870
|
+
this.selectedIndexSignal.set(selected);
|
|
1417
1871
|
// Update config immutably
|
|
1418
1872
|
if (this.config) {
|
|
1419
1873
|
this.config = produce(this.config, (draft) => {
|
|
1420
1874
|
if (!draft.group) {
|
|
1421
|
-
draft.group = { selectedIndex:
|
|
1875
|
+
draft.group = { selectedIndex: selected };
|
|
1422
1876
|
}
|
|
1423
1877
|
else {
|
|
1424
|
-
draft.group.selectedIndex =
|
|
1878
|
+
draft.group.selectedIndex = selected;
|
|
1425
1879
|
}
|
|
1426
1880
|
});
|
|
1427
|
-
|
|
1428
|
-
this.storage.saveConfig(this.storageKey(), this.config);
|
|
1429
|
-
}
|
|
1881
|
+
this.persistConfig(this.config);
|
|
1430
1882
|
}
|
|
1431
1883
|
// Lazy: mark as loaded
|
|
1432
|
-
this.groupLoaded.add(
|
|
1433
|
-
this.selectedIndexChange.emit(
|
|
1884
|
+
this.groupLoaded.add(selected);
|
|
1885
|
+
this.selectedIndexChange.emit(selected);
|
|
1434
1886
|
}
|
|
1435
1887
|
closeTab(index) {
|
|
1436
1888
|
if (!this.config?.tabs)
|
|
1437
1889
|
return;
|
|
1890
|
+
if (index < 0 || index >= this.config.tabs.length)
|
|
1891
|
+
return;
|
|
1892
|
+
const currentSelected = this.selectedIndexSignal();
|
|
1438
1893
|
this.config = produce(this.config, (draft) => {
|
|
1439
1894
|
draft.tabs.splice(index, 1);
|
|
1895
|
+
const tabsLength = draft.tabs.length;
|
|
1896
|
+
if (!draft.group) {
|
|
1897
|
+
draft.group = {};
|
|
1898
|
+
}
|
|
1899
|
+
if (tabsLength <= 0) {
|
|
1900
|
+
draft.group.selectedIndex = 0;
|
|
1901
|
+
return;
|
|
1902
|
+
}
|
|
1903
|
+
const adjusted = currentSelected > index ? currentSelected - 1 : currentSelected;
|
|
1904
|
+
draft.group.selectedIndex = this.clampIndex(adjusted, tabsLength);
|
|
1440
1905
|
});
|
|
1441
|
-
|
|
1442
|
-
|
|
1906
|
+
const nextSelected = this.clampIndex(this.config?.group?.selectedIndex, this.config?.tabs?.length ?? 0);
|
|
1907
|
+
this.selectedIndexSignal.set(nextSelected);
|
|
1908
|
+
this.groupLoaded.clear();
|
|
1909
|
+
if ((this.config?.tabs?.length ?? 0) > 0) {
|
|
1910
|
+
this.groupLoaded.add(nextSelected);
|
|
1911
|
+
}
|
|
1912
|
+
this.persistConfig(this.config);
|
|
1443
1913
|
}
|
|
1444
1914
|
moveTab(index, delta) {
|
|
1445
1915
|
if (!this.config?.tabs)
|
|
@@ -1470,10 +1940,12 @@ class PraxisTabs {
|
|
|
1470
1940
|
const sel = this.selectedIndexSignal() ?? 0;
|
|
1471
1941
|
this.groupLoaded.clear();
|
|
1472
1942
|
this.groupLoaded.add(sel);
|
|
1943
|
+
this.persistConfig(this.config);
|
|
1473
1944
|
}
|
|
1474
1945
|
openEditor() {
|
|
1946
|
+
const key = this.storageKey() || this.tabsId || 'default';
|
|
1475
1947
|
const ref = this.settings.open({
|
|
1476
|
-
id: `praxis-tabs-editor:${
|
|
1948
|
+
id: `praxis-tabs-editor:${key}`,
|
|
1477
1949
|
title: 'Configurar Tabs',
|
|
1478
1950
|
content: {
|
|
1479
1951
|
component: PraxisTabsConfigEditor,
|
|
@@ -1481,25 +1953,20 @@ class PraxisTabs {
|
|
|
1481
1953
|
},
|
|
1482
1954
|
});
|
|
1483
1955
|
// Essential preview: apply updates without closing
|
|
1484
|
-
ref.applied$.subscribe((value) => {
|
|
1956
|
+
ref.applied$.pipe(takeUntil(this.destroy$)).subscribe((value) => {
|
|
1485
1957
|
const nextCfg = value?.config || value;
|
|
1486
1958
|
if (nextCfg) {
|
|
1487
1959
|
this.config = produce(this.config || {}, () => nextCfg);
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
this.selectedIndexSignal.set(this.config?.group?.selectedIndex ?? 0);
|
|
1491
|
-
this.currentNavIndex.set(this.config?.nav?.selectedIndex ?? 0);
|
|
1960
|
+
this.persistConfig(this.config);
|
|
1961
|
+
this.syncSelectionFromConfig();
|
|
1492
1962
|
}
|
|
1493
1963
|
});
|
|
1494
|
-
ref.saved$.subscribe((value) => {
|
|
1964
|
+
ref.saved$.pipe(takeUntil(this.destroy$)).subscribe((value) => {
|
|
1495
1965
|
const nextCfg = value?.config || value;
|
|
1496
1966
|
if (nextCfg) {
|
|
1497
1967
|
this.config = produce(this.config || {}, () => nextCfg);
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
// Sync indices
|
|
1501
|
-
this.selectedIndexSignal.set(this.config?.group?.selectedIndex ?? 0);
|
|
1502
|
-
this.currentNavIndex.set(this.config?.nav?.selectedIndex ?? 0);
|
|
1968
|
+
this.persistConfig(this.config);
|
|
1969
|
+
this.syncSelectionFromConfig();
|
|
1503
1970
|
}
|
|
1504
1971
|
});
|
|
1505
1972
|
}
|
|
@@ -1513,16 +1980,16 @@ class PraxisTabs {
|
|
|
1513
1980
|
draft.group.selectedIndex = (draft.tabs.length || 1) - 1;
|
|
1514
1981
|
});
|
|
1515
1982
|
this.config = next;
|
|
1516
|
-
|
|
1517
|
-
this.storage.saveConfig(this.storageKey(), this.config);
|
|
1983
|
+
this.persistConfig(this.config);
|
|
1518
1984
|
this.selectedIndexSignal.set(this.config?.group?.selectedIndex ?? 0);
|
|
1519
1985
|
}
|
|
1520
1986
|
/** Clears persisted tabs configuration to fallback to defaults */
|
|
1521
1987
|
resetPreferences() {
|
|
1522
|
-
|
|
1988
|
+
const key = this.storageKey();
|
|
1989
|
+
if (!key)
|
|
1523
1990
|
return;
|
|
1524
1991
|
try {
|
|
1525
|
-
this.storage.clearConfig(
|
|
1992
|
+
this.storage.clearConfig(key).pipe(take(1)).subscribe({ error: () => { } });
|
|
1526
1993
|
}
|
|
1527
1994
|
catch { }
|
|
1528
1995
|
try {
|
|
@@ -1532,8 +1999,9 @@ class PraxisTabs {
|
|
|
1532
1999
|
// keep current in-memory config; caller may choose to reload
|
|
1533
2000
|
}
|
|
1534
2001
|
openQuickSetup() {
|
|
2002
|
+
const key = this.storageKey() || this.tabsId || 'default';
|
|
1535
2003
|
const ref = this.settings.open({
|
|
1536
|
-
id: `praxis-tabs-quick-setup:${
|
|
2004
|
+
id: `praxis-tabs-quick-setup:${key}`,
|
|
1537
2005
|
title: 'Criar abas rapidamente',
|
|
1538
2006
|
content: {
|
|
1539
2007
|
component: TabsQuickSetupComponent,
|
|
@@ -1544,17 +2012,77 @@ class PraxisTabs {
|
|
|
1544
2012
|
const nextCfg = value?.config || value;
|
|
1545
2013
|
if (nextCfg) {
|
|
1546
2014
|
this.config = produce(this.config || {}, () => nextCfg);
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
this.selectedIndexSignal.set(this.config?.group?.selectedIndex ?? 0);
|
|
1550
|
-
this.currentNavIndex.set(this.config?.nav?.selectedIndex ?? 0);
|
|
2015
|
+
this.persistConfig(this.config);
|
|
2016
|
+
this.syncSelectionFromConfig();
|
|
1551
2017
|
}
|
|
1552
2018
|
};
|
|
1553
|
-
ref.applied$.subscribe(apply);
|
|
1554
|
-
ref.saved$.subscribe(apply);
|
|
2019
|
+
ref.applied$.pipe(takeUntil(this.destroy$)).subscribe(apply);
|
|
2020
|
+
ref.saved$.pipe(takeUntil(this.destroy$)).subscribe(apply);
|
|
1555
2021
|
}
|
|
1556
2022
|
storageKey() {
|
|
1557
|
-
|
|
2023
|
+
const id = this.componentKeyId();
|
|
2024
|
+
return id ? `tabs:${id}` : null;
|
|
2025
|
+
}
|
|
2026
|
+
syncSelectionFromConfig() {
|
|
2027
|
+
this.groupLoaded.clear();
|
|
2028
|
+
this.navLoaded.clear();
|
|
2029
|
+
const tabsLength = this.config?.tabs?.length ?? 0;
|
|
2030
|
+
const linksLength = this.config?.nav?.links?.length ?? 0;
|
|
2031
|
+
const groupIndex = this.clampIndex(this.config?.group?.selectedIndex, tabsLength);
|
|
2032
|
+
const navIndex = this.clampIndex(this.config?.nav?.selectedIndex, linksLength);
|
|
2033
|
+
this.selectedIndexSignal.set(groupIndex);
|
|
2034
|
+
this.currentNavIndex.set(navIndex);
|
|
2035
|
+
if (tabsLength > 0)
|
|
2036
|
+
this.groupLoaded.add(groupIndex);
|
|
2037
|
+
if (linksLength > 0)
|
|
2038
|
+
this.navLoaded.add(navIndex);
|
|
2039
|
+
}
|
|
2040
|
+
persistConfig(config) {
|
|
2041
|
+
const key = this.storageKey();
|
|
2042
|
+
if (!key || !config)
|
|
2043
|
+
return;
|
|
2044
|
+
this.storage.saveConfig(key, config).pipe(take(1)).subscribe({ error: () => { } });
|
|
2045
|
+
}
|
|
2046
|
+
componentKeyId() {
|
|
2047
|
+
const key = this.componentKeys.buildComponentId({
|
|
2048
|
+
componentType: 'praxis-tabs',
|
|
2049
|
+
componentId: this.tabsId,
|
|
2050
|
+
instanceKey: this.componentInstanceId,
|
|
2051
|
+
componentRef: this,
|
|
2052
|
+
route: this.route,
|
|
2053
|
+
requireComponentId: true,
|
|
2054
|
+
});
|
|
2055
|
+
if (!key)
|
|
2056
|
+
this.warnMissingId();
|
|
2057
|
+
return key;
|
|
2058
|
+
}
|
|
2059
|
+
warnMissingId() {
|
|
2060
|
+
if (this.warnedMissingId)
|
|
2061
|
+
return;
|
|
2062
|
+
this.warnedMissingId = true;
|
|
2063
|
+
this.logger.warnOnce('[PraxisTabs] tabsId is required for config persistence.', {
|
|
2064
|
+
context: {
|
|
2065
|
+
lib: 'praxis-tabs',
|
|
2066
|
+
component: 'PraxisTabs',
|
|
2067
|
+
},
|
|
2068
|
+
data: {
|
|
2069
|
+
tabsId: this.tabsId,
|
|
2070
|
+
componentInstanceId: this.componentInstanceId,
|
|
2071
|
+
},
|
|
2072
|
+
dedupeKey: 'praxis-tabs:missing-tabs-id',
|
|
2073
|
+
});
|
|
2074
|
+
}
|
|
2075
|
+
clampIndex(index, size) {
|
|
2076
|
+
if (size <= 0)
|
|
2077
|
+
return 0;
|
|
2078
|
+
const numeric = Number(index);
|
|
2079
|
+
const safe = Number.isFinite(numeric) ? Math.trunc(numeric) : 0;
|
|
2080
|
+
return Math.min(Math.max(safe, 0), size - 1);
|
|
2081
|
+
}
|
|
2082
|
+
applyConfigFromAdapter(next) {
|
|
2083
|
+
this.config = next;
|
|
2084
|
+
this.syncSelectionFromConfig();
|
|
2085
|
+
this.persistConfig(this.config);
|
|
1558
2086
|
}
|
|
1559
2087
|
// =====================
|
|
1560
2088
|
// Lazy load helpers
|
|
@@ -1576,82 +2104,145 @@ class PraxisTabs {
|
|
|
1576
2104
|
emitWidgetEvent(loc, ev) {
|
|
1577
2105
|
this.widgetEvent.emit({ ...loc, ...ev });
|
|
1578
2106
|
}
|
|
2107
|
+
styleScopeId() {
|
|
2108
|
+
const scopeSeed = [this.tabsId, this.componentInstanceId]
|
|
2109
|
+
.filter((v) => typeof v === 'string' && !!v.trim())
|
|
2110
|
+
.join('--');
|
|
2111
|
+
const raw = String(scopeSeed || 'default').trim();
|
|
2112
|
+
const sanitized = raw
|
|
2113
|
+
.replace(/[^a-zA-Z0-9_-]+/g, '-')
|
|
2114
|
+
.replace(/-+/g, '-')
|
|
2115
|
+
.replace(/^-|-$/g, '');
|
|
2116
|
+
return sanitized || 'default';
|
|
2117
|
+
}
|
|
2118
|
+
safeCustomCss() {
|
|
2119
|
+
const css = this.config?.appearance?.customCss;
|
|
2120
|
+
if (!css)
|
|
2121
|
+
return null;
|
|
2122
|
+
const value = String(css).trim();
|
|
2123
|
+
if (!value)
|
|
2124
|
+
return null;
|
|
2125
|
+
const forbidden = [
|
|
2126
|
+
/@import/i,
|
|
2127
|
+
/expression\s*\(/i,
|
|
2128
|
+
/behavior\s*:/i,
|
|
2129
|
+
/<\/style/i,
|
|
2130
|
+
/<script/i,
|
|
2131
|
+
/url\s*\(\s*(['"]?)\s*(javascript:|data:text\/html)/i,
|
|
2132
|
+
];
|
|
2133
|
+
if (forbidden.some((pattern) => pattern.test(value))) {
|
|
2134
|
+
return null;
|
|
2135
|
+
}
|
|
2136
|
+
return value;
|
|
2137
|
+
}
|
|
2138
|
+
sanitizeCssValue(value) {
|
|
2139
|
+
if (typeof value !== 'string')
|
|
2140
|
+
return null;
|
|
2141
|
+
const trimmed = value.trim();
|
|
2142
|
+
if (!trimmed)
|
|
2143
|
+
return null;
|
|
2144
|
+
const forbidden = [
|
|
2145
|
+
/@import/i,
|
|
2146
|
+
/expression\s*\(/i,
|
|
2147
|
+
/behavior\s*:/i,
|
|
2148
|
+
/url\s*\(\s*(['"]?)\s*(javascript:|data:text\/html)/i,
|
|
2149
|
+
];
|
|
2150
|
+
if (forbidden.some((pattern) => pattern.test(trimmed))) {
|
|
2151
|
+
return null;
|
|
2152
|
+
}
|
|
2153
|
+
const sanitized = trimmed.replace(/[{};<>]/g, '').trim();
|
|
2154
|
+
return sanitized || null;
|
|
2155
|
+
}
|
|
1579
2156
|
styleCss() {
|
|
1580
2157
|
const t = this.config?.appearance?.tokens;
|
|
1581
2158
|
if (!t)
|
|
1582
2159
|
return null;
|
|
1583
|
-
const scope = `.praxis-tabs-root[data-tabs-id="${
|
|
2160
|
+
const scope = `.praxis-tabs-root[data-tabs-id="${this.styleScopeId()}"]`;
|
|
1584
2161
|
const rules = [];
|
|
1585
2162
|
const push = (selector, decls) => {
|
|
1586
2163
|
rules.push(`${scope} ${selector}{${decls.join('')}}`);
|
|
1587
2164
|
};
|
|
1588
2165
|
// Active indicator underline
|
|
1589
|
-
|
|
1590
|
-
|
|
2166
|
+
const activeIndicatorColor = this.sanitizeCssValue(t['active-indicator-color']);
|
|
2167
|
+
if (activeIndicatorColor) {
|
|
2168
|
+
push(' .mat-mdc-tab .mdc-tab-indicator__content--underline', [`background-color:${activeIndicatorColor}!important;`]);
|
|
1591
2169
|
}
|
|
1592
2170
|
// Active label
|
|
1593
|
-
|
|
2171
|
+
const activeLabelColor = this.sanitizeCssValue(t['active-label-text-color']);
|
|
2172
|
+
if (activeLabelColor) {
|
|
1594
2173
|
push(' .mdc-tab--active .mdc-tab__text-label', [
|
|
1595
|
-
`color:${
|
|
2174
|
+
`color:${activeLabelColor}!important;`,
|
|
1596
2175
|
]);
|
|
1597
2176
|
}
|
|
1598
|
-
|
|
2177
|
+
const activeHoverLabelColor = this.sanitizeCssValue(t['active-hover-label-text-color']);
|
|
2178
|
+
if (activeHoverLabelColor) {
|
|
1599
2179
|
push(' .mdc-tab--active:hover .mdc-tab__text-label', [
|
|
1600
|
-
`color:${
|
|
2180
|
+
`color:${activeHoverLabelColor}!important;`,
|
|
1601
2181
|
]);
|
|
1602
2182
|
}
|
|
1603
|
-
|
|
2183
|
+
const activeFocusLabelColor = this.sanitizeCssValue(t['active-focus-label-text-color']);
|
|
2184
|
+
if (activeFocusLabelColor) {
|
|
1604
2185
|
push(' .mdc-tab--active:focus .mdc-tab__text-label', [
|
|
1605
|
-
`color:${
|
|
2186
|
+
`color:${activeFocusLabelColor}!important;`,
|
|
1606
2187
|
]);
|
|
1607
2188
|
}
|
|
1608
|
-
|
|
2189
|
+
const activeFocusIndicatorColor = this.sanitizeCssValue(t['active-focus-indicator-color']);
|
|
2190
|
+
if (activeFocusIndicatorColor) {
|
|
1609
2191
|
push(' .mdc-tab--active:focus .mdc-tab-indicator__content--underline', [
|
|
1610
|
-
`background-color:${
|
|
2192
|
+
`background-color:${activeFocusIndicatorColor}!important;`,
|
|
1611
2193
|
]);
|
|
1612
2194
|
}
|
|
1613
|
-
|
|
2195
|
+
const activeHoverIndicatorColor = this.sanitizeCssValue(t['active-hover-indicator-color']);
|
|
2196
|
+
if (activeHoverIndicatorColor) {
|
|
1614
2197
|
push(' .mdc-tab--active:hover .mdc-tab-indicator__content--underline', [
|
|
1615
|
-
`background-color:${
|
|
2198
|
+
`background-color:${activeHoverIndicatorColor}!important;`,
|
|
1616
2199
|
]);
|
|
1617
2200
|
}
|
|
1618
2201
|
// Inactive label
|
|
1619
|
-
|
|
2202
|
+
const inactiveLabelColor = this.sanitizeCssValue(t['inactive-label-text-color']);
|
|
2203
|
+
if (inactiveLabelColor) {
|
|
1620
2204
|
push(' .mdc-tab:not(.mdc-tab--active) .mdc-tab__text-label', [
|
|
1621
|
-
`color:${
|
|
2205
|
+
`color:${inactiveLabelColor}!important;`,
|
|
1622
2206
|
]);
|
|
1623
2207
|
}
|
|
1624
|
-
|
|
2208
|
+
const inactiveHoverLabelColor = this.sanitizeCssValue(t['inactive-hover-label-text-color']);
|
|
2209
|
+
if (inactiveHoverLabelColor) {
|
|
1625
2210
|
push(' .mdc-tab:not(.mdc-tab--active):hover .mdc-tab__text-label', [
|
|
1626
|
-
`color:${
|
|
2211
|
+
`color:${inactiveHoverLabelColor}!important;`,
|
|
1627
2212
|
]);
|
|
1628
2213
|
}
|
|
1629
|
-
|
|
2214
|
+
const inactiveFocusLabelColor = this.sanitizeCssValue(t['inactive-focus-label-text-color']);
|
|
2215
|
+
if (inactiveFocusLabelColor) {
|
|
1630
2216
|
push(' .mdc-tab:not(.mdc-tab--active):focus .mdc-tab__text-label', [
|
|
1631
|
-
`color:${
|
|
2217
|
+
`color:${inactiveFocusLabelColor}!important;`,
|
|
1632
2218
|
]);
|
|
1633
2219
|
}
|
|
1634
2220
|
// Pagination chevrons
|
|
1635
|
-
|
|
2221
|
+
const paginationIconColor = this.sanitizeCssValue(t['pagination-icon-color']);
|
|
2222
|
+
if (paginationIconColor) {
|
|
1636
2223
|
push(' .mat-mdc-tab-header-pagination-chevron', [
|
|
1637
|
-
`color:${
|
|
2224
|
+
`color:${paginationIconColor}!important;`,
|
|
1638
2225
|
]);
|
|
1639
2226
|
}
|
|
1640
2227
|
// Divider / background
|
|
1641
2228
|
const containerDecls = [];
|
|
1642
|
-
|
|
1643
|
-
|
|
2229
|
+
const dividerColor = this.sanitizeCssValue(t['divider-color']);
|
|
2230
|
+
if (dividerColor) {
|
|
2231
|
+
containerDecls.push(`border-bottom-color:${dividerColor}!important;`);
|
|
1644
2232
|
}
|
|
1645
2233
|
if (containerDecls.length) {
|
|
1646
2234
|
push(' .mat-mdc-tab-header', containerDecls);
|
|
2235
|
+
push(' .mat-mdc-tab-nav-bar', containerDecls);
|
|
1647
2236
|
}
|
|
1648
|
-
|
|
1649
|
-
|
|
2237
|
+
const backgroundColor = this.sanitizeCssValue(t['background-color']);
|
|
2238
|
+
if (backgroundColor) {
|
|
2239
|
+
push(' .mat-mdc-tab-header', [`background:${backgroundColor}!important;`]);
|
|
2240
|
+
push(' .mat-mdc-tab-nav-bar', [`background:${backgroundColor}!important;`]);
|
|
1650
2241
|
}
|
|
1651
2242
|
return rules.length ? rules.join('\n') : null;
|
|
1652
2243
|
}
|
|
1653
2244
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisTabs, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1654
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisTabs, isStandalone: true, selector: "praxis-tabs", inputs: { config: "config", tabsId: "tabsId", editModeEnabled: "editModeEnabled", form: "form", context: "context" }, outputs: { animationDone: "animationDone", focusChange: "focusChange", selectedIndexChange: "selectedIndexChange", selectedTabChange: "selectedTabChange", indexFocused: "indexFocused", selectFocusedIndex: "selectFocusedIndex", widgetEvent: "widgetEvent" }, usesOnChanges: true, ngImport: i0, template: `
|
|
2245
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisTabs, isStandalone: true, selector: "praxis-tabs", inputs: { config: "config", tabsId: "tabsId", componentInstanceId: "componentInstanceId", editModeEnabled: "editModeEnabled", form: "form", context: "context" }, outputs: { animationDone: "animationDone", focusChange: "focusChange", selectedIndexChange: "selectedIndexChange", selectedTabChange: "selectedTabChange", indexFocused: "indexFocused", selectFocusedIndex: "selectFocusedIndex", widgetEvent: "widgetEvent" }, usesOnChanges: true, ngImport: i0, template: `
|
|
1655
2246
|
<div
|
|
1656
2247
|
class="praxis-tabs-root"
|
|
1657
2248
|
[class.density-compact]="config?.appearance?.density === 'compact'"
|
|
@@ -1660,13 +2251,17 @@ class PraxisTabs {
|
|
|
1660
2251
|
[class.high-contrast]="config?.accessibility?.highContrast"
|
|
1661
2252
|
[class.reduce-motion]="config?.accessibility?.reduceMotion"
|
|
1662
2253
|
[ngClass]="config?.appearance?.themeClass || ''"
|
|
1663
|
-
[attr.data-tabs-id]="
|
|
2254
|
+
[attr.data-tabs-id]="styleScopeId()"
|
|
1664
2255
|
>
|
|
1665
2256
|
<!-- Inline custom CSS, if provided -->
|
|
1666
|
-
<style *ngIf="
|
|
2257
|
+
<style *ngIf="safeCustomCss() as css" [innerHTML]="css"></style>
|
|
1667
2258
|
<!-- Runtime style derived from tokens -->
|
|
1668
2259
|
<style *ngIf="styleCss() as s" [innerHTML]="s"></style>
|
|
1669
2260
|
|
|
2261
|
+
<div class="tabs-ai-assistant" *ngIf="editModeEnabled">
|
|
2262
|
+
<praxis-ai-assistant [adapter]="aiAdapter"></praxis-ai-assistant>
|
|
2263
|
+
</div>
|
|
2264
|
+
|
|
1670
2265
|
<!-- Empty state (global) -->
|
|
1671
2266
|
<ng-container *ngIf="isEmptyGlobal(); else notEmpty">
|
|
1672
2267
|
<praxis-empty-state-card
|
|
@@ -1686,6 +2281,7 @@ class PraxisTabs {
|
|
|
1686
2281
|
<ng-container *ngIf="isNavMode(); else groupMode">
|
|
1687
2282
|
<nav
|
|
1688
2283
|
mat-tab-nav-bar
|
|
2284
|
+
[tabPanel]="tabPanel"
|
|
1689
2285
|
cdkDropList
|
|
1690
2286
|
cdkDropListOrientation="horizontal"
|
|
1691
2287
|
[cdkDropListDisabled]="!config?.behavior?.reorderable"
|
|
@@ -1722,39 +2318,41 @@ class PraxisTabs {
|
|
|
1722
2318
|
</a>
|
|
1723
2319
|
</nav>
|
|
1724
2320
|
|
|
1725
|
-
<
|
|
1726
|
-
<
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
<ng-container *ngIf="l.content &&
|
|
1731
|
-
<ng-container
|
|
1732
|
-
dynamicFieldLoader
|
|
1733
|
-
[fields]="l.content || []"
|
|
1734
|
-
[formGroup]="form!"
|
|
1735
|
-
></ng-container>
|
|
1736
|
-
</ng-container>
|
|
1737
|
-
<ng-container *ngIf="l.widgets?.length">
|
|
1738
|
-
<ng-container *ngFor="let w of l.widgets; let wi = index">
|
|
2321
|
+
<mat-tab-nav-panel #tabPanel>
|
|
2322
|
+
<div class="praxis-tabnav-content" *ngIf="currentNavIndex() >= 0">
|
|
2323
|
+
<ng-container
|
|
2324
|
+
*ngIf="config?.nav?.links?.[currentNavIndex()] as l"
|
|
2325
|
+
>
|
|
2326
|
+
<ng-container *ngIf="(l.content?.length || l.widgets?.length) && navContentReady(currentNavIndex()); else emptyNav">
|
|
2327
|
+
<ng-container *ngIf="l.content && form">
|
|
1739
2328
|
<ng-container
|
|
1740
|
-
|
|
1741
|
-
[
|
|
1742
|
-
|
|
2329
|
+
dynamicFieldLoader
|
|
2330
|
+
[fields]="l.content || []"
|
|
2331
|
+
[formGroup]="form!"
|
|
1743
2332
|
></ng-container>
|
|
1744
2333
|
</ng-container>
|
|
2334
|
+
<ng-container *ngIf="l.widgets?.length">
|
|
2335
|
+
<ng-container *ngFor="let w of l.widgets; let wi = index">
|
|
2336
|
+
<ng-container
|
|
2337
|
+
[dynamicWidgetLoader]="w"
|
|
2338
|
+
[context]="context || {}"
|
|
2339
|
+
(widgetEvent)="emitWidgetEvent({ linkId: l.id, linkIndex: currentNavIndex() }, $event)"
|
|
2340
|
+
></ng-container>
|
|
2341
|
+
</ng-container>
|
|
2342
|
+
</ng-container>
|
|
1745
2343
|
</ng-container>
|
|
2344
|
+
<ng-template #emptyNav>
|
|
2345
|
+
<praxis-empty-state-card
|
|
2346
|
+
[inline]="true"
|
|
2347
|
+
icon="add_to_queue"
|
|
2348
|
+
[title]="'Sem conteúdo neste link'"
|
|
2349
|
+
[description]="'Adicione conteúdo ou use o editor para configurar.'"
|
|
2350
|
+
[primaryAction]="{ label: 'Abrir editor', icon: 'tune', action: openEditor.bind(this) }"
|
|
2351
|
+
></praxis-empty-state-card>
|
|
2352
|
+
</ng-template>
|
|
1746
2353
|
</ng-container>
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
[inline]="true"
|
|
1750
|
-
icon="add_to_queue"
|
|
1751
|
-
[title]="'Sem conteúdo neste link'"
|
|
1752
|
-
[description]="'Adicione conteúdo ou use o editor para configurar.'"
|
|
1753
|
-
[primaryAction]="{ label: 'Abrir editor', icon: 'tune', action: openEditor.bind(this) }"
|
|
1754
|
-
></praxis-empty-state-card>
|
|
1755
|
-
</ng-template>
|
|
1756
|
-
</ng-container>
|
|
1757
|
-
</div>
|
|
2354
|
+
</div>
|
|
2355
|
+
</mat-tab-nav-panel>
|
|
1758
2356
|
</ng-container>
|
|
1759
2357
|
|
|
1760
2358
|
<!-- Tab Group variant -->
|
|
@@ -1796,15 +2394,33 @@ class PraxisTabs {
|
|
|
1796
2394
|
mat-icon-button
|
|
1797
2395
|
type="button"
|
|
1798
2396
|
(click)="closeTab(i); $event.stopPropagation()"
|
|
2397
|
+
(keydown.enter)="$event.stopPropagation()"
|
|
2398
|
+
(keydown.space)="$event.stopPropagation()"
|
|
1799
2399
|
aria-label="Fechar aba"
|
|
1800
2400
|
>
|
|
1801
2401
|
<mat-icon fontIcon="close"></mat-icon>
|
|
1802
2402
|
</button>
|
|
1803
2403
|
<ng-container *ngIf="config?.behavior?.reorderable">
|
|
1804
|
-
<button
|
|
2404
|
+
<button
|
|
2405
|
+
mat-icon-button
|
|
2406
|
+
type="button"
|
|
2407
|
+
(click)="moveTab(i, -1); $event.stopPropagation()"
|
|
2408
|
+
(keydown.enter)="$event.stopPropagation()"
|
|
2409
|
+
(keydown.space)="$event.stopPropagation()"
|
|
2410
|
+
[disabled]="i===0"
|
|
2411
|
+
aria-label="Mover aba para esquerda"
|
|
2412
|
+
>
|
|
1805
2413
|
<mat-icon fontIcon="arrow_back"></mat-icon>
|
|
1806
2414
|
</button>
|
|
1807
|
-
<button
|
|
2415
|
+
<button
|
|
2416
|
+
mat-icon-button
|
|
2417
|
+
type="button"
|
|
2418
|
+
(click)="moveTab(i, 1); $event.stopPropagation()"
|
|
2419
|
+
(keydown.enter)="$event.stopPropagation()"
|
|
2420
|
+
(keydown.space)="$event.stopPropagation()"
|
|
2421
|
+
[disabled]="i===(config?.tabs?.length||1)-1"
|
|
2422
|
+
aria-label="Mover aba para direita"
|
|
2423
|
+
>
|
|
1808
2424
|
<mat-icon fontIcon="arrow_forward"></mat-icon>
|
|
1809
2425
|
</button>
|
|
1810
2426
|
</ng-container>
|
|
@@ -1857,8 +2473,7 @@ class PraxisTabs {
|
|
|
1857
2473
|
<button
|
|
1858
2474
|
*ngIf="editModeEnabled && tabsId"
|
|
1859
2475
|
mat-mini-fab
|
|
1860
|
-
class="edit-fab"
|
|
1861
|
-
style="right: 56px"
|
|
2476
|
+
class="edit-fab edit-fab-secondary"
|
|
1862
2477
|
aria-label="Redefinir preferências de tabs"
|
|
1863
2478
|
(click)="resetPreferences()"
|
|
1864
2479
|
matTooltip="Redefinir preferências de tabs"
|
|
@@ -1866,7 +2481,7 @@ class PraxisTabs {
|
|
|
1866
2481
|
<mat-icon [praxisIcon]="'restart_alt'"></mat-icon>
|
|
1867
2482
|
</button>
|
|
1868
2483
|
</div>
|
|
1869
|
-
`, isInline: true, styles: [".praxis-tabs-root{position:relative;display:block}.praxis-tabs-group.align-start .mat-mdc-tab-header{justify-content:flex-start}.praxis-tabs-group.align-center .mat-mdc-tab-header{justify-content:center}.praxis-tabs-group.align-end .mat-mdc-tab-header{justify-content:flex-end}.density-compact .mat-mdc-tab-body-content{padding:8px}.density-comfortable .mat-mdc-tab-body-content{padding:16px}.density-spacious .mat-mdc-tab-body-content{padding:24px}.edit-fab{position:absolute;right:12px;bottom:12px;z-index:2}.tab-empty{padding:16px;color
|
|
2484
|
+
`, isInline: true, styles: [".praxis-tabs-root{position:relative;display:block}.praxis-tabs-group.align-start .mat-mdc-tab-header{justify-content:flex-start}.praxis-tabs-group.align-center .mat-mdc-tab-header{justify-content:center}.praxis-tabs-group.align-end .mat-mdc-tab-header{justify-content:flex-end}.density-compact .mat-mdc-tab-body-content{padding:8px}.density-comfortable .mat-mdc-tab-body-content{padding:16px}.density-spacious .mat-mdc-tab-body-content{padding:24px}.tabs-ai-assistant{position:absolute;right:12px;bottom:72px;z-index:3}.edit-fab{position:absolute;right:12px;bottom:12px;z-index:2}.edit-fab-secondary{right:56px}.tab-empty{padding:16px;color:var(--md-sys-color-on-surface-variant);font-style:italic}.high-contrast{filter:contrast(1.2)}.reduce-motion{--mat-animation-duration: 0ms}.drag-handle{display:inline-flex;align-items:center;vertical-align:middle;margin-right:4px;cursor:grab}:host-context(.pdx-gridster-item) .praxis-tabs-root{display:flex;flex-direction:column;height:100%;min-height:0}:host-context(.pdx-gridster-item) .praxis-tabs-group,:host-context(.pdx-gridster-item) .mat-mdc-tab-group{flex:1 1 auto;min-height:0}:host-context(.pdx-gridster-item) .mat-mdc-tab-body-wrapper,:host-context(.pdx-gridster-item) .mat-mdc-tab-body-content{height:100%;min-height:0}:host-context(.pdx-gridster-item) .mat-mdc-tab-body-content{overflow:auto}:host-context(.pdx-gridster-item) .praxis-tabnav-content{flex:1 1 auto;min-height:0;overflow:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "directive", type: i3$1.MatTabContent, selector: "[matTabContent]" }, { kind: "directive", type: i3$1.MatTabLabel, selector: "[mat-tab-label], [matTabLabel]" }, { kind: "component", type: i3$1.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i3$1.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "component", type: i3$1.MatTabNav, selector: "[mat-tab-nav-bar]", inputs: ["fitInkBarToContent", "mat-stretch-tabs", "animationDuration", "backgroundColor", "disableRipple", "color", "tabPanel"], exportAs: ["matTabNavBar", "matTabNav"] }, { kind: "component", type: i3$1.MatTabNavPanel, selector: "mat-tab-nav-panel", inputs: ["id"], exportAs: ["matTabNavPanel"] }, { kind: "component", type: i3$1.MatTabLink, selector: "[mat-tab-link], [matTabLink]", inputs: ["active", "disabled", "disableRipple", "tabIndex", "id"], exportAs: ["matTabLink"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i11.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6$1.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i6$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i6$1.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i10.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i10.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i10.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone"] }, { kind: "directive", type: DynamicFieldLoaderDirective, selector: "[dynamicFieldLoader]", inputs: ["fields", "formGroup", "enableExternalControlBinding", "itemTemplate", "debugTrace", "debugTraceLabel", "readonlyMode", "disabledMode", "presentationMode", "visible", "canvasMode"], outputs: ["componentsCreated", "fieldCreated", "fieldDestroyed", "renderError", "canvasMouseEnter", "canvasMouseLeave", "canvasClick"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent"], exportAs: ["dynamicWidgetLoader"] }, { kind: "component", type: PraxisAiAssistantComponent, selector: "praxis-ai-assistant", inputs: ["adapter", "riskPolicy", "allowManualPatchEdit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1870
2485
|
}
|
|
1871
2486
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisTabs, decorators: [{
|
|
1872
2487
|
type: Component,
|
|
@@ -1875,12 +2490,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
1875
2490
|
ReactiveFormsModule,
|
|
1876
2491
|
MatTabsModule,
|
|
1877
2492
|
MatIconModule,
|
|
2493
|
+
MatTooltipModule,
|
|
1878
2494
|
PraxisIconDirective,
|
|
1879
2495
|
MatButtonModule,
|
|
1880
2496
|
DragDropModule,
|
|
1881
2497
|
EmptyStateCardComponent,
|
|
1882
2498
|
DynamicFieldLoaderDirective,
|
|
1883
2499
|
DynamicWidgetLoaderDirective,
|
|
2500
|
+
PraxisAiAssistantComponent,
|
|
1884
2501
|
], template: `
|
|
1885
2502
|
<div
|
|
1886
2503
|
class="praxis-tabs-root"
|
|
@@ -1890,13 +2507,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
1890
2507
|
[class.high-contrast]="config?.accessibility?.highContrast"
|
|
1891
2508
|
[class.reduce-motion]="config?.accessibility?.reduceMotion"
|
|
1892
2509
|
[ngClass]="config?.appearance?.themeClass || ''"
|
|
1893
|
-
[attr.data-tabs-id]="
|
|
2510
|
+
[attr.data-tabs-id]="styleScopeId()"
|
|
1894
2511
|
>
|
|
1895
2512
|
<!-- Inline custom CSS, if provided -->
|
|
1896
|
-
<style *ngIf="
|
|
2513
|
+
<style *ngIf="safeCustomCss() as css" [innerHTML]="css"></style>
|
|
1897
2514
|
<!-- Runtime style derived from tokens -->
|
|
1898
2515
|
<style *ngIf="styleCss() as s" [innerHTML]="s"></style>
|
|
1899
2516
|
|
|
2517
|
+
<div class="tabs-ai-assistant" *ngIf="editModeEnabled">
|
|
2518
|
+
<praxis-ai-assistant [adapter]="aiAdapter"></praxis-ai-assistant>
|
|
2519
|
+
</div>
|
|
2520
|
+
|
|
1900
2521
|
<!-- Empty state (global) -->
|
|
1901
2522
|
<ng-container *ngIf="isEmptyGlobal(); else notEmpty">
|
|
1902
2523
|
<praxis-empty-state-card
|
|
@@ -1916,6 +2537,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
1916
2537
|
<ng-container *ngIf="isNavMode(); else groupMode">
|
|
1917
2538
|
<nav
|
|
1918
2539
|
mat-tab-nav-bar
|
|
2540
|
+
[tabPanel]="tabPanel"
|
|
1919
2541
|
cdkDropList
|
|
1920
2542
|
cdkDropListOrientation="horizontal"
|
|
1921
2543
|
[cdkDropListDisabled]="!config?.behavior?.reorderable"
|
|
@@ -1952,39 +2574,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
1952
2574
|
</a>
|
|
1953
2575
|
</nav>
|
|
1954
2576
|
|
|
1955
|
-
<
|
|
1956
|
-
<
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
<ng-container *ngIf="l.content &&
|
|
1961
|
-
<ng-container
|
|
1962
|
-
dynamicFieldLoader
|
|
1963
|
-
[fields]="l.content || []"
|
|
1964
|
-
[formGroup]="form!"
|
|
1965
|
-
></ng-container>
|
|
1966
|
-
</ng-container>
|
|
1967
|
-
<ng-container *ngIf="l.widgets?.length">
|
|
1968
|
-
<ng-container *ngFor="let w of l.widgets; let wi = index">
|
|
2577
|
+
<mat-tab-nav-panel #tabPanel>
|
|
2578
|
+
<div class="praxis-tabnav-content" *ngIf="currentNavIndex() >= 0">
|
|
2579
|
+
<ng-container
|
|
2580
|
+
*ngIf="config?.nav?.links?.[currentNavIndex()] as l"
|
|
2581
|
+
>
|
|
2582
|
+
<ng-container *ngIf="(l.content?.length || l.widgets?.length) && navContentReady(currentNavIndex()); else emptyNav">
|
|
2583
|
+
<ng-container *ngIf="l.content && form">
|
|
1969
2584
|
<ng-container
|
|
1970
|
-
|
|
1971
|
-
[
|
|
1972
|
-
|
|
2585
|
+
dynamicFieldLoader
|
|
2586
|
+
[fields]="l.content || []"
|
|
2587
|
+
[formGroup]="form!"
|
|
1973
2588
|
></ng-container>
|
|
1974
2589
|
</ng-container>
|
|
2590
|
+
<ng-container *ngIf="l.widgets?.length">
|
|
2591
|
+
<ng-container *ngFor="let w of l.widgets; let wi = index">
|
|
2592
|
+
<ng-container
|
|
2593
|
+
[dynamicWidgetLoader]="w"
|
|
2594
|
+
[context]="context || {}"
|
|
2595
|
+
(widgetEvent)="emitWidgetEvent({ linkId: l.id, linkIndex: currentNavIndex() }, $event)"
|
|
2596
|
+
></ng-container>
|
|
2597
|
+
</ng-container>
|
|
2598
|
+
</ng-container>
|
|
1975
2599
|
</ng-container>
|
|
2600
|
+
<ng-template #emptyNav>
|
|
2601
|
+
<praxis-empty-state-card
|
|
2602
|
+
[inline]="true"
|
|
2603
|
+
icon="add_to_queue"
|
|
2604
|
+
[title]="'Sem conteúdo neste link'"
|
|
2605
|
+
[description]="'Adicione conteúdo ou use o editor para configurar.'"
|
|
2606
|
+
[primaryAction]="{ label: 'Abrir editor', icon: 'tune', action: openEditor.bind(this) }"
|
|
2607
|
+
></praxis-empty-state-card>
|
|
2608
|
+
</ng-template>
|
|
1976
2609
|
</ng-container>
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
[inline]="true"
|
|
1980
|
-
icon="add_to_queue"
|
|
1981
|
-
[title]="'Sem conteúdo neste link'"
|
|
1982
|
-
[description]="'Adicione conteúdo ou use o editor para configurar.'"
|
|
1983
|
-
[primaryAction]="{ label: 'Abrir editor', icon: 'tune', action: openEditor.bind(this) }"
|
|
1984
|
-
></praxis-empty-state-card>
|
|
1985
|
-
</ng-template>
|
|
1986
|
-
</ng-container>
|
|
1987
|
-
</div>
|
|
2610
|
+
</div>
|
|
2611
|
+
</mat-tab-nav-panel>
|
|
1988
2612
|
</ng-container>
|
|
1989
2613
|
|
|
1990
2614
|
<!-- Tab Group variant -->
|
|
@@ -2026,15 +2650,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
2026
2650
|
mat-icon-button
|
|
2027
2651
|
type="button"
|
|
2028
2652
|
(click)="closeTab(i); $event.stopPropagation()"
|
|
2653
|
+
(keydown.enter)="$event.stopPropagation()"
|
|
2654
|
+
(keydown.space)="$event.stopPropagation()"
|
|
2029
2655
|
aria-label="Fechar aba"
|
|
2030
2656
|
>
|
|
2031
2657
|
<mat-icon fontIcon="close"></mat-icon>
|
|
2032
2658
|
</button>
|
|
2033
2659
|
<ng-container *ngIf="config?.behavior?.reorderable">
|
|
2034
|
-
<button
|
|
2660
|
+
<button
|
|
2661
|
+
mat-icon-button
|
|
2662
|
+
type="button"
|
|
2663
|
+
(click)="moveTab(i, -1); $event.stopPropagation()"
|
|
2664
|
+
(keydown.enter)="$event.stopPropagation()"
|
|
2665
|
+
(keydown.space)="$event.stopPropagation()"
|
|
2666
|
+
[disabled]="i===0"
|
|
2667
|
+
aria-label="Mover aba para esquerda"
|
|
2668
|
+
>
|
|
2035
2669
|
<mat-icon fontIcon="arrow_back"></mat-icon>
|
|
2036
2670
|
</button>
|
|
2037
|
-
<button
|
|
2671
|
+
<button
|
|
2672
|
+
mat-icon-button
|
|
2673
|
+
type="button"
|
|
2674
|
+
(click)="moveTab(i, 1); $event.stopPropagation()"
|
|
2675
|
+
(keydown.enter)="$event.stopPropagation()"
|
|
2676
|
+
(keydown.space)="$event.stopPropagation()"
|
|
2677
|
+
[disabled]="i===(config?.tabs?.length||1)-1"
|
|
2678
|
+
aria-label="Mover aba para direita"
|
|
2679
|
+
>
|
|
2038
2680
|
<mat-icon fontIcon="arrow_forward"></mat-icon>
|
|
2039
2681
|
</button>
|
|
2040
2682
|
</ng-container>
|
|
@@ -2087,8 +2729,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
2087
2729
|
<button
|
|
2088
2730
|
*ngIf="editModeEnabled && tabsId"
|
|
2089
2731
|
mat-mini-fab
|
|
2090
|
-
class="edit-fab"
|
|
2091
|
-
style="right: 56px"
|
|
2732
|
+
class="edit-fab edit-fab-secondary"
|
|
2092
2733
|
aria-label="Redefinir preferências de tabs"
|
|
2093
2734
|
(click)="resetPreferences()"
|
|
2094
2735
|
matTooltip="Redefinir preferências de tabs"
|
|
@@ -2096,10 +2737,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
2096
2737
|
<mat-icon [praxisIcon]="'restart_alt'"></mat-icon>
|
|
2097
2738
|
</button>
|
|
2098
2739
|
</div>
|
|
2099
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".praxis-tabs-root{position:relative;display:block}.praxis-tabs-group.align-start .mat-mdc-tab-header{justify-content:flex-start}.praxis-tabs-group.align-center .mat-mdc-tab-header{justify-content:center}.praxis-tabs-group.align-end .mat-mdc-tab-header{justify-content:flex-end}.density-compact .mat-mdc-tab-body-content{padding:8px}.density-comfortable .mat-mdc-tab-body-content{padding:16px}.density-spacious .mat-mdc-tab-body-content{padding:24px}.edit-fab{position:absolute;right:12px;bottom:12px;z-index:2}.tab-empty{padding:16px;color
|
|
2740
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".praxis-tabs-root{position:relative;display:block}.praxis-tabs-group.align-start .mat-mdc-tab-header{justify-content:flex-start}.praxis-tabs-group.align-center .mat-mdc-tab-header{justify-content:center}.praxis-tabs-group.align-end .mat-mdc-tab-header{justify-content:flex-end}.density-compact .mat-mdc-tab-body-content{padding:8px}.density-comfortable .mat-mdc-tab-body-content{padding:16px}.density-spacious .mat-mdc-tab-body-content{padding:24px}.tabs-ai-assistant{position:absolute;right:12px;bottom:72px;z-index:3}.edit-fab{position:absolute;right:12px;bottom:12px;z-index:2}.edit-fab-secondary{right:56px}.tab-empty{padding:16px;color:var(--md-sys-color-on-surface-variant);font-style:italic}.high-contrast{filter:contrast(1.2)}.reduce-motion{--mat-animation-duration: 0ms}.drag-handle{display:inline-flex;align-items:center;vertical-align:middle;margin-right:4px;cursor:grab}:host-context(.pdx-gridster-item) .praxis-tabs-root{display:flex;flex-direction:column;height:100%;min-height:0}:host-context(.pdx-gridster-item) .praxis-tabs-group,:host-context(.pdx-gridster-item) .mat-mdc-tab-group{flex:1 1 auto;min-height:0}:host-context(.pdx-gridster-item) .mat-mdc-tab-body-wrapper,:host-context(.pdx-gridster-item) .mat-mdc-tab-body-content{height:100%;min-height:0}:host-context(.pdx-gridster-item) .mat-mdc-tab-body-content{overflow:auto}:host-context(.pdx-gridster-item) .praxis-tabnav-content{flex:1 1 auto;min-height:0;overflow:auto}\n"] }]
|
|
2100
2741
|
}], propDecorators: { config: [{
|
|
2101
2742
|
type: Input
|
|
2102
2743
|
}], tabsId: [{
|
|
2744
|
+
type: Input,
|
|
2745
|
+
args: [{ required: true }]
|
|
2746
|
+
}], componentInstanceId: [{
|
|
2103
2747
|
type: Input
|
|
2104
2748
|
}], editModeEnabled: [{
|
|
2105
2749
|
type: Input
|
|
@@ -2128,15 +2772,21 @@ const PRAXIS_TABS_COMPONENT_METADATA = {
|
|
|
2128
2772
|
selector: 'praxis-tabs',
|
|
2129
2773
|
component: PraxisTabs,
|
|
2130
2774
|
friendlyName: 'Praxis Tabs',
|
|
2131
|
-
description: 'Abas dinâmicas baseadas em metadata,
|
|
2775
|
+
description: 'Abas dinâmicas baseadas em metadata, com MatTabGroup/TabNav e suporte a tokens M3 via appearance.',
|
|
2132
2776
|
icon: 'tab',
|
|
2133
2777
|
inputs: [
|
|
2134
|
-
{ name: 'config', type: 'TabsMetadata', label: 'Configuração', description: 'Configuração JSON (tabs/nav e widgets internos)' },
|
|
2778
|
+
{ name: 'config', type: 'TabsMetadata', label: 'Configuração', description: 'Configuração JSON (tabs/nav, aparência e widgets internos)' },
|
|
2135
2779
|
{
|
|
2136
2780
|
name: 'tabsId',
|
|
2137
2781
|
type: 'string',
|
|
2138
2782
|
label: 'ID das Tabs',
|
|
2139
|
-
description: 'Identificador para persistência
|
|
2783
|
+
description: 'Identificador para persistência (obrigatório)',
|
|
2784
|
+
},
|
|
2785
|
+
{
|
|
2786
|
+
name: 'componentInstanceId',
|
|
2787
|
+
type: 'string',
|
|
2788
|
+
label: 'ID da instância',
|
|
2789
|
+
description: 'Identificador opcional para múltiplas instâncias na mesma rota',
|
|
2140
2790
|
},
|
|
2141
2791
|
{
|
|
2142
2792
|
name: 'editModeEnabled',
|
|
@@ -2151,6 +2801,12 @@ const PRAXIS_TABS_COMPONENT_METADATA = {
|
|
|
2151
2801
|
label: 'FormGroup',
|
|
2152
2802
|
description: 'FormGroup para conteúdo com campos dinâmicos',
|
|
2153
2803
|
},
|
|
2804
|
+
{
|
|
2805
|
+
name: 'context',
|
|
2806
|
+
type: 'Record<string, any>',
|
|
2807
|
+
label: 'Contexto',
|
|
2808
|
+
description: 'Contexto entregue aos widgets internos',
|
|
2809
|
+
},
|
|
2154
2810
|
],
|
|
2155
2811
|
outputs: [
|
|
2156
2812
|
{ name: 'selectedIndexChange', type: 'number', label: 'Índice selecionado' },
|
|
@@ -2166,6 +2822,78 @@ const PRAXIS_TABS_COMPONENT_METADATA = {
|
|
|
2166
2822
|
description: 'Eventos reemitidos de componentes dinâmicos dentro da aba/link',
|
|
2167
2823
|
},
|
|
2168
2824
|
],
|
|
2825
|
+
actions: [
|
|
2826
|
+
{
|
|
2827
|
+
id: 'select-tab',
|
|
2828
|
+
label: 'Selecionar aba',
|
|
2829
|
+
icon: 'tab',
|
|
2830
|
+
description: 'Emite alteração do índice selecionado',
|
|
2831
|
+
emit: 'selectedIndexChange',
|
|
2832
|
+
payloadSchema: {
|
|
2833
|
+
type: 'number',
|
|
2834
|
+
example: 0,
|
|
2835
|
+
},
|
|
2836
|
+
scope: 'any',
|
|
2837
|
+
},
|
|
2838
|
+
{
|
|
2839
|
+
id: 'tab-change',
|
|
2840
|
+
label: 'Troca de aba',
|
|
2841
|
+
icon: 'swap_horiz',
|
|
2842
|
+
description: 'Emite evento de troca de aba',
|
|
2843
|
+
emit: 'selectedTabChange',
|
|
2844
|
+
payloadSchema: {
|
|
2845
|
+
type: 'object',
|
|
2846
|
+
properties: {
|
|
2847
|
+
index: { type: 'number', description: 'Índice selecionado' },
|
|
2848
|
+
tab: { type: 'object', description: 'Referência da aba' },
|
|
2849
|
+
},
|
|
2850
|
+
required: ['index'],
|
|
2851
|
+
example: { index: 1 },
|
|
2852
|
+
},
|
|
2853
|
+
scope: 'any',
|
|
2854
|
+
},
|
|
2855
|
+
{
|
|
2856
|
+
id: 'focus-change',
|
|
2857
|
+
label: 'Foco alterado',
|
|
2858
|
+
icon: 'center_focus_strong',
|
|
2859
|
+
description: 'Emite evento quando o foco muda',
|
|
2860
|
+
emit: 'focusChange',
|
|
2861
|
+
payloadSchema: {
|
|
2862
|
+
type: 'object',
|
|
2863
|
+
properties: {
|
|
2864
|
+
index: { type: 'number', description: 'Índice focado' },
|
|
2865
|
+
tab: { type: 'object', description: 'Referência da aba' },
|
|
2866
|
+
},
|
|
2867
|
+
required: ['index'],
|
|
2868
|
+
example: { index: 1 },
|
|
2869
|
+
},
|
|
2870
|
+
scope: 'any',
|
|
2871
|
+
},
|
|
2872
|
+
{
|
|
2873
|
+
id: 'focus-index',
|
|
2874
|
+
label: 'Índice focado',
|
|
2875
|
+
icon: 'filter_center_focus',
|
|
2876
|
+
description: 'Emite o índice focado',
|
|
2877
|
+
emit: 'indexFocused',
|
|
2878
|
+
payloadSchema: {
|
|
2879
|
+
type: 'number',
|
|
2880
|
+
example: 0,
|
|
2881
|
+
},
|
|
2882
|
+
scope: 'any',
|
|
2883
|
+
},
|
|
2884
|
+
{
|
|
2885
|
+
id: 'select-focus',
|
|
2886
|
+
label: 'Selecionar foco',
|
|
2887
|
+
icon: 'gps_fixed',
|
|
2888
|
+
description: 'Emite seleção do índice focado',
|
|
2889
|
+
emit: 'selectFocusedIndex',
|
|
2890
|
+
payloadSchema: {
|
|
2891
|
+
type: 'number',
|
|
2892
|
+
example: 0,
|
|
2893
|
+
},
|
|
2894
|
+
scope: 'any',
|
|
2895
|
+
},
|
|
2896
|
+
],
|
|
2169
2897
|
tags: ['widget', 'tabs', 'configurable', 'stable'],
|
|
2170
2898
|
lib: '@praxisui/tabs',
|
|
2171
2899
|
};
|
|
@@ -2188,5 +2916,5 @@ function providePraxisTabsMetadata() {
|
|
|
2188
2916
|
* Generated bundle index. Do not edit.
|
|
2189
2917
|
*/
|
|
2190
2918
|
|
|
2191
|
-
export { PRAXIS_TABS_COMPONENT_METADATA, PraxisTabs, PraxisTabsConfigEditor, providePraxisTabsMetadata };
|
|
2919
|
+
export { PRAXIS_TABS_COMPONENT_METADATA, PraxisTabs, PraxisTabsConfigEditor, TABS_AI_CAPABILITIES, providePraxisTabsMetadata };
|
|
2192
2920
|
//# sourceMappingURL=praxisui-tabs.mjs.map
|