@praxisui/page-builder 0.0.1

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.
@@ -0,0 +1,620 @@
1
+ import * as i3$2 from '@angular/common';
2
+ import { CommonModule } from '@angular/common';
3
+ import * as i0 from '@angular/core';
4
+ import { Inject, ChangeDetectionStrategy, Component, EventEmitter, Output, Input, signal, computed, effect } from '@angular/core';
5
+ import * as i2 from '@angular/material/button';
6
+ import { MatButtonModule } from '@angular/material/button';
7
+ import * as i1 from '@angular/material/dialog';
8
+ import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
9
+ import * as i3 from '@angular/material/icon';
10
+ import { MatIconModule } from '@angular/material/icon';
11
+ import * as i2$1 from '@praxisui/core';
12
+ import { PraxisIconDirective } from '@praxisui/core';
13
+ import * as i3$1 from '@angular/material/tooltip';
14
+ import { MatTooltipModule } from '@angular/material/tooltip';
15
+ import * as i6 from '@angular/material/form-field';
16
+ import { MatFormFieldModule } from '@angular/material/form-field';
17
+ import * as i7 from '@angular/material/input';
18
+ import { MatInputModule } from '@angular/material/input';
19
+ import * as i4 from '@angular/forms';
20
+ import { FormsModule } from '@angular/forms';
21
+ import * as i9 from '@angular/material/select';
22
+ import { MatSelectModule } from '@angular/material/select';
23
+ import * as i12 from '@angular/material/list';
24
+ import { MatListModule } from '@angular/material/list';
25
+ import { MatAutocompleteModule } from '@angular/material/autocomplete';
26
+ import { MatMenuModule } from '@angular/material/menu';
27
+ import * as i3$3 from '@angular/material/snack-bar';
28
+ import { MatSnackBarModule } from '@angular/material/snack-bar';
29
+ import { MatTabsModule } from '@angular/material/tabs';
30
+ import * as i8 from '@angular/cdk/scrolling';
31
+ import { ScrollingModule } from '@angular/cdk/scrolling';
32
+ import { MatProgressBarModule } from '@angular/material/progress-bar';
33
+ import { MatCheckboxModule } from '@angular/material/checkbox';
34
+
35
+ const PLACEHOLDER = 1;
36
+
37
+ class ConfirmDialogComponent {
38
+ data;
39
+ ref;
40
+ constructor(data, ref) {
41
+ this.data = data;
42
+ this.ref = ref;
43
+ }
44
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ConfirmDialogComponent, deps: [{ token: MAT_DIALOG_DATA }, { token: i1.MatDialogRef }], target: i0.ɵɵFactoryTarget.Component });
45
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: ConfirmDialogComponent, isStandalone: true, selector: "praxis-confirm-dialog", ngImport: i0, template: `
46
+ <h2 mat-dialog-title>
47
+ <mat-icon aria-hidden="true" style="vertical-align: middle; margin-right: 8px;" [praxisIcon]="data.icon || 'warning'"></mat-icon>
48
+ {{ data.title || 'Confirmar ação' }}
49
+ </h2>
50
+ <div mat-dialog-content>
51
+ <p>{{ data.message || 'Tem certeza que deseja prosseguir?' }}</p>
52
+ </div>
53
+ <div mat-dialog-actions align="end">
54
+ <button mat-button mat-dialog-close>{{ data.cancelLabel || 'Cancelar' }}</button>
55
+ <button mat-raised-button color="warn" [mat-dialog-close]="true">{{ data.confirmLabel || 'Excluir' }}</button>
56
+ </div>
57
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
58
+ }
59
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ConfirmDialogComponent, decorators: [{
60
+ type: Component,
61
+ args: [{
62
+ selector: 'praxis-confirm-dialog',
63
+ standalone: true,
64
+ imports: [CommonModule, MatDialogModule, MatButtonModule, MatIconModule, PraxisIconDirective],
65
+ template: `
66
+ <h2 mat-dialog-title>
67
+ <mat-icon aria-hidden="true" style="vertical-align: middle; margin-right: 8px;" [praxisIcon]="data.icon || 'warning'"></mat-icon>
68
+ {{ data.title || 'Confirmar ação' }}
69
+ </h2>
70
+ <div mat-dialog-content>
71
+ <p>{{ data.message || 'Tem certeza que deseja prosseguir?' }}</p>
72
+ </div>
73
+ <div mat-dialog-actions align="end">
74
+ <button mat-button mat-dialog-close>{{ data.cancelLabel || 'Cancelar' }}</button>
75
+ <button mat-raised-button color="warn" [mat-dialog-close]="true">{{ data.confirmLabel || 'Excluir' }}</button>
76
+ </div>
77
+ `,
78
+ changeDetection: ChangeDetectionStrategy.OnPush,
79
+ }]
80
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
81
+ type: Inject,
82
+ args: [MAT_DIALOG_DATA]
83
+ }] }, { type: i1.MatDialogRef }] });
84
+
85
+ class TileToolbarComponent {
86
+ selected = false;
87
+ widgetType = null;
88
+ remove = new EventEmitter();
89
+ settings = new EventEmitter();
90
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: TileToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
91
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: TileToolbarComponent, isStandalone: true, selector: "praxis-tile-toolbar", inputs: { selected: "selected", widgetType: "widgetType" }, outputs: { remove: "remove", settings: "settings" }, ngImport: i0, template: `
92
+ <div class="pdx-tile-toolbar" [class.always-visible]="selected" role="toolbar" aria-label="Ações do widget">
93
+ <button
94
+ mat-mini-fab
95
+ (click)="settings.emit()"
96
+ [matTooltip]="'Configurar widget'"
97
+ aria-label="Configurar widget"
98
+ >
99
+ <mat-icon [praxisIcon]="'settings'"></mat-icon>
100
+ </button>
101
+ <button
102
+ mat-mini-fab
103
+ color="primary"
104
+ class="pdx-drag-handle"
105
+ [matTooltip]="'Arrastar tile'"
106
+ aria-label="Arrastar tile"
107
+ >
108
+ <mat-icon [praxisIcon]="'drag_indicator'"></mat-icon>
109
+ </button>
110
+ <button
111
+ mat-mini-fab
112
+ color="warn"
113
+ (click)="remove.emit()"
114
+ [matTooltip]="'Excluir widget'"
115
+ aria-label="Excluir widget"
116
+ >
117
+ <mat-icon [praxisIcon]="'delete'"></mat-icon>
118
+ </button>
119
+ </div>
120
+ `, isInline: true, styles: [":host{position:absolute;inset:0;pointer-events:none}.pdx-tile-toolbar{position:absolute;right:6px;top:-18px;display:flex;gap:6px;z-index:5;opacity:0;transition:opacity .12s ease-in-out;pointer-events:auto;background:color-mix(in oklab,var(--md-sys-color-surface) 92%,transparent);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);border-radius:999px;padding:4px;box-shadow:var(--mat-elevation-level3, 0 4px 8px rgba(0,0,0,.2))}.pdx-tile-toolbar.always-visible{opacity:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
121
+ }
122
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: TileToolbarComponent, decorators: [{
123
+ type: Component,
124
+ args: [{ selector: 'praxis-tile-toolbar', standalone: true, imports: [CommonModule, MatButtonModule, MatIconModule, MatTooltipModule, PraxisIconDirective], template: `
125
+ <div class="pdx-tile-toolbar" [class.always-visible]="selected" role="toolbar" aria-label="Ações do widget">
126
+ <button
127
+ mat-mini-fab
128
+ (click)="settings.emit()"
129
+ [matTooltip]="'Configurar widget'"
130
+ aria-label="Configurar widget"
131
+ >
132
+ <mat-icon [praxisIcon]="'settings'"></mat-icon>
133
+ </button>
134
+ <button
135
+ mat-mini-fab
136
+ color="primary"
137
+ class="pdx-drag-handle"
138
+ [matTooltip]="'Arrastar tile'"
139
+ aria-label="Arrastar tile"
140
+ >
141
+ <mat-icon [praxisIcon]="'drag_indicator'"></mat-icon>
142
+ </button>
143
+ <button
144
+ mat-mini-fab
145
+ color="warn"
146
+ (click)="remove.emit()"
147
+ [matTooltip]="'Excluir widget'"
148
+ aria-label="Excluir widget"
149
+ >
150
+ <mat-icon [praxisIcon]="'delete'"></mat-icon>
151
+ </button>
152
+ </div>
153
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{position:absolute;inset:0;pointer-events:none}.pdx-tile-toolbar{position:absolute;right:6px;top:-18px;display:flex;gap:6px;z-index:5;opacity:0;transition:opacity .12s ease-in-out;pointer-events:auto;background:color-mix(in oklab,var(--md-sys-color-surface) 92%,transparent);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);border-radius:999px;padding:4px;box-shadow:var(--mat-elevation-level3, 0 4px 8px rgba(0,0,0,.2))}.pdx-tile-toolbar.always-visible{opacity:1}\n"] }]
154
+ }], propDecorators: { selected: [{
155
+ type: Input
156
+ }], widgetType: [{
157
+ type: Input
158
+ }], remove: [{
159
+ type: Output
160
+ }], settings: [{
161
+ type: Output
162
+ }] } });
163
+
164
+ class FloatingToolbarComponent {
165
+ visible = false;
166
+ canUndo = false;
167
+ canRedo = false;
168
+ add = new EventEmitter();
169
+ undo = new EventEmitter();
170
+ redo = new EventEmitter();
171
+ settings = new EventEmitter();
172
+ preview = new EventEmitter();
173
+ connections = new EventEmitter();
174
+ connectionsEdit = new EventEmitter();
175
+ connectionsVisual = new EventEmitter();
176
+ save = new EventEmitter();
177
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: FloatingToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
178
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: FloatingToolbarComponent, isStandalone: true, selector: "praxis-floating-toolbar", inputs: { visible: "visible", canUndo: "canUndo", canRedo: "canRedo" }, outputs: { add: "add", undo: "undo", redo: "redo", settings: "settings", preview: "preview", connections: "connections", connectionsEdit: "connectionsEdit", connectionsVisual: "connectionsVisual", save: "save" }, ngImport: i0, template: `
179
+ <div class="pdx-floating-toolbar" *ngIf="visible">
180
+ <button mat-fab color="primary" class="pdx-fab" [matTooltip]="'Ações rápidas'">
181
+ <mat-icon [praxisIcon]="'build'"></mat-icon>
182
+ </button>
183
+ <div class="pdx-actions">
184
+ <button mat-mini-fab color="primary" (click)="add.emit()" [matTooltip]="'Inserir componente'" aria-label="Inserir componente">
185
+ <mat-icon [praxisIcon]="'add'"></mat-icon>
186
+ </button>
187
+ <button mat-mini-fab (click)="connections.emit()" [matTooltip]="'Visualizar conexões (Diagrama)'" aria-label="Visualizar conexões (Diagrama)">
188
+ <mat-icon [praxisIcon]="'device_hub'"></mat-icon>
189
+ </button>
190
+ <button mat-mini-fab (click)="connectionsVisual.emit()" [matTooltip]="'Editor Visual (beta)'" aria-label="Editor Visual (beta)">
191
+ <mat-icon [praxisIcon]="'schema'"></mat-icon>
192
+ </button>
193
+ <button mat-mini-fab (click)="connectionsEdit.emit()" [matTooltip]="'Editar conexões (Builder)'" aria-label="Editar conexões (Builder)">
194
+ <mat-icon [praxisIcon]="'tune'"></mat-icon>
195
+ </button>
196
+ <button mat-mini-fab color="accent" (click)="save.emit()" [matTooltip]="'Salvar página'" aria-label="Salvar página">
197
+ <mat-icon [praxisIcon]="'save'"></mat-icon>
198
+ </button>
199
+ <button mat-mini-fab (click)="undo.emit()" [disabled]="!canUndo" [matTooltip]="'Desfazer'" aria-label="Desfazer">
200
+ <mat-icon [praxisIcon]="'undo'"></mat-icon>
201
+ </button>
202
+ <button mat-mini-fab (click)="redo.emit()" [disabled]="!canRedo" [matTooltip]="'Refazer'" aria-label="Refazer">
203
+ <mat-icon [praxisIcon]="'redo'"></mat-icon>
204
+ </button>
205
+ <button mat-mini-fab (click)="settings.emit()" [matTooltip]="'Configurações da página'" aria-label="Configurações da página">
206
+ <mat-icon [praxisIcon]="'settings'"></mat-icon>
207
+ </button>
208
+ <button mat-mini-fab (click)="preview.emit()" [matTooltip]="'Pré-visualizar'" aria-label="Pré-visualizar">
209
+ <mat-icon [praxisIcon]="'visibility'"></mat-icon>
210
+ </button>
211
+ </div>
212
+ </div>
213
+ `, isInline: true, styles: [":host{position:absolute;inset:0;pointer-events:none}.pdx-floating-toolbar{position:absolute;right:16px;bottom:16px;display:flex;gap:8px;align-items:center;pointer-events:auto}.pdx-actions{display:flex;gap:8px}.pdx-fab{box-shadow:var(--mat-elevation-transition),var(--mat-elevation-level6, 0 6px 12px rgba(0,0,0,.24))}@media (max-width: 720px){.pdx-actions{gap:6px}.pdx-floating-toolbar{right:12px;bottom:12px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
214
+ }
215
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: FloatingToolbarComponent, decorators: [{
216
+ type: Component,
217
+ args: [{ selector: 'praxis-floating-toolbar', standalone: true, imports: [CommonModule, MatButtonModule, MatIconModule, MatTooltipModule, PraxisIconDirective], template: `
218
+ <div class="pdx-floating-toolbar" *ngIf="visible">
219
+ <button mat-fab color="primary" class="pdx-fab" [matTooltip]="'Ações rápidas'">
220
+ <mat-icon [praxisIcon]="'build'"></mat-icon>
221
+ </button>
222
+ <div class="pdx-actions">
223
+ <button mat-mini-fab color="primary" (click)="add.emit()" [matTooltip]="'Inserir componente'" aria-label="Inserir componente">
224
+ <mat-icon [praxisIcon]="'add'"></mat-icon>
225
+ </button>
226
+ <button mat-mini-fab (click)="connections.emit()" [matTooltip]="'Visualizar conexões (Diagrama)'" aria-label="Visualizar conexões (Diagrama)">
227
+ <mat-icon [praxisIcon]="'device_hub'"></mat-icon>
228
+ </button>
229
+ <button mat-mini-fab (click)="connectionsVisual.emit()" [matTooltip]="'Editor Visual (beta)'" aria-label="Editor Visual (beta)">
230
+ <mat-icon [praxisIcon]="'schema'"></mat-icon>
231
+ </button>
232
+ <button mat-mini-fab (click)="connectionsEdit.emit()" [matTooltip]="'Editar conexões (Builder)'" aria-label="Editar conexões (Builder)">
233
+ <mat-icon [praxisIcon]="'tune'"></mat-icon>
234
+ </button>
235
+ <button mat-mini-fab color="accent" (click)="save.emit()" [matTooltip]="'Salvar página'" aria-label="Salvar página">
236
+ <mat-icon [praxisIcon]="'save'"></mat-icon>
237
+ </button>
238
+ <button mat-mini-fab (click)="undo.emit()" [disabled]="!canUndo" [matTooltip]="'Desfazer'" aria-label="Desfazer">
239
+ <mat-icon [praxisIcon]="'undo'"></mat-icon>
240
+ </button>
241
+ <button mat-mini-fab (click)="redo.emit()" [disabled]="!canRedo" [matTooltip]="'Refazer'" aria-label="Refazer">
242
+ <mat-icon [praxisIcon]="'redo'"></mat-icon>
243
+ </button>
244
+ <button mat-mini-fab (click)="settings.emit()" [matTooltip]="'Configurações da página'" aria-label="Configurações da página">
245
+ <mat-icon [praxisIcon]="'settings'"></mat-icon>
246
+ </button>
247
+ <button mat-mini-fab (click)="preview.emit()" [matTooltip]="'Pré-visualizar'" aria-label="Pré-visualizar">
248
+ <mat-icon [praxisIcon]="'visibility'"></mat-icon>
249
+ </button>
250
+ </div>
251
+ </div>
252
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{position:absolute;inset:0;pointer-events:none}.pdx-floating-toolbar{position:absolute;right:16px;bottom:16px;display:flex;gap:8px;align-items:center;pointer-events:auto}.pdx-actions{display:flex;gap:8px}.pdx-fab{box-shadow:var(--mat-elevation-transition),var(--mat-elevation-level6, 0 6px 12px rgba(0,0,0,.24))}@media (max-width: 720px){.pdx-actions{gap:6px}.pdx-floating-toolbar{right:12px;bottom:12px}}\n"] }]
253
+ }], propDecorators: { visible: [{
254
+ type: Input
255
+ }], canUndo: [{
256
+ type: Input
257
+ }], canRedo: [{
258
+ type: Input
259
+ }], add: [{
260
+ type: Output
261
+ }], undo: [{
262
+ type: Output
263
+ }], redo: [{
264
+ type: Output
265
+ }], settings: [{
266
+ type: Output
267
+ }], preview: [{
268
+ type: Output
269
+ }], connections: [{
270
+ type: Output
271
+ }], connectionsEdit: [{
272
+ type: Output
273
+ }], connectionsVisual: [{
274
+ type: Output
275
+ }], save: [{
276
+ type: Output
277
+ }] } });
278
+
279
+ class ComponentPaletteDialogComponent {
280
+ dialogRef;
281
+ registry;
282
+ data;
283
+ query = '';
284
+ all = signal([], ...(ngDevMode ? [{ debugName: "all" }] : []));
285
+ filtered = computed(() => this.applyFilters(), ...(ngDevMode ? [{ debugName: "filtered" }] : []));
286
+ density = computed(() => {
287
+ const n = this.filtered().length;
288
+ if (n <= 4)
289
+ return 'roomy';
290
+ if (n > 12)
291
+ return 'dense';
292
+ return 'normal';
293
+ }, ...(ngDevMode ? [{ debugName: "density" }] : []));
294
+ constructor(dialogRef, registry, data) {
295
+ this.dialogRef = dialogRef;
296
+ this.registry = registry;
297
+ this.data = data;
298
+ }
299
+ ngOnInit() {
300
+ this.all.set(this.registry.getAll());
301
+ }
302
+ select(id) {
303
+ this.dialogRef.close(id);
304
+ }
305
+ trackById = (_, m) => m.id;
306
+ getPreview(m) {
307
+ return (m.description || m.selector || m.friendlyName || m.id || '').toString();
308
+ }
309
+ // Create effect in injection context (field initializer is allowed)
310
+ _adjustSizeEffect = effect(() => {
311
+ const n = this.filtered().length;
312
+ let width = '720px';
313
+ if (n <= 4)
314
+ width = '560px';
315
+ else if (n <= 8)
316
+ width = '680px';
317
+ const container = this.dialogRef._containerInstance;
318
+ if (container && container._config) {
319
+ container._config.width = width;
320
+ }
321
+ }, ...(ngDevMode ? [{ debugName: "_adjustSizeEffect" }] : []));
322
+ applyFilters() {
323
+ const list = (this.all() || []);
324
+ const q = (this.query || '').toLowerCase();
325
+ const allowIds = new Set((this.data?.allowedWidgetIds || []).map((s) => s.toLowerCase()));
326
+ const allowTags = new Set((this.data?.allowedWidgetTags || []).map((s) => s.toLowerCase()));
327
+ return list.filter((m) => {
328
+ if (q) {
329
+ const hay = `${m.id} ${m.friendlyName || ''} ${m.description || ''} ${m.selector || ''}`.toLowerCase();
330
+ if (!hay.includes(q))
331
+ return false;
332
+ }
333
+ if (allowIds.size > 0 && !allowIds.has((m.id || '').toLowerCase()))
334
+ return false;
335
+ if (allowTags.size > 0 && !m.tags?.some(t => allowTags.has(t.toLowerCase())))
336
+ return false;
337
+ if (typeof this.data?.predicate === 'function' && !this.data.predicate(m))
338
+ return false;
339
+ return true;
340
+ });
341
+ }
342
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ComponentPaletteDialogComponent, deps: [{ token: i1.MatDialogRef }, { token: i2$1.ComponentMetadataRegistry }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
343
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: ComponentPaletteDialogComponent, isStandalone: true, selector: "praxis-component-palette-dialog", ngImport: i0, template: `
344
+ <h2 mat-dialog-title>
345
+ <div class="dlg-title">
346
+ <mat-icon class="dlg-icon" [praxisIcon]="'widgets'"></mat-icon>
347
+ <div class="dlg-texts">
348
+ <div class="dlg-head">{{ data?.title || 'Inserir componente' }}</div>
349
+ <div class="dlg-sub">Escolha um componente para adicionar à página · {{ filtered().length }} disponíveis</div>
350
+ </div>
351
+ </div>
352
+ </h2>
353
+ <div mat-dialog-content class="pdx-palette-content">
354
+ <div class="pdx-grid" [ngClass]="density()" *ngIf="filtered().length; else emptyState">
355
+ <div
356
+ *ngFor="let m of filtered(); trackBy: trackById"
357
+ class="pdx-card mat-elevation-z2"
358
+ tabindex="0"
359
+ role="button"
360
+ [attr.aria-label]="'Adicionar ' + (m.friendlyName || m.id)"
361
+ (click)="select(m.id)"
362
+ (keydown.enter)="select(m.id)"
363
+ (keydown.space)="select(m.id)"
364
+ >
365
+ <div class="pdx-card-icon">
366
+ <mat-icon [praxisIcon]="m.icon || 'widgets'"></mat-icon>
367
+ </div>
368
+ <div class="pdx-card-body">
369
+ <div class="pdx-card-title">{{ m.friendlyName || m.id }}</div>
370
+ <div class="pdx-card-desc">{{ m.description || m.selector }}</div>
371
+ </div>
372
+ </div>
373
+ </div>
374
+
375
+ <ng-template #emptyState>
376
+ <div class="pdx-empty">
377
+ <mat-icon [praxisIcon]="'sentiment_dissatisfied'"></mat-icon>
378
+ <div>Nenhum componente disponível</div>
379
+ </div>
380
+ </ng-template>
381
+ </div>
382
+ <div mat-dialog-actions align="end">
383
+ <button mat-stroked-button color="primary" mat-dialog-close>Cancelar</button>
384
+ </div>
385
+ `, isInline: true, styles: [":host{display:block}h2[mat-dialog-title]{margin:0;padding:12px 24px 10px;border-bottom:1px solid var(--md-sys-color-outline-variant, rgba(0,0,0,.12))}.dlg-title{display:flex;align-items:center;gap:10px}.dlg-icon{color:var(--md-sys-color-primary, #3f51b5)}.dlg-head{font-size:18px;font-weight:600;line-height:1.2}.dlg-sub{font-size:12px;opacity:.85;color:var(--md-sys-color-on-surface-variant, rgba(0,0,0,.62))}.pdx-palette-content{min-width:480px;max-width:920px;padding-top:8px}.pdx-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:14px}.pdx-grid.dense{grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}.pdx-grid.roomy{grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:16px}.pdx-card{position:relative;display:grid;grid-template-columns:44px 1fr;grid-template-rows:auto auto;gap:10px;padding:14px;border:1px solid transparent;border-radius:14px;cursor:pointer;outline:none;min-height:92px;background:linear-gradient(var(--md-sys-color-surface),var(--md-sys-color-surface)) padding-box,linear-gradient(135deg,color-mix(in oklab,var(--md-sys-color-primary, #3f51b5) 55%,transparent),color-mix(in oklab,var(--md-sys-color-secondary, #ff4081) 45%,transparent)) border-box;transition:box-shadow .2s ease,background .25s ease,transform .06s ease}.pdx-grid.dense .pdx-card{padding:10px;border-radius:12px;min-height:84px}.pdx-grid.roomy .pdx-card{padding:16px;border-radius:16px;min-height:100px}.pdx-card:focus,.pdx-card:hover{box-shadow:var(--mat-elevation-transition),var(--mat-elevation-level6, 0 6px 12px rgba(0,0,0,.22));background:linear-gradient(var(--md-sys-color-surface),var(--md-sys-color-surface)) padding-box,linear-gradient(135deg,color-mix(in oklab,var(--md-sys-color-primary) 70%,transparent),color-mix(in oklab,var(--md-sys-color-secondary) 55%,transparent)) border-box}.pdx-card:active{transform:translateY(1px)}.pdx-card-icon{grid-row:span 2;display:flex;align-items:center;justify-content:center;color:color-mix(in oklab,var(--md-sys-color-primary) 70%,#666)}.pdx-card-title{font-weight:600;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pdx-card-desc{color:#000000b3;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;word-break:break-word}.pdx-empty{padding:24px;display:grid;place-items:center;color:#0009;gap:8px}@media (max-width: 600px){.pdx-palette-content{min-width:320px}.pdx-grid{grid-template-columns:repeat(auto-fill,minmax(200px,1fr))}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
386
+ }
387
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ComponentPaletteDialogComponent, decorators: [{
388
+ type: Component,
389
+ args: [{ selector: 'praxis-component-palette-dialog', standalone: true, imports: [CommonModule, FormsModule, MatDialogModule, MatFormFieldModule, MatInputModule, MatIconModule, MatButtonModule, PraxisIconDirective], template: `
390
+ <h2 mat-dialog-title>
391
+ <div class="dlg-title">
392
+ <mat-icon class="dlg-icon" [praxisIcon]="'widgets'"></mat-icon>
393
+ <div class="dlg-texts">
394
+ <div class="dlg-head">{{ data?.title || 'Inserir componente' }}</div>
395
+ <div class="dlg-sub">Escolha um componente para adicionar à página · {{ filtered().length }} disponíveis</div>
396
+ </div>
397
+ </div>
398
+ </h2>
399
+ <div mat-dialog-content class="pdx-palette-content">
400
+ <div class="pdx-grid" [ngClass]="density()" *ngIf="filtered().length; else emptyState">
401
+ <div
402
+ *ngFor="let m of filtered(); trackBy: trackById"
403
+ class="pdx-card mat-elevation-z2"
404
+ tabindex="0"
405
+ role="button"
406
+ [attr.aria-label]="'Adicionar ' + (m.friendlyName || m.id)"
407
+ (click)="select(m.id)"
408
+ (keydown.enter)="select(m.id)"
409
+ (keydown.space)="select(m.id)"
410
+ >
411
+ <div class="pdx-card-icon">
412
+ <mat-icon [praxisIcon]="m.icon || 'widgets'"></mat-icon>
413
+ </div>
414
+ <div class="pdx-card-body">
415
+ <div class="pdx-card-title">{{ m.friendlyName || m.id }}</div>
416
+ <div class="pdx-card-desc">{{ m.description || m.selector }}</div>
417
+ </div>
418
+ </div>
419
+ </div>
420
+
421
+ <ng-template #emptyState>
422
+ <div class="pdx-empty">
423
+ <mat-icon [praxisIcon]="'sentiment_dissatisfied'"></mat-icon>
424
+ <div>Nenhum componente disponível</div>
425
+ </div>
426
+ </ng-template>
427
+ </div>
428
+ <div mat-dialog-actions align="end">
429
+ <button mat-stroked-button color="primary" mat-dialog-close>Cancelar</button>
430
+ </div>
431
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}h2[mat-dialog-title]{margin:0;padding:12px 24px 10px;border-bottom:1px solid var(--md-sys-color-outline-variant, rgba(0,0,0,.12))}.dlg-title{display:flex;align-items:center;gap:10px}.dlg-icon{color:var(--md-sys-color-primary, #3f51b5)}.dlg-head{font-size:18px;font-weight:600;line-height:1.2}.dlg-sub{font-size:12px;opacity:.85;color:var(--md-sys-color-on-surface-variant, rgba(0,0,0,.62))}.pdx-palette-content{min-width:480px;max-width:920px;padding-top:8px}.pdx-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:14px}.pdx-grid.dense{grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}.pdx-grid.roomy{grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:16px}.pdx-card{position:relative;display:grid;grid-template-columns:44px 1fr;grid-template-rows:auto auto;gap:10px;padding:14px;border:1px solid transparent;border-radius:14px;cursor:pointer;outline:none;min-height:92px;background:linear-gradient(var(--md-sys-color-surface),var(--md-sys-color-surface)) padding-box,linear-gradient(135deg,color-mix(in oklab,var(--md-sys-color-primary, #3f51b5) 55%,transparent),color-mix(in oklab,var(--md-sys-color-secondary, #ff4081) 45%,transparent)) border-box;transition:box-shadow .2s ease,background .25s ease,transform .06s ease}.pdx-grid.dense .pdx-card{padding:10px;border-radius:12px;min-height:84px}.pdx-grid.roomy .pdx-card{padding:16px;border-radius:16px;min-height:100px}.pdx-card:focus,.pdx-card:hover{box-shadow:var(--mat-elevation-transition),var(--mat-elevation-level6, 0 6px 12px rgba(0,0,0,.22));background:linear-gradient(var(--md-sys-color-surface),var(--md-sys-color-surface)) padding-box,linear-gradient(135deg,color-mix(in oklab,var(--md-sys-color-primary) 70%,transparent),color-mix(in oklab,var(--md-sys-color-secondary) 55%,transparent)) border-box}.pdx-card:active{transform:translateY(1px)}.pdx-card-icon{grid-row:span 2;display:flex;align-items:center;justify-content:center;color:color-mix(in oklab,var(--md-sys-color-primary) 70%,#666)}.pdx-card-title{font-weight:600;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pdx-card-desc{color:#000000b3;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;word-break:break-word}.pdx-empty{padding:24px;display:grid;place-items:center;color:#0009;gap:8px}@media (max-width: 600px){.pdx-palette-content{min-width:320px}.pdx-grid{grid-template-columns:repeat(auto-fill,minmax(200px,1fr))}}\n"] }]
432
+ }], ctorParameters: () => [{ type: i1.MatDialogRef }, { type: i2$1.ComponentMetadataRegistry }, { type: undefined, decorators: [{
433
+ type: Inject,
434
+ args: [MAT_DIALOG_DATA]
435
+ }] }] });
436
+
437
+ class ConnectionBuilderComponent {
438
+ dialog;
439
+ registry;
440
+ snack;
441
+ page;
442
+ widgets;
443
+ pageChange = new EventEmitter();
444
+ // State
445
+ originalSnapshot = '';
446
+ showOnlyIssues = false;
447
+ showFriendly = true;
448
+ filterText = '';
449
+ groupBy = 'none';
450
+ sortBy = 'from';
451
+ // Move braces-containing placeholder into TS (AGENTS.md policy)
452
+ mapPlaceholder = 'payload | payload.id | ${payload.id}';
453
+ // Signals
454
+ connections = signal([], ...(ngDevMode ? [{ debugName: "connections" }] : []));
455
+ selectedIndex = signal(-1, ...(ngDevMode ? [{ debugName: "selectedIndex" }] : []));
456
+ // Derived lists
457
+ filteredConnections = computed(() => this.applyFilters(this.connections()), ...(ngDevMode ? [{ debugName: "filteredConnections" }] : []));
458
+ groupedConnections = computed(() => this.applyGrouping(this.filteredConnections()), ...(ngDevMode ? [{ debugName: "groupedConnections" }] : []));
459
+ constructor(dialog, registry, snack) {
460
+ this.dialog = dialog;
461
+ this.registry = registry;
462
+ this.snack = snack;
463
+ }
464
+ ngOnInit() {
465
+ const p = this.parsePage(this.page);
466
+ const ws = this.widgets || p?.widgets || [];
467
+ this.widgets = ws;
468
+ const conns = [...(p?.connections || [])];
469
+ this.connections.set(conns);
470
+ this.originalSnapshot = JSON.stringify(conns);
471
+ }
472
+ ngOnChanges(changes) {
473
+ if (changes['page'] || changes['widgets']) {
474
+ const p = this.parsePage(this.page);
475
+ this.widgets = this.widgets || p?.widgets || [];
476
+ const next = [...(p?.connections || [])];
477
+ this.connections.set(next);
478
+ this.originalSnapshot = JSON.stringify(next);
479
+ }
480
+ }
481
+ // UI helpers
482
+ isExpanded(i) { return i === this.selectedIndex(); }
483
+ toggleExpanded(i, ev) { if (ev)
484
+ ev.stopPropagation(); this.selectedIndex.set(this.selectedIndex() === i ? -1 : i); }
485
+ setSortBy(v) { this.sortBy = v; this.connections.set(this.sortList([...this.connections()])); }
486
+ onGroupByChange() { }
487
+ toggleShowOnlyIssues() { this.showOnlyIssues = !this.showOnlyIssues; }
488
+ toggleFriendly() { this.showFriendly = !this.showFriendly; }
489
+ trackByIndex = (i) => i;
490
+ // Labels
491
+ fromLabel(c) { return `${c.from.widget}.${c.from.output}`; }
492
+ toLabel(c) { return `${c.to.widget}.${c.to.input}`; }
493
+ fromFriendly(c) { return `${this.widgetFriendlyNameForKey(c.from.widget)}.${c.from.output}`; }
494
+ toFriendly(c) { return `${this.widgetFriendlyNameForKey(c.to.widget)}.${c.to.input}`; }
495
+ outputDescription(c) { return this.registry.get(this.widgetTypeByKey(c.from.widget))?.outputs?.find(o => o.name === c.from.output)?.description || ''; }
496
+ inputDescription(c) { return this.registry.get(this.widgetTypeByKey(c.to.widget))?.inputs?.find(i => i.name === c.to.input)?.description || ''; }
497
+ widgetFriendlyNameForKey(key) { const id = this.widgetTypeByKey(key); return this.registry.get(id)?.friendlyName || id; }
498
+ componentIconForKey(key) { const id = this.widgetTypeByKey(key); return this.registry.get(id)?.icon || 'widgets'; }
499
+ widgetTypeByKey(key) { return this.widgets?.find(w => w.key === key)?.definition?.id || key; }
500
+ applyFilters(list) {
501
+ const q = (this.filterText || '').toLowerCase();
502
+ const arr = list.filter((c) => {
503
+ if (this.showOnlyIssues && this.connectionStatus(c) === 'ok')
504
+ return false;
505
+ if (!q)
506
+ return true;
507
+ const hay = `${c.from.widget}.${c.from.output} ${c.to.widget}.${c.to.input} ${c.map || ''}`.toLowerCase();
508
+ return hay.includes(q);
509
+ });
510
+ return this.sortList(arr);
511
+ }
512
+ applyGrouping(list) {
513
+ switch (this.groupBy) {
514
+ case 'from': return this.groupByKey(list, c => `${c.from.widget}.${c.from.output}`);
515
+ case 'to': return this.groupByKey(list, c => `${c.to.widget}.${c.to.input}`);
516
+ case 'event': return this.groupByKey(list, c => `${c.from.output}`);
517
+ default: return [{ label: 'Todas', list }];
518
+ }
519
+ }
520
+ groupByKey(list, keyFn) {
521
+ const map = new Map();
522
+ for (const c of list) {
523
+ const k = keyFn(c);
524
+ const arr = map.get(k) || [];
525
+ arr.push(c);
526
+ map.set(k, arr);
527
+ }
528
+ return Array.from(map.entries()).map(([k, v]) => ({ label: k, list: v }));
529
+ }
530
+ sortList(list) {
531
+ return [...list].sort((a, b) => {
532
+ if (this.sortBy === 'from')
533
+ return this.fromLabel(a).localeCompare(this.fromLabel(b));
534
+ return this.toLabel(a).localeCompare(this.toLabel(b));
535
+ });
536
+ }
537
+ // Editing
538
+ createNew() {
539
+ const fromKey = this.widgets?.[0]?.key || '';
540
+ const toKey = this.widgets?.[1]?.key || '';
541
+ const conn = { from: { widget: fromKey, output: 'submit' }, to: { widget: toKey, input: 'context' } };
542
+ this.connections.set([conn, ...this.connections()]);
543
+ }
544
+ startEdit(index, _c) { this.selectedIndex.set(index); }
545
+ startEditByConn(c) { const i = this.connections().indexOf(c); if (i >= 0)
546
+ this.startEdit(i, c); }
547
+ duplicateConnection(index) { const next = [...this.connections()]; const c = next[index]; if (!c)
548
+ return; next.splice(index + 1, 0, { ...c }); this.connections.set(next); }
549
+ removeConnection(index) { const next = [...this.connections()]; if (index < 0 || index >= next.length)
550
+ return; next.splice(index, 1); this.connections.set(next); }
551
+ // Validation
552
+ connectionStatus(c) {
553
+ if (!c.from?.widget || !c.from?.output || !c.to?.widget || !c.to?.input)
554
+ return 'err';
555
+ const wFrom = this.widgetTypeByKey(c.from.widget);
556
+ const wTo = this.widgetTypeByKey(c.to.widget);
557
+ const outOk = !!this.registry.get(wFrom)?.outputs?.some(o => o.name === c.from.output);
558
+ const inOk = !!this.registry.get(wTo)?.inputs?.some(i => i.name === c.to.input);
559
+ if (!outOk || !inOk)
560
+ return 'warn';
561
+ return 'ok';
562
+ }
563
+ // Persist/apply
564
+ onSave() {
565
+ const p = this.parsePage(this.page) || {};
566
+ const next = { ...p, connections: this.connections() };
567
+ this.page = next;
568
+ this.pageChange.emit(next);
569
+ this.snack.open('Conexões salvas', undefined, { duration: 1000 });
570
+ this.originalSnapshot = JSON.stringify(this.connections());
571
+ }
572
+ // Diagram helpers
573
+ openDiagramFor(_c) {
574
+ import('./praxisui-page-builder-connection-graph.component-C6x--6--.mjs').then(m => {
575
+ this.dialog.open(m.ConnectionGraphComponent, { width: '95vw', height: '80vh', maxWidth: '100vw', panelClass: 'praxis-conn-graph-dialog' });
576
+ });
577
+ }
578
+ openDiagramFullscreen() {
579
+ import('./praxisui-page-builder-connection-graph.component-C6x--6--.mjs').then(m => {
580
+ this.dialog.open(m.ConnectionGraphComponent, { width: '95vw', height: '95vh', maxWidth: '100vw', panelClass: 'praxis-conn-graph-dialog', autoFocus: false, restoreFocus: false });
581
+ });
582
+ }
583
+ parsePage(input) {
584
+ if (!input)
585
+ return undefined;
586
+ if (typeof input === 'string') {
587
+ try {
588
+ return JSON.parse(input);
589
+ }
590
+ catch {
591
+ return undefined;
592
+ }
593
+ }
594
+ return input;
595
+ }
596
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ConnectionBuilderComponent, deps: [{ token: i1.MatDialog }, { token: i2$1.ComponentMetadataRegistry }, { token: i3$3.MatSnackBar }], target: i0.ɵɵFactoryTarget.Component });
597
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: ConnectionBuilderComponent, isStandalone: true, selector: "praxis-connection-builder", inputs: { page: "page", widgets: "widgets" }, outputs: { pageChange: "pageChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"pdx-conn-root\" role=\"region\" aria-label=\"Construtor de Conex\u00F5es\">\n <div class=\"pdx-conn-head\">\n <span class=\"pdx-conn-title\">Conex\u00F5es</span>\n <span class=\"pdx-conn-count\" aria-label=\"Conex\u00F5es filtradas e total\">{{ filteredConnections().length }} / {{ connections().length }}</span>\n <mat-form-field appearance=\"outline\" class=\"pdx-conn-search\">\n <mat-label>Buscar</mat-label>\n <input matInput [(ngModel)]=\"filterText\" placeholder=\"Origem, Destino, Input, Map...\" />\n <button mat-icon-button matSuffix *ngIf=\"filterText\" (click)=\"filterText='';\" aria-label=\"Limpar busca\"><mat-icon [praxisIcon]=\"'close'\"></mat-icon></button>\n </mat-form-field>\n <span class=\"pdx-spacer\"></span>\n <button mat-button (click)=\"toggleShowOnlyIssues()\" [color]=\"showOnlyIssues ? 'primary': undefined\" aria-label=\"Somente avisos/erros\"><mat-icon [praxisIcon]=\"'report_problem'\"></mat-icon> Issues</button>\n <mat-form-field appearance=\"outline\" style=\"width: 160px;\">\n <mat-label>Ordenar por</mat-label>\n <mat-select [(ngModel)]=\"sortBy\" (ngModelChange)=\"setSortBy($event)\">\n <mat-option value=\"from\">Origem</mat-option>\n <mat-option value=\"to\">Destino</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"width: 170px;\">\n <mat-label>Agrupar por</mat-label>\n <mat-select [(ngModel)]=\"groupBy\" (ngModelChange)=\"onGroupByChange()\">\n <mat-option value=\"none\">Nenhum</mat-option>\n <mat-option value=\"from\">Origem</mat-option>\n <mat-option value=\"to\">Destino</mat-option>\n <mat-option value=\"event\">Evento</mat-option>\n </mat-select>\n </mat-form-field>\n <button mat-icon-button [color]=\"showFriendly ? 'primary' : undefined\" (click)=\"toggleFriendly()\" aria-label=\"Alternar nome amig\u00E1vel/t\u00E9cnico\"><mat-icon [praxisIcon]=\"'translate'\"></mat-icon></button>\n <button mat-stroked-button (click)=\"createNew()\" aria-label=\"Nova conex\u00E3o\"><mat-icon [praxisIcon]=\"'add'\"></mat-icon> Nova Conex\u00E3o</button>\n <button mat-flat-button color=\"accent\" class=\"pdx-diagram-cta\" (click)=\"openDiagramFullscreen()\" aria-label=\"Abrir diagrama em tela cheia\" matTooltip=\"Visualizar conex\u00F5es em grafo\"><mat-icon [praxisIcon]=\"'schema'\"></mat-icon><span>Diagrama</span></button>\n </div>\n\n <div class=\"pdx-conn-grid\">\n <!-- Left: read-only list -->\n <div class=\"pdx-conn-list\" role=\"list\" aria-label=\"Lista de conex\u00F5es\" cdkScrollable>\n <mat-list *ngIf=\"filteredConnections().length; else noConns\">\n <ng-container *ngIf=\"groupBy!=='none'; else flatList\">\n <div class=\"group-block\" *ngFor=\"let g of groupedConnections(); let gi = index\">\n <div class=\"group-header\">\n <span class=\"group-title\">{{ g.label }}</span>\n <span class=\"group-count\">{{ g.list.length }}</span>\n </div>\n <mat-divider></mat-divider>\n <div class=\"group-list\">\n <ng-container *ngFor=\"let c of g.list; let i = index\">\n <mat-list-item role=\"listitem\" (click)=\"startEdit(i, c)\" [class.selected]=\"selectedIndex()===i\">\n <div class=\"card-head\" matListItemTitle [matTooltip]=\"showFriendly ? (c.from.widget + '.' + c.from.output + ' \u2192 ' + (c.to.widget + '.' + c.to.input)) : ''\">\n <mat-icon class=\"comp-icon from\" [matTooltip]=\"widgetFriendlyNameForKey(c.from.widget)\">{{ componentIconForKey(c.from.widget) }}</mat-icon>\n <span class=\"pdx-badge from\" aria-hidden=\"true\"></span>\n <span class=\"from\">{{ showFriendly ? fromFriendly(c) : fromLabel(c) }}</span>\n <span class=\"arrow\">\u2192</span>\n <mat-icon class=\"comp-icon to\" [matTooltip]=\"widgetFriendlyNameForKey(c.to.widget)\">{{ componentIconForKey(c.to.widget) }}</mat-icon>\n <span class=\"pdx-badge to\" aria-hidden=\"true\"></span>\n <span class=\"to\">{{ showFriendly ? toFriendly(c) : toLabel(c) }}</span>\n <span class=\"spacer\"></span>\n <span class=\"status-pill\" [class.ok]=\"connectionStatus(c)==='ok'\" [class.warn]=\"connectionStatus(c)==='warn'\" [class.err]=\"connectionStatus(c)==='err'\">\n <mat-icon *ngIf=\"connectionStatus(c)==='ok'\">check_circle</mat-icon>\n <mat-icon *ngIf=\"connectionStatus(c)==='warn'\">warning</mat-icon>\n <mat-icon *ngIf=\"connectionStatus(c)==='err'\">error</mat-icon>\n </span>\n <button mat-icon-button class=\"expand-btn\" [attr.aria-expanded]=\"isExpanded(i)\" (click)=\"toggleExpanded(i, $event)\" [matTooltip]=\"isExpanded(i) ? 'Recolher detalhes' : 'Expandir detalhes'\">\n <mat-icon>{{ isExpanded(i) ? 'expand_less' : 'expand_more' }}</mat-icon>\n </button>\n </div>\n <div class=\"meta\" *ngIf=\"showFriendly\" matListItemLine>\n <span class=\"hint\">{{ outputDescription(c) }}</span>\n <span class=\"sep\" *ngIf=\"outputDescription(c) && inputDescription(c)\">\u2022</span>\n <span class=\"hint\">{{ inputDescription(c) }}</span>\n </div>\n <div class=\"map-chip\" *ngIf=\"c.map\" [matTooltip]=\"c.map || ''\" matListItemLine (click)=\"startEditByConn(c)\" title=\"Clique para editar Map\">\n <span class=\"pdx-badge map\" aria-hidden=\"true\"></span>\n <mat-icon class=\"map-icon\" inline>bolt</mat-icon>\n <span class=\"mono\">{{ c.map }}</span>\n </div>\n <div class=\"card-actions\" matListItemLine (click)=\"$event.stopPropagation()\">\n <span class=\"action-group\">\n <button mat-icon-button (click)=\"startEdit(i, c)\" matTooltip=\"Editar\"><mat-icon>settings</mat-icon></button>\n <button mat-icon-button (click)=\"duplicateConnection(i)\" matTooltip=\"Duplicar\"><mat-icon>content_copy</mat-icon></button>\n </span>\n <span class=\"action-group\">\n <button mat-stroked-button color=\"primary\" (click)=\"openDiagramFor(c)\" matTooltip=\"Ver rela\u00E7\u00E3o no diagrama\"><mat-icon>schema</mat-icon><span>Diagrama</span></button>\n </span>\n <span class=\"spacer\"></span>\n <span class=\"action-group\">\n <button mat-icon-button color=\"warn\" (click)=\"removeConnection(i)\" matTooltip=\"Remover\"><mat-icon>delete</mat-icon></button>\n </span>\n </div>\n <div class=\"card-details\" matListItemLine [class.expanded]=\"isExpanded(i)\" [style.maxHeight]=\"isExpanded(i) ? '240px' : '0px'\" [style.opacity]=\"isExpanded(i) ? 1 : 0\" [style.pointerEvents]=\"isExpanded(i) ? 'auto' : 'none'\">\n <div class=\"stepper\">\n <div class=\"step from-step\">\n <div class=\"dot from\"></div>\n <div class=\"content\">\n <div class=\"label\">De</div>\n <div class=\"value\">{{ showFriendly ? fromFriendly(c) : fromLabel(c) }}</div>\n </div>\n </div>\n <div class=\"step to-step\">\n <div class=\"dot to\"></div>\n <div class=\"content\">\n <div class=\"label\">Para</div>\n <div class=\"value\">{{ showFriendly ? toFriendly(c) : toLabel(c) }}</div>\n </div>\n </div>\n <div class=\"step map-step\" *ngIf=\"c.map\">\n <div class=\"dot map\"></div>\n <div class=\"content\">\n <div class=\"label\">Map</div>\n <div class=\"value mono\">{{ c.map }}</div>\n </div>\n </div>\n </div>\n </div>\n </mat-list-item>\n </ng-container>\n </div>\n </div>\n </ng-container>\n <ng-template #flatList>\n <ng-container *ngFor=\"let c of filteredConnections(); let i = index\">\n <mat-list-item role=\"listitem\" (click)=\"startEdit(i, c)\" [class.selected]=\"selectedIndex()===i\">\n <div class=\"card-head\" matListItemTitle [matTooltip]=\"showFriendly ? (c.from.widget + '.' + c.from.output + ' \u2192 ' + (c.to.widget + '.' + c.to.input)) : ''\">\n <mat-icon class=\"comp-icon from\" [matTooltip]=\"widgetFriendlyNameForKey(c.from.widget)\">{{ componentIconForKey(c.from.widget) }}</mat-icon>\n <span class=\"pdx-badge from\" aria-hidden=\"true\"></span>\n <span class=\"from\">{{ showFriendly ? fromFriendly(c) : fromLabel(c) }}</span>\n <span class=\"arrow\">\u2192</span>\n <mat-icon class=\"comp-icon to\" [matTooltip]=\"widgetFriendlyNameForKey(c.to.widget)\">{{ componentIconForKey(c.to.widget) }}</mat-icon>\n <span class=\"pdx-badge to\" aria-hidden=\"true\"></span>\n <span class=\"to\">{{ showFriendly ? toFriendly(c) : toLabel(c) }}</span>\n <span class=\"spacer\"></span>\n <span class=\"status-pill\" [class.ok]=\"connectionStatus(c)==='ok'\" [class.warn]=\"connectionStatus(c)==='warn'\" [class.err]=\"connectionStatus(c)==='err'\">\n <mat-icon *ngIf=\"connectionStatus(c)==='ok'\">check_circle</mat-icon>\n <mat-icon *ngIf=\"connectionStatus(c)==='warn'\">warning</mat-icon>\n <mat-icon *ngIf=\"connectionStatus(c)==='err'\">error</mat-icon>\n </span>\n <button mat-icon-button class=\"expand-btn\" [attr.aria-expanded]=\"isExpanded(i)\" (click)=\"toggleExpanded(i, $event)\" [matTooltip]=\"isExpanded(i) ? 'Recolher detalhes' : 'Expandir detalhes'\">\n <mat-icon>{{ isExpanded(i) ? 'expand_less' : 'expand_more' }}</mat-icon>\n </button>\n </div>\n <div class=\"meta\" *ngIf=\"showFriendly\" matListItemLine>\n <span class=\"hint\">{{ outputDescription(c) }}</span>\n <span class=\"sep\" *ngIf=\"outputDescription(c) && inputDescription(c)\">\u2022</span>\n <span class=\"hint\">{{ inputDescription(c) }}</span>\n </div>\n <div class=\"map-chip\" *ngIf=\"c.map\" [matTooltip]=\"c.map || ''\" matListItemLine (click)=\"startEditByConn(c)\" title=\"Clique para editar Map\">\n <span class=\"pdx-badge map\" aria-hidden=\"true\"></span>\n <mat-icon class=\"map-icon\" inline>bolt</mat-icon>\n <span class=\"mono\">{{ c.map }}</span>\n </div>\n <div class=\"card-actions\" matListItemLine (click)=\"$event.stopPropagation()\">\n <span class=\"action-group\">\n <button mat-icon-button (click)=\"startEdit(i, c)\" matTooltip=\"Editar\"><mat-icon>settings</mat-icon></button>\n <button mat-icon-button (click)=\"duplicateConnection(i)\" matTooltip=\"Duplicar\"><mat-icon>content_copy</mat-icon></button>\n </span>\n <span class=\"action-group\">\n <button mat-stroked-button color=\"primary\" (click)=\"openDiagramFor(c)\" matTooltip=\"Ver rela\u00E7\u00E3o no diagrama\"><mat-icon>schema</mat-icon><span>Diagrama</span></button>\n </span>\n <span class=\"spacer\"></span>\n <span class=\"action-group\">\n <button mat-icon-button color=\"warn\" (click)=\"removeConnection(i)\" matTooltip=\"Remover\"><mat-icon>delete</mat-icon></button>\n </span>\n </div>\n <div class=\"card-details\" matListItemLine [class.expanded]=\"isExpanded(i)\" [style.maxHeight]=\"isExpanded(i) ? '240px' : '0px'\" [style.opacity]=\"isExpanded(i) ? 1 : 0\" [style.pointerEvents]=\"isExpanded(i) ? 'auto' : 'none'\">\n <div class=\"stepper\">\n <div class=\"step from-step\">\n <div class=\"dot from\"></div>\n <div class=\"content\">\n <div class=\"label\">De</div>\n <div class=\"value\">{{ showFriendly ? fromFriendly(c) : fromLabel(c) }}</div>\n </div>\n </div>\n <div class=\"step to-step\">\n <div class=\"dot to\"></div>\n <div class=\"content\">\n <div class=\"label\">Para</div>\n <div class=\"value\">{{ showFriendly ? toFriendly(c) : toLabel(c) }}</div>\n </div>\n </div>\n <div class=\"step map-step\" *ngIf=\"c.map\">\n <div class=\"dot map\"></div>\n <div class=\"content\">\n <div class=\"label\">Map</div>\n <div class=\"value mono\">{{ c.map }}</div>\n </div>\n </div>\n </div>\n </div>\n </mat-list-item>\n </ng-container>\n </ng-template>\n </mat-list>\n <ng-template #noConns>\n <div class=\"pdx-empty-list\" role=\"status\" aria-live=\"polite\">\n <mat-icon>link_off</mat-icon>\n <div>Nenhuma conex\u00E3o definida. Use \u201CNova Conex\u00E3o\u201D.</div>\n </div>\n </ng-template>\n </div>\n\n <!-- Right: editor form -->\n <div class=\"pdx-conn-editor\" role=\"form\" aria-label=\"Editor de conex\u00E3o\">\n <ng-container *ngIf=\"selectedIndex() >= 0; else emptyEditor\">\n <div class=\"form-grid\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Origem (widget.key)</mat-label>\n <input matInput [(ngModel)]=\"connections()[selectedIndex()].from.widget\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Evento (output)</mat-label>\n <input matInput [(ngModel)]=\"connections()[selectedIndex()].from.output\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Destino (widget.key)</mat-label>\n <input matInput [(ngModel)]=\"connections()[selectedIndex()].to.widget\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Input</mat-label>\n <input matInput [(ngModel)]=\"connections()[selectedIndex()].to.input\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-span\">\n <mat-label>Map (opcional)</mat-label>\n <input matInput [(ngModel)]=\"connections()[selectedIndex()].map\" [placeholder]=\"mapPlaceholder\" />\n </mat-form-field>\n <div class=\"full-span\">\n <button mat-flat-button color=\"primary\" (click)=\"onSave()\"><mat-icon [praxisIcon]=\"'save'\"></mat-icon>Salvar</button>\n </div>\n </div>\n </ng-container>\n <ng-template #emptyEditor>\n <div class=\"pdx-empty-editor\">Selecione uma conex\u00E3o para editar.</div>\n </ng-template>\n </div>\n </div>\n</div>\n", styles: [".pdx-conn-root{display:grid;gap:12px}.pdx-conn-head{display:flex;align-items:center;gap:8px}.pdx-conn-title{font-weight:600}.pdx-conn-count{opacity:.8}.pdx-conn-search{width:260px}.pdx-spacer{flex:1}.pdx-diagram-cta span{margin-left:6px}.pdx-conn-grid{display:grid;grid-template-columns:1.4fr 1fr;gap:12px}.pdx-conn-list{height:540px;overflow:auto;padding:8px 0}.pdx-conn-list .mat-mdc-list-item.mdc-list-item{height:auto;padding:10px 8px 8px}.card-head{display:flex;align-items:center;gap:6px}.card-head .spacer{flex:1}.card-head .comp-icon{opacity:.85}.card-head .expand-btn{margin-left:4px}.status-pill{display:inline-flex;align-items:center;gap:4px;border-radius:999px;padding:2px 8px}.status-pill.ok{background:color-mix(in oklab,var(--md-sys-color-primary) 15%,transparent);color:color-mix(in oklab,var(--md-sys-color-primary) 60%,#0a0)}.status-pill.warn{background:color-mix(in oklab,var(--md-sys-color-tertiary) 15%,transparent);color:color-mix(in oklab,var(--md-sys-color-tertiary) 60%,#aa0)}.status-pill.err{background:color-mix(in oklab,var(--md-sys-color-error) 15%,transparent);color:color-mix(in oklab,var(--md-sys-color-error) 60%,#a00)}.map-chip{display:inline-flex;align-items:center;gap:6px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.map-chip .map-icon{font-size:16px}.pdx-conn-editor{min-height:540px;padding:8px;border-left:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .12))}.pdx-empty-list{padding:16px;display:grid;place-items:center;gap:6px;opacity:.8}.pdx-empty-editor{padding:16px;opacity:.75}.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;align-content:start}.full-span{grid-column:1/-1}.stepper{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px;padding:8px 0}.step{display:grid;grid-template-columns:12px 1fr;gap:8px;align-items:start}.dot{width:12px;height:12px;border-radius:50%;margin-top:5px}.dot.from{background:color-mix(in oklab,var(--md-sys-color-primary) 70%,transparent)}.dot.to{background:color-mix(in oklab,var(--md-sys-color-secondary) 70%,transparent)}.dot.map{background:color-mix(in oklab,var(--md-sys-color-tertiary) 70%,transparent)}.group-block{padding:6px 6px 10px}.group-header{display:flex;gap:8px;align-items:center;padding:8px 0}.group-title{font-weight:600}.group-count{opacity:.75}.group-list{display:grid;gap:6px}.pdx-badge{width:10px;height:10px;border-radius:50%;display:inline-block}.pdx-badge.from{background:color-mix(in oklab,var(--md-sys-color-primary) 50%,transparent)}.pdx-badge.to{background:color-mix(in oklab,var(--md-sys-color-secondary) 50%,transparent)}.pdx-badge.map{background:color-mix(in oklab,var(--md-sys-color-tertiary) 50%,transparent)}.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:12px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.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: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i6.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "directive", type: i6.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i7.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: MatSelectModule }, { kind: "directive", type: i8.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "component", type: i9.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i12.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i12.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "component", type: i12.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i12.MatListItemLine, selector: "[matListItemLine]" }, { kind: "directive", type: i12.MatListItemTitle, selector: "[matListItemTitle]" }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "ngmodule", type: MatMenuModule }, { kind: "ngmodule", type: MatTabsModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
598
+ }
599
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ConnectionBuilderComponent, decorators: [{
600
+ type: Component,
601
+ args: [{ selector: 'praxis-connection-builder', standalone: true, imports: [CommonModule, FormsModule, MatFormFieldModule, MatInputModule, MatSelectModule, MatButtonModule, MatIconModule, MatListModule, MatDialogModule, MatAutocompleteModule, MatMenuModule, MatTabsModule, MatTooltipModule, MatProgressBarModule, MatCheckboxModule, MatSnackBarModule, ScrollingModule, PraxisIconDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"pdx-conn-root\" role=\"region\" aria-label=\"Construtor de Conex\u00F5es\">\n <div class=\"pdx-conn-head\">\n <span class=\"pdx-conn-title\">Conex\u00F5es</span>\n <span class=\"pdx-conn-count\" aria-label=\"Conex\u00F5es filtradas e total\">{{ filteredConnections().length }} / {{ connections().length }}</span>\n <mat-form-field appearance=\"outline\" class=\"pdx-conn-search\">\n <mat-label>Buscar</mat-label>\n <input matInput [(ngModel)]=\"filterText\" placeholder=\"Origem, Destino, Input, Map...\" />\n <button mat-icon-button matSuffix *ngIf=\"filterText\" (click)=\"filterText='';\" aria-label=\"Limpar busca\"><mat-icon [praxisIcon]=\"'close'\"></mat-icon></button>\n </mat-form-field>\n <span class=\"pdx-spacer\"></span>\n <button mat-button (click)=\"toggleShowOnlyIssues()\" [color]=\"showOnlyIssues ? 'primary': undefined\" aria-label=\"Somente avisos/erros\"><mat-icon [praxisIcon]=\"'report_problem'\"></mat-icon> Issues</button>\n <mat-form-field appearance=\"outline\" style=\"width: 160px;\">\n <mat-label>Ordenar por</mat-label>\n <mat-select [(ngModel)]=\"sortBy\" (ngModelChange)=\"setSortBy($event)\">\n <mat-option value=\"from\">Origem</mat-option>\n <mat-option value=\"to\">Destino</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"width: 170px;\">\n <mat-label>Agrupar por</mat-label>\n <mat-select [(ngModel)]=\"groupBy\" (ngModelChange)=\"onGroupByChange()\">\n <mat-option value=\"none\">Nenhum</mat-option>\n <mat-option value=\"from\">Origem</mat-option>\n <mat-option value=\"to\">Destino</mat-option>\n <mat-option value=\"event\">Evento</mat-option>\n </mat-select>\n </mat-form-field>\n <button mat-icon-button [color]=\"showFriendly ? 'primary' : undefined\" (click)=\"toggleFriendly()\" aria-label=\"Alternar nome amig\u00E1vel/t\u00E9cnico\"><mat-icon [praxisIcon]=\"'translate'\"></mat-icon></button>\n <button mat-stroked-button (click)=\"createNew()\" aria-label=\"Nova conex\u00E3o\"><mat-icon [praxisIcon]=\"'add'\"></mat-icon> Nova Conex\u00E3o</button>\n <button mat-flat-button color=\"accent\" class=\"pdx-diagram-cta\" (click)=\"openDiagramFullscreen()\" aria-label=\"Abrir diagrama em tela cheia\" matTooltip=\"Visualizar conex\u00F5es em grafo\"><mat-icon [praxisIcon]=\"'schema'\"></mat-icon><span>Diagrama</span></button>\n </div>\n\n <div class=\"pdx-conn-grid\">\n <!-- Left: read-only list -->\n <div class=\"pdx-conn-list\" role=\"list\" aria-label=\"Lista de conex\u00F5es\" cdkScrollable>\n <mat-list *ngIf=\"filteredConnections().length; else noConns\">\n <ng-container *ngIf=\"groupBy!=='none'; else flatList\">\n <div class=\"group-block\" *ngFor=\"let g of groupedConnections(); let gi = index\">\n <div class=\"group-header\">\n <span class=\"group-title\">{{ g.label }}</span>\n <span class=\"group-count\">{{ g.list.length }}</span>\n </div>\n <mat-divider></mat-divider>\n <div class=\"group-list\">\n <ng-container *ngFor=\"let c of g.list; let i = index\">\n <mat-list-item role=\"listitem\" (click)=\"startEdit(i, c)\" [class.selected]=\"selectedIndex()===i\">\n <div class=\"card-head\" matListItemTitle [matTooltip]=\"showFriendly ? (c.from.widget + '.' + c.from.output + ' \u2192 ' + (c.to.widget + '.' + c.to.input)) : ''\">\n <mat-icon class=\"comp-icon from\" [matTooltip]=\"widgetFriendlyNameForKey(c.from.widget)\">{{ componentIconForKey(c.from.widget) }}</mat-icon>\n <span class=\"pdx-badge from\" aria-hidden=\"true\"></span>\n <span class=\"from\">{{ showFriendly ? fromFriendly(c) : fromLabel(c) }}</span>\n <span class=\"arrow\">\u2192</span>\n <mat-icon class=\"comp-icon to\" [matTooltip]=\"widgetFriendlyNameForKey(c.to.widget)\">{{ componentIconForKey(c.to.widget) }}</mat-icon>\n <span class=\"pdx-badge to\" aria-hidden=\"true\"></span>\n <span class=\"to\">{{ showFriendly ? toFriendly(c) : toLabel(c) }}</span>\n <span class=\"spacer\"></span>\n <span class=\"status-pill\" [class.ok]=\"connectionStatus(c)==='ok'\" [class.warn]=\"connectionStatus(c)==='warn'\" [class.err]=\"connectionStatus(c)==='err'\">\n <mat-icon *ngIf=\"connectionStatus(c)==='ok'\">check_circle</mat-icon>\n <mat-icon *ngIf=\"connectionStatus(c)==='warn'\">warning</mat-icon>\n <mat-icon *ngIf=\"connectionStatus(c)==='err'\">error</mat-icon>\n </span>\n <button mat-icon-button class=\"expand-btn\" [attr.aria-expanded]=\"isExpanded(i)\" (click)=\"toggleExpanded(i, $event)\" [matTooltip]=\"isExpanded(i) ? 'Recolher detalhes' : 'Expandir detalhes'\">\n <mat-icon>{{ isExpanded(i) ? 'expand_less' : 'expand_more' }}</mat-icon>\n </button>\n </div>\n <div class=\"meta\" *ngIf=\"showFriendly\" matListItemLine>\n <span class=\"hint\">{{ outputDescription(c) }}</span>\n <span class=\"sep\" *ngIf=\"outputDescription(c) && inputDescription(c)\">\u2022</span>\n <span class=\"hint\">{{ inputDescription(c) }}</span>\n </div>\n <div class=\"map-chip\" *ngIf=\"c.map\" [matTooltip]=\"c.map || ''\" matListItemLine (click)=\"startEditByConn(c)\" title=\"Clique para editar Map\">\n <span class=\"pdx-badge map\" aria-hidden=\"true\"></span>\n <mat-icon class=\"map-icon\" inline>bolt</mat-icon>\n <span class=\"mono\">{{ c.map }}</span>\n </div>\n <div class=\"card-actions\" matListItemLine (click)=\"$event.stopPropagation()\">\n <span class=\"action-group\">\n <button mat-icon-button (click)=\"startEdit(i, c)\" matTooltip=\"Editar\"><mat-icon>settings</mat-icon></button>\n <button mat-icon-button (click)=\"duplicateConnection(i)\" matTooltip=\"Duplicar\"><mat-icon>content_copy</mat-icon></button>\n </span>\n <span class=\"action-group\">\n <button mat-stroked-button color=\"primary\" (click)=\"openDiagramFor(c)\" matTooltip=\"Ver rela\u00E7\u00E3o no diagrama\"><mat-icon>schema</mat-icon><span>Diagrama</span></button>\n </span>\n <span class=\"spacer\"></span>\n <span class=\"action-group\">\n <button mat-icon-button color=\"warn\" (click)=\"removeConnection(i)\" matTooltip=\"Remover\"><mat-icon>delete</mat-icon></button>\n </span>\n </div>\n <div class=\"card-details\" matListItemLine [class.expanded]=\"isExpanded(i)\" [style.maxHeight]=\"isExpanded(i) ? '240px' : '0px'\" [style.opacity]=\"isExpanded(i) ? 1 : 0\" [style.pointerEvents]=\"isExpanded(i) ? 'auto' : 'none'\">\n <div class=\"stepper\">\n <div class=\"step from-step\">\n <div class=\"dot from\"></div>\n <div class=\"content\">\n <div class=\"label\">De</div>\n <div class=\"value\">{{ showFriendly ? fromFriendly(c) : fromLabel(c) }}</div>\n </div>\n </div>\n <div class=\"step to-step\">\n <div class=\"dot to\"></div>\n <div class=\"content\">\n <div class=\"label\">Para</div>\n <div class=\"value\">{{ showFriendly ? toFriendly(c) : toLabel(c) }}</div>\n </div>\n </div>\n <div class=\"step map-step\" *ngIf=\"c.map\">\n <div class=\"dot map\"></div>\n <div class=\"content\">\n <div class=\"label\">Map</div>\n <div class=\"value mono\">{{ c.map }}</div>\n </div>\n </div>\n </div>\n </div>\n </mat-list-item>\n </ng-container>\n </div>\n </div>\n </ng-container>\n <ng-template #flatList>\n <ng-container *ngFor=\"let c of filteredConnections(); let i = index\">\n <mat-list-item role=\"listitem\" (click)=\"startEdit(i, c)\" [class.selected]=\"selectedIndex()===i\">\n <div class=\"card-head\" matListItemTitle [matTooltip]=\"showFriendly ? (c.from.widget + '.' + c.from.output + ' \u2192 ' + (c.to.widget + '.' + c.to.input)) : ''\">\n <mat-icon class=\"comp-icon from\" [matTooltip]=\"widgetFriendlyNameForKey(c.from.widget)\">{{ componentIconForKey(c.from.widget) }}</mat-icon>\n <span class=\"pdx-badge from\" aria-hidden=\"true\"></span>\n <span class=\"from\">{{ showFriendly ? fromFriendly(c) : fromLabel(c) }}</span>\n <span class=\"arrow\">\u2192</span>\n <mat-icon class=\"comp-icon to\" [matTooltip]=\"widgetFriendlyNameForKey(c.to.widget)\">{{ componentIconForKey(c.to.widget) }}</mat-icon>\n <span class=\"pdx-badge to\" aria-hidden=\"true\"></span>\n <span class=\"to\">{{ showFriendly ? toFriendly(c) : toLabel(c) }}</span>\n <span class=\"spacer\"></span>\n <span class=\"status-pill\" [class.ok]=\"connectionStatus(c)==='ok'\" [class.warn]=\"connectionStatus(c)==='warn'\" [class.err]=\"connectionStatus(c)==='err'\">\n <mat-icon *ngIf=\"connectionStatus(c)==='ok'\">check_circle</mat-icon>\n <mat-icon *ngIf=\"connectionStatus(c)==='warn'\">warning</mat-icon>\n <mat-icon *ngIf=\"connectionStatus(c)==='err'\">error</mat-icon>\n </span>\n <button mat-icon-button class=\"expand-btn\" [attr.aria-expanded]=\"isExpanded(i)\" (click)=\"toggleExpanded(i, $event)\" [matTooltip]=\"isExpanded(i) ? 'Recolher detalhes' : 'Expandir detalhes'\">\n <mat-icon>{{ isExpanded(i) ? 'expand_less' : 'expand_more' }}</mat-icon>\n </button>\n </div>\n <div class=\"meta\" *ngIf=\"showFriendly\" matListItemLine>\n <span class=\"hint\">{{ outputDescription(c) }}</span>\n <span class=\"sep\" *ngIf=\"outputDescription(c) && inputDescription(c)\">\u2022</span>\n <span class=\"hint\">{{ inputDescription(c) }}</span>\n </div>\n <div class=\"map-chip\" *ngIf=\"c.map\" [matTooltip]=\"c.map || ''\" matListItemLine (click)=\"startEditByConn(c)\" title=\"Clique para editar Map\">\n <span class=\"pdx-badge map\" aria-hidden=\"true\"></span>\n <mat-icon class=\"map-icon\" inline>bolt</mat-icon>\n <span class=\"mono\">{{ c.map }}</span>\n </div>\n <div class=\"card-actions\" matListItemLine (click)=\"$event.stopPropagation()\">\n <span class=\"action-group\">\n <button mat-icon-button (click)=\"startEdit(i, c)\" matTooltip=\"Editar\"><mat-icon>settings</mat-icon></button>\n <button mat-icon-button (click)=\"duplicateConnection(i)\" matTooltip=\"Duplicar\"><mat-icon>content_copy</mat-icon></button>\n </span>\n <span class=\"action-group\">\n <button mat-stroked-button color=\"primary\" (click)=\"openDiagramFor(c)\" matTooltip=\"Ver rela\u00E7\u00E3o no diagrama\"><mat-icon>schema</mat-icon><span>Diagrama</span></button>\n </span>\n <span class=\"spacer\"></span>\n <span class=\"action-group\">\n <button mat-icon-button color=\"warn\" (click)=\"removeConnection(i)\" matTooltip=\"Remover\"><mat-icon>delete</mat-icon></button>\n </span>\n </div>\n <div class=\"card-details\" matListItemLine [class.expanded]=\"isExpanded(i)\" [style.maxHeight]=\"isExpanded(i) ? '240px' : '0px'\" [style.opacity]=\"isExpanded(i) ? 1 : 0\" [style.pointerEvents]=\"isExpanded(i) ? 'auto' : 'none'\">\n <div class=\"stepper\">\n <div class=\"step from-step\">\n <div class=\"dot from\"></div>\n <div class=\"content\">\n <div class=\"label\">De</div>\n <div class=\"value\">{{ showFriendly ? fromFriendly(c) : fromLabel(c) }}</div>\n </div>\n </div>\n <div class=\"step to-step\">\n <div class=\"dot to\"></div>\n <div class=\"content\">\n <div class=\"label\">Para</div>\n <div class=\"value\">{{ showFriendly ? toFriendly(c) : toLabel(c) }}</div>\n </div>\n </div>\n <div class=\"step map-step\" *ngIf=\"c.map\">\n <div class=\"dot map\"></div>\n <div class=\"content\">\n <div class=\"label\">Map</div>\n <div class=\"value mono\">{{ c.map }}</div>\n </div>\n </div>\n </div>\n </div>\n </mat-list-item>\n </ng-container>\n </ng-template>\n </mat-list>\n <ng-template #noConns>\n <div class=\"pdx-empty-list\" role=\"status\" aria-live=\"polite\">\n <mat-icon>link_off</mat-icon>\n <div>Nenhuma conex\u00E3o definida. Use \u201CNova Conex\u00E3o\u201D.</div>\n </div>\n </ng-template>\n </div>\n\n <!-- Right: editor form -->\n <div class=\"pdx-conn-editor\" role=\"form\" aria-label=\"Editor de conex\u00E3o\">\n <ng-container *ngIf=\"selectedIndex() >= 0; else emptyEditor\">\n <div class=\"form-grid\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Origem (widget.key)</mat-label>\n <input matInput [(ngModel)]=\"connections()[selectedIndex()].from.widget\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Evento (output)</mat-label>\n <input matInput [(ngModel)]=\"connections()[selectedIndex()].from.output\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Destino (widget.key)</mat-label>\n <input matInput [(ngModel)]=\"connections()[selectedIndex()].to.widget\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Input</mat-label>\n <input matInput [(ngModel)]=\"connections()[selectedIndex()].to.input\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-span\">\n <mat-label>Map (opcional)</mat-label>\n <input matInput [(ngModel)]=\"connections()[selectedIndex()].map\" [placeholder]=\"mapPlaceholder\" />\n </mat-form-field>\n <div class=\"full-span\">\n <button mat-flat-button color=\"primary\" (click)=\"onSave()\"><mat-icon [praxisIcon]=\"'save'\"></mat-icon>Salvar</button>\n </div>\n </div>\n </ng-container>\n <ng-template #emptyEditor>\n <div class=\"pdx-empty-editor\">Selecione uma conex\u00E3o para editar.</div>\n </ng-template>\n </div>\n </div>\n</div>\n", styles: [".pdx-conn-root{display:grid;gap:12px}.pdx-conn-head{display:flex;align-items:center;gap:8px}.pdx-conn-title{font-weight:600}.pdx-conn-count{opacity:.8}.pdx-conn-search{width:260px}.pdx-spacer{flex:1}.pdx-diagram-cta span{margin-left:6px}.pdx-conn-grid{display:grid;grid-template-columns:1.4fr 1fr;gap:12px}.pdx-conn-list{height:540px;overflow:auto;padding:8px 0}.pdx-conn-list .mat-mdc-list-item.mdc-list-item{height:auto;padding:10px 8px 8px}.card-head{display:flex;align-items:center;gap:6px}.card-head .spacer{flex:1}.card-head .comp-icon{opacity:.85}.card-head .expand-btn{margin-left:4px}.status-pill{display:inline-flex;align-items:center;gap:4px;border-radius:999px;padding:2px 8px}.status-pill.ok{background:color-mix(in oklab,var(--md-sys-color-primary) 15%,transparent);color:color-mix(in oklab,var(--md-sys-color-primary) 60%,#0a0)}.status-pill.warn{background:color-mix(in oklab,var(--md-sys-color-tertiary) 15%,transparent);color:color-mix(in oklab,var(--md-sys-color-tertiary) 60%,#aa0)}.status-pill.err{background:color-mix(in oklab,var(--md-sys-color-error) 15%,transparent);color:color-mix(in oklab,var(--md-sys-color-error) 60%,#a00)}.map-chip{display:inline-flex;align-items:center;gap:6px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.map-chip .map-icon{font-size:16px}.pdx-conn-editor{min-height:540px;padding:8px;border-left:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .12))}.pdx-empty-list{padding:16px;display:grid;place-items:center;gap:6px;opacity:.8}.pdx-empty-editor{padding:16px;opacity:.75}.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;align-content:start}.full-span{grid-column:1/-1}.stepper{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px;padding:8px 0}.step{display:grid;grid-template-columns:12px 1fr;gap:8px;align-items:start}.dot{width:12px;height:12px;border-radius:50%;margin-top:5px}.dot.from{background:color-mix(in oklab,var(--md-sys-color-primary) 70%,transparent)}.dot.to{background:color-mix(in oklab,var(--md-sys-color-secondary) 70%,transparent)}.dot.map{background:color-mix(in oklab,var(--md-sys-color-tertiary) 70%,transparent)}.group-block{padding:6px 6px 10px}.group-header{display:flex;gap:8px;align-items:center;padding:8px 0}.group-title{font-weight:600}.group-count{opacity:.75}.group-list{display:grid;gap:6px}.pdx-badge{width:10px;height:10px;border-radius:50%;display:inline-block}.pdx-badge.from{background:color-mix(in oklab,var(--md-sys-color-primary) 50%,transparent)}.pdx-badge.to{background:color-mix(in oklab,var(--md-sys-color-secondary) 50%,transparent)}.pdx-badge.map{background:color-mix(in oklab,var(--md-sys-color-tertiary) 50%,transparent)}.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:12px}\n"] }]
602
+ }], ctorParameters: () => [{ type: i1.MatDialog }, { type: i2$1.ComponentMetadataRegistry }, { type: i3$3.MatSnackBar }], propDecorators: { page: [{
603
+ type: Input
604
+ }], widgets: [{
605
+ type: Input
606
+ }], pageChange: [{
607
+ type: Output
608
+ }] } });
609
+
610
+ /*
611
+ * Public API Surface of @praxisui/page-builder
612
+ */
613
+ // Temporary minimal export for build isolation
614
+
615
+ /**
616
+ * Generated bundle index. Do not edit.
617
+ */
618
+
619
+ export { ComponentPaletteDialogComponent, ConfirmDialogComponent, ConnectionBuilderComponent, FloatingToolbarComponent, PLACEHOLDER, TileToolbarComponent };
620
+ //# sourceMappingURL=praxisui-page-builder.mjs.map