@praxisui/core 9.0.66 → 9.0.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,11 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, InjectionToken, Injectable, inject, Inject, Optional, SkipSelf, makeEnvironmentProviders, APP_INITIALIZER, signal, computed, DestroyRef, ENVIRONMENT_INITIALIZER, ErrorHandler, Input, Directive, input, booleanAttribute, ChangeDetectionStrategy, EventEmitter, Output, SecurityContext, ViewContainerRef, Injector, isSignal, effect, SimpleChange, ChangeDetectorRef, ElementRef, afterEveryRender, contentChild, HostBinding, output, afterNextRender, HostListener, ViewChildren, ViewChild } from '@angular/core';
2
+ import { Component, InjectionToken, Injectable, inject, Inject, Optional, SkipSelf, makeEnvironmentProviders, APP_INITIALIZER, signal, computed, DestroyRef, ENVIRONMENT_INITIALIZER, ErrorHandler, Input, Directive, input, booleanAttribute, ChangeDetectionStrategy, EventEmitter, Output, SecurityContext, ViewContainerRef, Injector, isSignal, effect, SimpleChange, ChangeDetectorRef, ElementRef, afterEveryRender, contentChild, viewChild, HostBinding, output, afterNextRender, HostListener, ViewChildren, ViewChild } from '@angular/core';
3
3
  import * as i1 from '@angular/common/http';
4
4
  import { HttpHeaders, HttpClient, HttpParams, HttpResponse, HttpContextToken, HTTP_INTERCEPTORS, withInterceptors } from '@angular/common/http';
5
- import { of, defer, throwError, from, EMPTY, BehaviorSubject, firstValueFrom, Subject, finalize as finalize$1, shareReplay as shareReplay$1, map as map$1, switchMap as switchMap$1, catchError as catchError$1, forkJoin } from 'rxjs';
5
+ import { of, defer, throwError, from, EMPTY, BehaviorSubject, firstValueFrom, Subject, finalize as finalize$1, shareReplay as shareReplay$1, map as map$1, switchMap as switchMap$1, catchError as catchError$1, forkJoin, timeout } from 'rxjs';
6
6
  import { switchMap, map, take, catchError, concatMap, tap, shareReplay, takeUntil, toArray, finalize } from 'rxjs/operators';
7
7
  import * as i1$3 from '@angular/common';
8
- import { Location, DOCUMENT, CommonModule } from '@angular/common';
8
+ import { Location, DOCUMENT, CommonModule, NgComponentOutlet } from '@angular/common';
9
9
  import { Router, ActivatedRoute } from '@angular/router';
10
10
  import * as i1$2 from '@angular/forms';
11
11
  import { Validators, FormGroup, FormControl, FormArray, FormsModule, ReactiveFormsModule } from '@angular/forms';
@@ -14,7 +14,7 @@ import * as i1$1 from '@angular/material/icon';
14
14
  import { MatIconRegistry, MatIconModule } from '@angular/material/icon';
15
15
  import * as i2 from '@angular/material/button';
16
16
  import { MatButtonModule } from '@angular/material/button';
17
- import * as i4 from '@angular/material/form-field';
17
+ import * as i3 from '@angular/material/form-field';
18
18
  import { MatFormFieldModule } from '@angular/material/form-field';
19
19
  import * as i5 from '@angular/material/input';
20
20
  import { MatInputModule } from '@angular/material/input';
@@ -22,18 +22,22 @@ import * as i6 from '@angular/material/select';
22
22
  import { MatSelectModule } from '@angular/material/select';
23
23
  import * as i7 from '@angular/material/slide-toggle';
24
24
  import { MatSlideToggleModule } from '@angular/material/slide-toggle';
25
- import * as i3 from '@angular/material/tooltip';
25
+ import * as i3$1 from '@angular/material/tooltip';
26
26
  import { MatTooltipModule } from '@angular/material/tooltip';
27
27
  import { DomSanitizer } from '@angular/platform-browser';
28
- import * as i4$1 from '@angular/material/menu';
29
- import { MatMenuModule } from '@angular/material/menu';
30
- import * as i4$2 from '@angular/cdk/overlay';
28
+ import * as i4 from '@angular/material/menu';
29
+ import { MatMenuTrigger, MatMenuModule } from '@angular/material/menu';
30
+ import * as i5$2 from '@angular/cdk/a11y';
31
+ import { A11yModule } from '@angular/cdk/a11y';
32
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
33
+ import * as i5$1 from '@angular/material/radio';
34
+ import { MatRadioModule } from '@angular/material/radio';
35
+ import * as i4$1 from '@angular/cdk/overlay';
31
36
  import { OverlayModule } from '@angular/cdk/overlay';
32
- import * as i3$1 from '@angular/material/progress-spinner';
37
+ import * as i3$2 from '@angular/material/progress-spinner';
33
38
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
34
- import * as i3$2 from '@angular/material/button-toggle';
39
+ import * as i3$3 from '@angular/material/button-toggle';
35
40
  import { MatButtonToggleModule } from '@angular/material/button-toggle';
36
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
37
41
  import * as i1$4 from '@angular/material/dialog';
38
42
  import { MAT_DIALOG_DATA, MatDialogModule, MatDialog } from '@angular/material/dialog';
39
43
  import * as i8 from '@angular/material/chips';
@@ -8818,9 +8822,11 @@ const SURFACE_NAVIGATION_I18N_CONFIG = {
8818
8822
  [SURFACE_NAVIGATION_I18N_NAMESPACE]: {
8819
8823
  'pt-BR': {
8820
8824
  'session.navigationRejected': 'Não foi possível abrir esta etapa agora. Revise a etapa em andamento e tente novamente.',
8825
+ 'surface.openFailed': 'Não foi possível abrir esta superfície agora. Tente novamente ou confirme se ela continua disponível.',
8821
8826
  },
8822
8827
  'en-US': {
8823
8828
  'session.navigationRejected': 'This step could not be opened right now. Review the current step and try again.',
8829
+ 'surface.openFailed': 'This surface could not be opened right now. Try again or confirm that it is still available.',
8824
8830
  },
8825
8831
  },
8826
8832
  },
@@ -8832,6 +8838,13 @@ function translateSurfaceNavigationRejected(i18n) {
8832
8838
  : 'Não foi possível abrir esta etapa agora. Revise a etapa em andamento e tente novamente.';
8833
8839
  return i18n.t('session.navigationRejected', undefined, fallback, SURFACE_NAVIGATION_I18N_NAMESPACE);
8834
8840
  }
8841
+ function translateSurfaceOpenFailed(i18n) {
8842
+ const locale = String(i18n.getLocale?.() || 'pt-BR').toLowerCase();
8843
+ const fallback = locale.startsWith('en')
8844
+ ? 'This surface could not be opened right now. Try again or confirm that it is still available.'
8845
+ : 'Não foi possível abrir esta superfície agora. Tente novamente ou confirme se ela continua disponível.';
8846
+ return i18n.t('surface.openFailed', undefined, fallback, SURFACE_NAVIGATION_I18N_NAMESPACE);
8847
+ }
8835
8848
 
8836
8849
  /**
8837
8850
  * Controlled failure emitted when an active runtime surface session refuses a
@@ -8987,7 +9000,16 @@ class GlobalActionService {
8987
9000
  retryable: false,
8988
9001
  };
8989
9002
  }
8990
- return { success: false, error: err?.message || String(err) };
9003
+ if (id === 'surface.open') {
9004
+ return {
9005
+ success: false,
9006
+ error: translateSurfaceOpenFailed(this.i18n),
9007
+ errorCode: 'SURFACE_OPEN_FAILED',
9008
+ retryable: false,
9009
+ };
9010
+ }
9011
+ const message = err && typeof err === 'object' && 'message' in err ? err.message : undefined;
9012
+ return { success: false, error: typeof message === 'string' && message ? message : String(err) };
8991
9013
  }
8992
9014
  }
8993
9015
  async executeRef(ref, context) {
@@ -9107,7 +9129,12 @@ class GlobalActionService {
9107
9129
  }, () => [this.providerRequirement('GLOBAL_DIALOG_SERVICE', this.dialog, 'dialog.open')]);
9108
9130
  this.register('surface.open', async (payload, context) => {
9109
9131
  if (!this.surface)
9110
- return { success: false, error: 'Surface service not available' };
9132
+ return {
9133
+ success: false,
9134
+ error: translateSurfaceOpenFailed(this.i18n),
9135
+ errorCode: 'SURFACE_SERVICE_UNAVAILABLE',
9136
+ retryable: false,
9137
+ };
9111
9138
  const surfacePayload = payload;
9112
9139
  if (!surfacePayload?.widget?.id) {
9113
9140
  return { success: false, error: 'surface.open requires widget.id' };
@@ -16051,6 +16078,178 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
16051
16078
  args: [{ providedIn: 'any' }]
16052
16079
  }] });
16053
16080
 
16081
+ const GOVERNED_COLOR_PALETTE_OPTIONS = new InjectionToken('GOVERNED_COLOR_PALETTE_OPTIONS');
16082
+ class GovernedColorPaletteService {
16083
+ http = inject(HttpClient);
16084
+ options = inject(GOVERNED_COLOR_PALETTE_OPTIONS, {
16085
+ optional: true,
16086
+ });
16087
+ baseUrl = (this.options?.baseUrl ?? '/api/praxis/config/color-palettes').replace(/\/$/, '');
16088
+ cache = new Map();
16089
+ list(familyKey) {
16090
+ const params = familyKey
16091
+ ? new HttpParams().set('familyKey', familyKey)
16092
+ : undefined;
16093
+ return this.http
16094
+ .get(this.baseUrl, {
16095
+ headers: this.headers(),
16096
+ params,
16097
+ })
16098
+ .pipe(map$1((palettes) => palettes.map((palette) => this.assertCompleteProjection(palette))));
16099
+ }
16100
+ get(ref) {
16101
+ const normalizedRef = typeof ref === 'string' ? { paletteKey: ref } : ref;
16102
+ const requestHeaders = this.headers();
16103
+ const cacheKey = this.cacheKey(normalizedRef, requestHeaders);
16104
+ const cached = this.cache.get(cacheKey);
16105
+ const params = normalizedRef.version
16106
+ ? new HttpParams().set('version', normalizedRef.version)
16107
+ : undefined;
16108
+ return this.http
16109
+ .get(`${this.baseUrl}/${encodeURIComponent(normalizedRef.paletteKey)}`, {
16110
+ observe: 'response',
16111
+ params,
16112
+ headers: cached?.etag
16113
+ ? requestHeaders.set('If-None-Match', this.formatEtag(cached.etag))
16114
+ : requestHeaders,
16115
+ })
16116
+ .pipe(map$1((response) => this.acceptResponse(response, normalizedRef, cacheKey)), catchError$1((error) => error.status === 304 && cached
16117
+ ? defer(() => of(this.acceptPalette(cached, normalizedRef, cacheKey)))
16118
+ : throwError(() => error)));
16119
+ }
16120
+ preview(request) {
16121
+ return this.http.post(`${this.baseUrl}/previews`, request, { headers: this.headers() });
16122
+ }
16123
+ capabilities() {
16124
+ return this.http.get(`${this.baseUrl}/capabilities`, { headers: this.headers() });
16125
+ }
16126
+ invalidate(ref) {
16127
+ if (ref === undefined) {
16128
+ this.cache.clear();
16129
+ return;
16130
+ }
16131
+ const normalizedRef = typeof ref === 'string' ? { paletteKey: ref } : ref;
16132
+ const key = this.cacheKey(normalizedRef, this.headers());
16133
+ this.cache.delete(key);
16134
+ }
16135
+ materializeColors(palette, purposes) {
16136
+ return materializeGovernedPaletteColors(palette, purposes);
16137
+ }
16138
+ acceptResponse(response, ref, cacheKey) {
16139
+ const palette = response.body;
16140
+ if (!palette) {
16141
+ throw new Error(`Empty governed palette response: ${ref.paletteKey}`);
16142
+ }
16143
+ return this.acceptPalette(palette, ref, cacheKey);
16144
+ }
16145
+ acceptPalette(palette, ref, cacheKey) {
16146
+ this.assertCompleteProjection(palette);
16147
+ if (palette.paletteKey !== ref.paletteKey) {
16148
+ throw new Error(`Governed palette identity mismatch for ${ref.paletteKey}`);
16149
+ }
16150
+ if (ref.version !== undefined && palette.version !== ref.version) {
16151
+ throw new Error(`Governed palette version mismatch for ${ref.paletteKey}: expected ${ref.version}, received ${palette.version}`);
16152
+ }
16153
+ if (ref.etag !== undefined &&
16154
+ this.normalizeEtag(palette.etag) !== this.normalizeEtag(ref.etag)) {
16155
+ throw new Error(`Governed palette ETag mismatch for ${ref.paletteKey}`);
16156
+ }
16157
+ this.cache.set(cacheKey, palette);
16158
+ return palette;
16159
+ }
16160
+ assertCompleteProjection(palette) {
16161
+ const variant = palette.variant;
16162
+ const completeVariant = !!variant &&
16163
+ typeof variant.key === 'string' &&
16164
+ !!variant.key.trim() &&
16165
+ typeof variant.displayName === 'string' &&
16166
+ !!variant.displayName.trim() &&
16167
+ this.isStringRecord(variant.dimensions);
16168
+ const completeEntries = Array.isArray(palette.entries) &&
16169
+ palette.entries.every((entry) => typeof entry.displayName === 'string' &&
16170
+ !!entry.displayName.trim() &&
16171
+ Array.isArray(entry.aliases) &&
16172
+ entry.aliases.every((alias) => typeof alias === 'string' && !!alias.trim()));
16173
+ if (typeof palette.familyKey !== 'string' ||
16174
+ !palette.familyKey.trim() ||
16175
+ !completeVariant ||
16176
+ !completeEntries) {
16177
+ throw new Error(`Incomplete governed palette projection: ${palette.paletteKey ?? 'unknown'}`);
16178
+ }
16179
+ return palette;
16180
+ }
16181
+ isStringRecord(value) {
16182
+ return (typeof value === 'object' &&
16183
+ value !== null &&
16184
+ !Array.isArray(value) &&
16185
+ Object.values(value).every((item) => typeof item === 'string' && !!item.trim()));
16186
+ }
16187
+ cacheKey(ref, headers) {
16188
+ const tenant = headers.get('X-Tenant-ID') ?? '';
16189
+ const environment = headers.get('X-Env') ?? '';
16190
+ return `${tenant}\u0000${environment}\u0000${ref.paletteKey}\u0000${ref.version ?? 'latest'}`;
16191
+ }
16192
+ headers() {
16193
+ const values = this.options?.headersFactory?.() ?? {};
16194
+ let headers = new HttpHeaders();
16195
+ for (const [key, value] of Object.entries(values)) {
16196
+ if (typeof value === 'string' && value.trim()) {
16197
+ headers = headers.set(key, value);
16198
+ }
16199
+ }
16200
+ return headers;
16201
+ }
16202
+ formatEtag(etag) {
16203
+ const normalized = this.normalizeEtag(etag);
16204
+ return `"${normalized}"`;
16205
+ }
16206
+ normalizeEtag(etag) {
16207
+ return etag.trim().replace(/^W\//, '').replace(/^"|"$/g, '');
16208
+ }
16209
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: GovernedColorPaletteService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
16210
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: GovernedColorPaletteService, providedIn: 'root' });
16211
+ }
16212
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: GovernedColorPaletteService, decorators: [{
16213
+ type: Injectable,
16214
+ args: [{ providedIn: 'root' }]
16215
+ }] });
16216
+ function materializeGovernedPaletteColors(palette, purposes) {
16217
+ return materializeGovernedPaletteEntries(palette, purposes).map((item) => item.color);
16218
+ }
16219
+ /** Preserves entry identity even when multiple tokens materialize to the same color. */
16220
+ function materializeGovernedPaletteEntries(palette, purposes) {
16221
+ if (!palette.validation.valid ||
16222
+ palette.entries.some((entry) => !!entry.fallback && !!entry.fallbackTokenId)) {
16223
+ return [];
16224
+ }
16225
+ const requiredPurposes = new Set(purposes ?? []);
16226
+ const byId = new Map(palette.entries.map((entry) => [entry.tokenId, entry]));
16227
+ return palette.entries
16228
+ .filter((entry) => requiredPurposes.size === 0 ||
16229
+ entry.purposes.some((purpose) => requiredPurposes.has(purpose)))
16230
+ .flatMap((entry) => {
16231
+ const color = materializeEntry(entry, byId, new Set());
16232
+ return color ? [{ entry, color }] : [];
16233
+ });
16234
+ }
16235
+ function materializeEntry(entry, byId, visited) {
16236
+ if (visited.has(entry.tokenId)) {
16237
+ return null;
16238
+ }
16239
+ visited.add(entry.tokenId);
16240
+ const fallbackEntry = entry.fallbackTokenId
16241
+ ? byId.get(entry.fallbackTokenId)
16242
+ : undefined;
16243
+ const fallback = fallbackEntry
16244
+ ? materializeEntry(fallbackEntry, byId, visited)
16245
+ : entry.fallback;
16246
+ if (!fallback) {
16247
+ return entry.cssReference;
16248
+ }
16249
+ const tokenName = /^var\((--[A-Za-z0-9_-]+)\)$/.exec(entry.cssReference)?.[1];
16250
+ return tokenName ? `var(${tokenName}, ${fallback})` : entry.cssReference;
16251
+ }
16252
+
16054
16253
  const PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS = new InjectionToken('PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS');
16055
16254
  const PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY = new InjectionToken('PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY');
16056
16255
  function providePraxisEnterpriseRuntimeContext(options = {}) {
@@ -20851,6 +21050,17 @@ const RESOURCE_DISCOVERY_I18N_CONFIG = {
20851
21050
  namespaces: {
20852
21051
  [RESOURCE_DISCOVERY_I18N_NAMESPACE]: {
20853
21052
  'pt-BR': {
21053
+ 'quickConnect.resource': 'Recurso de dados',
21054
+ 'quickConnect.loading': 'Carregando recursos…',
21055
+ 'quickConnect.unavailable': 'Não foi possível carregar o catálogo. Tente novamente ou informe a rota avançada.',
21056
+ 'quickConnect.empty': 'O catálogo não publicou recursos disponíveis.',
21057
+ 'quickConnect.advanced': 'Conexão avançada por rota',
21058
+ 'quickConnect.path': 'Rota do recurso (API)',
21059
+ 'quickConnect.invalid': 'Informe uma rota válida da API.',
21060
+ 'quickConnect.retry': 'Tentar novamente',
21061
+ 'quickConnect.hint': 'Escolha um recurso publicado pela API.',
21062
+ 'quickConnect.fields': 'Carregar campos do filtro',
21063
+ 'quickConnect.fieldsError': 'Não foi possível carregar os campos. Verifique o recurso e tente novamente.',
20854
21064
  'workflow.unavailable.default': 'A\u00e7\u00e3o indispon\u00edvel no contexto atual.',
20855
21065
  'workflow.unavailable.withReason': 'A\u00e7\u00e3o indispon\u00edvel: {{reason}}',
20856
21066
  'rowActions.menu.loading': 'Carregando a\u00e7\u00f5es contextuais',
@@ -20863,6 +21073,17 @@ const RESOURCE_DISCOVERY_I18N_CONFIG = {
20863
21073
  'availability.reason.unknown': 'O contexto atual n\u00e3o permite esta a\u00e7\u00e3o.',
20864
21074
  },
20865
21075
  'en-US': {
21076
+ 'quickConnect.resource': 'Data resource',
21077
+ 'quickConnect.loading': 'Loading resources…',
21078
+ 'quickConnect.unavailable': 'The catalog could not be loaded. Retry or enter the advanced resource path.',
21079
+ 'quickConnect.empty': 'The catalog did not publish any available resources.',
21080
+ 'quickConnect.advanced': 'Advanced connection by path',
21081
+ 'quickConnect.path': 'Resource path (API)',
21082
+ 'quickConnect.invalid': 'Enter a valid API resource path.',
21083
+ 'quickConnect.retry': 'Retry',
21084
+ 'quickConnect.hint': 'Choose a resource published by the API.',
21085
+ 'quickConnect.fields': 'Load filter fields',
21086
+ 'quickConnect.fieldsError': 'Fields could not be loaded. Check the resource and retry.',
20866
21087
  'workflow.unavailable.default': 'Action is unavailable in the current context.',
20867
21088
  'workflow.unavailable.withReason': 'Action unavailable: {{reason}}',
20868
21089
  'rowActions.menu.loading': 'Loading contextual actions',
@@ -27541,7 +27762,7 @@ class SurfaceOpenActionEditorComponent {
27541
27762
  </mat-form-field>
27542
27763
  </div>
27543
27764
  </div>
27544
- `, isInline: true, styles: [".surface-editor{display:grid;gap:14px;min-width:0}.surface-section{display:grid;gap:10px;min-width:0;padding:14px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low)}.surface-section-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:0}.surface-section-title{font-size:12px;font-weight:700;letter-spacing:0;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant);margin-bottom:0}.surface-section-header .surface-section-title{margin-bottom:0}.surface-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:12px 16px;min-width:0}.surface-preset-row{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.surface-span-2{grid-column:span 2}.surface-span-all{width:100%;min-width:0}.surface-component-meta{display:grid;gap:4px;padding:10px 12px;border-radius:8px;background:var(--md-sys-color-surface-container)}.surface-component-title{font-weight:600;color:var(--md-sys-color-on-surface)}.surface-component-description,.surface-empty{color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.surface-bindings{display:grid;gap:10px;min-width:0}.surface-binding-row{display:grid;grid-template-columns:minmax(min(220px,100%),1.15fr) minmax(min(240px,100%),1.25fr) minmax(128px,.55fr) auto;gap:10px;align-items:start;min-width:0;padding:10px;border-radius:8px;background:var(--md-sys-color-surface-container)}.surface-binding-row mat-form-field:nth-child(4){grid-column:1 / -2}.surface-binding-remove{color:var(--md-sys-color-error)}.surface-guidance{display:grid;gap:4px;padding:10px 12px;border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 18%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.surface-guidance__item{overflow-wrap:anywhere}.surface-guidance__item--primary{color:var(--md-sys-color-on-surface)}mat-form-field{width:100%;min-width:0}@media(max-width:960px){.surface-section{padding:12px}.surface-span-2{grid-column:1 / -1}.surface-binding-row{grid-template-columns:minmax(0,1fr)}.surface-binding-row mat-form-field:nth-child(4){grid-column:auto}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: "component", type: i6.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: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i7.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: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }] });
27765
+ `, isInline: true, styles: [".surface-editor{display:grid;gap:14px;min-width:0}.surface-section{display:grid;gap:10px;min-width:0;padding:14px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low)}.surface-section-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:0}.surface-section-title{font-size:12px;font-weight:700;letter-spacing:0;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant);margin-bottom:0}.surface-section-header .surface-section-title{margin-bottom:0}.surface-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:12px 16px;min-width:0}.surface-preset-row{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.surface-span-2{grid-column:span 2}.surface-span-all{width:100%;min-width:0}.surface-component-meta{display:grid;gap:4px;padding:10px 12px;border-radius:8px;background:var(--md-sys-color-surface-container)}.surface-component-title{font-weight:600;color:var(--md-sys-color-on-surface)}.surface-component-description,.surface-empty{color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.surface-bindings{display:grid;gap:10px;min-width:0}.surface-binding-row{display:grid;grid-template-columns:minmax(min(220px,100%),1.15fr) minmax(min(240px,100%),1.25fr) minmax(128px,.55fr) auto;gap:10px;align-items:start;min-width:0;padding:10px;border-radius:8px;background:var(--md-sys-color-surface-container)}.surface-binding-row mat-form-field:nth-child(4){grid-column:1 / -2}.surface-binding-remove{color:var(--md-sys-color-error)}.surface-guidance{display:grid;gap:4px;padding:10px 12px;border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 18%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.surface-guidance__item{overflow-wrap:anywhere}.surface-guidance__item--primary{color:var(--md-sys-color-on-surface)}mat-form-field{width:100%;min-width:0}@media(max-width:960px){.surface-section{padding:12px}.surface-span-2{grid-column:1 / -1}.surface-binding-row{grid-template-columns:minmax(0,1fr)}.surface-binding-row mat-form-field:nth-child(4){grid-column:auto}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i3.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: "component", type: i6.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: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i7.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: MatTooltipModule }, { kind: "directive", type: i3$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }] });
27545
27766
  }
27546
27767
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SurfaceOpenActionEditorComponent, decorators: [{
27547
27768
  type: Component,
@@ -29231,7 +29452,7 @@ const ENUMS = {
29231
29452
  ],
29232
29453
  shellKind: ['dashboard-card', 'none'],
29233
29454
  actionVariant: ['icon', 'text', 'outlined'],
29234
- actionPlacement: ['header', 'window'],
29455
+ actionPlacement: ['header', 'window', 'menu'],
29235
29456
  };
29236
29457
  const CAPS = [
29237
29458
  {
@@ -33351,6 +33572,70 @@ const BUILTIN_SHELL_PRESETS = {
33351
33572
  },
33352
33573
  };
33353
33574
  class WidgetShellComponent {
33575
+ stickyAncestorHeight = signal(0, ...(ngDevMode ? [{ debugName: "stickyAncestorHeight" }] : /* istanbul ignore next */ []));
33576
+ stickyAncestorObserver;
33577
+ stickyAncestorHeaders = [];
33578
+ get stickyAncestorTop() {
33579
+ const height = this.stickyAncestorHeight();
33580
+ return this.stickyHeaderActive && height > 0
33581
+ ? `calc(var(--pdx-shell-sticky-header-offset, 0px) + ${height}px)` : null;
33582
+ }
33583
+ observeStickyAncestors() {
33584
+ const headers = [];
33585
+ if (this.stickyHeaderActive
33586
+ && this.element.nativeElement.parentElement?.closest('.pdx-shell--sticky-header')) {
33587
+ let ancestor = this.element.nativeElement.parentElement;
33588
+ while (ancestor) {
33589
+ // A distinct scrollport owns its own sticky stack. A header outside
33590
+ // that port must not consume space in the child's scrolling surface.
33591
+ if (['auto', 'scroll', 'hidden', 'overlay'].includes(getComputedStyle(ancestor).overflowY))
33592
+ break;
33593
+ if (ancestor.classList.contains('pdx-shell--sticky-header')) {
33594
+ const header = ancestor.querySelector(':scope > .pdx-shell-header');
33595
+ if (header)
33596
+ headers.push(header);
33597
+ }
33598
+ ancestor = ancestor.parentElement;
33599
+ }
33600
+ }
33601
+ if (headers.length !== this.stickyAncestorHeaders.length
33602
+ || headers.some((header, index) => header !== this.stickyAncestorHeaders[index])) {
33603
+ this.stickyAncestorObserver?.disconnect();
33604
+ this.stickyAncestorObserver = undefined;
33605
+ this.stickyAncestorHeaders = headers;
33606
+ if (headers.length && typeof ResizeObserver !== 'undefined') {
33607
+ this.stickyAncestorObserver = new ResizeObserver(() => this.measureStickyAncestors());
33608
+ headers.forEach(header => this.stickyAncestorObserver.observe(header));
33609
+ }
33610
+ }
33611
+ this.measureStickyAncestors();
33612
+ }
33613
+ measureStickyAncestors() {
33614
+ if (this.destroyRef.destroyed)
33615
+ return;
33616
+ this.stickyAncestorHeight.set(this.stickyAncestorHeaders.reduce((height, header) => height + header.getBoundingClientRect().height, 0));
33617
+ }
33618
+ get stickyHeaderActive() {
33619
+ return this.shell?.stickyHeader === true && this.shellEnabled && this.showHeader
33620
+ && !this.dragSurfaceInteractive && !this.collapsed && !this.expanded
33621
+ && !this.fullscreen && !this.scrollRecovery();
33622
+ }
33623
+ revealStickyHeaderFocus(event) {
33624
+ if (!this.stickyHeaderActive || !(event.target instanceof HTMLElement))
33625
+ return;
33626
+ const header = this.element.nativeElement.querySelector(':scope > .pdx-shell > .pdx-shell-header');
33627
+ if (!header || header.contains(event.target))
33628
+ return;
33629
+ const target = event.target.getBoundingClientRect();
33630
+ const boundary = header.getBoundingClientRect().bottom + 8;
33631
+ if (!target.height || target.top >= boundary)
33632
+ return;
33633
+ let owner = this.element.nativeElement.parentElement;
33634
+ while (owner && !['auto', 'scroll', 'hidden', 'overlay'].includes(getComputedStyle(owner).overflowY)) {
33635
+ owner = owner.parentElement;
33636
+ }
33637
+ (owner ?? header.ownerDocument.scrollingElement)?.scrollBy({ top: target.top - boundary, behavior: 'instant' });
33638
+ }
33354
33639
  i18n = inject(PraxisI18nService);
33355
33640
  changeDetector = inject(ChangeDetectorRef);
33356
33641
  destroyRef = inject(DestroyRef);
@@ -33362,8 +33647,15 @@ class WidgetShellComponent {
33362
33647
  scrollObservedBody;
33363
33648
  scrollFrame;
33364
33649
  constructor() {
33365
- afterEveryRender({ read: () => this.observeScrollGeometry() });
33366
- this.destroyRef.onDestroy(() => this.disconnectScrollGeometry());
33650
+ afterEveryRender({ read: () => {
33651
+ this.observeScrollGeometry();
33652
+ this.observeStickyAncestors();
33653
+ } });
33654
+ this.destroyRef.onDestroy(() => {
33655
+ this.disconnectScrollGeometry();
33656
+ this.stickyAncestorObserver?.disconnect();
33657
+ this.stickyAncestorHeaders = [];
33658
+ });
33367
33659
  }
33368
33660
  disconnectScrollGeometry() {
33369
33661
  this.scrollResizeObserver?.disconnect();
@@ -33476,6 +33768,7 @@ class WidgetShellComponent {
33476
33768
  this.shell?.subtitle ||
33477
33769
  this.shell?.icon ||
33478
33770
  this.headerActions.length ||
33771
+ this.overflowHeaderActions.length ||
33479
33772
  this.windowActions.length);
33480
33773
  }
33481
33774
  get headerActions() {
@@ -33487,7 +33780,7 @@ class WidgetShellComponent {
33487
33780
  }
33488
33781
  get overflowHeaderActions() {
33489
33782
  const max = this.maxHeaderActions;
33490
- return this.headerActions.slice(max);
33783
+ return [...this.headerActions.slice(max), ...this.mergedActions.filter(a => this.isVisible(a) && a.placement === 'menu')];
33491
33784
  }
33492
33785
  get maxHeaderActions() {
33493
33786
  return 3;
@@ -33508,6 +33801,13 @@ class WidgetShellComponent {
33508
33801
  }
33509
33802
  return action.pressed === true || action.pressed === 'true';
33510
33803
  }
33804
+ overflowTrigger = viewChild(MatMenuTrigger, ...(ngDevMode ? [{ debugName: "overflowTrigger" }] : /* istanbul ignore next */ []));
33805
+ onOverflowAction(action, event) {
33806
+ if (action.disabled)
33807
+ return;
33808
+ this.overflowTrigger()?.closeMenu();
33809
+ this.onAction(action, event);
33810
+ }
33511
33811
  onAction(action, ev) {
33512
33812
  ev.stopPropagation();
33513
33813
  if (action.disabled)
@@ -33722,7 +34022,7 @@ class WidgetShellComponent {
33722
34022
  return this.i18n.t(key, undefined, fallback, WIDGET_SHELL_I18N_NAMESPACE);
33723
34023
  }
33724
34024
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: WidgetShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
33725
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: WidgetShellComponent, isStandalone: true, selector: "praxis-widget-shell", inputs: { shell: "shell", context: "context", dragSurfaceEnabled: "dragSurfaceEnabled", dragSurfaceLabel: "dragSurfaceLabel" }, outputs: { action: "action", dragSurfacePointerDown: "dragSurfacePointerDown", dragSurfaceKeydown: "dragSurfaceKeydown" }, host: { listeners: { "keydown.escape": "onOverlayEscape($event)" }, properties: { "class.pdx-widget-shell-collapsed": "this.hostCollapsed" } }, providers: [providePraxisI18nConfig(WIDGET_SHELL_I18N_CONFIG)], queries: [{ propertyName: "loader", first: true, predicate: DynamicWidgetLoaderDirective, descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: `
34025
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: WidgetShellComponent, isStandalone: true, selector: "praxis-widget-shell", inputs: { shell: "shell", context: "context", dragSurfaceEnabled: "dragSurfaceEnabled", dragSurfaceLabel: "dragSurfaceLabel" }, outputs: { action: "action", dragSurfacePointerDown: "dragSurfacePointerDown", dragSurfaceKeydown: "dragSurfaceKeydown" }, host: { listeners: { "keydown.escape": "onOverlayEscape($event)", "focusin": "revealStickyHeaderFocus($event)" }, properties: { "class.pdx-widget-shell-collapsed": "this.hostCollapsed" } }, providers: [providePraxisI18nConfig(WIDGET_SHELL_I18N_CONFIG)], queries: [{ propertyName: "loader", first: true, predicate: DynamicWidgetLoaderDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "overflowTrigger", first: true, predicate: MatMenuTrigger, descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: `
33726
34026
  @if (expanded || fullscreen) {
33727
34027
  <div
33728
34028
  class="pdx-shell-overlay-surface"
@@ -33742,6 +34042,7 @@ class WidgetShellComponent {
33742
34042
  [class.fullscreen]="fullscreen"
33743
34043
  [class.body-fill]="shell?.bodyLayout === 'fill'"
33744
34044
  [class.body-scroll]="shell?.bodyLayout === 'scroll'"
34045
+ [class.pdx-shell--sticky-header]="stickyHeaderActive"
33745
34046
  [class.pdx-shell--scroll-recovery]="scrollRecovery() && !collapsed && !expanded && !fullscreen"
33746
34047
  [style.--pdx-shell-card-bg]="appearance?.card?.background || null"
33747
34048
  [style.--pdx-shell-card-border]="appearance?.card?.borderColor || null"
@@ -33771,6 +34072,7 @@ class WidgetShellComponent {
33771
34072
  @if (showHeader) {
33772
34073
  <header
33773
34074
  class="pdx-shell-header"
34075
+ [style.top]="stickyAncestorTop"
33774
34076
  [class.pdx-shell-header--drag-enabled]="dragSurfaceInteractive"
33775
34077
  [attr.aria-label]="dragSurfaceInteractive ? dragSurfaceLabel : null"
33776
34078
  [attr.tabindex]="dragSurfaceInteractive ? 0 : null"
@@ -33908,7 +34210,7 @@ class WidgetShellComponent {
33908
34210
  [attr.aria-expanded]="
33909
34211
  action.ariaExpanded == null ? null : action.ariaExpanded
33910
34212
  "
33911
- (click)="onAction(action, $event)"
34213
+ (click)="onOverflowAction(action, $event)"
33912
34214
  >
33913
34215
  @if (displayActionIcon(action); as actionIcon) {
33914
34216
  <mat-icon [praxisIcon]="actionIcon"></mat-icon>
@@ -33938,7 +34240,7 @@ class WidgetShellComponent {
33938
34240
  @if (expanded || fullscreen) {
33939
34241
  <div class="pdx-shell-backdrop" (click)="closeOverlay()"></div>
33940
34242
  }
33941
- `, isInline: true, styles: [":host{display:block;height:100%}:host(.pdx-widget-shell-collapsed){height:auto}.pdx-shell{box-sizing:border-box;position:relative;height:100%;display:flex;flex-direction:column}.pdx-shell.no-shell{background:transparent;border:none;border-radius:0;box-shadow:none}.pdx-shell.dashboard{background:var( --pdx-shell-card-bg, var( --pdx-dashboard-card-bg, var(--md-sys-color-surface-container-low) ) );border:1px solid var( --pdx-shell-card-border, var( --pdx-dashboard-card-border, var(--md-sys-color-outline-variant) ) );border-radius:var(--pdx-shell-card-radius, 12px);box-shadow:var( --pdx-shell-card-shadow, 0 4px 12px rgba(15, 23, 42, .06) );overflow:hidden}.pdx-shell-header{flex-shrink:0;display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding:8px 10px 7px;border-bottom:1px solid var(--pdx-shell-header-border, var(--md-sys-color-outline-variant));background:var( --pdx-shell-header-bg, var(--md-sys-color-surface-container) )}.pdx-shell-header--drag-enabled{cursor:grab;-webkit-user-select:none;user-select:none;touch-action:none}.pdx-shell-header--drag-enabled:active{cursor:grabbing}.pdx-shell-header--drag-enabled:focus-visible{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary) 72%,white 28%);outline-offset:-2px}.pdx-shell-authoring-drag{flex:0 0 auto;align-self:flex-start;margin:4px 6px 0;z-index:2;cursor:grab;touch-action:none}.pdx-shell-authoring-drag:active{cursor:grabbing}.pdx-shell-title{display:flex;align-items:center;gap:8px;min-width:0;flex:1 1 14rem;max-width:100%;color:var(--pdx-shell-title-color, inherit)}.pdx-shell-title mat-icon{flex:0 0 auto;color:var(--pdx-shell-icon-color, currentColor)}.pdx-shell-text{min-width:0;flex:1}.pdx-shell-title-text{font-weight:var(--pdx-shell-title-weight, 600);font-size:var(--pdx-shell-title-size, 13px);line-height:1.15;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-shell-subtitle{font-size:var(--pdx-shell-subtitle-size, 11px);color:var( --pdx-shell-subtitle-color, var(--md-sys-color-on-surface-variant, currentColor) );white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-shell-actions,.pdx-shell-window-actions{display:flex;flex-wrap:wrap;align-items:center;gap:4px;max-width:100%}.pdx-shell-actions{margin-left:auto;min-width:0}.pdx-shell-actions>button{max-width:100%}.pdx-shell-window-actions{margin-left:auto}.pdx-shell-text{display:grid;gap:2px}.pdx-shell-title-text,.pdx-shell-subtitle{display:-webkit-box;white-space:normal;overflow-wrap:anywhere;-webkit-box-orient:vertical;-webkit-line-clamp:2}.pdx-action-outlined{border:1px solid var(--md-sys-color-outline-variant);border-radius:999px;padding:0 10px}.pdx-action-text{padding:0 8px}.pdx-shell-action--pressed:not(.praxis-icon-button){color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}.pdx-action-label{font-size:12px;font-weight:500}.pdx-shell-body{flex:1;min-height:0;padding:var(--pdx-shell-body-padding, 8px 10px 10px 10px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit)}.pdx-shell.no-shell .pdx-shell-body{padding:0}.pdx-shell-body.hidden{display:none}.pdx-shell.collapsed{height:auto}.pdx-shell.collapsed .pdx-shell-header{border-bottom-color:transparent}.pdx-shell.body-fill .pdx-shell-body,.pdx-shell.body-scroll .pdx-shell-body,.pdx-shell.expanded .pdx-shell-body,.pdx-shell.fullscreen .pdx-shell-body{overflow:auto;display:flex;flex-direction:column;min-height:0}.pdx-shell.collapsed .pdx-shell-body{display:none}.pdx-shell.body-fill .pdx-shell-body{overflow:hidden}.pdx-shell.body-scroll .pdx-shell-body,.pdx-shell.body-scroll.pdx-shell--scroll-recovery{overflow:auto}.pdx-shell.body-scroll.pdx-shell--scroll-recovery>.pdx-shell-body{flex:0 0 auto;overflow:visible}.pdx-shell.body-fill .pdx-shell-body>*,.pdx-shell.body-scroll .pdx-shell-body>*,.pdx-shell.expanded .pdx-shell-body>*,.pdx-shell.fullscreen .pdx-shell-body>*{flex:1 1 auto;min-height:0;width:100%}.pdx-shell.expanded,.pdx-shell-overlay-surface.expanded{position:fixed;top:10vh;left:50%;width:min(920px,92vw);height:min(640px,82vh);transform:translate(-50%);z-index:var(--praxis-layer-widget-shell-expanded, 1290);box-shadow:var(--mat-elevation-level8)}.pdx-shell.fullscreen,.pdx-shell-overlay-surface.fullscreen{position:fixed;inset:0;width:auto;height:auto;transform:none;border-radius:0;z-index:var(--praxis-layer-widget-shell-fullscreen, 1291);box-shadow:var(--mat-elevation-level8)}.pdx-shell-overlay-surface{background:var(--md-sys-color-surface);border-radius:var(--pdx-dashboard-card-radius, 16px);pointer-events:none}.pdx-shell-backdrop{position:fixed;inset:0;z-index:var(--praxis-layer-widget-shell-backdrop, 1280);background:#0000008c;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
34243
+ `, isInline: true, styles: [":host{display:block;height:100%}:host(.pdx-widget-shell-collapsed){height:auto}.pdx-shell{box-sizing:border-box;position:relative;height:100%;display:flex;flex-direction:column}.pdx-shell.no-shell{background:transparent;border:none;border-radius:0;box-shadow:none}.pdx-shell.dashboard{background:var( --pdx-shell-card-bg, var( --pdx-dashboard-card-bg, var(--md-sys-color-surface-container-low) ) );border:1px solid var( --pdx-shell-card-border, var( --pdx-dashboard-card-border, var(--md-sys-color-outline-variant) ) );border-radius:var(--pdx-shell-card-radius, 12px);box-shadow:var( --pdx-shell-card-shadow, 0 4px 12px rgba(15, 23, 42, .06) );overflow:hidden}.pdx-shell-header{flex-shrink:0;display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding:8px 10px 7px;border-bottom:1px solid var(--pdx-shell-header-border, var(--md-sys-color-outline-variant));background:var( --pdx-shell-header-bg, var(--md-sys-color-surface-container) )}.pdx-shell-header--drag-enabled{cursor:grab;-webkit-user-select:none;user-select:none;touch-action:none}.pdx-shell-header--drag-enabled:active{cursor:grabbing}.pdx-shell-header--drag-enabled:focus-visible{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary) 72%,white 28%);outline-offset:-2px}.pdx-shell-authoring-drag{flex:0 0 auto;align-self:flex-start;margin:4px 6px 0;z-index:2;cursor:grab;touch-action:none}.pdx-shell-authoring-drag:active{cursor:grabbing}.pdx-shell-title{display:flex;align-items:center;gap:8px;min-width:0;flex:1 1 min(14rem,50%);max-width:100%;color:var(--pdx-shell-title-color, inherit)}.pdx-shell-title mat-icon{flex:0 0 auto;color:var(--pdx-shell-icon-color, currentColor)}.pdx-shell-text{min-width:0;flex:1}.pdx-shell-title-text{font-weight:var(--pdx-shell-title-weight, 600);font-size:var(--pdx-shell-title-size, 13px);line-height:1.15;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-shell-subtitle{font-size:var(--pdx-shell-subtitle-size, 11px);color:var( --pdx-shell-subtitle-color, var(--md-sys-color-on-surface-variant, currentColor) );white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-shell-actions,.pdx-shell-window-actions{display:flex;flex-wrap:wrap;align-items:center;gap:4px;max-width:100%}.pdx-shell-actions{margin-left:auto;min-width:0}.pdx-shell-actions>button{max-width:100%}.pdx-shell-window-actions{margin-left:auto}.pdx-shell-text{display:grid;gap:2px}.pdx-shell-title-text,.pdx-shell-subtitle{display:-webkit-box;white-space:normal;overflow-wrap:anywhere;-webkit-box-orient:vertical;-webkit-line-clamp:2}.pdx-action-outlined{border:1px solid var(--md-sys-color-outline-variant);border-radius:999px;padding:0 10px}.pdx-action-text{padding:0 8px}.pdx-shell-action--pressed:not(.praxis-icon-button){color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}.pdx-action-label{font-size:12px;font-weight:500}.pdx-shell.dashboard.pdx-shell--sticky-header{overflow:clip}.pdx-shell--sticky-header>.pdx-shell-header{position:sticky;top:var(--pdx-shell-sticky-header-offset, 0px);z-index:2;isolation:isolate;background:var(--md-sys-color-surface-container)}.pdx-shell--sticky-header>.pdx-shell-header:before{content:\"\";position:absolute;inset:0;z-index:-1;pointer-events:none;background:var(--pdx-shell-header-bg, transparent)}.pdx-shell--sticky-header>.pdx-shell-body{isolation:isolate}.pdx-shell-body{flex:1;min-height:0;padding:var(--pdx-shell-body-padding, 8px 10px 10px 10px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit)}.pdx-shell.no-shell>.pdx-shell-body{padding:0}.pdx-shell-body.hidden{display:none}.pdx-shell.collapsed{height:auto}.pdx-shell.collapsed>.pdx-shell-header{border-bottom-color:transparent}.pdx-shell.body-fill>.pdx-shell-body,.pdx-shell.body-scroll>.pdx-shell-body,.pdx-shell.expanded>.pdx-shell-body,.pdx-shell.fullscreen>.pdx-shell-body{overflow:auto;display:flex;flex-direction:column;min-height:0}.pdx-shell.collapsed>.pdx-shell-body{display:none}.pdx-shell.body-fill>.pdx-shell-body{overflow:hidden}.pdx-shell.body-scroll>.pdx-shell-body{overflow:auto}.pdx-shell.body-scroll.pdx-shell--scroll-recovery{overflow:auto}.pdx-shell.body-scroll.pdx-shell--scroll-recovery>.pdx-shell-body{flex:0 0 auto;overflow:visible}.pdx-shell.body-fill>.pdx-shell-body>*,.pdx-shell.body-scroll>.pdx-shell-body>*,.pdx-shell.expanded>.pdx-shell-body>*,.pdx-shell.fullscreen>.pdx-shell-body>*{flex:1 1 auto;min-height:0;width:100%}.pdx-shell.expanded,.pdx-shell-overlay-surface.expanded{position:fixed;top:10vh;left:50%;width:min(920px,92vw);height:min(640px,82vh);transform:translate(-50%);z-index:var(--praxis-layer-widget-shell-expanded, 1290);box-shadow:var(--mat-elevation-level8)}.pdx-shell.fullscreen,.pdx-shell-overlay-surface.fullscreen{position:fixed;inset:0;width:auto;height:auto;transform:none;border-radius:0;z-index:var(--praxis-layer-widget-shell-fullscreen, 1291);box-shadow:var(--mat-elevation-level8)}.pdx-shell-overlay-surface{background:var(--md-sys-color-surface);border-radius:var(--pdx-dashboard-card-radius, 16px);pointer-events:none}.pdx-shell-backdrop{position:fixed;inset:0;z-index:var(--praxis-layer-widget-shell-backdrop, 1280);background:#0000008c;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
33942
34244
  }
33943
34245
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: WidgetShellComponent, decorators: [{
33944
34246
  type: Component,
@@ -33950,7 +34252,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
33950
34252
  MatTooltipModule,
33951
34253
  PraxisIconButtonComponent,
33952
34254
  PraxisIconDirective,
33953
- ], providers: [providePraxisI18nConfig(WIDGET_SHELL_I18N_CONFIG)], host: { '(keydown.escape)': 'onOverlayEscape($event)' }, template: `
34255
+ ], providers: [providePraxisI18nConfig(WIDGET_SHELL_I18N_CONFIG)], host: {
34256
+ '(keydown.escape)': 'onOverlayEscape($event)',
34257
+ '(focusin)': 'revealStickyHeaderFocus($event)',
34258
+ }, template: `
33954
34259
  @if (expanded || fullscreen) {
33955
34260
  <div
33956
34261
  class="pdx-shell-overlay-surface"
@@ -33970,6 +34275,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
33970
34275
  [class.fullscreen]="fullscreen"
33971
34276
  [class.body-fill]="shell?.bodyLayout === 'fill'"
33972
34277
  [class.body-scroll]="shell?.bodyLayout === 'scroll'"
34278
+ [class.pdx-shell--sticky-header]="stickyHeaderActive"
33973
34279
  [class.pdx-shell--scroll-recovery]="scrollRecovery() && !collapsed && !expanded && !fullscreen"
33974
34280
  [style.--pdx-shell-card-bg]="appearance?.card?.background || null"
33975
34281
  [style.--pdx-shell-card-border]="appearance?.card?.borderColor || null"
@@ -33999,6 +34305,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
33999
34305
  @if (showHeader) {
34000
34306
  <header
34001
34307
  class="pdx-shell-header"
34308
+ [style.top]="stickyAncestorTop"
34002
34309
  [class.pdx-shell-header--drag-enabled]="dragSurfaceInteractive"
34003
34310
  [attr.aria-label]="dragSurfaceInteractive ? dragSurfaceLabel : null"
34004
34311
  [attr.tabindex]="dragSurfaceInteractive ? 0 : null"
@@ -34136,7 +34443,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
34136
34443
  [attr.aria-expanded]="
34137
34444
  action.ariaExpanded == null ? null : action.ariaExpanded
34138
34445
  "
34139
- (click)="onAction(action, $event)"
34446
+ (click)="onOverflowAction(action, $event)"
34140
34447
  >
34141
34448
  @if (displayActionIcon(action); as actionIcon) {
34142
34449
  <mat-icon [praxisIcon]="actionIcon"></mat-icon>
@@ -34166,7 +34473,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
34166
34473
  @if (expanded || fullscreen) {
34167
34474
  <div class="pdx-shell-backdrop" (click)="closeOverlay()"></div>
34168
34475
  }
34169
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;height:100%}:host(.pdx-widget-shell-collapsed){height:auto}.pdx-shell{box-sizing:border-box;position:relative;height:100%;display:flex;flex-direction:column}.pdx-shell.no-shell{background:transparent;border:none;border-radius:0;box-shadow:none}.pdx-shell.dashboard{background:var( --pdx-shell-card-bg, var( --pdx-dashboard-card-bg, var(--md-sys-color-surface-container-low) ) );border:1px solid var( --pdx-shell-card-border, var( --pdx-dashboard-card-border, var(--md-sys-color-outline-variant) ) );border-radius:var(--pdx-shell-card-radius, 12px);box-shadow:var( --pdx-shell-card-shadow, 0 4px 12px rgba(15, 23, 42, .06) );overflow:hidden}.pdx-shell-header{flex-shrink:0;display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding:8px 10px 7px;border-bottom:1px solid var(--pdx-shell-header-border, var(--md-sys-color-outline-variant));background:var( --pdx-shell-header-bg, var(--md-sys-color-surface-container) )}.pdx-shell-header--drag-enabled{cursor:grab;-webkit-user-select:none;user-select:none;touch-action:none}.pdx-shell-header--drag-enabled:active{cursor:grabbing}.pdx-shell-header--drag-enabled:focus-visible{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary) 72%,white 28%);outline-offset:-2px}.pdx-shell-authoring-drag{flex:0 0 auto;align-self:flex-start;margin:4px 6px 0;z-index:2;cursor:grab;touch-action:none}.pdx-shell-authoring-drag:active{cursor:grabbing}.pdx-shell-title{display:flex;align-items:center;gap:8px;min-width:0;flex:1 1 14rem;max-width:100%;color:var(--pdx-shell-title-color, inherit)}.pdx-shell-title mat-icon{flex:0 0 auto;color:var(--pdx-shell-icon-color, currentColor)}.pdx-shell-text{min-width:0;flex:1}.pdx-shell-title-text{font-weight:var(--pdx-shell-title-weight, 600);font-size:var(--pdx-shell-title-size, 13px);line-height:1.15;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-shell-subtitle{font-size:var(--pdx-shell-subtitle-size, 11px);color:var( --pdx-shell-subtitle-color, var(--md-sys-color-on-surface-variant, currentColor) );white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-shell-actions,.pdx-shell-window-actions{display:flex;flex-wrap:wrap;align-items:center;gap:4px;max-width:100%}.pdx-shell-actions{margin-left:auto;min-width:0}.pdx-shell-actions>button{max-width:100%}.pdx-shell-window-actions{margin-left:auto}.pdx-shell-text{display:grid;gap:2px}.pdx-shell-title-text,.pdx-shell-subtitle{display:-webkit-box;white-space:normal;overflow-wrap:anywhere;-webkit-box-orient:vertical;-webkit-line-clamp:2}.pdx-action-outlined{border:1px solid var(--md-sys-color-outline-variant);border-radius:999px;padding:0 10px}.pdx-action-text{padding:0 8px}.pdx-shell-action--pressed:not(.praxis-icon-button){color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}.pdx-action-label{font-size:12px;font-weight:500}.pdx-shell-body{flex:1;min-height:0;padding:var(--pdx-shell-body-padding, 8px 10px 10px 10px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit)}.pdx-shell.no-shell .pdx-shell-body{padding:0}.pdx-shell-body.hidden{display:none}.pdx-shell.collapsed{height:auto}.pdx-shell.collapsed .pdx-shell-header{border-bottom-color:transparent}.pdx-shell.body-fill .pdx-shell-body,.pdx-shell.body-scroll .pdx-shell-body,.pdx-shell.expanded .pdx-shell-body,.pdx-shell.fullscreen .pdx-shell-body{overflow:auto;display:flex;flex-direction:column;min-height:0}.pdx-shell.collapsed .pdx-shell-body{display:none}.pdx-shell.body-fill .pdx-shell-body{overflow:hidden}.pdx-shell.body-scroll .pdx-shell-body,.pdx-shell.body-scroll.pdx-shell--scroll-recovery{overflow:auto}.pdx-shell.body-scroll.pdx-shell--scroll-recovery>.pdx-shell-body{flex:0 0 auto;overflow:visible}.pdx-shell.body-fill .pdx-shell-body>*,.pdx-shell.body-scroll .pdx-shell-body>*,.pdx-shell.expanded .pdx-shell-body>*,.pdx-shell.fullscreen .pdx-shell-body>*{flex:1 1 auto;min-height:0;width:100%}.pdx-shell.expanded,.pdx-shell-overlay-surface.expanded{position:fixed;top:10vh;left:50%;width:min(920px,92vw);height:min(640px,82vh);transform:translate(-50%);z-index:var(--praxis-layer-widget-shell-expanded, 1290);box-shadow:var(--mat-elevation-level8)}.pdx-shell.fullscreen,.pdx-shell-overlay-surface.fullscreen{position:fixed;inset:0;width:auto;height:auto;transform:none;border-radius:0;z-index:var(--praxis-layer-widget-shell-fullscreen, 1291);box-shadow:var(--mat-elevation-level8)}.pdx-shell-overlay-surface{background:var(--md-sys-color-surface);border-radius:var(--pdx-dashboard-card-radius, 16px);pointer-events:none}.pdx-shell-backdrop{position:fixed;inset:0;z-index:var(--praxis-layer-widget-shell-backdrop, 1280);background:#0000008c;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"] }]
34476
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;height:100%}:host(.pdx-widget-shell-collapsed){height:auto}.pdx-shell{box-sizing:border-box;position:relative;height:100%;display:flex;flex-direction:column}.pdx-shell.no-shell{background:transparent;border:none;border-radius:0;box-shadow:none}.pdx-shell.dashboard{background:var( --pdx-shell-card-bg, var( --pdx-dashboard-card-bg, var(--md-sys-color-surface-container-low) ) );border:1px solid var( --pdx-shell-card-border, var( --pdx-dashboard-card-border, var(--md-sys-color-outline-variant) ) );border-radius:var(--pdx-shell-card-radius, 12px);box-shadow:var( --pdx-shell-card-shadow, 0 4px 12px rgba(15, 23, 42, .06) );overflow:hidden}.pdx-shell-header{flex-shrink:0;display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding:8px 10px 7px;border-bottom:1px solid var(--pdx-shell-header-border, var(--md-sys-color-outline-variant));background:var( --pdx-shell-header-bg, var(--md-sys-color-surface-container) )}.pdx-shell-header--drag-enabled{cursor:grab;-webkit-user-select:none;user-select:none;touch-action:none}.pdx-shell-header--drag-enabled:active{cursor:grabbing}.pdx-shell-header--drag-enabled:focus-visible{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary) 72%,white 28%);outline-offset:-2px}.pdx-shell-authoring-drag{flex:0 0 auto;align-self:flex-start;margin:4px 6px 0;z-index:2;cursor:grab;touch-action:none}.pdx-shell-authoring-drag:active{cursor:grabbing}.pdx-shell-title{display:flex;align-items:center;gap:8px;min-width:0;flex:1 1 min(14rem,50%);max-width:100%;color:var(--pdx-shell-title-color, inherit)}.pdx-shell-title mat-icon{flex:0 0 auto;color:var(--pdx-shell-icon-color, currentColor)}.pdx-shell-text{min-width:0;flex:1}.pdx-shell-title-text{font-weight:var(--pdx-shell-title-weight, 600);font-size:var(--pdx-shell-title-size, 13px);line-height:1.15;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-shell-subtitle{font-size:var(--pdx-shell-subtitle-size, 11px);color:var( --pdx-shell-subtitle-color, var(--md-sys-color-on-surface-variant, currentColor) );white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-shell-actions,.pdx-shell-window-actions{display:flex;flex-wrap:wrap;align-items:center;gap:4px;max-width:100%}.pdx-shell-actions{margin-left:auto;min-width:0}.pdx-shell-actions>button{max-width:100%}.pdx-shell-window-actions{margin-left:auto}.pdx-shell-text{display:grid;gap:2px}.pdx-shell-title-text,.pdx-shell-subtitle{display:-webkit-box;white-space:normal;overflow-wrap:anywhere;-webkit-box-orient:vertical;-webkit-line-clamp:2}.pdx-action-outlined{border:1px solid var(--md-sys-color-outline-variant);border-radius:999px;padding:0 10px}.pdx-action-text{padding:0 8px}.pdx-shell-action--pressed:not(.praxis-icon-button){color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}.pdx-action-label{font-size:12px;font-weight:500}.pdx-shell.dashboard.pdx-shell--sticky-header{overflow:clip}.pdx-shell--sticky-header>.pdx-shell-header{position:sticky;top:var(--pdx-shell-sticky-header-offset, 0px);z-index:2;isolation:isolate;background:var(--md-sys-color-surface-container)}.pdx-shell--sticky-header>.pdx-shell-header:before{content:\"\";position:absolute;inset:0;z-index:-1;pointer-events:none;background:var(--pdx-shell-header-bg, transparent)}.pdx-shell--sticky-header>.pdx-shell-body{isolation:isolate}.pdx-shell-body{flex:1;min-height:0;padding:var(--pdx-shell-body-padding, 8px 10px 10px 10px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit)}.pdx-shell.no-shell>.pdx-shell-body{padding:0}.pdx-shell-body.hidden{display:none}.pdx-shell.collapsed{height:auto}.pdx-shell.collapsed>.pdx-shell-header{border-bottom-color:transparent}.pdx-shell.body-fill>.pdx-shell-body,.pdx-shell.body-scroll>.pdx-shell-body,.pdx-shell.expanded>.pdx-shell-body,.pdx-shell.fullscreen>.pdx-shell-body{overflow:auto;display:flex;flex-direction:column;min-height:0}.pdx-shell.collapsed>.pdx-shell-body{display:none}.pdx-shell.body-fill>.pdx-shell-body{overflow:hidden}.pdx-shell.body-scroll>.pdx-shell-body{overflow:auto}.pdx-shell.body-scroll.pdx-shell--scroll-recovery{overflow:auto}.pdx-shell.body-scroll.pdx-shell--scroll-recovery>.pdx-shell-body{flex:0 0 auto;overflow:visible}.pdx-shell.body-fill>.pdx-shell-body>*,.pdx-shell.body-scroll>.pdx-shell-body>*,.pdx-shell.expanded>.pdx-shell-body>*,.pdx-shell.fullscreen>.pdx-shell-body>*{flex:1 1 auto;min-height:0;width:100%}.pdx-shell.expanded,.pdx-shell-overlay-surface.expanded{position:fixed;top:10vh;left:50%;width:min(920px,92vw);height:min(640px,82vh);transform:translate(-50%);z-index:var(--praxis-layer-widget-shell-expanded, 1290);box-shadow:var(--mat-elevation-level8)}.pdx-shell.fullscreen,.pdx-shell-overlay-surface.fullscreen{position:fixed;inset:0;width:auto;height:auto;transform:none;border-radius:0;z-index:var(--praxis-layer-widget-shell-fullscreen, 1291);box-shadow:var(--mat-elevation-level8)}.pdx-shell-overlay-surface{background:var(--md-sys-color-surface);border-radius:var(--pdx-dashboard-card-radius, 16px);pointer-events:none}.pdx-shell-backdrop{position:fixed;inset:0;z-index:var(--praxis-layer-widget-shell-backdrop, 1280);background:#0000008c;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"] }]
34170
34477
  }], ctorParameters: () => [], propDecorators: { hostCollapsed: [{
34171
34478
  type: HostBinding,
34172
34479
  args: ['class.pdx-widget-shell-collapsed']
@@ -34184,7 +34491,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
34184
34491
  type: Output
34185
34492
  }], dragSurfaceKeydown: [{
34186
34493
  type: Output
34187
- }], loader: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DynamicWidgetLoaderDirective), { isSignal: true }] }] } });
34494
+ }], loader: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DynamicWidgetLoaderDirective), { isSignal: true }] }], overflowTrigger: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatMenuTrigger), { isSignal: true }] }] } });
34188
34495
 
34189
34496
  class PraxisResourceIdentityComponent {
34190
34497
  identity = null;
@@ -38621,12 +38928,328 @@ function clone(value) {
38621
38928
  return JSON.parse(JSON.stringify(value));
38622
38929
  }
38623
38930
 
38931
+ const DYNAMIC_WIDGET_PAGE_I18N_NAMESPACE = 'dynamicWidgetPage';
38932
+ const DYNAMIC_WIDGET_PAGE_I18N_CONFIG = {
38933
+ namespaces: {
38934
+ [DYNAMIC_WIDGET_PAGE_I18N_NAMESPACE]: {
38935
+ 'pt-BR': {
38936
+ 'size.title': 'Tamanho…',
38937
+ 'size.presets': 'Larguras da grade',
38938
+ 'size.presetLabel': '{{fraction}} da grade: {{columns}} colunas',
38939
+ 'size.presetLabelSingle': '{{fraction}} da grade: 1 coluna',
38940
+ 'size.presetHelp': 'Fração da grade · número de colunas',
38941
+ 'size.undo': 'Desfazer último redimensionamento',
38942
+ 'size.undoHelp': 'Restaura o widget e os vizinhos alterados no último ajuste desta sessão.',
38943
+ 'size.undoBlocked': 'O layout ou seus limites mudaram depois. O ajuste anterior não pode ser restaurado com segurança.',
38944
+ 'size.undoDone': 'Último redimensionamento desfeito, incluindo os vizinhos afetados.',
38945
+ 'size.width': 'Largura',
38946
+ 'size.height': 'Altura',
38947
+ 'size.columns': 'Colunas da grade',
38948
+ 'size.rows': 'Linhas da grade',
38949
+ 'size.pixels': 'Pixels',
38950
+ 'size.anchor': 'Canto que permanece fixo',
38951
+ 'size.topLeft': 'Superior esquerdo',
38952
+ 'size.topRight': 'Superior direito',
38953
+ 'size.bottomLeft': 'Inferior esquerdo',
38954
+ 'size.bottomRight': 'Inferior direito',
38955
+ 'size.help': 'A prévia inclui os vizinhos afetados. Aplicar confirma; Cancelar descarta o ajuste.',
38956
+ 'size.apply': 'Aplicar',
38957
+ 'size.invalid': 'Informe números inteiros maiores que zero.',
38958
+ 'size.unavailable': 'Esse tamanho excede os limites ou o espaço disponível.',
38959
+ 'size.select': 'Widget {{widget}}. Tab acessa os controles; Esc volta à seleção.',
38960
+ 'size.scope.base': 'Layout base · compartilhado pelos dispositivos que o herdam',
38961
+ 'size.scope.desktop': 'Layout de desktop',
38962
+ 'size.scope.tablet': 'Layout de tablet',
38963
+ 'size.scope.mobile': 'Layout de celular',
38964
+ 'heightValidation.measureFirst': 'Use altura Automática para aplicar a nova geometria; depois reabra o editor para definir a altura ajustável.',
38965
+ 'heightValidation.minimum': 'Use pelo menos {{height}}px nesta largura. Ajuste a altura/máximo ou use Automática.',
38966
+ 'announcements.contentSize': '{{action}}. Largura {{columns}} colunas, altura {{height}} pixels, recuo superior {{top}} pixels.',
38967
+ 'resizeFeedback.valid': 'Ajuste disponível',
38968
+ 'resizeFeedback.minimum': 'Tamanho mínimo atingido',
38969
+ 'resizeFeedback.blocked': 'Limite excedido — prévia limitada ao espaço disponível',
38970
+ 'resizeFeedback.committedLimit': 'Layout ajustado até o limite permitido',
38971
+ 'resizeFeedback.unchanged': 'Tamanho mantido — nenhum ajuste aplicado',
38972
+ 'controls.pageSettings': 'Configurar página',
38973
+ 'controls.componentSettings': 'Configurar conteúdo',
38974
+ 'controls.componentSettingsTooltip': 'Abrir configurações do componente',
38975
+ 'controls.widgetSettings': 'Configurar widget',
38976
+ 'controls.widgetSettingsTooltip': 'Abrir configurações do widget',
38977
+ 'controls.widgetAssistant': 'Abrir assistente do widget',
38978
+ 'controls.widgetAssistantTooltip': 'Abrir o assistente Praxis com contexto deste widget',
38979
+ 'controls.widgetRemove': 'Excluir widget',
38980
+ 'controls.widgetRemoveTooltip': 'Excluir este widget e limpar conexões vinculadas',
38981
+ 'controls.widgetRemoveConfirmTitle': 'Excluir widget?',
38982
+ 'controls.widgetRemoveConfirmMessage': 'O widget "{{widget}}" será removido da página. Conexões e posições vinculadas também serão limpas.',
38983
+ 'controls.widgetRemoveConfirm': 'Excluir widget',
38984
+ 'controls.cancel': 'Cancelar',
38985
+ 'controls.cardSettings': 'Configurar card',
38986
+ 'controls.moreWidgetActions': 'Mais ações do widget',
38987
+ 'controls.widgetContextToolbar': 'Ações do widget {{widget}}',
38988
+ 'controls.widgetContextTooltip': 'Editando {{widget}}',
38989
+ 'controls.widgetLayoutToolbar': 'Ações de layout do widget',
38990
+ 'controls.dragWidget': 'Arrastar widget',
38991
+ 'controls.resizeWidget': 'Redimensionar widget',
38992
+ 'controls.resizeAlternative': 'Controles alternativos de tamanho',
38993
+ 'controls.resizeSelect': 'Selecione um widget',
38994
+ 'controls.resizeClose': 'Fechar controles de tamanho',
38995
+ 'controls.resizeContextHelp': 'Arraste um controle ou use as setas do teclado. Esc fecha os controles.',
38996
+ 'controls.resizeHelp': 'Selecione o widget. Arraste uma borda ou canto pelos botões, ou use as setas do teclado.',
38997
+ 'controls.resize.north': 'Redimensionar widget pela borda superior',
38998
+ 'controls.resize.south': 'Redimensionar widget pela borda inferior',
38999
+ 'controls.resize.east': 'Redimensionar widget pela borda direita',
39000
+ 'controls.resize.west': 'Redimensionar widget pela borda esquerda',
39001
+ 'controls.resize.north-east': 'Redimensionar widget pelo canto superior direito',
39002
+ 'controls.resize.north-west': 'Redimensionar widget pelo canto superior esquerdo',
39003
+ 'controls.resize.south-east': 'Redimensionar widget pelo canto inferior direito',
39004
+ 'controls.resize.south-west': 'Redimensionar widget pelo canto inferior esquerdo',
39005
+ 'announcements.moved': 'Widget movido: {{widget}}',
39006
+ 'announcements.swapped': 'Widget trocado com {{target}}: {{widget}}',
39007
+ 'announcements.resized': 'Widget redimensionado: {{widget}}',
39008
+ 'announcements.interactionCancelled': 'Alteração de layout cancelada.',
39009
+ 'announcements.position': '{{action}} para coluna {{col}}, linha {{row}}, largura {{colSpan}}, altura {{rowSpan}}.',
39010
+ 'announcements.dragBlocked': 'Movimento bloqueado: o widget colidiria com outro item.',
39011
+ 'announcements.resizeBlocked': 'Redimensionamento bloqueado: o widget colidiria com outro item.',
39012
+ },
39013
+ 'en-US': {
39014
+ 'size.title': 'Size…',
39015
+ 'size.presets': 'Grid widths',
39016
+ 'size.presetLabel': '{{fraction}} of the grid: {{columns}} columns',
39017
+ 'size.presetLabelSingle': '{{fraction}} of the grid: 1 column',
39018
+ 'size.presetHelp': 'Grid fraction · number of columns',
39019
+ 'size.undo': 'Undo last resize',
39020
+ 'size.undoHelp': 'Restores the widget and neighbors changed by the last resize in this session.',
39021
+ 'size.undoBlocked': 'The layout or its limits changed afterwards. The previous size cannot be safely restored.',
39022
+ 'size.undoDone': 'Last resize undone, including affected neighbors.',
39023
+ 'size.width': 'Width',
39024
+ 'size.height': 'Height',
39025
+ 'size.columns': 'Grid columns',
39026
+ 'size.rows': 'Grid rows',
39027
+ 'size.pixels': 'Pixels',
39028
+ 'size.anchor': 'Corner to keep fixed',
39029
+ 'size.topLeft': 'Top left',
39030
+ 'size.topRight': 'Top right',
39031
+ 'size.bottomLeft': 'Bottom left',
39032
+ 'size.bottomRight': 'Bottom right',
39033
+ 'size.help': 'The preview includes affected neighbors. Apply confirms; Cancel discards the change.',
39034
+ 'size.apply': 'Apply',
39035
+ 'size.invalid': 'Enter whole numbers greater than zero.',
39036
+ 'size.unavailable': 'This size exceeds the limits or available space.',
39037
+ 'size.select': 'Widget {{widget}}. Tab reaches controls; Escape returns to selection.',
39038
+ 'size.scope.base': 'Base layout · shared by devices that inherit it',
39039
+ 'size.scope.desktop': 'Desktop layout',
39040
+ 'size.scope.tablet': 'Tablet layout',
39041
+ 'size.scope.mobile': 'Mobile layout',
39042
+ 'heightValidation.measureFirst': 'Use Automatic height to apply the new geometry, then reopen the editor to set an adjustable height.',
39043
+ 'heightValidation.minimum': 'Use at least {{height}}px at this width. Adjust the height/maximum, or use Automatic.',
39044
+ 'announcements.contentSize': '{{action}}. Width {{columns}} columns, height {{height}} pixels, top inset {{top}} pixels.',
39045
+ 'resizeFeedback.valid': 'Resize available',
39046
+ 'resizeFeedback.minimum': 'Minimum size reached',
39047
+ 'resizeFeedback.blocked': 'Limit exceeded — preview constrained to available space',
39048
+ 'resizeFeedback.committedLimit': 'Layout resized to the allowed limit',
39049
+ 'resizeFeedback.unchanged': 'Size unchanged — no adjustment applied',
39050
+ 'controls.pageSettings': 'Configure page',
39051
+ 'controls.componentSettings': 'Configure content',
39052
+ 'controls.componentSettingsTooltip': 'Open component settings',
39053
+ 'controls.widgetSettings': 'Configure widget',
39054
+ 'controls.widgetSettingsTooltip': 'Open widget settings',
39055
+ 'controls.widgetAssistant': 'Open widget assistant',
39056
+ 'controls.widgetAssistantTooltip': 'Open the Praxis assistant with this widget context',
39057
+ 'controls.widgetRemove': 'Delete widget',
39058
+ 'controls.widgetRemoveTooltip': 'Delete this widget and clean linked connections',
39059
+ 'controls.widgetRemoveConfirmTitle': 'Delete widget?',
39060
+ 'controls.widgetRemoveConfirmMessage': 'The widget "{{widget}}" will be removed from the page. Linked connections and positions will also be cleaned.',
39061
+ 'controls.widgetRemoveConfirm': 'Delete widget',
39062
+ 'controls.cancel': 'Cancel',
39063
+ 'controls.cardSettings': 'Configure card',
39064
+ 'controls.moreWidgetActions': 'More widget actions',
39065
+ 'controls.widgetContextToolbar': 'Widget {{widget}} actions',
39066
+ 'controls.widgetContextTooltip': 'Editing {{widget}}',
39067
+ 'controls.widgetLayoutToolbar': 'Widget layout actions',
39068
+ 'controls.dragWidget': 'Drag widget',
39069
+ 'controls.resizeWidget': 'Resize widget',
39070
+ 'controls.resizeAlternative': 'Alternative resize controls',
39071
+ 'controls.resizeSelect': 'Select a widget',
39072
+ 'controls.resizeClose': 'Close resize controls',
39073
+ 'controls.resizeContextHelp': 'Drag a control or use the arrow keys. Esc closes the controls.',
39074
+ 'controls.resizeHelp': 'Select the widget. Drag an edge or corner using the buttons, or use the arrow keys.',
39075
+ 'controls.resize.north': 'Resize widget from the top edge',
39076
+ 'controls.resize.south': 'Resize widget from the bottom edge',
39077
+ 'controls.resize.east': 'Resize widget from the right edge',
39078
+ 'controls.resize.west': 'Resize widget from the left edge',
39079
+ 'controls.resize.north-east': 'Resize widget from the top-right corner',
39080
+ 'controls.resize.north-west': 'Resize widget from the top-left corner',
39081
+ 'controls.resize.south-east': 'Resize widget from the bottom-right corner',
39082
+ 'controls.resize.south-west': 'Resize widget from the bottom-left corner',
39083
+ 'announcements.moved': 'Widget moved: {{widget}}',
39084
+ 'announcements.swapped': 'Widget swapped with {{target}}: {{widget}}',
39085
+ 'announcements.resized': 'Widget resized: {{widget}}',
39086
+ 'announcements.interactionCancelled': 'Layout change cancelled.',
39087
+ 'announcements.position': '{{action}} to column {{col}}, row {{row}}, width {{colSpan}}, height {{rowSpan}}.',
39088
+ 'announcements.dragBlocked': 'Move blocked: the widget would overlap another item.',
39089
+ 'announcements.resizeBlocked': 'Resize blocked: the widget would overlap another item.',
39090
+ },
39091
+ },
39092
+ },
39093
+ };
39094
+
39095
+ class CanvasSizeEditorComponent {
39096
+ columns = input.required(...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
39097
+ hasUndo = input(false, ...(ngDevMode ? [{ debugName: "hasUndo" }] : /* istanbul ignore next */ []));
39098
+ canUndo = input(false, ...(ngDevMode ? [{ debugName: "canUndo" }] : /* istanbul ignore next */ []));
39099
+ undo = output();
39100
+ widthPresets = computed(() => [
39101
+ { numerator: 1, denominator: 3, fraction: '⅓' },
39102
+ { numerator: 1, denominator: 2, fraction: '½' },
39103
+ { numerator: 2, denominator: 3, fraction: '⅔' },
39104
+ { numerator: 1, denominator: 1, fraction: '100%' },
39105
+ ].map(preset => ({ ...preset, width: this.columns() * preset.numerator / preset.denominator }))
39106
+ .filter(preset => Number.isInteger(preset.width) && preset.width >= 1), ...(ngDevMode ? [{ debugName: "widthPresets" }] : /* istanbul ignore next */ []));
39107
+ width = input.required(...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
39108
+ height = input.required(...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
39109
+ contentRows = input(false, ...(ngDevMode ? [{ debugName: "contentRows" }] : /* istanbul ignore next */ []));
39110
+ widgetLabel = input.required(...(ngDevMode ? [{ debugName: "widgetLabel" }] : /* istanbul ignore next */ []));
39111
+ scopeLabel = input.required(...(ngDevMode ? [{ debugName: "scopeLabel" }] : /* istanbul ignore next */ []));
39112
+ error = input(null, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
39113
+ preview = output();
39114
+ apply = output();
39115
+ cancel = output();
39116
+ i18n = inject(PraxisI18nService);
39117
+ destroyRef = inject(DestroyRef);
39118
+ anchors = [
39119
+ { handle: 'south-east', label: 'size.topLeft' },
39120
+ { handle: 'south-west', label: 'size.topRight' },
39121
+ { handle: 'north-east', label: 'size.bottomLeft' },
39122
+ { handle: 'north-west', label: 'size.bottomRight' },
39123
+ ];
39124
+ form = new FormGroup({
39125
+ width: new FormControl(1, { nonNullable: true, validators: [Validators.required, Validators.min(1), Validators.pattern(/^\d+$/)] }),
39126
+ height: new FormControl(1, { nonNullable: true, validators: [Validators.required, Validators.min(1), Validators.pattern(/^\d+$/)] }),
39127
+ handle: new FormControl('south-east', { nonNullable: true }),
39128
+ });
39129
+ ngOnInit() {
39130
+ this.form.reset({ width: this.width(), height: this.height(), handle: 'south-east' }, { emitEvent: false });
39131
+ this.form.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.preview.emit(this.form.valid ? this.form.getRawValue() : null));
39132
+ }
39133
+ setPresetWidth(width) {
39134
+ this.form.markAsDirty();
39135
+ this.form.controls.width.setValue(width);
39136
+ }
39137
+ t(key, params) {
39138
+ return this.i18n.t(key, params, undefined, DYNAMIC_WIDGET_PAGE_I18N_NAMESPACE);
39139
+ }
39140
+ submit() {
39141
+ if (this.form.valid && !this.error())
39142
+ this.apply.emit(this.form.getRawValue());
39143
+ }
39144
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CanvasSizeEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
39145
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CanvasSizeEditorComponent, isStandalone: true, selector: "praxis-canvas-size-editor", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, hasUndo: { classPropertyName: "hasUndo", publicName: "hasUndo", isSignal: true, isRequired: false, transformFunction: null }, canUndo: { classPropertyName: "canUndo", publicName: "canUndo", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: true, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: true, transformFunction: null }, contentRows: { classPropertyName: "contentRows", publicName: "contentRows", isSignal: true, isRequired: false, transformFunction: null }, widgetLabel: { classPropertyName: "widgetLabel", publicName: "widgetLabel", isSignal: true, isRequired: true, transformFunction: null }, scopeLabel: { classPropertyName: "scopeLabel", publicName: "scopeLabel", isSignal: true, isRequired: true, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { undo: "undo", preview: "preview", apply: "apply", cancel: "cancel" }, ngImport: i0, template: `
39146
+ <form [formGroup]="form" (ngSubmit)="submit()">
39147
+ <header><strong>{{ t('size.title') }}</strong><span>{{ widgetLabel() }}</span></header>
39148
+ <p class="scope">{{ scopeLabel() }}</p>
39149
+ <div class="dimensions">
39150
+ <mat-form-field appearance="outline">
39151
+ <mat-label>{{ t('size.width') }}</mat-label>
39152
+ <input matInput type="number" min="1" step="1" formControlName="width" data-testid="canvas-size-width" />
39153
+ <mat-hint>{{ t('size.columns') }}</mat-hint>
39154
+ </mat-form-field>
39155
+ <mat-form-field appearance="outline">
39156
+ <mat-label>{{ t('size.height') }}</mat-label>
39157
+ <input matInput type="number" min="1" step="1" formControlName="height" data-testid="canvas-size-height" />
39158
+ <mat-hint>{{ t(contentRows() ? 'size.pixels' : 'size.rows') }}</mat-hint>
39159
+ </mat-form-field>
39160
+ </div>
39161
+ <div class="presets" role="group" [attr.aria-label]="t('size.presets')">
39162
+ @for (preset of widthPresets(); track preset.width) {
39163
+ <button mat-stroked-button type="button" (click)="setPresetWidth(preset.width)"
39164
+ [attr.data-size-preset]="preset.fraction" [attr.aria-label]="t(preset.width === 1 ? 'size.presetLabelSingle' : 'size.presetLabel', { fraction: preset.fraction, columns: preset.width })">
39165
+ {{ preset.fraction }} · {{ preset.width }}
39166
+ </button>
39167
+ }
39168
+ </div>
39169
+ <p class="hint">{{ t('size.presetHelp') }}</p>
39170
+ <details>
39171
+ <summary>{{ t('size.anchor') }}</summary>
39172
+ <mat-radio-group formControlName="handle" [attr.aria-label]="t('size.anchor')">
39173
+ @for (anchor of anchors; track anchor.handle) {
39174
+ <mat-radio-button [value]="anchor.handle">{{ t(anchor.label) }}</mat-radio-button>
39175
+ }
39176
+ </mat-radio-group>
39177
+ </details>
39178
+ <p class="hint">{{ t('size.help') }}</p>
39179
+ @if (error() || form.invalid) {
39180
+ <p class="error" role="status">{{ error() || t('size.invalid') }}</p>
39181
+ }
39182
+ @if (hasUndo()) {
39183
+ <div class="recovery">
39184
+ <button mat-button type="button" [disabled]="!canUndo()" (click)="undo.emit()" data-testid="canvas-size-undo">{{ t('size.undo') }}</button>
39185
+ <p class="hint" role="status">{{ t(canUndo() ? 'size.undoHelp' : 'size.undoBlocked') }}</p>
39186
+ </div>
39187
+ }
39188
+ <footer>
39189
+ <button mat-button type="button" (click)="cancel.emit()">{{ t('controls.cancel') }}</button>
39190
+ <button mat-flat-button type="submit" [disabled]="form.invalid || !!error() || form.pristine">{{ t('size.apply') }}</button>
39191
+ </footer>
39192
+ </form>
39193
+ `, isInline: true, styles: [":host{display:block;box-sizing:border-box;width:min(380px,calc(100vw - 32px));max-height:calc(100dvh - 32px);overflow:auto;border:1px solid var(--md-sys-color-outline-variant);border-radius:var(--mat-sys-corner-medium, 12px);background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}form{display:grid;gap:16px;padding:16px}header{display:grid;gap:4px;overflow-wrap:anywhere}header span,.scope,.hint{color:var(--md-sys-color-on-surface-variant);font-size:12px}p{margin:0}.dimensions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}mat-form-field{min-width:0}.presets{display:flex;flex-wrap:wrap;gap:8px}.recovery{display:grid;gap:4px;justify-items:start}mat-radio-group{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}summary{cursor:pointer;padding-block:8px}footer{display:flex;gap:8px;justify-content:flex-end}.error{color:var(--md-sys-color-error)}@media(max-width:380px){.dimensions,mat-radio-group{grid-template-columns:minmax(0,1fr)}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: MatRadioModule }, { kind: "directive", type: i5$1.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i5$1.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
39194
+ }
39195
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CanvasSizeEditorComponent, decorators: [{
39196
+ type: Component,
39197
+ args: [{ selector: 'praxis-canvas-size-editor', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ReactiveFormsModule, MatButtonModule, MatFormFieldModule, MatInputModule, MatRadioModule], template: `
39198
+ <form [formGroup]="form" (ngSubmit)="submit()">
39199
+ <header><strong>{{ t('size.title') }}</strong><span>{{ widgetLabel() }}</span></header>
39200
+ <p class="scope">{{ scopeLabel() }}</p>
39201
+ <div class="dimensions">
39202
+ <mat-form-field appearance="outline">
39203
+ <mat-label>{{ t('size.width') }}</mat-label>
39204
+ <input matInput type="number" min="1" step="1" formControlName="width" data-testid="canvas-size-width" />
39205
+ <mat-hint>{{ t('size.columns') }}</mat-hint>
39206
+ </mat-form-field>
39207
+ <mat-form-field appearance="outline">
39208
+ <mat-label>{{ t('size.height') }}</mat-label>
39209
+ <input matInput type="number" min="1" step="1" formControlName="height" data-testid="canvas-size-height" />
39210
+ <mat-hint>{{ t(contentRows() ? 'size.pixels' : 'size.rows') }}</mat-hint>
39211
+ </mat-form-field>
39212
+ </div>
39213
+ <div class="presets" role="group" [attr.aria-label]="t('size.presets')">
39214
+ @for (preset of widthPresets(); track preset.width) {
39215
+ <button mat-stroked-button type="button" (click)="setPresetWidth(preset.width)"
39216
+ [attr.data-size-preset]="preset.fraction" [attr.aria-label]="t(preset.width === 1 ? 'size.presetLabelSingle' : 'size.presetLabel', { fraction: preset.fraction, columns: preset.width })">
39217
+ {{ preset.fraction }} · {{ preset.width }}
39218
+ </button>
39219
+ }
39220
+ </div>
39221
+ <p class="hint">{{ t('size.presetHelp') }}</p>
39222
+ <details>
39223
+ <summary>{{ t('size.anchor') }}</summary>
39224
+ <mat-radio-group formControlName="handle" [attr.aria-label]="t('size.anchor')">
39225
+ @for (anchor of anchors; track anchor.handle) {
39226
+ <mat-radio-button [value]="anchor.handle">{{ t(anchor.label) }}</mat-radio-button>
39227
+ }
39228
+ </mat-radio-group>
39229
+ </details>
39230
+ <p class="hint">{{ t('size.help') }}</p>
39231
+ @if (error() || form.invalid) {
39232
+ <p class="error" role="status">{{ error() || t('size.invalid') }}</p>
39233
+ }
39234
+ @if (hasUndo()) {
39235
+ <div class="recovery">
39236
+ <button mat-button type="button" [disabled]="!canUndo()" (click)="undo.emit()" data-testid="canvas-size-undo">{{ t('size.undo') }}</button>
39237
+ <p class="hint" role="status">{{ t(canUndo() ? 'size.undoHelp' : 'size.undoBlocked') }}</p>
39238
+ </div>
39239
+ }
39240
+ <footer>
39241
+ <button mat-button type="button" (click)="cancel.emit()">{{ t('controls.cancel') }}</button>
39242
+ <button mat-flat-button type="submit" [disabled]="form.invalid || !!error() || form.pristine">{{ t('size.apply') }}</button>
39243
+ </footer>
39244
+ </form>
39245
+ `, styles: [":host{display:block;box-sizing:border-box;width:min(380px,calc(100vw - 32px));max-height:calc(100dvh - 32px);overflow:auto;border:1px solid var(--md-sys-color-outline-variant);border-radius:var(--mat-sys-corner-medium, 12px);background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}form{display:grid;gap:16px;padding:16px}header{display:grid;gap:4px;overflow-wrap:anywhere}header span,.scope,.hint{color:var(--md-sys-color-on-surface-variant);font-size:12px}p{margin:0}.dimensions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}mat-form-field{min-width:0}.presets{display:flex;flex-wrap:wrap;gap:8px}.recovery{display:grid;gap:4px;justify-items:start}mat-radio-group{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}summary{cursor:pointer;padding-block:8px}footer{display:flex;gap:8px;justify-content:flex-end}.error{color:var(--md-sys-color-error)}@media(max-width:380px){.dimensions,mat-radio-group{grid-template-columns:minmax(0,1fr)}}\n"] }]
39246
+ }], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], hasUndo: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasUndo", required: false }] }], canUndo: [{ type: i0.Input, args: [{ isSignal: true, alias: "canUndo", required: false }] }], undo: [{ type: i0.Output, args: ["undo"] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: true }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: true }] }], contentRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentRows", required: false }] }], widgetLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "widgetLabel", required: true }] }], scopeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "scopeLabel", required: true }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], preview: [{ type: i0.Output, args: ["preview"] }], apply: [{ type: i0.Output, args: ["apply"] }], cancel: [{ type: i0.Output, args: ["cancel"] }] } });
39247
+
38624
39248
  class DynamicWidgetContextToolbarComponent {
38625
- showResize = input(false, ...(ngDevMode ? [{ debugName: "showResize" }] : /* istanbul ignore next */ []));
38626
- resizeLabel = input('', ...(ngDevMode ? [{ debugName: "resizeLabel" }] : /* istanbul ignore next */ []));
38627
- resizeControls = input(null, ...(ngDevMode ? [{ debugName: "resizeControls" }] : /* istanbul ignore next */ []));
38628
- resizeExpanded = input(false, ...(ngDevMode ? [{ debugName: "resizeExpanded" }] : /* istanbul ignore next */ []));
38629
- resize = output();
39249
+ showSize = input(false, ...(ngDevMode ? [{ debugName: "showSize" }] : /* istanbul ignore next */ []));
39250
+ sizeDisabled = input(false, ...(ngDevMode ? [{ debugName: "sizeDisabled" }] : /* istanbul ignore next */ []));
39251
+ sizeLabel = input('', ...(ngDevMode ? [{ debugName: "sizeLabel" }] : /* istanbul ignore next */ []));
39252
+ size = output();
38630
39253
  toolbarLabel = '';
38631
39254
  contextLabel = '';
38632
39255
  contextTooltip = '';
@@ -38648,7 +39271,7 @@ class DynamicWidgetContextToolbarComponent {
38648
39271
  shellSettings = new EventEmitter();
38649
39272
  remove = new EventEmitter();
38650
39273
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicWidgetContextToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
38651
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicWidgetContextToolbarComponent, isStandalone: true, selector: "praxis-dynamic-widget-context-toolbar", inputs: { showResize: { classPropertyName: "showResize", publicName: "showResize", isSignal: true, isRequired: false, transformFunction: null }, resizeLabel: { classPropertyName: "resizeLabel", publicName: "resizeLabel", isSignal: true, isRequired: false, transformFunction: null }, resizeControls: { classPropertyName: "resizeControls", publicName: "resizeControls", isSignal: true, isRequired: false, transformFunction: null }, resizeExpanded: { classPropertyName: "resizeExpanded", publicName: "resizeExpanded", isSignal: true, isRequired: false, transformFunction: null }, toolbarLabel: { classPropertyName: "toolbarLabel", publicName: "toolbarLabel", isSignal: false, isRequired: false, transformFunction: null }, contextLabel: { classPropertyName: "contextLabel", publicName: "contextLabel", isSignal: false, isRequired: false, transformFunction: null }, contextTooltip: { classPropertyName: "contextTooltip", publicName: "contextTooltip", isSignal: false, isRequired: false, transformFunction: null }, showAssistant: { classPropertyName: "showAssistant", publicName: "showAssistant", isSignal: false, isRequired: false, transformFunction: null }, assistantLabel: { classPropertyName: "assistantLabel", publicName: "assistantLabel", isSignal: false, isRequired: false, transformFunction: null }, assistantTooltip: { classPropertyName: "assistantTooltip", publicName: "assistantTooltip", isSignal: false, isRequired: false, transformFunction: null }, showComponentSettings: { classPropertyName: "showComponentSettings", publicName: "showComponentSettings", isSignal: false, isRequired: false, transformFunction: null }, componentSettingsBusy: { classPropertyName: "componentSettingsBusy", publicName: "componentSettingsBusy", isSignal: true, isRequired: false, transformFunction: null }, componentSettingsLabel: { classPropertyName: "componentSettingsLabel", publicName: "componentSettingsLabel", isSignal: false, isRequired: false, transformFunction: null }, componentSettingsTooltip: { classPropertyName: "componentSettingsTooltip", publicName: "componentSettingsTooltip", isSignal: false, isRequired: false, transformFunction: null }, showShellSettings: { classPropertyName: "showShellSettings", publicName: "showShellSettings", isSignal: false, isRequired: false, transformFunction: null }, shellSettingsLabel: { classPropertyName: "shellSettingsLabel", publicName: "shellSettingsLabel", isSignal: false, isRequired: false, transformFunction: null }, shellSettingsTooltip: { classPropertyName: "shellSettingsTooltip", publicName: "shellSettingsTooltip", isSignal: false, isRequired: false, transformFunction: null }, showRemove: { classPropertyName: "showRemove", publicName: "showRemove", isSignal: false, isRequired: false, transformFunction: null }, moreActionsLabel: { classPropertyName: "moreActionsLabel", publicName: "moreActionsLabel", isSignal: false, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { resize: "resize", assistant: "assistant", componentSettings: "componentSettings", shellSettings: "shellSettings", remove: "remove" }, ngImport: i0, template: `
39274
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicWidgetContextToolbarComponent, isStandalone: true, selector: "praxis-dynamic-widget-context-toolbar", inputs: { showSize: { classPropertyName: "showSize", publicName: "showSize", isSignal: true, isRequired: false, transformFunction: null }, sizeDisabled: { classPropertyName: "sizeDisabled", publicName: "sizeDisabled", isSignal: true, isRequired: false, transformFunction: null }, sizeLabel: { classPropertyName: "sizeLabel", publicName: "sizeLabel", isSignal: true, isRequired: false, transformFunction: null }, toolbarLabel: { classPropertyName: "toolbarLabel", publicName: "toolbarLabel", isSignal: false, isRequired: false, transformFunction: null }, contextLabel: { classPropertyName: "contextLabel", publicName: "contextLabel", isSignal: false, isRequired: false, transformFunction: null }, contextTooltip: { classPropertyName: "contextTooltip", publicName: "contextTooltip", isSignal: false, isRequired: false, transformFunction: null }, showAssistant: { classPropertyName: "showAssistant", publicName: "showAssistant", isSignal: false, isRequired: false, transformFunction: null }, assistantLabel: { classPropertyName: "assistantLabel", publicName: "assistantLabel", isSignal: false, isRequired: false, transformFunction: null }, assistantTooltip: { classPropertyName: "assistantTooltip", publicName: "assistantTooltip", isSignal: false, isRequired: false, transformFunction: null }, showComponentSettings: { classPropertyName: "showComponentSettings", publicName: "showComponentSettings", isSignal: false, isRequired: false, transformFunction: null }, componentSettingsBusy: { classPropertyName: "componentSettingsBusy", publicName: "componentSettingsBusy", isSignal: true, isRequired: false, transformFunction: null }, componentSettingsLabel: { classPropertyName: "componentSettingsLabel", publicName: "componentSettingsLabel", isSignal: false, isRequired: false, transformFunction: null }, componentSettingsTooltip: { classPropertyName: "componentSettingsTooltip", publicName: "componentSettingsTooltip", isSignal: false, isRequired: false, transformFunction: null }, showShellSettings: { classPropertyName: "showShellSettings", publicName: "showShellSettings", isSignal: false, isRequired: false, transformFunction: null }, shellSettingsLabel: { classPropertyName: "shellSettingsLabel", publicName: "shellSettingsLabel", isSignal: false, isRequired: false, transformFunction: null }, shellSettingsTooltip: { classPropertyName: "shellSettingsTooltip", publicName: "shellSettingsTooltip", isSignal: false, isRequired: false, transformFunction: null }, showRemove: { classPropertyName: "showRemove", publicName: "showRemove", isSignal: false, isRequired: false, transformFunction: null }, moreActionsLabel: { classPropertyName: "moreActionsLabel", publicName: "moreActionsLabel", isSignal: false, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { size: "size", assistant: "assistant", componentSettings: "componentSettings", shellSettings: "shellSettings", remove: "remove" }, ngImport: i0, template: `
38652
39275
  <div
38653
39276
  class="pdx-widget-context-toolbar"
38654
39277
  [class.pdx-widget-context-toolbar--with-context]="!!contextLabel"
@@ -38667,13 +39290,6 @@ class DynamicWidgetContextToolbarComponent {
38667
39290
  {{ contextLabel }}
38668
39291
  </span>
38669
39292
  }
38670
- @if (showResize()) {
38671
- <button praxisIconButton="ms:open_in_full" type="button"
38672
- data-testid="dynamic-widget-resize"
38673
- [matTooltip]="resizeLabel()" [attr.aria-label]="resizeLabel()"
38674
- [attr.aria-controls]="resizeControls()" [attr.aria-expanded]="resizeExpanded()"
38675
- (click)="resize.emit()"></button>
38676
- }
38677
39293
  @if (showAssistant) {
38678
39294
  <button
38679
39295
  praxisIconButton="auto_awesome"
@@ -38709,7 +39325,7 @@ class DynamicWidgetContextToolbarComponent {
38709
39325
  (click)="shellSettings.emit()"
38710
39326
  ></button>
38711
39327
  }
38712
- @if (showRemove) {
39328
+ @if (showRemove || showSize()) {
38713
39329
  <button
38714
39330
  praxisIconButton="ms:more_horiz"
38715
39331
  size="dense"
@@ -38720,14 +39336,21 @@ class DynamicWidgetContextToolbarComponent {
38720
39336
  [matMenuTriggerFor]="widgetContextMenu"
38721
39337
  ></button>
38722
39338
  <mat-menu #widgetContextMenu="matMenu">
39339
+ @if (showSize()) {
39340
+ <button mat-menu-item type="button" [disabled]="sizeDisabled()" (click)="size.emit()" data-testid="dynamic-widget-size">
39341
+ <mat-icon [praxisIcon]="'ms:straighten'"></mat-icon><span>{{ sizeLabel() }}</span>
39342
+ </button>
39343
+ }
39344
+ @if (showRemove) {
38723
39345
  <button mat-menu-item type="button" data-testid="dynamic-widget-remove" (click)="remove.emit()">
38724
39346
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
38725
39347
  <span>{{ removeLabel }}</span>
38726
39348
  </button>
39349
+ }
38727
39350
  </mat-menu>
38728
39351
  }
38729
39352
  </div>
38730
- `, isInline: true, styles: [".pdx-widget-context-toolbar{position:absolute;top:-19px;right:12px;z-index:4;display:inline-flex;align-items:center;gap:4px;min-height:34px;padding:2px 4px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 28%,var(--md-sys-color-outline-variant));border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 88%,transparent);box-shadow:0 10px 28px #0f172a38,0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.pdx-widget-context-toolbar--with-context{border-radius:18px}.pdx-widget-context-toolbar__context{display:inline-flex;align-items:center;align-self:stretch;max-width:180px;padding:0 8px 0 10px;border-right:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 64%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:11px;font-weight:700;letter-spacing:.01em;line-height:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
39353
+ `, isInline: true, styles: [".pdx-widget-context-toolbar{position:absolute;top:-19px;right:12px;z-index:4;display:inline-flex;align-items:center;gap:4px;min-height:34px;padding:2px 4px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 28%,var(--md-sys-color-outline-variant));border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 88%,transparent);box-shadow:0 10px 28px #0f172a38,0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.pdx-widget-context-toolbar--with-context{border-radius:18px}.pdx-widget-context-toolbar__context{display:inline-flex;align-items:center;align-self:stretch;max-width:180px;padding:0 8px 0 10px;border-right:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 64%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:11px;font-weight:700;letter-spacing:.01em;line-height:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: 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"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
38731
39354
  }
38732
39355
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicWidgetContextToolbarComponent, decorators: [{
38733
39356
  type: Component,
@@ -38756,13 +39379,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
38756
39379
  {{ contextLabel }}
38757
39380
  </span>
38758
39381
  }
38759
- @if (showResize()) {
38760
- <button praxisIconButton="ms:open_in_full" type="button"
38761
- data-testid="dynamic-widget-resize"
38762
- [matTooltip]="resizeLabel()" [attr.aria-label]="resizeLabel()"
38763
- [attr.aria-controls]="resizeControls()" [attr.aria-expanded]="resizeExpanded()"
38764
- (click)="resize.emit()"></button>
38765
- }
38766
39382
  @if (showAssistant) {
38767
39383
  <button
38768
39384
  praxisIconButton="auto_awesome"
@@ -38798,7 +39414,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
38798
39414
  (click)="shellSettings.emit()"
38799
39415
  ></button>
38800
39416
  }
38801
- @if (showRemove) {
39417
+ @if (showRemove || showSize()) {
38802
39418
  <button
38803
39419
  praxisIconButton="ms:more_horiz"
38804
39420
  size="dense"
@@ -38809,15 +39425,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
38809
39425
  [matMenuTriggerFor]="widgetContextMenu"
38810
39426
  ></button>
38811
39427
  <mat-menu #widgetContextMenu="matMenu">
39428
+ @if (showSize()) {
39429
+ <button mat-menu-item type="button" [disabled]="sizeDisabled()" (click)="size.emit()" data-testid="dynamic-widget-size">
39430
+ <mat-icon [praxisIcon]="'ms:straighten'"></mat-icon><span>{{ sizeLabel() }}</span>
39431
+ </button>
39432
+ }
39433
+ @if (showRemove) {
38812
39434
  <button mat-menu-item type="button" data-testid="dynamic-widget-remove" (click)="remove.emit()">
38813
39435
  <mat-icon [praxisIcon]="'delete'"></mat-icon>
38814
39436
  <span>{{ removeLabel }}</span>
38815
39437
  </button>
39438
+ }
38816
39439
  </mat-menu>
38817
39440
  }
38818
39441
  </div>
38819
39442
  `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".pdx-widget-context-toolbar{position:absolute;top:-19px;right:12px;z-index:4;display:inline-flex;align-items:center;gap:4px;min-height:34px;padding:2px 4px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 28%,var(--md-sys-color-outline-variant));border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 88%,transparent);box-shadow:0 10px 28px #0f172a38,0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.pdx-widget-context-toolbar--with-context{border-radius:18px}.pdx-widget-context-toolbar__context{display:inline-flex;align-items:center;align-self:stretch;max-width:180px;padding:0 8px 0 10px;border-right:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 64%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:11px;font-weight:700;letter-spacing:.01em;line-height:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"] }]
38820
- }], propDecorators: { showResize: [{ type: i0.Input, args: [{ isSignal: true, alias: "showResize", required: false }] }], resizeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizeLabel", required: false }] }], resizeControls: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizeControls", required: false }] }], resizeExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizeExpanded", required: false }] }], resize: [{ type: i0.Output, args: ["resize"] }], toolbarLabel: [{
39443
+ }], propDecorators: { showSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSize", required: false }] }], sizeDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "sizeDisabled", required: false }] }], sizeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sizeLabel", required: false }] }], size: [{ type: i0.Output, args: ["size"] }], toolbarLabel: [{
38821
39444
  type: Input
38822
39445
  }], contextLabel: [{
38823
39446
  type: Input
@@ -38857,114 +39480,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
38857
39480
  type: Output
38858
39481
  }] } });
38859
39482
 
38860
- const DYNAMIC_WIDGET_PAGE_I18N_NAMESPACE = 'dynamicWidgetPage';
38861
- const DYNAMIC_WIDGET_PAGE_I18N_CONFIG = {
38862
- namespaces: {
38863
- [DYNAMIC_WIDGET_PAGE_I18N_NAMESPACE]: {
38864
- 'pt-BR': {
38865
- 'heightValidation.measureFirst': 'Use altura Automática para aplicar a nova geometria; depois reabra o editor para definir a altura ajustável.',
38866
- 'heightValidation.minimum': 'Use pelo menos {{height}}px nesta largura. Ajuste a altura/máximo ou use Automática.',
38867
- 'announcements.contentSize': '{{action}}. Largura {{columns}} colunas, altura {{height}} pixels, recuo superior {{top}} pixels.',
38868
- 'resizeFeedback.valid': 'Ajuste disponível',
38869
- 'resizeFeedback.minimum': 'Tamanho mínimo atingido',
38870
- 'resizeFeedback.blocked': 'Limite excedido — prévia limitada ao espaço disponível',
38871
- 'resizeFeedback.committedLimit': 'Layout ajustado até o limite permitido',
38872
- 'resizeFeedback.unchanged': 'Tamanho mantido — nenhum ajuste aplicado',
38873
- 'controls.pageSettings': 'Configurar página',
38874
- 'controls.componentSettings': 'Configurar conteúdo',
38875
- 'controls.componentSettingsTooltip': 'Abrir configurações do componente',
38876
- 'controls.widgetSettings': 'Configurar widget',
38877
- 'controls.widgetSettingsTooltip': 'Abrir configurações do widget',
38878
- 'controls.widgetAssistant': 'Abrir assistente do widget',
38879
- 'controls.widgetAssistantTooltip': 'Abrir o assistente Praxis com contexto deste widget',
38880
- 'controls.widgetRemove': 'Excluir widget',
38881
- 'controls.widgetRemoveTooltip': 'Excluir este widget e limpar conexões vinculadas',
38882
- 'controls.widgetRemoveConfirmTitle': 'Excluir widget?',
38883
- 'controls.widgetRemoveConfirmMessage': 'O widget "{{widget}}" será removido da página. Conexões e posições vinculadas também serão limpas.',
38884
- 'controls.widgetRemoveConfirm': 'Excluir widget',
38885
- 'controls.cancel': 'Cancelar',
38886
- 'controls.cardSettings': 'Configurar card',
38887
- 'controls.moreWidgetActions': 'Mais ações do widget',
38888
- 'controls.widgetContextToolbar': 'Ações do widget {{widget}}',
38889
- 'controls.widgetContextTooltip': 'Editando {{widget}}',
38890
- 'controls.widgetLayoutToolbar': 'Ações de layout do widget',
38891
- 'controls.dragWidget': 'Arrastar widget',
38892
- 'controls.resizeWidget': 'Redimensionar widget',
38893
- 'controls.resizeAlternative': 'Controles alternativos de tamanho',
38894
- 'controls.resizeSelect': 'Selecione um widget',
38895
- 'controls.resizeClose': 'Fechar controles de tamanho',
38896
- 'controls.resizeContextHelp': 'Arraste um controle ou use as setas do teclado. Esc fecha os controles.',
38897
- 'controls.resizeHelp': 'Selecione o widget. Arraste uma borda ou canto pelos botões, ou use as setas do teclado.',
38898
- 'controls.resize.north': 'Redimensionar widget pela borda superior',
38899
- 'controls.resize.south': 'Redimensionar widget pela borda inferior',
38900
- 'controls.resize.east': 'Redimensionar widget pela borda direita',
38901
- 'controls.resize.west': 'Redimensionar widget pela borda esquerda',
38902
- 'controls.resize.north-east': 'Redimensionar widget pelo canto superior direito',
38903
- 'controls.resize.north-west': 'Redimensionar widget pelo canto superior esquerdo',
38904
- 'controls.resize.south-east': 'Redimensionar widget pelo canto inferior direito',
38905
- 'controls.resize.south-west': 'Redimensionar widget pelo canto inferior esquerdo',
38906
- 'announcements.moved': 'Widget movido: {{widget}}',
38907
- 'announcements.swapped': 'Widget trocado com {{target}}: {{widget}}',
38908
- 'announcements.resized': 'Widget redimensionado: {{widget}}',
38909
- 'announcements.interactionCancelled': 'Alteração de layout cancelada.',
38910
- 'announcements.position': '{{action}} para coluna {{col}}, linha {{row}}, largura {{colSpan}}, altura {{rowSpan}}.',
38911
- 'announcements.dragBlocked': 'Movimento bloqueado: o widget colidiria com outro item.',
38912
- 'announcements.resizeBlocked': 'Redimensionamento bloqueado: o widget colidiria com outro item.',
38913
- },
38914
- 'en-US': {
38915
- 'heightValidation.measureFirst': 'Use Automatic height to apply the new geometry, then reopen the editor to set an adjustable height.',
38916
- 'heightValidation.minimum': 'Use at least {{height}}px at this width. Adjust the height/maximum, or use Automatic.',
38917
- 'announcements.contentSize': '{{action}}. Width {{columns}} columns, height {{height}} pixels, top inset {{top}} pixels.',
38918
- 'resizeFeedback.valid': 'Resize available',
38919
- 'resizeFeedback.minimum': 'Minimum size reached',
38920
- 'resizeFeedback.blocked': 'Limit exceeded — preview constrained to available space',
38921
- 'resizeFeedback.committedLimit': 'Layout resized to the allowed limit',
38922
- 'resizeFeedback.unchanged': 'Size unchanged — no adjustment applied',
38923
- 'controls.pageSettings': 'Configure page',
38924
- 'controls.componentSettings': 'Configure content',
38925
- 'controls.componentSettingsTooltip': 'Open component settings',
38926
- 'controls.widgetSettings': 'Configure widget',
38927
- 'controls.widgetSettingsTooltip': 'Open widget settings',
38928
- 'controls.widgetAssistant': 'Open widget assistant',
38929
- 'controls.widgetAssistantTooltip': 'Open the Praxis assistant with this widget context',
38930
- 'controls.widgetRemove': 'Delete widget',
38931
- 'controls.widgetRemoveTooltip': 'Delete this widget and clean linked connections',
38932
- 'controls.widgetRemoveConfirmTitle': 'Delete widget?',
38933
- 'controls.widgetRemoveConfirmMessage': 'The widget "{{widget}}" will be removed from the page. Linked connections and positions will also be cleaned.',
38934
- 'controls.widgetRemoveConfirm': 'Delete widget',
38935
- 'controls.cancel': 'Cancel',
38936
- 'controls.cardSettings': 'Configure card',
38937
- 'controls.moreWidgetActions': 'More widget actions',
38938
- 'controls.widgetContextToolbar': 'Widget {{widget}} actions',
38939
- 'controls.widgetContextTooltip': 'Editing {{widget}}',
38940
- 'controls.widgetLayoutToolbar': 'Widget layout actions',
38941
- 'controls.dragWidget': 'Drag widget',
38942
- 'controls.resizeWidget': 'Resize widget',
38943
- 'controls.resizeAlternative': 'Alternative resize controls',
38944
- 'controls.resizeSelect': 'Select a widget',
38945
- 'controls.resizeClose': 'Close resize controls',
38946
- 'controls.resizeContextHelp': 'Drag a control or use the arrow keys. Esc closes the controls.',
38947
- 'controls.resizeHelp': 'Select the widget. Drag an edge or corner using the buttons, or use the arrow keys.',
38948
- 'controls.resize.north': 'Resize widget from the top edge',
38949
- 'controls.resize.south': 'Resize widget from the bottom edge',
38950
- 'controls.resize.east': 'Resize widget from the right edge',
38951
- 'controls.resize.west': 'Resize widget from the left edge',
38952
- 'controls.resize.north-east': 'Resize widget from the top-right corner',
38953
- 'controls.resize.north-west': 'Resize widget from the top-left corner',
38954
- 'controls.resize.south-east': 'Resize widget from the bottom-right corner',
38955
- 'controls.resize.south-west': 'Resize widget from the bottom-left corner',
38956
- 'announcements.moved': 'Widget moved: {{widget}}',
38957
- 'announcements.swapped': 'Widget swapped with {{target}}: {{widget}}',
38958
- 'announcements.resized': 'Widget resized: {{widget}}',
38959
- 'announcements.interactionCancelled': 'Layout change cancelled.',
38960
- 'announcements.position': '{{action}} to column {{col}}, row {{row}}, width {{colSpan}}, height {{rowSpan}}.',
38961
- 'announcements.dragBlocked': 'Move blocked: the widget would overlap another item.',
38962
- 'announcements.resizeBlocked': 'Resize blocked: the widget would overlap another item.',
38963
- },
38964
- },
38965
- },
38966
- };
38967
-
38968
39483
  /** Internal materialization of the canonical content-row size, never DOM state. */
38969
39484
  function contentSize(item) {
38970
39485
  const size = item.contentSize;
@@ -39214,10 +39729,6 @@ class DynamicWidgetPageComponent {
39214
39729
  gridAutoRows = 'auto';
39215
39730
  layoutAnnouncement = '';
39216
39731
  canvasResizeHandles = CANVAS_RESIZE_HANDLES;
39217
- contextualResizeHandles = [...CANVAS_RESIZE_HANDLES].sort((a, b) => {
39218
- const order = ['north-west', 'north', 'north-east', 'west', 'east', 'south-west', 'south', 'south-east'];
39219
- return order.indexOf(a.id) - order.indexOf(b.id);
39220
- });
39221
39732
  pageDefinition;
39222
39733
  /**
39223
39734
  * Last canonical definition accepted from the host or published by the
@@ -39304,16 +39815,16 @@ class DynamicWidgetPageComponent {
39304
39815
  runtimeObservationRegistration = null;
39305
39816
  hostElement = inject((ElementRef));
39306
39817
  changeDetector = inject(ChangeDetectorRef);
39307
- static resizePopoverSequence = 0;
39308
- resizePopoverId = `pdx-canvas-resize-${++DynamicWidgetPageComponent.resizePopoverSequence}`;
39309
- resizePopoverOrigin = signal(null, ...(ngDevMode ? [{ debugName: "resizePopoverOrigin" }] : /* istanbul ignore next */ []));
39310
- resizePopoverReturnFocus = null;
39311
- projectedResizeActions = new WeakSet();
39312
- resizePopoverPositions = [
39313
- { originX: 'end', originY: 'top', overlayX: 'start', overlayY: 'top', offsetX: 8 },
39314
- { originX: 'start', originY: 'top', overlayX: 'end', overlayY: 'top', offsetX: -8 },
39315
- { originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 8 },
39818
+ lastCanvasResize = signal(null, ...(ngDevMode ? [{ debugName: "lastCanvasResize" }] : /* istanbul ignore next */ []));
39819
+ sizeEditorOrigin = signal(null, ...(ngDevMode ? [{ debugName: "sizeEditorOrigin" }] : /* istanbul ignore next */ []));
39820
+ sizeEditorSeed = signal(null, ...(ngDevMode ? [{ debugName: "sizeEditorSeed" }] : /* istanbul ignore next */ []));
39821
+ sizeEditorError = signal(null, ...(ngDevMode ? [{ debugName: "sizeEditorError" }] : /* istanbul ignore next */ []));
39822
+ projectedSizeActions = new WeakSet();
39823
+ sizeEditorPositions = [
39824
+ { originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'top' },
39825
+ { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'top' },
39316
39826
  ];
39827
+ sizeEditorResizeObserver;
39317
39828
  hostResizeObserver;
39318
39829
  containerWidth;
39319
39830
  widgetLoaders;
@@ -39322,7 +39833,7 @@ class DynamicWidgetPageComponent {
39322
39833
  afterNextRender({ read: () => this.observeHostWidth() });
39323
39834
  }
39324
39835
  ngOnDestroy() {
39325
- this.closeResizePopover(false);
39836
+ this.closeSizeEditor(false);
39326
39837
  if (this.activeCanvasInteraction) {
39327
39838
  this.cancelCanvasInteractionForWidget(this.activeCanvasInteraction.widgetKey);
39328
39839
  }
@@ -39334,8 +39845,10 @@ class DynamicWidgetPageComponent {
39334
39845
  this.compositionRuntime.destroy();
39335
39846
  }
39336
39847
  ngOnChanges(changes) {
39337
- if (changes['pageIdentity'] || changes['enableCustomization'] || changes['authoringCapabilities']) {
39338
- this.closeResizePopover(false);
39848
+ if (changes['pageIdentity'] || changes['componentInstanceId'])
39849
+ this.lastCanvasResize.set(null);
39850
+ if (changes['page'] || changes['context'] || changes['pageIdentity'] || changes['enableCustomization'] || changes['authoringCapabilities']) {
39851
+ this.closeSizeEditor(false);
39339
39852
  }
39340
39853
  if (this.activeCanvasInteraction &&
39341
39854
  (changes['page'] || changes['context'] || changes['pageIdentity'] ||
@@ -40894,15 +41407,12 @@ class DynamicWidgetPageComponent {
40894
41407
  buildProjectedWidgetShellActions(widget) {
40895
41408
  const actions = [];
40896
41409
  if (this.canCustomizeCanvas() && this.isCanvasMode()) {
40897
- const resizeAction = {
40898
- id: 'widget-resize-controls',
40899
- label: this.resizeWidgetLabel(), tooltip: this.resizeWidgetLabel(),
40900
- icon: 'ms:open_in_full', variant: 'icon', placement: 'header',
40901
- ariaControls: this.resizePopoverId,
40902
- ariaExpanded: !!this.resizePopoverOrigin() && this.isWidgetSelected(widget.key),
41410
+ const sizeAction = {
41411
+ id: 'widget-size', label: this.sizeEditorLabel(), icon: 'ms:straighten',
41412
+ placement: 'menu', disabled: !!this.currentCanvasItem(widget.key)?.constraints?.lockSize,
40903
41413
  };
40904
- this.projectedResizeActions.add(resizeAction);
40905
- actions.push(resizeAction);
41414
+ this.projectedSizeActions.add(sizeAction);
41415
+ actions.push(sizeAction);
40906
41416
  }
40907
41417
  if (this.canRequestWidgetAssistant()) {
40908
41418
  actions.push({
@@ -40941,7 +41451,7 @@ class DynamicWidgetPageComponent {
40941
41451
  tooltip: this.widgetRemoveLabel(),
40942
41452
  icon: 'delete',
40943
41453
  variant: 'icon',
40944
- placement: 'header',
41454
+ placement: 'menu',
40945
41455
  });
40946
41456
  }
40947
41457
  return actions;
@@ -40998,12 +41508,12 @@ class DynamicWidgetPageComponent {
40998
41508
  this.widgetDiagnosticsChange.emit({ ...this.widgetDiagnostics });
40999
41509
  }
41000
41510
  onShellAction(fromKey, evt) {
41001
- if (evt.id === 'widget-resize-controls' && evt.action && this.projectedResizeActions.has(evt.action)) {
41002
- this.toggleResizePopover(fromKey);
41511
+ if (evt.id === 'widget-size' && evt.action && this.projectedSizeActions.has(evt.action)) {
41512
+ this.openSizeEditor(fromKey);
41003
41513
  return;
41004
41514
  }
41005
- if (this.resizePopoverOrigin())
41006
- this.closeResizePopover(false);
41515
+ if (this.sizeEditorOrigin())
41516
+ this.closeSizeEditor(false);
41007
41517
  if (evt.id === 'expand' || evt.id === 'fullscreen' || evt.id === 'collapse') {
41008
41518
  this.cancelCanvasInteractionForWidget(fromKey);
41009
41519
  }
@@ -41526,7 +42036,8 @@ class DynamicWidgetPageComponent {
41526
42036
  const editor = this.pageEditorComponent || this.defaultPageEditor;
41527
42037
  if (!editor)
41528
42038
  return;
41529
- const page = this.ensurePageDefinition();
42039
+ // Layout authoring must not capture runtime inputs such as loaded table rows.
42040
+ const page = this.clonePageDefinition(this.authoredPageDefinition ?? this.ensurePageDefinition());
41530
42041
  const uiShell = page.context?.ui?.shell || {};
41531
42042
  const ref = this.settingsPanel.open({
41532
42043
  id: 'dynamic-page-settings',
@@ -41617,6 +42128,7 @@ class DynamicWidgetPageComponent {
41617
42128
  'title',
41618
42129
  'subtitle',
41619
42130
  'showHeader',
42131
+ 'stickyHeader',
41620
42132
  'windowActions',
41621
42133
  'collapsed',
41622
42134
  'expanded',
@@ -42119,9 +42631,31 @@ class DynamicWidgetPageComponent {
42119
42631
  },
42120
42632
  };
42121
42633
  }
42634
+ const columns = Math.max(1, Number(variant?.columns ?? canvas.columns) || 1);
42635
+ if (columns < canvas.columns) {
42636
+ // Reflow inherited desktop positions only. Explicit device positions are
42637
+ // anchors, including intentional overlays; the authored base stays intact.
42638
+ const anchored = Object.keys(items).filter(key => overrideItems[key]?.col !== undefined && overrideItems[key]?.row !== undefined);
42639
+ for (const key of anchored)
42640
+ items[key] = this.normalizeCanvasItem(items[key], columns);
42641
+ const placed = anchored.map(key => items[key]);
42642
+ const inherited = Object.entries(items)
42643
+ .filter(([key]) => !anchored.includes(key))
42644
+ .sort(([leftKey, left], [rightKey, right]) => left.row - right.row || left.col - right.col || leftKey.localeCompare(rightKey));
42645
+ for (const [key, item] of inherited) {
42646
+ const next = this.normalizeCanvasItem(item, columns);
42647
+ let collisions = placed.filter(other => this.canvasItemsOverlap(next, other));
42648
+ while (collisions.length) {
42649
+ next.row = Math.max(...collisions.map(other => other.row + other.rowSpan));
42650
+ collisions = placed.filter(other => this.canvasItemsOverlap(next, other));
42651
+ }
42652
+ items[key] = next;
42653
+ placed.push(next);
42654
+ }
42655
+ }
42122
42656
  return {
42123
42657
  ...canvas,
42124
- columns: Math.max(1, Number(variant?.columns ?? canvas.columns) || 1),
42658
+ columns,
42125
42659
  rowUnit: variant?.rowUnit ?? canvas.rowUnit,
42126
42660
  gap: variant?.gap ?? canvas.gap,
42127
42661
  autoRows: variant?.autoRows ?? canvas.autoRows,
@@ -42209,7 +42743,7 @@ class DynamicWidgetPageComponent {
42209
42743
  if (this.activeCanvasInteraction && this.activeCanvasInteraction.widgetKey !== widgetKey)
42210
42744
  return;
42211
42745
  if (this.selectedWidgetKeyState() !== widgetKey) {
42212
- this.closeResizePopover(false);
42746
+ this.closeSizeEditor(false);
42213
42747
  this.selectedWidgetKeyState.set(widgetKey);
42214
42748
  this.widgetSelectionChange.emit(widgetKey);
42215
42749
  }
@@ -42240,81 +42774,196 @@ class DynamicWidgetPageComponent {
42240
42774
  return this.canCustomizeCanvas() && this.isWidgetSelected(widgetKey)
42241
42775
  && !this.currentCanvasItem(widgetKey)?.constraints?.lockSize;
42242
42776
  }
42243
- contextualResizeHandle() {
42244
- const interaction = this.activeCanvasInteraction;
42245
- return this.resizePopoverOrigin() && interaction?.kind === 'resize'
42246
- && interaction.widgetKey === this.selectedCanvasWidget()?.key
42247
- ? interaction.resizeHandle ?? null : null;
42248
- }
42249
- selectCanvasResizeTarget(event) {
42250
- const key = event.target.value;
42251
- if (this.widgets().some((widget) => widget.key === key)) {
42252
- this.selectCanvasWidget(key);
42253
- }
42777
+ canvasSelectionLabel(key) {
42778
+ return this.t('size.select', 'Widget {{widget}}. Tab acessa os controles; Esc volta à seleção.', { widget: this.widgetContextLabel(this.widgets().find(w => w.key === key)) });
42254
42779
  }
42255
- toggleResizePopover(widgetKey) {
42256
- if (!this.canCustomizeCanvas() || !this.isCanvasMode() || this.canvasInteractionActive()
42257
- || this.isCanvasWidgetInOverlay(widgetKey))
42258
- return;
42259
- if (this.resizePopoverOrigin() && this.isWidgetSelected(widgetKey)) {
42260
- this.closeResizePopover(true);
42780
+ onCanvasSelectionKeydown(key, event) {
42781
+ if (event.key !== 'Escape' || this.activeCanvasInteraction || this.sizeEditorOrigin())
42261
42782
  return;
42783
+ const target = event.target;
42784
+ if (target instanceof HTMLElement && target.hasAttribute('data-canvas-edge')) {
42785
+ event.preventDefault();
42786
+ event.stopPropagation();
42787
+ event.currentTarget.focus({ preventScroll: true });
42262
42788
  }
42263
- const owner = Array.from(this.pageCanvasHost?.nativeElement.children || [])
42264
- .find((element) => element.getAttribute('data-widget-key') === widgetKey);
42265
- const header = owner?.querySelector('.pdx-shell-header')
42266
- ?? owner?.querySelector('[data-testid="dynamic-widget-context-toolbar"]');
42267
- if (!header)
42268
- return;
42269
- this.selectCanvasWidget(widgetKey);
42270
- const focused = this.hostElement.nativeElement.ownerDocument.activeElement;
42271
- this.resizePopoverReturnFocus = focused instanceof HTMLElement && header.contains(focused)
42272
- ? focused : (header.querySelector('button[aria-haspopup="menu"]') ?? header.querySelector('button'));
42273
- this.resizePopoverOrigin.set(header);
42274
42789
  }
42275
- focusResizePopover(overlay) {
42276
- overlay.querySelector('[data-resize-handle]')?.focus({ preventScroll: true });
42790
+ isCanvasSizeLocked(key) { return !!this.currentCanvasItem(key)?.constraints?.lockSize; }
42791
+ sizeEditorWidgetLabel() {
42792
+ const widget = this.widgets().find(w => w.key === this.sizeEditorSeed()?.key);
42793
+ return widget ? this.widgetContextLabel(widget) : '';
42794
+ }
42795
+ sizeEditorLabel() { return this.t('size.title', 'Tamanho…'); }
42796
+ sizeEditorScopeLabel() {
42797
+ const seed = this.sizeEditorSeed();
42798
+ const scope = seed && this.authoredPageDefinition?.deviceLayouts?.[seed.device]?.canvas ? seed.device : 'base';
42799
+ return this.t(`size.scope.${scope}`, scope);
42277
42800
  }
42278
- closeResizePopover(restoreFocus) {
42279
- if (!this.resizePopoverOrigin())
42801
+ openSizeEditor(key) {
42802
+ if (!this.canCustomizeCanvas() || !this.isCanvasMode() || this.canvasInteractionActive() || this.isCanvasWidgetInOverlay(key))
42280
42803
  return;
42281
- const widget = this.selectedCanvasWidget();
42282
- if (widget)
42283
- this.cancelCanvasInteractionForWidget(widget.key);
42284
- const target = this.resizePopoverReturnFocus;
42285
- this.resizePopoverOrigin.set(null);
42286
- this.resizePopoverReturnFocus = null;
42287
- if (restoreFocus && target?.isConnected)
42288
- target.focus({ preventScroll: true });
42289
- }
42290
- onResizePopoverOutsideClick(event) {
42291
- if (this.canvasInteractionActive())
42804
+ const item = this.currentCanvasItem(key);
42805
+ if (!item || item.constraints?.lockSize)
42292
42806
  return;
42293
- const target = event.target;
42294
- if (target instanceof Node && this.resizePopoverOrigin()?.contains(target))
42807
+ const owner = Array.from(this.pageCanvasHost?.nativeElement.children || [])
42808
+ .find(element => element.getAttribute('data-widget-key') === key);
42809
+ if (!owner)
42295
42810
  return;
42296
- this.closeResizePopover(false);
42811
+ this.selectWidget(key);
42812
+ this.sizeEditorError.set(null);
42813
+ const contentRows = this.canvas?.autoRows === 'content';
42814
+ this.sizeEditorSeed.set({ key, item: structuredClone(item), contentRows,
42815
+ height: contentRows ? Math.round(this.measureCanvasContentHeight(key) || 160) : item.rowSpan,
42816
+ columns: this.canvas?.columns || 1, device: this.resolveDeviceKind() });
42817
+ this.sizeEditorOrigin.set(owner);
42818
+ }
42819
+ focusSizeEditor(overlay) {
42820
+ overlay.overlayElement.querySelector('input')?.focus({ preventScroll: true });
42821
+ this.sizeEditorResizeObserver?.disconnect();
42822
+ this.sizeEditorResizeObserver = new ResizeObserver(() => {
42823
+ if (overlay.hasAttached())
42824
+ overlay.updatePosition();
42825
+ });
42826
+ this.sizeEditorResizeObserver.observe(overlay.overlayElement);
42297
42827
  }
42298
- onResizePopoverKeydown(event) {
42828
+ closeSizeEditor(restoreFocus) {
42829
+ if (!this.sizeEditorOrigin())
42830
+ return;
42831
+ const owner = this.sizeEditorOrigin();
42832
+ this.sizeEditorResizeObserver?.disconnect();
42833
+ this.sizeEditorResizeObserver = undefined;
42834
+ this.sizeEditorOrigin.set(null);
42835
+ this.sizeEditorSeed.set(null);
42836
+ this.sizeEditorError.set(null);
42837
+ this.clearSizePreview();
42838
+ if (restoreFocus && owner?.isConnected)
42839
+ owner.focus({ preventScroll: true });
42840
+ }
42841
+ onSizeEditorKeydown(event) {
42299
42842
  if (event.key !== 'Escape')
42300
42843
  return;
42301
42844
  event.preventDefault();
42302
42845
  event.stopPropagation();
42303
- this.cancelCanvasGesture();
42304
- this.closeResizePopover(true);
42846
+ this.closeSizeEditor(true);
42847
+ }
42848
+ clearSizePreview() {
42849
+ this.transientCanvasItemsState.set({});
42850
+ this.resizeFeedbackState.set({});
42851
+ this.canvasPreviewState.set(null);
42852
+ this.canvasPreviewInvalidState.set(false);
42853
+ }
42854
+ resolveSizeRequest(request) {
42855
+ const seed = this.sizeEditorSeed();
42856
+ if (!seed || !this.canCustomizeCanvas() || this.isCanvasWidgetInOverlay(seed.key))
42857
+ return null;
42858
+ const page = this.ensurePageDefinition();
42859
+ const variant = this.resolveDeviceVariant(page.deviceLayouts);
42860
+ const canvas = this.resolveCanvas(page.canvas, variant?.canvas);
42861
+ const current = canvas?.items[seed.key];
42862
+ if (!canvas || !current || current.constraints?.lockSize || this.resolveDeviceKind() !== seed.device
42863
+ || canvas.columns !== seed.columns || !this.isSameCanvasItem(seed.item, current))
42864
+ return null;
42865
+ if (!Number.isSafeInteger(request.width) || !Number.isSafeInteger(request.height) || request.width < 1 || request.height < 1)
42866
+ return null;
42867
+ const colDelta = (request.width - current.colSpan) * (request.handle.includes('west') ? -1 : 1);
42868
+ const rowDelta = (request.height - seed.height) * (request.handle.includes('north') ? -1 : 1);
42869
+ const result = this.applyCanvasResize(current, { startItem: current, columns: canvas.columns,
42870
+ resizeHandle: request.handle, contentHeight: seed.contentRows ? seed.height : undefined,
42871
+ minimumContentHeight: this.measureCanvasMinimumHeight(seed.key) }, colDelta, rowDelta);
42872
+ if (result.constrained)
42873
+ return null;
42874
+ if (current.constraints?.lockPosition && (result.item.col !== current.col || result.item.row !== current.row
42875
+ || contentSize(result.item)?.offsetTopPx !== contentSize(current)?.offsetTopPx))
42876
+ return null;
42877
+ const placement = resolveCanvasResizePlacement(seed.key, result.item, canvas.items);
42878
+ if (placement.limited)
42879
+ return null;
42880
+ return { item: result.item, canvas, page, key: seed.key };
42305
42881
  }
42306
- resizeCloseLabel() {
42307
- return this.t('controls.resizeClose', 'Fechar controles de tamanho');
42882
+ previewCanvasSize(request) {
42883
+ if (!request) {
42884
+ this.clearSizePreview();
42885
+ this.sizeEditorError.set(null);
42886
+ return;
42887
+ }
42888
+ const resolved = this.resolveSizeRequest(request);
42889
+ if (!resolved) {
42890
+ this.clearSizePreview();
42891
+ this.sizeEditorError.set(this.t('size.unavailable', 'Esse tamanho excede os limites ou o espaço disponível.'));
42892
+ return;
42893
+ }
42894
+ this.sizeEditorError.set(null);
42895
+ this.updateCanvasResize(resolved.key, resolved.item, resolved.canvas, resolved.page, false);
42308
42896
  }
42309
- resizeContextHelpLabel() {
42310
- return this.t('controls.resizeContextHelp', 'Arraste um controle ou use as setas do teclado. Esc fecha os controles.');
42897
+ applyCanvasSize(request) {
42898
+ const resolved = this.resolveSizeRequest(request);
42899
+ if (!resolved) {
42900
+ this.previewCanvasSize(request);
42901
+ return;
42902
+ }
42903
+ this.updateCanvasResize(resolved.key, resolved.item, resolved.canvas, resolved.page, true, this.canvasAnnouncement('resize', resolved.key));
42904
+ this.closeSizeEditor(true);
42311
42905
  }
42312
- resizePopoverGridArea(handle) {
42313
- const positions = {
42314
- north: '1 / 2', 'north-east': '1 / 3', east: '2 / 3', 'south-east': '3 / 3',
42315
- south: '3 / 2', 'south-west': '3 / 1', west: '2 / 1', 'north-west': '1 / 1',
42316
- };
42317
- return positions[handle];
42906
+ hasCanvasResizeUndo(key) {
42907
+ return this.lastCanvasResize()?.key === key;
42908
+ }
42909
+ canvasResizeUndoPage(key) {
42910
+ const operation = this.lastCanvasResize();
42911
+ if (!operation || operation.key !== key || !this.canCustomizeCanvas() || this.canvasInteractionActive())
42912
+ return null;
42913
+ const page = this.clonePageDefinition(this.ensurePageDefinition());
42914
+ const device = this.resolveDeviceKind();
42915
+ const scope = page.deviceLayouts?.[device]?.canvas ? device : 'base';
42916
+ if (scope !== operation.scope)
42917
+ return null;
42918
+ const canvas = this.resolveCanvas(page.canvas, page.deviceLayouts?.[device]?.canvas);
42919
+ if (!canvas || !this.sameJsonStructure({ ...canvas, items: {} }, { ...operation.canvas, items: {} }))
42920
+ return null;
42921
+ const target = this.resolveCanvasTarget(page);
42922
+ const restored = { ...canvas.items };
42923
+ for (const itemKey of Object.keys(operation.after)) {
42924
+ const current = canvas.items[itemKey];
42925
+ const previous = operation.canvas.items[itemKey];
42926
+ if (!current || !previous || this.isCanvasWidgetInOverlay(itemKey)
42927
+ || current.constraints?.lockSize
42928
+ || !this.sameJsonStructure(current, operation.after[itemKey])
42929
+ || !this.sameJsonStructure(target.items[itemKey], operation.authoredAfter[itemKey]))
42930
+ return null;
42931
+ if (!this.isSameCanvasItem(this.normalizeCanvasItem(previous, canvas.columns), previous))
42932
+ return null;
42933
+ const size = contentSize(previous);
42934
+ if (size && size.heightPx < Math.max(contentHeightLimits(previous).min, this.measureCanvasMinimumHeight(itemKey) || 0))
42935
+ return null;
42936
+ restored[itemKey] = previous;
42937
+ }
42938
+ // Validate the complete inverse distribution against today's unrelated widgets.
42939
+ for (const itemKey of Object.keys(operation.after)) {
42940
+ if (Object.entries(restored).some(([otherKey, item]) => otherKey !== itemKey && this.canvasItemsOverlap(restored[itemKey], item)))
42941
+ return null;
42942
+ }
42943
+ for (const itemKey of Object.keys(operation.after)) {
42944
+ const original = operation.before[itemKey];
42945
+ if (original)
42946
+ target.items[itemKey] = structuredClone(original);
42947
+ else
42948
+ delete target.items[itemKey];
42949
+ }
42950
+ // Removing an inherited override must still resolve to the captured geometry.
42951
+ const effective = this.resolveCanvas(page.canvas, page.deviceLayouts?.[device]?.canvas);
42952
+ if (!effective || Object.keys(operation.after).some(itemKey => !this.sameJsonStructure(effective.items[itemKey], operation.canvas.items[itemKey])))
42953
+ return null;
42954
+ return page;
42955
+ }
42956
+ canUndoCanvasResize(key) {
42957
+ return this.canvasResizeUndoPage(key) !== null;
42958
+ }
42959
+ undoCanvasResize(key) {
42960
+ const page = this.canvasResizeUndoPage(key);
42961
+ if (!page)
42962
+ return;
42963
+ this.lastCanvasResize.set(null);
42964
+ this.closeSizeEditor(true);
42965
+ this.applyAuthoringPageUpdate(page, true);
42966
+ this.layoutAnnouncement = this.t('size.undoDone', 'Último redimensionamento desfeito, incluindo os vizinhos afetados.');
42318
42967
  }
42319
42968
  onSelectedCanvasResizePointerDown(handle, event) {
42320
42969
  const widget = this.selectedCanvasWidget();
@@ -42724,9 +43373,18 @@ class DynamicWidgetPageComponent {
42724
43373
  this.blockedCanvasWidgetKey = null;
42725
43374
  if (changed) {
42726
43375
  const target = this.resolveCanvasTarget(page);
43376
+ const affected = Object.keys(placement.items).filter(itemKey => !this.isSameCanvasItem(canvas.items[itemKey], placement.items[itemKey]));
43377
+ const before = Object.fromEntries(affected.map(itemKey => [itemKey, target.items[itemKey] ? structuredClone(target.items[itemKey]) : undefined]));
42727
43378
  for (const [itemKey, item] of Object.entries(placement.items)) {
42728
43379
  target.items[itemKey] = { ...item, constraints: item.constraints ? { ...item.constraints } : undefined };
42729
43380
  }
43381
+ const device = this.resolveDeviceKind();
43382
+ this.lastCanvasResize.set({
43383
+ key, scope: page.deviceLayouts?.[device]?.canvas ? device : 'base',
43384
+ canvas: structuredClone(canvas), before,
43385
+ after: Object.fromEntries(affected.map(itemKey => [itemKey, structuredClone(placement.items[itemKey])])),
43386
+ authoredAfter: Object.fromEntries(affected.map(itemKey => [itemKey, structuredClone(target.items[itemKey])])),
43387
+ });
42730
43388
  this.applyAuthoringPageUpdate(page, true);
42731
43389
  }
42732
43390
  this.layoutAnnouncement = this.positionedCanvasAnnouncement(!changed ? this.t('resizeFeedback.unchanged', 'Tamanho mantido — nenhum ajuste aplicado')
@@ -42849,15 +43507,6 @@ class DynamicWidgetPageComponent {
42849
43507
  resizeWidgetLabel() {
42850
43508
  return this.t('controls.resizeWidget', 'Redimensionar widget');
42851
43509
  }
42852
- resizeAlternativeLabel() {
42853
- return this.t('controls.resizeAlternative', 'Controles alternativos de tamanho');
42854
- }
42855
- resizeSelectLabel() {
42856
- return this.t('controls.resizeSelect', 'Selecione um widget');
42857
- }
42858
- resizeHelpLabel() {
42859
- return this.t('controls.resizeHelp', 'Selecione o widget. Arraste uma borda ou canto pelos botões, ou use as setas do teclado.');
42860
- }
42861
43510
  resizeHandleLabel(handle) {
42862
43511
  return this.t(`controls.resize.${handle}`, this.resizeWidgetLabel());
42863
43512
  }
@@ -43561,80 +44210,24 @@ class DynamicWidgetPageComponent {
43561
44210
  (click)="openPageSettings()"
43562
44211
  ></button>
43563
44212
  }
43564
- @if (canCustomizeCanvas() && isCanvasMode()) {
43565
- <details class="pdx-canvas-resize-alternative" data-testid="canvas-resize-alternative"
43566
- [attr.inert]="resizePopoverOrigin() && selectedCanvasWidget() ? '' : null">
43567
- <summary>{{ resizeAlternativeLabel() }}</summary>
43568
- <div class="pdx-canvas-tools" data-testid="canvas-resize-tools"
43569
- [attr.inert]="resizePopoverOrigin() && selectedCanvasWidget() ? '' : null"
43570
- [attr.data-resize-widget-key]="selectedCanvasWidget()?.key || null"
43571
- role="group" [attr.aria-label]="resizeWidgetLabel()">
43572
- <label class="pdx-canvas-tools-target">
43573
- <span>{{ resizeWidgetLabel() }}</span>
43574
- <select data-testid="canvas-resize-target"
43575
- [disabled]="canvasInteractionActive()"
43576
- (change)="selectCanvasResizeTarget($event)">
43577
- <option value="" disabled [selected]="!selectedCanvasWidget()">{{ resizeSelectLabel() }}</option>
43578
- @for (widget of widgets(); track widget.key) {
43579
- <option [value]="widget.key" [selected]="isWidgetSelected(widget.key)">{{ widgetContextLabel(widget) }}</option>
43580
- }
43581
- </select>
43582
- </label>
43583
- <div class="pdx-canvas-tools-directions">
43584
- @for (handle of canvasResizeHandles; track handle.id) {
43585
- <button class="pdx-canvas-resize" type="button"
43586
- [praxisIconButton]="'ms:' + handle.icon"
43587
- [attr.data-resize-handle]="handle.id"
43588
- [attr.aria-label]="resizeHandleLabel(handle.id)"
43589
- [matTooltip]="resizeHandleLabel(handle.id)"
43590
- [disabled]="!selectedCanvasWidget()"
43591
- (pointerdown)="onSelectedCanvasResizePointerDown(handle.id, $event)"
43592
- (keydown)="onSelectedCanvasResizeKeydown(handle.id, $event)">
43593
- </button>
43594
- }
43595
- </div>
43596
- <p class="pdx-canvas-tools-hint">{{ resizeHelpLabel() }}</p>
43597
- </div>
43598
- </details>
43599
- }
43600
- @if (resizePopoverOrigin(); as origin) {
43601
- @if (canCustomizeCanvas() && isCanvasMode() && selectedCanvasWidget(); as widget) {
43602
- <ng-template cdkConnectedOverlay #resizeOverlay="cdkConnectedOverlay"
43603
- [cdkConnectedOverlayOrigin]="origin"
43604
- [cdkConnectedOverlayOpen]="true"
43605
- [cdkConnectedOverlayPositions]="resizePopoverPositions"
43606
- [cdkConnectedOverlayPush]="true"
43607
- [cdkConnectedOverlayViewportMargin]="12"
43608
- [cdkConnectedOverlayHasBackdrop]="false"
43609
- (attach)="focusResizePopover(resizeOverlay.overlayRef.overlayElement)"
43610
- (detach)="closeResizePopover(false)"
43611
- (overlayOutsideClick)="onResizePopoverOutsideClick($event)"
43612
- (overlayKeydown)="onResizePopoverKeydown($event)">
43613
- <section class="pdx-resize-popover" data-testid="canvas-context-resize"
43614
- [class.pdx-resize-popover--gesturing]="!!contextualResizeHandle()"
43615
- role="region" [id]="resizePopoverId" [attr.aria-label]="resizeWidgetLabel()"
43616
- (pointerdown)="$event.stopPropagation()" (click)="$event.stopPropagation()">
43617
- <header>
43618
- <div><strong>{{ resizeWidgetLabel() }}</strong><span>{{ widgetContextLabel(widget) }}</span></div>
43619
- <button type="button" praxisIconButton="ms:close"
43620
- [attr.aria-label]="resizeCloseLabel()" [matTooltip]="resizeCloseLabel()"
43621
- (click)="closeResizePopover(true)"></button>
43622
- </header>
43623
- <div class="pdx-canvas-tools-directions">
43624
- @for (handle of contextualResizeHandles; track handle.id) {
43625
- <button class="pdx-canvas-resize" type="button"
43626
- [praxisIconButton]="'ms:' + handle.icon"
43627
- [attr.data-resize-handle]="handle.id"
43628
- [style.grid-area]="resizePopoverGridArea(handle.id)"
43629
- [class.pdx-resize-active-handle]="contextualResizeHandle() === handle.id"
43630
- [attr.aria-label]="resizeHandleLabel(handle.id)"
43631
- [matTooltip]="resizeHandleLabel(handle.id)"
43632
- [matTooltipDisabled]="!!contextualResizeHandle()"
43633
- (pointerdown)="onSelectedCanvasResizePointerDown(handle.id, $event)"
43634
- (keydown)="onSelectedCanvasResizeKeydown(handle.id, $event)"></button>
43635
- }
43636
- </div>
43637
- <p class="pdx-canvas-tools-hint">{{ resizeContextHelpLabel() }}</p>
44213
+ @if (sizeEditorOrigin(); as origin) {
44214
+ @if (sizeEditorSeed(); as seed) {
44215
+ <ng-template cdkConnectedOverlay #sizeOverlay="cdkConnectedOverlay"
44216
+ [cdkConnectedOverlayOrigin]="origin" [cdkConnectedOverlayOpen]="true"
44217
+ [cdkConnectedOverlayPositions]="sizeEditorPositions" [cdkConnectedOverlayPush]="true"
44218
+ [cdkConnectedOverlayViewportMargin]="16" [cdkConnectedOverlayHasBackdrop]="true"
44219
+ cdkConnectedOverlayBackdropClass="cdk-overlay-transparent-backdrop"
44220
+ (backdropClick)="closeSizeEditor(true)" (overlayKeydown)="onSizeEditorKeydown($event)"
44221
+ (attach)="focusSizeEditor(sizeOverlay.overlayRef)">
44222
+ <section role="dialog" aria-modal="true" [attr.aria-label]="sizeEditorLabel()"
44223
+ cdkTrapFocus data-testid="canvas-size-editor">
44224
+ <praxis-canvas-size-editor [width]="seed.item.colSpan" [height]="seed.height"
44225
+ [contentRows]="seed.contentRows" [widgetLabel]="sizeEditorWidgetLabel()"
44226
+ [columns]="seed.columns" [hasUndo]="hasCanvasResizeUndo(seed.key)"
44227
+ [canUndo]="canUndoCanvasResize(seed.key)" (undo)="undoCanvasResize(seed.key)"
44228
+ [scopeLabel]="sizeEditorScopeLabel()" [error]="sizeEditorError()"
44229
+ (preview)="previewCanvasSize($event)" (apply)="applyCanvasSize($event)"
44230
+ (cancel)="closeSizeEditor(true)" />
43638
44231
  </section>
43639
44232
  </ng-template>
43640
44233
  }
@@ -43674,6 +44267,10 @@ class DynamicWidgetPageComponent {
43674
44267
  <div
43675
44268
  class="pdx-widget pdx-widget--canvas"
43676
44269
  [attr.data-widget-key]="w.key"
44270
+ [attr.tabindex]="canCustomizeCanvas() ? 0 : null"
44271
+ [attr.role]="canCustomizeCanvas() ? 'group' : null"
44272
+ [attr.aria-label]="canCustomizeCanvas() ? canvasSelectionLabel(w.key) : null"
44273
+ (keydown)="onCanvasSelectionKeydown(w.key, $event)"
43677
44274
  [attr.data-resize-feedback]="resizeFeedback(w.key)"
43678
44275
  [class.pdx-widget--interactive]="canSelectWidgets()"
43679
44276
  [class.pdx-widget--selected]="
@@ -43729,7 +44326,6 @@ class DynamicWidgetPageComponent {
43729
44326
  }
43730
44327
  @if (canShowCanvasEdges(w.key)) {
43731
44328
  <div class="pdx-canvas-edges" data-testid="canvas-edge-controls"
43732
- [attr.inert]="resizePopoverOrigin() ? '' : null"
43733
44329
  role="group" [attr.aria-label]="resizeWidgetLabel()">
43734
44330
  @for (handle of canvasResizeHandles; track handle.id) {
43735
44331
  <button type="button" class="pdx-canvas-edge"
@@ -43745,11 +44341,10 @@ class DynamicWidgetPageComponent {
43745
44341
  }
43746
44342
  @if (shouldRenderWidgetContextOverlay(w)) {
43747
44343
  <praxis-dynamic-widget-context-toolbar
43748
- [showResize]="canCustomizeCanvas()"
43749
- [resizeLabel]="resizeWidgetLabel()"
43750
- [resizeControls]="resizePopoverId"
43751
- [resizeExpanded]="!!resizePopoverOrigin() && isWidgetSelected(w.key)"
43752
- (resize)="toggleResizePopover(w.key)"
44344
+ [showSize]="canCustomizeCanvas()"
44345
+ [sizeDisabled]="isCanvasSizeLocked(w.key)"
44346
+ [sizeLabel]="sizeEditorLabel()"
44347
+ (size)="openSizeEditor(w.key)"
43753
44348
  [toolbarLabel]="widgetContextToolbarLabel(w.key)"
43754
44349
  [contextLabel]="widgetContextLabel(w)"
43755
44350
  [contextTooltip]="widgetContextTooltip(w)"
@@ -44051,7 +44646,7 @@ class DynamicWidgetPageComponent {
44051
44646
  </div>
44052
44647
  }
44053
44648
  </div>
44054
- `, isInline: true, styles: [":host{display:block;min-width:0}.pdx-page-wrapper{position:relative;display:block;background:var(--pdx-page-bg, transparent);color:var(--pdx-page-color, inherit)}.pdx-page{display:grid;gap:var(--pdx-page-gap, 12px);grid-template-columns:minmax(0,1fr)}.pdx-page--canvas{align-items:start;grid-auto-flow:dense}.pdx-page-wrapper.editing .pdx-page--canvas{padding-block-start:var(--pdx-canvas-context-toolbar-safe-area, 22px);padding-block-end:22px;padding-inline:22px;box-sizing:border-box}.pdx-page-settings{position:sticky;top:8px;z-index:2;color:inherit;margin-bottom:6px}.pdx-widget{position:relative;background:var(--pfx-surface, transparent);border-radius:6px;min-width:0;min-height:0}.pdx-widget--interactive{cursor:pointer}.pdx-widget--selected:before{content:\"\";position:absolute;inset:0;border:1px dashed color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent);border-radius:14px;pointer-events:none;z-index:1;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent),0 8px 20px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent)}.pdx-widget--canvas{align-self:stretch;--pdx-resize-gradient-diagonal-se: linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-widget--canvas:after{content:\"\";position:absolute;inset:0;padding:2px;border-radius:14px;background:var(--pdx-active-resize-gradient);opacity:0;pointer-events:none;transition:opacity .14s ease,filter .14s ease;filter:saturate(1.02) drop-shadow(0 0 5px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude}.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{content:\"\";position:absolute;inset:0;border-radius:14px;pointer-events:none;z-index:1;transition:opacity .14s ease,box-shadow .14s ease,border-color .14s ease}.pdx-widget--canvas-blocked:before{border:1px solid color-mix(in srgb,var(--md-sys-color-error) 74%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 20%,transparent),0 10px 24px color-mix(in srgb,var(--md-sys-color-error) 12%,transparent)}.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:hover):after,.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:focus-visible):after,.pdx-page-wrapper:has(>.pdx-canvas-resize-alternative .pdx-canvas-resize:hover)>.pdx-page>.pdx-widget--canvas-selected:after,.pdx-page-wrapper:has(>.pdx-canvas-resize-alternative .pdx-canvas-resize:focus-visible)>.pdx-page>.pdx-widget--canvas-selected:after{opacity:.82}.pdx-canvas-resize-alternative>summary{display:list-item;width:fit-content;padding:12px;min-height:44px;box-sizing:border-box;cursor:pointer;font-size:12px;color:var(--md-sys-color-on-surface-variant)}[data-resize-feedback=valid]{--pdx-resize-feedback-color: #27864b}[data-resize-feedback=minimum]{--pdx-resize-feedback-color: #bc8a00}[data-resize-feedback=blocked]{--pdx-resize-feedback-color: var(--md-sys-color-error)}.pdx-widget--canvas[data-resize-feedback]:after{background:var(--pdx-resize-feedback-color);opacity:1;z-index:2}.pdx-resize-feedback{position:absolute;inset-inline:8px;bottom:8px;width:fit-content;max-width:calc(100% - 16px);box-sizing:border-box;display:flex;align-items:center;gap:6px;padding:4px 8px;border:2px solid var(--pdx-resize-feedback-color);border-radius:8px;color:var(--md-sys-color-on-surface);background:var(--md-sys-color-surface);font-size:12px;line-height:18px;pointer-events:none;z-index:3}.pdx-resize-feedback mat-icon{flex:0 0 18px;width:18px;height:18px;font-size:18px}.pdx-resize-feedback--floating{position:static;max-width:min(320px,calc(100vw - 24px));overflow-wrap:anywhere}.pdx-resize-feedback--floating strong{display:block}.pdx-canvas-edges{position:absolute;inset:0;pointer-events:none;z-index:2}.pdx-canvas-edge{position:absolute;display:grid;place-items:center;box-sizing:border-box;width:24px;height:24px;padding:0;border:0;background:transparent;color:var(--md-sys-color-primary);pointer-events:auto;touch-action:none;transform:translate(-50%,-50%)}.pdx-canvas-edge:after{content:\"\";width:8px;height:8px;border:2px solid currentColor;border-radius:2px;background:var(--md-sys-color-surface)}.pdx-canvas-edge:hover:after,.pdx-canvas-edge:focus-visible:after{background:var(--md-sys-color-primary-container)}.pdx-canvas-edge[data-canvas-edge=north-west]{left:0;top:0;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=north]{left:50%;top:0;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=north-east]{left:100%;top:0;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=east]{left:100%;top:50%;cursor:ew-resize}.pdx-canvas-edge[data-canvas-edge=south-east]{left:100%;top:100%;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=south]{left:50%;top:100%;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=south-west]{left:0;top:100%;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=west]{left:0;top:50%;cursor:ew-resize}.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.expanded)>.pdx-page>.pdx-widget>.pdx-canvas-edges,.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.fullscreen)>.pdx-page>.pdx-widget>.pdx-canvas-edges{display:none}.pdx-canvas-tools{container-type:inline-size;display:flex;flex-wrap:wrap;align-items:end;gap:8px 16px;padding:12px;color:var(--md-sys-color-on-surface);background:var(--md-sys-color-surface-container-low);border-radius:12px}.pdx-resize-popover{box-sizing:border-box;display:grid;gap:12px;width:248px;max-width:calc(100vw - 24px);padding:12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:12px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}.pdx-resize-popover header{display:flex;align-items:start;gap:8px}.pdx-resize-popover header div{display:grid;gap:4px;flex:1;min-width:0}.pdx-resize-popover strong{font-size:13px}.pdx-resize-popover header span{font-size:12px;overflow-wrap:anywhere;color:var(--md-sys-color-on-surface-variant)}.pdx-resize-popover header button{flex:0 0 44px;width:44px;height:44px}.pdx-resize-popover .pdx-canvas-tools-directions{grid-template-columns:repeat(3,44px);justify-content:space-between}.pdx-resize-popover--gesturing{background:transparent;border-color:transparent;pointer-events:none}.pdx-resize-popover--gesturing header,.pdx-resize-popover--gesturing .pdx-canvas-tools-hint,.pdx-resize-popover--gesturing .pdx-canvas-resize{visibility:hidden}.pdx-resize-popover--gesturing .pdx-canvas-resize.pdx-resize-active-handle{visibility:visible;pointer-events:auto;background:var(--md-sys-color-surface-container-high)}.pdx-canvas-tools-target{display:grid;gap:4px;flex:1 1 220px;min-width:0;font-size:12px;font-weight:600}.pdx-canvas-tools-target select{box-sizing:border-box;width:100%;min-width:0;min-height:44px;padding:8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);font:inherit}.pdx-canvas-tools-directions{display:grid;grid-template-columns:repeat(4,44px);gap:4px;max-width:100%}@container (min-width: 650px){.pdx-canvas-tools-directions{grid-template-columns:repeat(8,44px)}}.pdx-canvas-tools-hint{flex-basis:100%;margin:0;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.expanded)>.pdx-canvas-resize-alternative,.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.fullscreen)>.pdx-canvas-resize-alternative{visibility:hidden}.pdx-canvas-resize{flex:0 0 44px;width:44px;height:44px;touch-action:none;cursor:grab}.pdx-canvas-resize:active{cursor:grabbing}.pdx-canvas-resize:focus-visible,.pdx-canvas-edge:focus-visible,.pdx-canvas-resize-alternative>summary:focus-visible,.pdx-canvas-tools-target select:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-snap-preview{position:relative;align-self:stretch;border-radius:12px;pointer-events:none;z-index:0;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent),color-mix(in srgb,var(--md-sys-color-tertiary) 12%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 42%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 55%,transparent);animation:pdx-snap-preview-pulse .48s ease-out infinite alternate}.pdx-canvas-snap-preview:before,.pdx-canvas-snap-preview:after{content:\"\";position:absolute;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary) 82%,var(--md-sys-color-tertiary) 18%);opacity:.72}.pdx-canvas-snap-preview:before{inset:0 auto 0 0;width:3px}.pdx-canvas-snap-preview:after{inset:0 0 auto;height:3px}.pdx-canvas-snap-preview--invalid{background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-error) 18%,transparent),color-mix(in srgb,var(--md-sys-color-error-container) 22%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 58%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 40%,transparent)}.pdx-canvas-snap-preview--invalid:before,.pdx-canvas-snap-preview--invalid:after{background:color-mix(in srgb,var(--md-sys-color-error) 86%,var(--md-sys-color-error-container) 14%)}@media(prefers-reduced-motion:reduce){.pdx-canvas-snap-preview{animation:none}.pdx-widget--canvas:after,.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{transition:none}}@media(forced-colors:active){.pdx-widget--canvas-selected:before{border:2px solid Highlight}.pdx-canvas-resize:focus-visible,.pdx-canvas-edge:focus-visible,.pdx-canvas-resize-alternative>summary:focus-visible,.pdx-canvas-tools-target select:focus-visible{outline-color:Highlight}}@keyframes pdx-snap-preview-pulse{0%{opacity:.72;transform:scale(.996)}to{opacity:1;transform:scale(1)}}.pdx-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pdx-group{display:grid;gap:12px;grid-column:1 / -1;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 76%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent)}.pdx-group--hero{padding:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 42%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-low) 86%,transparent))}.pdx-group--rail{align-self:start}.pdx-group-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.pdx-group-title{font-size:.95rem;font-weight:600;color:var(--md-sys-color-on-surface)}.pdx-group-content{display:grid;gap:12px}.pdx-group-content--stack{grid-template-columns:minmax(0,1fr)}.pdx-group-content--row{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.pdx-group-content--grid{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.pdx-group-tabs{display:grid;gap:12px}.pdx-tabs-header{display:flex;flex-wrap:wrap;gap:8px}.pdx-tab-chip{appearance:none;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-lowest);color:var(--md-sys-color-on-surface);border-radius:999px;padding:8px 12px;font:inherit;cursor:pointer}.pdx-tab-chip.active{border-color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 78%,transparent);color:var(--md-sys-color-on-primary-container)}.pdx-page-wrapper.editing .pdx-widget-settings{opacity:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i4$2.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "component", type: DynamicWidgetContextToolbarComponent, selector: "praxis-dynamic-widget-context-toolbar", inputs: ["showResize", "resizeLabel", "resizeControls", "resizeExpanded", "toolbarLabel", "contextLabel", "contextTooltip", "showAssistant", "assistantLabel", "assistantTooltip", "showComponentSettings", "componentSettingsBusy", "componentSettingsLabel", "componentSettingsTooltip", "showShellSettings", "shellSettingsLabel", "shellSettingsTooltip", "showRemove", "moreActionsLabel", "removeLabel"], outputs: ["resize", "assistant", "componentSettings", "shellSettings", "remove"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { kind: "component", type: WidgetShellComponent, selector: "praxis-widget-shell", inputs: ["shell", "context", "dragSurfaceEnabled", "dragSurfaceLabel"], outputs: ["action", "dragSurfacePointerDown", "dragSurfaceKeydown"] }] });
44649
+ `, isInline: true, styles: [":host{display:block;min-width:0}.pdx-page-wrapper{position:relative;display:block;background:var(--pdx-page-bg, transparent);color:var(--pdx-page-color, inherit)}.pdx-page{display:grid;gap:var(--pdx-page-gap, 12px);grid-template-columns:minmax(0,1fr)}.pdx-page--canvas{align-items:start;grid-auto-flow:dense}.pdx-page-wrapper.editing .pdx-page--canvas{padding-block-start:var(--pdx-canvas-context-toolbar-safe-area, 22px);padding-block-end:22px;padding-inline:22px;box-sizing:border-box}.pdx-page-settings{position:sticky;top:8px;z-index:2;color:inherit;margin-bottom:6px}.pdx-widget{position:relative;background:var(--pfx-surface, transparent);border-radius:6px;min-width:0;min-height:0}.pdx-widget--interactive{cursor:pointer}.pdx-widget--selected:before{content:\"\";position:absolute;inset:0;border:1px dashed color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent);border-radius:14px;pointer-events:none;z-index:1;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent),0 8px 20px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent)}.pdx-widget--canvas{align-self:stretch;--pdx-resize-gradient-diagonal-se: linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-widget--canvas:after{content:\"\";position:absolute;inset:0;padding:2px;border-radius:14px;background:var(--pdx-active-resize-gradient);opacity:0;pointer-events:none;transition:opacity .14s ease,filter .14s ease;filter:saturate(1.02) drop-shadow(0 0 5px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude}.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{content:\"\";position:absolute;inset:0;border-radius:14px;pointer-events:none;z-index:1;transition:opacity .14s ease,box-shadow .14s ease,border-color .14s ease}.pdx-widget--canvas-blocked:before{border:1px solid color-mix(in srgb,var(--md-sys-color-error) 74%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 20%,transparent),0 10px 24px color-mix(in srgb,var(--md-sys-color-error) 12%,transparent)}.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:hover):after,.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:focus-visible):after{opacity:.82}[data-resize-feedback=valid]{--pdx-resize-feedback-color: #27864b}[data-resize-feedback=minimum]{--pdx-resize-feedback-color: #bc8a00}[data-resize-feedback=blocked]{--pdx-resize-feedback-color: var(--md-sys-color-error)}.pdx-widget--canvas[data-resize-feedback]:after{background:var(--pdx-resize-feedback-color);opacity:1;z-index:2}.pdx-resize-feedback{position:absolute;inset-inline:8px;bottom:8px;width:fit-content;max-width:calc(100% - 16px);box-sizing:border-box;display:flex;align-items:center;gap:6px;padding:4px 8px;border:2px solid var(--pdx-resize-feedback-color);border-radius:8px;color:var(--md-sys-color-on-surface);background:var(--md-sys-color-surface);font-size:12px;line-height:18px;pointer-events:none;z-index:3}.pdx-resize-feedback mat-icon{flex:0 0 18px;width:18px;height:18px;font-size:18px}.pdx-resize-feedback--floating{position:static;max-width:min(320px,calc(100vw - 24px));overflow-wrap:anywhere}.pdx-resize-feedback--floating strong{display:block}.pdx-canvas-edges{position:absolute;inset:0;pointer-events:none;z-index:5}.pdx-canvas-edge{position:absolute;display:grid;place-items:center;box-sizing:border-box;width:24px;height:24px;padding:0;border:0;background:transparent;color:var(--md-sys-color-primary);pointer-events:auto;touch-action:none;transform:translate(-50%,-50%)}.pdx-canvas-edge:after{content:\"\";width:8px;height:8px;border:2px solid currentColor;border-radius:2px;background:var(--md-sys-color-surface)}.pdx-canvas-edge:hover:after,.pdx-canvas-edge:focus-visible:after{background:var(--md-sys-color-primary-container)}.pdx-canvas-edge[data-canvas-edge=north-west]{left:0;top:0;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=north]{left:50%;top:0;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=north-east]{left:100%;top:0;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=east]{left:100%;top:50%;cursor:ew-resize}.pdx-canvas-edge[data-canvas-edge=south-east]{left:100%;top:100%;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=south]{left:50%;top:100%;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=south-west]{left:0;top:100%;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=west]{left:0;top:50%;cursor:ew-resize}.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.expanded)>.pdx-page>.pdx-widget>.pdx-canvas-edges,.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.fullscreen)>.pdx-page>.pdx-widget>.pdx-canvas-edges{display:none}.pdx-widget--canvas:focus-visible,.pdx-canvas-edge:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-snap-preview{position:relative;align-self:stretch;border-radius:12px;pointer-events:none;z-index:0;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent),color-mix(in srgb,var(--md-sys-color-tertiary) 12%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 42%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 55%,transparent);animation:pdx-snap-preview-pulse .48s ease-out infinite alternate}.pdx-canvas-snap-preview:before,.pdx-canvas-snap-preview:after{content:\"\";position:absolute;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary) 82%,var(--md-sys-color-tertiary) 18%);opacity:.72}.pdx-canvas-snap-preview:before{inset:0 auto 0 0;width:3px}.pdx-canvas-snap-preview:after{inset:0 0 auto;height:3px}.pdx-canvas-snap-preview--invalid{background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-error) 18%,transparent),color-mix(in srgb,var(--md-sys-color-error-container) 22%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 58%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 40%,transparent)}.pdx-canvas-snap-preview--invalid:before,.pdx-canvas-snap-preview--invalid:after{background:color-mix(in srgb,var(--md-sys-color-error) 86%,var(--md-sys-color-error-container) 14%)}@media(prefers-reduced-motion:reduce){.pdx-canvas-snap-preview{animation:none}.pdx-widget--canvas:after,.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{transition:none}}@media(forced-colors:active){.pdx-widget--canvas-selected:before{border:2px solid Highlight}.pdx-widget--canvas:focus-visible,.pdx-canvas-edge:focus-visible{outline-color:Highlight}}@keyframes pdx-snap-preview-pulse{0%{opacity:.72;transform:scale(.996)}to{opacity:1;transform:scale(1)}}.pdx-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pdx-group{display:grid;gap:12px;grid-column:1 / -1;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 76%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent)}.pdx-group--hero{padding:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 42%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-low) 86%,transparent))}.pdx-group--rail{align-self:start}.pdx-group-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.pdx-group-title{font-size:.95rem;font-weight:600;color:var(--md-sys-color-on-surface)}.pdx-group-content{display:grid;gap:12px}.pdx-group-content--stack{grid-template-columns:minmax(0,1fr)}.pdx-group-content--row{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.pdx-group-content--grid{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.pdx-group-tabs{display:grid;gap:12px}.pdx-tabs-header{display:flex;flex-wrap:wrap;gap:8px}.pdx-tab-chip{appearance:none;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-lowest);color:var(--md-sys-color-on-surface);border-radius:999px;padding:8px 12px;font:inherit;cursor:pointer}.pdx-tab-chip.active{border-color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 78%,transparent);color:var(--md-sys-color-on-primary-container)}.pdx-page-wrapper.editing .pdx-widget-settings{opacity:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.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: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i4$1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i5$2.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: CanvasSizeEditorComponent, selector: "praxis-canvas-size-editor", inputs: ["columns", "hasUndo", "canUndo", "width", "height", "contentRows", "widgetLabel", "scopeLabel", "error"], outputs: ["undo", "preview", "apply", "cancel"] }, { kind: "component", type: DynamicWidgetContextToolbarComponent, selector: "praxis-dynamic-widget-context-toolbar", inputs: ["showSize", "sizeDisabled", "sizeLabel", "toolbarLabel", "contextLabel", "contextTooltip", "showAssistant", "assistantLabel", "assistantTooltip", "showComponentSettings", "componentSettingsBusy", "componentSettingsLabel", "componentSettingsTooltip", "showShellSettings", "shellSettingsLabel", "shellSettingsTooltip", "showRemove", "moreActionsLabel", "removeLabel"], outputs: ["size", "assistant", "componentSettings", "shellSettings", "remove"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { kind: "component", type: WidgetShellComponent, selector: "praxis-widget-shell", inputs: ["shell", "context", "dragSurfaceEnabled", "dragSurfaceLabel"], outputs: ["action", "dragSurfacePointerDown", "dragSurfaceKeydown"] }] });
44055
44650
  }
44056
44651
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicWidgetPageComponent, decorators: [{
44057
44652
  type: Component,
@@ -44064,6 +44659,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
44064
44659
  MatTooltipModule,
44065
44660
  PraxisIconButtonComponent,
44066
44661
  OverlayModule,
44662
+ A11yModule,
44663
+ CanvasSizeEditorComponent,
44067
44664
  DynamicWidgetContextToolbarComponent,
44068
44665
  DynamicWidgetLoaderDirective,
44069
44666
  WidgetShellComponent,
@@ -44088,80 +44685,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
44088
44685
  (click)="openPageSettings()"
44089
44686
  ></button>
44090
44687
  }
44091
- @if (canCustomizeCanvas() && isCanvasMode()) {
44092
- <details class="pdx-canvas-resize-alternative" data-testid="canvas-resize-alternative"
44093
- [attr.inert]="resizePopoverOrigin() && selectedCanvasWidget() ? '' : null">
44094
- <summary>{{ resizeAlternativeLabel() }}</summary>
44095
- <div class="pdx-canvas-tools" data-testid="canvas-resize-tools"
44096
- [attr.inert]="resizePopoverOrigin() && selectedCanvasWidget() ? '' : null"
44097
- [attr.data-resize-widget-key]="selectedCanvasWidget()?.key || null"
44098
- role="group" [attr.aria-label]="resizeWidgetLabel()">
44099
- <label class="pdx-canvas-tools-target">
44100
- <span>{{ resizeWidgetLabel() }}</span>
44101
- <select data-testid="canvas-resize-target"
44102
- [disabled]="canvasInteractionActive()"
44103
- (change)="selectCanvasResizeTarget($event)">
44104
- <option value="" disabled [selected]="!selectedCanvasWidget()">{{ resizeSelectLabel() }}</option>
44105
- @for (widget of widgets(); track widget.key) {
44106
- <option [value]="widget.key" [selected]="isWidgetSelected(widget.key)">{{ widgetContextLabel(widget) }}</option>
44107
- }
44108
- </select>
44109
- </label>
44110
- <div class="pdx-canvas-tools-directions">
44111
- @for (handle of canvasResizeHandles; track handle.id) {
44112
- <button class="pdx-canvas-resize" type="button"
44113
- [praxisIconButton]="'ms:' + handle.icon"
44114
- [attr.data-resize-handle]="handle.id"
44115
- [attr.aria-label]="resizeHandleLabel(handle.id)"
44116
- [matTooltip]="resizeHandleLabel(handle.id)"
44117
- [disabled]="!selectedCanvasWidget()"
44118
- (pointerdown)="onSelectedCanvasResizePointerDown(handle.id, $event)"
44119
- (keydown)="onSelectedCanvasResizeKeydown(handle.id, $event)">
44120
- </button>
44121
- }
44122
- </div>
44123
- <p class="pdx-canvas-tools-hint">{{ resizeHelpLabel() }}</p>
44124
- </div>
44125
- </details>
44126
- }
44127
- @if (resizePopoverOrigin(); as origin) {
44128
- @if (canCustomizeCanvas() && isCanvasMode() && selectedCanvasWidget(); as widget) {
44129
- <ng-template cdkConnectedOverlay #resizeOverlay="cdkConnectedOverlay"
44130
- [cdkConnectedOverlayOrigin]="origin"
44131
- [cdkConnectedOverlayOpen]="true"
44132
- [cdkConnectedOverlayPositions]="resizePopoverPositions"
44133
- [cdkConnectedOverlayPush]="true"
44134
- [cdkConnectedOverlayViewportMargin]="12"
44135
- [cdkConnectedOverlayHasBackdrop]="false"
44136
- (attach)="focusResizePopover(resizeOverlay.overlayRef.overlayElement)"
44137
- (detach)="closeResizePopover(false)"
44138
- (overlayOutsideClick)="onResizePopoverOutsideClick($event)"
44139
- (overlayKeydown)="onResizePopoverKeydown($event)">
44140
- <section class="pdx-resize-popover" data-testid="canvas-context-resize"
44141
- [class.pdx-resize-popover--gesturing]="!!contextualResizeHandle()"
44142
- role="region" [id]="resizePopoverId" [attr.aria-label]="resizeWidgetLabel()"
44143
- (pointerdown)="$event.stopPropagation()" (click)="$event.stopPropagation()">
44144
- <header>
44145
- <div><strong>{{ resizeWidgetLabel() }}</strong><span>{{ widgetContextLabel(widget) }}</span></div>
44146
- <button type="button" praxisIconButton="ms:close"
44147
- [attr.aria-label]="resizeCloseLabel()" [matTooltip]="resizeCloseLabel()"
44148
- (click)="closeResizePopover(true)"></button>
44149
- </header>
44150
- <div class="pdx-canvas-tools-directions">
44151
- @for (handle of contextualResizeHandles; track handle.id) {
44152
- <button class="pdx-canvas-resize" type="button"
44153
- [praxisIconButton]="'ms:' + handle.icon"
44154
- [attr.data-resize-handle]="handle.id"
44155
- [style.grid-area]="resizePopoverGridArea(handle.id)"
44156
- [class.pdx-resize-active-handle]="contextualResizeHandle() === handle.id"
44157
- [attr.aria-label]="resizeHandleLabel(handle.id)"
44158
- [matTooltip]="resizeHandleLabel(handle.id)"
44159
- [matTooltipDisabled]="!!contextualResizeHandle()"
44160
- (pointerdown)="onSelectedCanvasResizePointerDown(handle.id, $event)"
44161
- (keydown)="onSelectedCanvasResizeKeydown(handle.id, $event)"></button>
44162
- }
44163
- </div>
44164
- <p class="pdx-canvas-tools-hint">{{ resizeContextHelpLabel() }}</p>
44688
+ @if (sizeEditorOrigin(); as origin) {
44689
+ @if (sizeEditorSeed(); as seed) {
44690
+ <ng-template cdkConnectedOverlay #sizeOverlay="cdkConnectedOverlay"
44691
+ [cdkConnectedOverlayOrigin]="origin" [cdkConnectedOverlayOpen]="true"
44692
+ [cdkConnectedOverlayPositions]="sizeEditorPositions" [cdkConnectedOverlayPush]="true"
44693
+ [cdkConnectedOverlayViewportMargin]="16" [cdkConnectedOverlayHasBackdrop]="true"
44694
+ cdkConnectedOverlayBackdropClass="cdk-overlay-transparent-backdrop"
44695
+ (backdropClick)="closeSizeEditor(true)" (overlayKeydown)="onSizeEditorKeydown($event)"
44696
+ (attach)="focusSizeEditor(sizeOverlay.overlayRef)">
44697
+ <section role="dialog" aria-modal="true" [attr.aria-label]="sizeEditorLabel()"
44698
+ cdkTrapFocus data-testid="canvas-size-editor">
44699
+ <praxis-canvas-size-editor [width]="seed.item.colSpan" [height]="seed.height"
44700
+ [contentRows]="seed.contentRows" [widgetLabel]="sizeEditorWidgetLabel()"
44701
+ [columns]="seed.columns" [hasUndo]="hasCanvasResizeUndo(seed.key)"
44702
+ [canUndo]="canUndoCanvasResize(seed.key)" (undo)="undoCanvasResize(seed.key)"
44703
+ [scopeLabel]="sizeEditorScopeLabel()" [error]="sizeEditorError()"
44704
+ (preview)="previewCanvasSize($event)" (apply)="applyCanvasSize($event)"
44705
+ (cancel)="closeSizeEditor(true)" />
44165
44706
  </section>
44166
44707
  </ng-template>
44167
44708
  }
@@ -44201,6 +44742,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
44201
44742
  <div
44202
44743
  class="pdx-widget pdx-widget--canvas"
44203
44744
  [attr.data-widget-key]="w.key"
44745
+ [attr.tabindex]="canCustomizeCanvas() ? 0 : null"
44746
+ [attr.role]="canCustomizeCanvas() ? 'group' : null"
44747
+ [attr.aria-label]="canCustomizeCanvas() ? canvasSelectionLabel(w.key) : null"
44748
+ (keydown)="onCanvasSelectionKeydown(w.key, $event)"
44204
44749
  [attr.data-resize-feedback]="resizeFeedback(w.key)"
44205
44750
  [class.pdx-widget--interactive]="canSelectWidgets()"
44206
44751
  [class.pdx-widget--selected]="
@@ -44256,7 +44801,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
44256
44801
  }
44257
44802
  @if (canShowCanvasEdges(w.key)) {
44258
44803
  <div class="pdx-canvas-edges" data-testid="canvas-edge-controls"
44259
- [attr.inert]="resizePopoverOrigin() ? '' : null"
44260
44804
  role="group" [attr.aria-label]="resizeWidgetLabel()">
44261
44805
  @for (handle of canvasResizeHandles; track handle.id) {
44262
44806
  <button type="button" class="pdx-canvas-edge"
@@ -44272,11 +44816,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
44272
44816
  }
44273
44817
  @if (shouldRenderWidgetContextOverlay(w)) {
44274
44818
  <praxis-dynamic-widget-context-toolbar
44275
- [showResize]="canCustomizeCanvas()"
44276
- [resizeLabel]="resizeWidgetLabel()"
44277
- [resizeControls]="resizePopoverId"
44278
- [resizeExpanded]="!!resizePopoverOrigin() && isWidgetSelected(w.key)"
44279
- (resize)="toggleResizePopover(w.key)"
44819
+ [showSize]="canCustomizeCanvas()"
44820
+ [sizeDisabled]="isCanvasSizeLocked(w.key)"
44821
+ [sizeLabel]="sizeEditorLabel()"
44822
+ (size)="openSizeEditor(w.key)"
44280
44823
  [toolbarLabel]="widgetContextToolbarLabel(w.key)"
44281
44824
  [contextLabel]="widgetContextLabel(w)"
44282
44825
  [contextTooltip]="widgetContextTooltip(w)"
@@ -44578,7 +45121,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
44578
45121
  </div>
44579
45122
  }
44580
45123
  </div>
44581
- `, styles: [":host{display:block;min-width:0}.pdx-page-wrapper{position:relative;display:block;background:var(--pdx-page-bg, transparent);color:var(--pdx-page-color, inherit)}.pdx-page{display:grid;gap:var(--pdx-page-gap, 12px);grid-template-columns:minmax(0,1fr)}.pdx-page--canvas{align-items:start;grid-auto-flow:dense}.pdx-page-wrapper.editing .pdx-page--canvas{padding-block-start:var(--pdx-canvas-context-toolbar-safe-area, 22px);padding-block-end:22px;padding-inline:22px;box-sizing:border-box}.pdx-page-settings{position:sticky;top:8px;z-index:2;color:inherit;margin-bottom:6px}.pdx-widget{position:relative;background:var(--pfx-surface, transparent);border-radius:6px;min-width:0;min-height:0}.pdx-widget--interactive{cursor:pointer}.pdx-widget--selected:before{content:\"\";position:absolute;inset:0;border:1px dashed color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent);border-radius:14px;pointer-events:none;z-index:1;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent),0 8px 20px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent)}.pdx-widget--canvas{align-self:stretch;--pdx-resize-gradient-diagonal-se: linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-widget--canvas:after{content:\"\";position:absolute;inset:0;padding:2px;border-radius:14px;background:var(--pdx-active-resize-gradient);opacity:0;pointer-events:none;transition:opacity .14s ease,filter .14s ease;filter:saturate(1.02) drop-shadow(0 0 5px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude}.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{content:\"\";position:absolute;inset:0;border-radius:14px;pointer-events:none;z-index:1;transition:opacity .14s ease,box-shadow .14s ease,border-color .14s ease}.pdx-widget--canvas-blocked:before{border:1px solid color-mix(in srgb,var(--md-sys-color-error) 74%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 20%,transparent),0 10px 24px color-mix(in srgb,var(--md-sys-color-error) 12%,transparent)}.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:hover):after,.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:focus-visible):after,.pdx-page-wrapper:has(>.pdx-canvas-resize-alternative .pdx-canvas-resize:hover)>.pdx-page>.pdx-widget--canvas-selected:after,.pdx-page-wrapper:has(>.pdx-canvas-resize-alternative .pdx-canvas-resize:focus-visible)>.pdx-page>.pdx-widget--canvas-selected:after{opacity:.82}.pdx-canvas-resize-alternative>summary{display:list-item;width:fit-content;padding:12px;min-height:44px;box-sizing:border-box;cursor:pointer;font-size:12px;color:var(--md-sys-color-on-surface-variant)}[data-resize-feedback=valid]{--pdx-resize-feedback-color: #27864b}[data-resize-feedback=minimum]{--pdx-resize-feedback-color: #bc8a00}[data-resize-feedback=blocked]{--pdx-resize-feedback-color: var(--md-sys-color-error)}.pdx-widget--canvas[data-resize-feedback]:after{background:var(--pdx-resize-feedback-color);opacity:1;z-index:2}.pdx-resize-feedback{position:absolute;inset-inline:8px;bottom:8px;width:fit-content;max-width:calc(100% - 16px);box-sizing:border-box;display:flex;align-items:center;gap:6px;padding:4px 8px;border:2px solid var(--pdx-resize-feedback-color);border-radius:8px;color:var(--md-sys-color-on-surface);background:var(--md-sys-color-surface);font-size:12px;line-height:18px;pointer-events:none;z-index:3}.pdx-resize-feedback mat-icon{flex:0 0 18px;width:18px;height:18px;font-size:18px}.pdx-resize-feedback--floating{position:static;max-width:min(320px,calc(100vw - 24px));overflow-wrap:anywhere}.pdx-resize-feedback--floating strong{display:block}.pdx-canvas-edges{position:absolute;inset:0;pointer-events:none;z-index:2}.pdx-canvas-edge{position:absolute;display:grid;place-items:center;box-sizing:border-box;width:24px;height:24px;padding:0;border:0;background:transparent;color:var(--md-sys-color-primary);pointer-events:auto;touch-action:none;transform:translate(-50%,-50%)}.pdx-canvas-edge:after{content:\"\";width:8px;height:8px;border:2px solid currentColor;border-radius:2px;background:var(--md-sys-color-surface)}.pdx-canvas-edge:hover:after,.pdx-canvas-edge:focus-visible:after{background:var(--md-sys-color-primary-container)}.pdx-canvas-edge[data-canvas-edge=north-west]{left:0;top:0;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=north]{left:50%;top:0;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=north-east]{left:100%;top:0;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=east]{left:100%;top:50%;cursor:ew-resize}.pdx-canvas-edge[data-canvas-edge=south-east]{left:100%;top:100%;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=south]{left:50%;top:100%;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=south-west]{left:0;top:100%;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=west]{left:0;top:50%;cursor:ew-resize}.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.expanded)>.pdx-page>.pdx-widget>.pdx-canvas-edges,.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.fullscreen)>.pdx-page>.pdx-widget>.pdx-canvas-edges{display:none}.pdx-canvas-tools{container-type:inline-size;display:flex;flex-wrap:wrap;align-items:end;gap:8px 16px;padding:12px;color:var(--md-sys-color-on-surface);background:var(--md-sys-color-surface-container-low);border-radius:12px}.pdx-resize-popover{box-sizing:border-box;display:grid;gap:12px;width:248px;max-width:calc(100vw - 24px);padding:12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:12px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}.pdx-resize-popover header{display:flex;align-items:start;gap:8px}.pdx-resize-popover header div{display:grid;gap:4px;flex:1;min-width:0}.pdx-resize-popover strong{font-size:13px}.pdx-resize-popover header span{font-size:12px;overflow-wrap:anywhere;color:var(--md-sys-color-on-surface-variant)}.pdx-resize-popover header button{flex:0 0 44px;width:44px;height:44px}.pdx-resize-popover .pdx-canvas-tools-directions{grid-template-columns:repeat(3,44px);justify-content:space-between}.pdx-resize-popover--gesturing{background:transparent;border-color:transparent;pointer-events:none}.pdx-resize-popover--gesturing header,.pdx-resize-popover--gesturing .pdx-canvas-tools-hint,.pdx-resize-popover--gesturing .pdx-canvas-resize{visibility:hidden}.pdx-resize-popover--gesturing .pdx-canvas-resize.pdx-resize-active-handle{visibility:visible;pointer-events:auto;background:var(--md-sys-color-surface-container-high)}.pdx-canvas-tools-target{display:grid;gap:4px;flex:1 1 220px;min-width:0;font-size:12px;font-weight:600}.pdx-canvas-tools-target select{box-sizing:border-box;width:100%;min-width:0;min-height:44px;padding:8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);font:inherit}.pdx-canvas-tools-directions{display:grid;grid-template-columns:repeat(4,44px);gap:4px;max-width:100%}@container (min-width: 650px){.pdx-canvas-tools-directions{grid-template-columns:repeat(8,44px)}}.pdx-canvas-tools-hint{flex-basis:100%;margin:0;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.expanded)>.pdx-canvas-resize-alternative,.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.fullscreen)>.pdx-canvas-resize-alternative{visibility:hidden}.pdx-canvas-resize{flex:0 0 44px;width:44px;height:44px;touch-action:none;cursor:grab}.pdx-canvas-resize:active{cursor:grabbing}.pdx-canvas-resize:focus-visible,.pdx-canvas-edge:focus-visible,.pdx-canvas-resize-alternative>summary:focus-visible,.pdx-canvas-tools-target select:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-snap-preview{position:relative;align-self:stretch;border-radius:12px;pointer-events:none;z-index:0;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent),color-mix(in srgb,var(--md-sys-color-tertiary) 12%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 42%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 55%,transparent);animation:pdx-snap-preview-pulse .48s ease-out infinite alternate}.pdx-canvas-snap-preview:before,.pdx-canvas-snap-preview:after{content:\"\";position:absolute;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary) 82%,var(--md-sys-color-tertiary) 18%);opacity:.72}.pdx-canvas-snap-preview:before{inset:0 auto 0 0;width:3px}.pdx-canvas-snap-preview:after{inset:0 0 auto;height:3px}.pdx-canvas-snap-preview--invalid{background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-error) 18%,transparent),color-mix(in srgb,var(--md-sys-color-error-container) 22%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 58%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 40%,transparent)}.pdx-canvas-snap-preview--invalid:before,.pdx-canvas-snap-preview--invalid:after{background:color-mix(in srgb,var(--md-sys-color-error) 86%,var(--md-sys-color-error-container) 14%)}@media(prefers-reduced-motion:reduce){.pdx-canvas-snap-preview{animation:none}.pdx-widget--canvas:after,.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{transition:none}}@media(forced-colors:active){.pdx-widget--canvas-selected:before{border:2px solid Highlight}.pdx-canvas-resize:focus-visible,.pdx-canvas-edge:focus-visible,.pdx-canvas-resize-alternative>summary:focus-visible,.pdx-canvas-tools-target select:focus-visible{outline-color:Highlight}}@keyframes pdx-snap-preview-pulse{0%{opacity:.72;transform:scale(.996)}to{opacity:1;transform:scale(1)}}.pdx-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pdx-group{display:grid;gap:12px;grid-column:1 / -1;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 76%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent)}.pdx-group--hero{padding:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 42%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-low) 86%,transparent))}.pdx-group--rail{align-self:start}.pdx-group-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.pdx-group-title{font-size:.95rem;font-weight:600;color:var(--md-sys-color-on-surface)}.pdx-group-content{display:grid;gap:12px}.pdx-group-content--stack{grid-template-columns:minmax(0,1fr)}.pdx-group-content--row{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.pdx-group-content--grid{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.pdx-group-tabs{display:grid;gap:12px}.pdx-tabs-header{display:flex;flex-wrap:wrap;gap:8px}.pdx-tab-chip{appearance:none;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-lowest);color:var(--md-sys-color-on-surface);border-radius:999px;padding:8px 12px;font:inherit;cursor:pointer}.pdx-tab-chip.active{border-color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 78%,transparent);color:var(--md-sys-color-on-primary-container)}.pdx-page-wrapper.editing .pdx-widget-settings{opacity:1}\n"] }]
45124
+ `, styles: [":host{display:block;min-width:0}.pdx-page-wrapper{position:relative;display:block;background:var(--pdx-page-bg, transparent);color:var(--pdx-page-color, inherit)}.pdx-page{display:grid;gap:var(--pdx-page-gap, 12px);grid-template-columns:minmax(0,1fr)}.pdx-page--canvas{align-items:start;grid-auto-flow:dense}.pdx-page-wrapper.editing .pdx-page--canvas{padding-block-start:var(--pdx-canvas-context-toolbar-safe-area, 22px);padding-block-end:22px;padding-inline:22px;box-sizing:border-box}.pdx-page-settings{position:sticky;top:8px;z-index:2;color:inherit;margin-bottom:6px}.pdx-widget{position:relative;background:var(--pfx-surface, transparent);border-radius:6px;min-width:0;min-height:0}.pdx-widget--interactive{cursor:pointer}.pdx-widget--selected:before{content:\"\";position:absolute;inset:0;border:1px dashed color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent);border-radius:14px;pointer-events:none;z-index:1;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent),0 8px 20px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent)}.pdx-widget--canvas{align-self:stretch;--pdx-resize-gradient-diagonal-se: linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-widget--canvas:after{content:\"\";position:absolute;inset:0;padding:2px;border-radius:14px;background:var(--pdx-active-resize-gradient);opacity:0;pointer-events:none;transition:opacity .14s ease,filter .14s ease;filter:saturate(1.02) drop-shadow(0 0 5px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude}.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{content:\"\";position:absolute;inset:0;border-radius:14px;pointer-events:none;z-index:1;transition:opacity .14s ease,box-shadow .14s ease,border-color .14s ease}.pdx-widget--canvas-blocked:before{border:1px solid color-mix(in srgb,var(--md-sys-color-error) 74%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 20%,transparent),0 10px 24px color-mix(in srgb,var(--md-sys-color-error) 12%,transparent)}.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:hover):after,.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:focus-visible):after{opacity:.82}[data-resize-feedback=valid]{--pdx-resize-feedback-color: #27864b}[data-resize-feedback=minimum]{--pdx-resize-feedback-color: #bc8a00}[data-resize-feedback=blocked]{--pdx-resize-feedback-color: var(--md-sys-color-error)}.pdx-widget--canvas[data-resize-feedback]:after{background:var(--pdx-resize-feedback-color);opacity:1;z-index:2}.pdx-resize-feedback{position:absolute;inset-inline:8px;bottom:8px;width:fit-content;max-width:calc(100% - 16px);box-sizing:border-box;display:flex;align-items:center;gap:6px;padding:4px 8px;border:2px solid var(--pdx-resize-feedback-color);border-radius:8px;color:var(--md-sys-color-on-surface);background:var(--md-sys-color-surface);font-size:12px;line-height:18px;pointer-events:none;z-index:3}.pdx-resize-feedback mat-icon{flex:0 0 18px;width:18px;height:18px;font-size:18px}.pdx-resize-feedback--floating{position:static;max-width:min(320px,calc(100vw - 24px));overflow-wrap:anywhere}.pdx-resize-feedback--floating strong{display:block}.pdx-canvas-edges{position:absolute;inset:0;pointer-events:none;z-index:5}.pdx-canvas-edge{position:absolute;display:grid;place-items:center;box-sizing:border-box;width:24px;height:24px;padding:0;border:0;background:transparent;color:var(--md-sys-color-primary);pointer-events:auto;touch-action:none;transform:translate(-50%,-50%)}.pdx-canvas-edge:after{content:\"\";width:8px;height:8px;border:2px solid currentColor;border-radius:2px;background:var(--md-sys-color-surface)}.pdx-canvas-edge:hover:after,.pdx-canvas-edge:focus-visible:after{background:var(--md-sys-color-primary-container)}.pdx-canvas-edge[data-canvas-edge=north-west]{left:0;top:0;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=north]{left:50%;top:0;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=north-east]{left:100%;top:0;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=east]{left:100%;top:50%;cursor:ew-resize}.pdx-canvas-edge[data-canvas-edge=south-east]{left:100%;top:100%;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=south]{left:50%;top:100%;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=south-west]{left:0;top:100%;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=west]{left:0;top:50%;cursor:ew-resize}.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.expanded)>.pdx-page>.pdx-widget>.pdx-canvas-edges,.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.fullscreen)>.pdx-page>.pdx-widget>.pdx-canvas-edges{display:none}.pdx-widget--canvas:focus-visible,.pdx-canvas-edge:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-snap-preview{position:relative;align-self:stretch;border-radius:12px;pointer-events:none;z-index:0;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent),color-mix(in srgb,var(--md-sys-color-tertiary) 12%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 42%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 55%,transparent);animation:pdx-snap-preview-pulse .48s ease-out infinite alternate}.pdx-canvas-snap-preview:before,.pdx-canvas-snap-preview:after{content:\"\";position:absolute;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary) 82%,var(--md-sys-color-tertiary) 18%);opacity:.72}.pdx-canvas-snap-preview:before{inset:0 auto 0 0;width:3px}.pdx-canvas-snap-preview:after{inset:0 0 auto;height:3px}.pdx-canvas-snap-preview--invalid{background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-error) 18%,transparent),color-mix(in srgb,var(--md-sys-color-error-container) 22%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 58%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 40%,transparent)}.pdx-canvas-snap-preview--invalid:before,.pdx-canvas-snap-preview--invalid:after{background:color-mix(in srgb,var(--md-sys-color-error) 86%,var(--md-sys-color-error-container) 14%)}@media(prefers-reduced-motion:reduce){.pdx-canvas-snap-preview{animation:none}.pdx-widget--canvas:after,.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{transition:none}}@media(forced-colors:active){.pdx-widget--canvas-selected:before{border:2px solid Highlight}.pdx-widget--canvas:focus-visible,.pdx-canvas-edge:focus-visible{outline-color:Highlight}}@keyframes pdx-snap-preview-pulse{0%{opacity:.72;transform:scale(.996)}to{opacity:1;transform:scale(1)}}.pdx-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pdx-group{display:grid;gap:12px;grid-column:1 / -1;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 76%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent)}.pdx-group--hero{padding:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 42%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-low) 86%,transparent))}.pdx-group--rail{align-self:start}.pdx-group-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.pdx-group-title{font-size:.95rem;font-weight:600;color:var(--md-sys-color-on-surface)}.pdx-group-content{display:grid;gap:12px}.pdx-group-content--stack{grid-template-columns:minmax(0,1fr)}.pdx-group-content--row{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.pdx-group-content--grid{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.pdx-group-tabs{display:grid;gap:12px}.pdx-tabs-header{display:flex;flex-wrap:wrap;gap:8px}.pdx-tab-chip{appearance:none;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-lowest);color:var(--md-sys-color-on-surface);border-radius:999px;padding:8px 12px;font:inherit;cursor:pointer}.pdx-tab-chip.active{border-color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 78%,transparent);color:var(--md-sys-color-on-primary-container)}.pdx-page-wrapper.editing .pdx-widget-settings{opacity:1}\n"] }]
44582
45125
  }], ctorParameters: () => [], propDecorators: { pageCanvasHost: [{
44583
45126
  type: ViewChild,
44584
45127
  args: ['pageCanvasHost']
@@ -45683,7 +46226,7 @@ class PraxisRelatedResourceOutletComponent {
45683
46226
  </div>
45684
46227
  }
45685
46228
  </section>
45686
- `, isInline: true, styles: [":host{display:block;min-width:0}.pdx-related-outlet{display:block;min-width:0;color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet__state{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--pdx-related-outlet-gap, 12px);min-height:var(--pdx-related-outlet-min-height, 64px);padding:var(--pdx-related-outlet-padding, 12px);border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .16));border-radius:var(--pdx-related-outlet-radius, 8px);background:var(--md-sys-color-surface-container-low, var(--md-sys-color-surface, transparent))}.pdx-related-outlet--compact .pdx-related-outlet__state{min-height:var(--pdx-related-outlet-compact-min-height, 48px);padding:var(--pdx-related-outlet-compact-padding, 8px 10px)}.pdx-related-outlet__state--ready{border-color:var(--md-sys-color-primary, currentColor)}.pdx-related-outlet__icon{display:inline-grid;place-items:center;width:32px;height:32px;color:var(--md-sys-color-primary, currentColor)}.pdx-related-outlet__state--busy .pdx-related-outlet__icon{color:var(--md-sys-color-secondary, currentColor)}.pdx-related-outlet__copy{display:grid;gap:2px;min-width:0}.pdx-related-outlet__copy h3,.pdx-related-outlet__copy p{margin:0}.pdx-related-outlet__copy h3{font:var(--md-sys-typescale-title-small, 600 .95rem/1.25rem system-ui);color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet__copy p{font:var(--md-sys-typescale-body-small, 400 .82rem/1.15rem system-ui);color:var(--md-sys-color-on-surface-variant, currentColor)}@media(max-width:600px){.pdx-related-outlet__state{grid-template-columns:auto minmax(0,1fr)}.pdx-related-outlet__state button{grid-column:1 / -1;justify-self:start}}\n"], dependencies: [{ kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { 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: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] });
46229
+ `, isInline: true, styles: [":host{display:block;min-width:0}.pdx-related-outlet{display:block;min-width:0;color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet__state{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--pdx-related-outlet-gap, 12px);min-height:var(--pdx-related-outlet-min-height, 64px);padding:var(--pdx-related-outlet-padding, 12px);border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .16));border-radius:var(--pdx-related-outlet-radius, 8px);background:var(--md-sys-color-surface-container-low, var(--md-sys-color-surface, transparent))}.pdx-related-outlet--compact .pdx-related-outlet__state{min-height:var(--pdx-related-outlet-compact-min-height, 48px);padding:var(--pdx-related-outlet-compact-padding, 8px 10px)}.pdx-related-outlet__state--ready{border-color:var(--md-sys-color-primary, currentColor)}.pdx-related-outlet__icon{display:inline-grid;place-items:center;width:32px;height:32px;color:var(--md-sys-color-primary, currentColor)}.pdx-related-outlet__state--busy .pdx-related-outlet__icon{color:var(--md-sys-color-secondary, currentColor)}.pdx-related-outlet__copy{display:grid;gap:2px;min-width:0}.pdx-related-outlet__copy h3,.pdx-related-outlet__copy p{margin:0}.pdx-related-outlet__copy h3{font:var(--md-sys-typescale-title-small, 600 .95rem/1.25rem system-ui);color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet__copy p{font:var(--md-sys-typescale-body-small, 400 .82rem/1.15rem system-ui);color:var(--md-sys-color-on-surface-variant, currentColor)}@media(max-width:600px){.pdx-related-outlet__state{grid-template-columns:auto minmax(0,1fr)}.pdx-related-outlet__state button{grid-column:1 / -1;justify-self:start}}\n"], dependencies: [{ kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { 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: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] });
45687
46230
  }
45688
46231
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisRelatedResourceOutletComponent, decorators: [{
45689
46232
  type: Component,
@@ -45946,7 +46489,7 @@ class PraxisIconPickerComponent {
45946
46489
  }
45947
46490
  </div>
45948
46491
  </div>
45949
- `, isInline: true, styles: [".pip-root{display:flex;flex-direction:column;min-width:340px;max-width:760px;max-height:80vh;overflow:hidden;padding:16px;color:var(--md-sys-color-on-surface)}.pip-head{display:flex;gap:12px;align-items:center;margin-bottom:12px;flex-wrap:wrap}.pip-search{flex:1;min-width:180px}.pip-spacer{flex:1}.pip-body{flex:1;overflow:auto;display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:10px;padding:4px}.pip-item{display:flex;gap:10px;align-items:center;justify-content:flex-start;padding:10px;border:1px solid var(--md-sys-color-outline-variant);border-radius:10px;background:var(--md-sys-color-surface);color:inherit;cursor:pointer;transition:background-color .18s ease,border-color .18s ease,box-shadow .18s ease}.pip-item:hover{background:var(--md-sys-color-surface-container)}.pip-item:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pip-item.selected{border-color:var(--md-sys-color-primary);box-shadow:0 0 0 2px var(--md-sys-color-primary)}.pip-name{font-size:12px;color:var(--md-sys-color-on-surface-variant);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.pip-hint{font-size:12px;color:var(--md-sys-color-on-surface-variant);margin:-6px 0 8px}.pip-stats{display:flex;justify-content:space-between;gap:8px;font-size:12px;color:var(--md-sys-color-on-surface-variant);margin-bottom:8px}.pip-shortcut{opacity:.9}.pip-empty{padding:12px;border:1px dashed var(--md-sys-color-outline-variant);border-radius:10px;color:var(--md-sys-color-on-surface-variant);background:var(--md-sys-color-surface-container);margin-top:8px}.pip-footer{display:flex;gap:12px;align-items:center;margin-top:10px}.pip-typed{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:12px;color:var(--md-sys-color-on-surface)}.pip-family{display:flex;align-items:center}.pip-family .mat-mdc-chip-listbox{min-width:260px}.pip-root .mat-icon{font-family:Material Icons,Material Symbols Outlined,Material Symbols Rounded,Material Symbols Sharp!important;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24;color:currentColor}.material-symbols-outlined{font-family:Material Symbols Outlined;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:\"liga\";-webkit-font-smoothing:antialiased;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24}.material-symbols-rounded{font-family:Material Symbols Rounded;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:\"liga\";-webkit-font-smoothing:antialiased;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24}.material-symbols-sharp{font-family:Material Symbols Sharp;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:\"liga\";-webkit-font-smoothing:antialiased;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: i1$1.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: "ngmodule", type: MatChipsModule }, { kind: "component", type: i8.MatChipListbox, selector: "mat-chip-listbox", inputs: ["multiple", "aria-orientation", "selectable", "compareWith", "required", "hideSingleSelectionIndicator", "value"], outputs: ["change"] }, { kind: "component", type: i8.MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
46492
+ `, isInline: true, styles: [".pip-root{display:flex;flex-direction:column;min-width:340px;max-width:760px;max-height:80vh;overflow:hidden;padding:16px;color:var(--md-sys-color-on-surface)}.pip-head{display:flex;gap:12px;align-items:center;margin-bottom:12px;flex-wrap:wrap}.pip-search{flex:1;min-width:180px}.pip-spacer{flex:1}.pip-body{flex:1;overflow:auto;display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:10px;padding:4px}.pip-item{display:flex;gap:10px;align-items:center;justify-content:flex-start;padding:10px;border:1px solid var(--md-sys-color-outline-variant);border-radius:10px;background:var(--md-sys-color-surface);color:inherit;cursor:pointer;transition:background-color .18s ease,border-color .18s ease,box-shadow .18s ease}.pip-item:hover{background:var(--md-sys-color-surface-container)}.pip-item:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pip-item.selected{border-color:var(--md-sys-color-primary);box-shadow:0 0 0 2px var(--md-sys-color-primary)}.pip-name{font-size:12px;color:var(--md-sys-color-on-surface-variant);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.pip-hint{font-size:12px;color:var(--md-sys-color-on-surface-variant);margin:-6px 0 8px}.pip-stats{display:flex;justify-content:space-between;gap:8px;font-size:12px;color:var(--md-sys-color-on-surface-variant);margin-bottom:8px}.pip-shortcut{opacity:.9}.pip-empty{padding:12px;border:1px dashed var(--md-sys-color-outline-variant);border-radius:10px;color:var(--md-sys-color-on-surface-variant);background:var(--md-sys-color-surface-container);margin-top:8px}.pip-footer{display:flex;gap:12px;align-items:center;margin-top:10px}.pip-typed{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:12px;color:var(--md-sys-color-on-surface)}.pip-family{display:flex;align-items:center}.pip-family .mat-mdc-chip-listbox{min-width:260px}.pip-root .mat-icon{font-family:Material Icons,Material Symbols Outlined,Material Symbols Rounded,Material Symbols Sharp!important;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24;color:currentColor}.material-symbols-outlined{font-family:Material Symbols Outlined;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:\"liga\";-webkit-font-smoothing:antialiased;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24}.material-symbols-rounded{font-family:Material Symbols Rounded;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:\"liga\";-webkit-font-smoothing:antialiased;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24}.material-symbols-sharp{font-family:Material Symbols Sharp;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:\"liga\";-webkit-font-smoothing:antialiased;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: i1$1.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: "ngmodule", type: MatChipsModule }, { kind: "component", type: i8.MatChipListbox, selector: "mat-chip-listbox", inputs: ["multiple", "aria-orientation", "selectable", "compareWith", "required", "hideSingleSelectionIndicator", "value"], outputs: ["change"] }, { kind: "component", type: i8.MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
45950
46493
  }
45951
46494
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisIconPickerComponent, decorators: [{
45952
46495
  type: Component,
@@ -46568,7 +47111,7 @@ class PraxisRelatedResourceOutletConfigEditorComponent {
46568
47111
  </span>
46569
47112
  </aside>
46570
47113
  </form>
46571
- `, isInline: true, styles: [":host{display:block;color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet-editor{display:grid;gap:var(--pdx-spacing-lg, 24px);padding:var(--pdx-spacing-md, 16px)}.pdx-related-outlet-editor__header,.pdx-related-outlet-editor__boundary{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;gap:var(--pdx-spacing-sm, 12px)}.pdx-related-outlet-editor__header-icon{display:inline-grid;place-items:center;width:40px;height:40px;border-radius:var(--md-sys-shape-corner-medium, 12px);color:var(--md-sys-color-primary, currentColor);background:var(--md-sys-color-primary-container, transparent)}.pdx-related-outlet-editor__header strong,.pdx-related-outlet-editor__boundary strong,.pdx-related-outlet-editor__header small,.pdx-related-outlet-editor__boundary small{display:block}.pdx-related-outlet-editor__header strong{font:var(--md-sys-typescale-title-medium, 600 1rem/1.4 system-ui)}.pdx-related-outlet-editor__header small,.pdx-related-outlet-editor__boundary small,.pdx-related-outlet-editor__section-heading p{color:var(--md-sys-color-on-surface-variant, currentColor)}.pdx-related-outlet-editor__section{display:grid;gap:var(--pdx-spacing-md, 16px)}.pdx-related-outlet-editor__section-heading h3,.pdx-related-outlet-editor__section-heading p{margin:0}.pdx-related-outlet-editor__section-heading h3{font:var(--md-sys-typescale-title-small, 600 .95rem/1.3 system-ui)}.pdx-related-outlet-editor__section-heading p{margin-top:4px;font:var(--md-sys-typescale-body-small, 400 .82rem/1.35 system-ui)}.pdx-related-outlet-editor__fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--pdx-spacing-sm, 12px)}.pdx-related-outlet-editor__wide{grid-column:1 / -1}.pdx-related-outlet-editor__choice-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--pdx-spacing-md, 16px)}.pdx-related-outlet-editor__appearance-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr));gap:var(--pdx-spacing-sm, 12px)}.pdx-related-outlet-editor__appearance-cluster{display:grid;align-content:start;gap:var(--pdx-spacing-sm, 12px);min-width:0}.pdx-related-outlet-editor__appearance-cluster--wide{grid-column:1 / -1}.pdx-related-outlet-editor__appearance-cluster mat-button-toggle-group{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,132px),1fr))}.pdx-related-outlet-editor__appearance-cluster mat-button-toggle{min-height:44px}.pdx-related-outlet-editor__density-cluster{gap:var(--pdx-spacing-md, 16px)}fieldset{min-width:0;margin:0;padding:0;border:0}legend{margin-bottom:8px;font:var(--md-sys-typescale-label-large, 500 .88rem/1.2 system-ui)}mat-button-toggle-group{width:100%}mat-button-toggle{flex:1 1 0}mat-button-toggle mat-icon{margin-right:6px}.pdx-related-outlet-editor__boundary{padding:var(--pdx-spacing-sm, 12px);border:1px solid var(--md-sys-color-outline-variant, currentColor);border-radius:var(--md-sys-shape-corner-medium, 12px);background:var(--md-sys-color-surface-container-low, transparent)}.pdx-related-outlet-editor__boundary mat-icon{color:var(--md-sys-color-on-surface-variant, currentColor)}@media(max-width:640px){.pdx-related-outlet-editor__fields,.pdx-related-outlet-editor__choice-grid{grid-template-columns:minmax(0,1fr)}.pdx-related-outlet-editor__wide{grid-column:auto}mat-button-toggle-group{display:grid}}@media(max-width:420px){.pdx-related-outlet-editor__appearance-cluster mat-button-toggle-group{grid-template-columns:minmax(0,1fr)}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i3$2.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i3$2.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: MatSlideToggleModule }, { kind: "component", type: i7.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
47114
+ `, isInline: true, styles: [":host{display:block;color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet-editor{display:grid;gap:var(--pdx-spacing-lg, 24px);padding:var(--pdx-spacing-md, 16px)}.pdx-related-outlet-editor__header,.pdx-related-outlet-editor__boundary{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;gap:var(--pdx-spacing-sm, 12px)}.pdx-related-outlet-editor__header-icon{display:inline-grid;place-items:center;width:40px;height:40px;border-radius:var(--md-sys-shape-corner-medium, 12px);color:var(--md-sys-color-primary, currentColor);background:var(--md-sys-color-primary-container, transparent)}.pdx-related-outlet-editor__header strong,.pdx-related-outlet-editor__boundary strong,.pdx-related-outlet-editor__header small,.pdx-related-outlet-editor__boundary small{display:block}.pdx-related-outlet-editor__header strong{font:var(--md-sys-typescale-title-medium, 600 1rem/1.4 system-ui)}.pdx-related-outlet-editor__header small,.pdx-related-outlet-editor__boundary small,.pdx-related-outlet-editor__section-heading p{color:var(--md-sys-color-on-surface-variant, currentColor)}.pdx-related-outlet-editor__section{display:grid;gap:var(--pdx-spacing-md, 16px)}.pdx-related-outlet-editor__section-heading h3,.pdx-related-outlet-editor__section-heading p{margin:0}.pdx-related-outlet-editor__section-heading h3{font:var(--md-sys-typescale-title-small, 600 .95rem/1.3 system-ui)}.pdx-related-outlet-editor__section-heading p{margin-top:4px;font:var(--md-sys-typescale-body-small, 400 .82rem/1.35 system-ui)}.pdx-related-outlet-editor__fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--pdx-spacing-sm, 12px)}.pdx-related-outlet-editor__wide{grid-column:1 / -1}.pdx-related-outlet-editor__choice-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--pdx-spacing-md, 16px)}.pdx-related-outlet-editor__appearance-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr));gap:var(--pdx-spacing-sm, 12px)}.pdx-related-outlet-editor__appearance-cluster{display:grid;align-content:start;gap:var(--pdx-spacing-sm, 12px);min-width:0}.pdx-related-outlet-editor__appearance-cluster--wide{grid-column:1 / -1}.pdx-related-outlet-editor__appearance-cluster mat-button-toggle-group{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,132px),1fr))}.pdx-related-outlet-editor__appearance-cluster mat-button-toggle{min-height:44px}.pdx-related-outlet-editor__density-cluster{gap:var(--pdx-spacing-md, 16px)}fieldset{min-width:0;margin:0;padding:0;border:0}legend{margin-bottom:8px;font:var(--md-sys-typescale-label-large, 500 .88rem/1.2 system-ui)}mat-button-toggle-group{width:100%}mat-button-toggle{flex:1 1 0}mat-button-toggle mat-icon{margin-right:6px}.pdx-related-outlet-editor__boundary{padding:var(--pdx-spacing-sm, 12px);border:1px solid var(--md-sys-color-outline-variant, currentColor);border-radius:var(--md-sys-shape-corner-medium, 12px);background:var(--md-sys-color-surface-container-low, transparent)}.pdx-related-outlet-editor__boundary mat-icon{color:var(--md-sys-color-on-surface-variant, currentColor)}@media(max-width:640px){.pdx-related-outlet-editor__fields,.pdx-related-outlet-editor__choice-grid{grid-template-columns:minmax(0,1fr)}.pdx-related-outlet-editor__wide{grid-column:auto}mat-button-toggle-group{display:grid}}@media(max-width:420px){.pdx-related-outlet-editor__appearance-cluster mat-button-toggle-group{grid-template-columns:minmax(0,1fr)}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i3$3.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i3$3.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: MatSlideToggleModule }, { kind: "component", type: i7.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
46572
47115
  }
46573
47116
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisRelatedResourceOutletConfigEditorComponent, decorators: [{
46574
47117
  type: Component,
@@ -47456,6 +47999,67 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
47456
47999
 
47457
48000
  class ResourceQuickConnectComponent {
47458
48001
  resourcePath = '';
48002
+ selector;
48003
+ registry = this.optionalInject(ComponentMetadataRegistry);
48004
+ discovery = this.optionalInject(ResourceDiscoveryService);
48005
+ i18n = this.optionalInject(PraxisI18nService);
48006
+ cdr = this.optionalInject(ChangeDetectorRef);
48007
+ selectorType = this.registry?.get('pdx-material-select')?.component;
48008
+ selectorInputs;
48009
+ catalogLoading = false;
48010
+ catalogError = false;
48011
+ accessor;
48012
+ tx(key) { return this.i18n?.t(`quickConnect.${key}`, undefined, key, 'resourceDiscovery') ?? key; }
48013
+ ngAfterViewChecked() {
48014
+ const instance = this.selector?.componentInstance;
48015
+ if (!instance || instance === this.accessor || !instance.registerOnChange || !instance.writeValue)
48016
+ return;
48017
+ instance.setInputMetadata?.(this.selectorInputs?.['metadata']);
48018
+ this.accessor = instance;
48019
+ this.accessor.writeValue(this.normalizedPath());
48020
+ this.accessor.registerOnChange((value) => {
48021
+ this.resourcePath = typeof value === 'string' ? value : '';
48022
+ this.updateState();
48023
+ });
48024
+ }
48025
+ async loadCatalog() {
48026
+ if (!this.discovery || !this.selectorType)
48027
+ return;
48028
+ this.catalogLoading = true;
48029
+ this.catalogError = false;
48030
+ this.cdr?.markForCheck();
48031
+ try {
48032
+ const catalog = await firstValueFrom(this.discovery.getSchemaCatalog().pipe(timeout(30000)));
48033
+ const resources = new Map();
48034
+ for (const endpoint of catalog.endpoints ?? []) {
48035
+ // Ground only declared resource-level capability endpoints; never infer user intent.
48036
+ if (endpoint.method !== 'GET' || !endpoint.resourceKey || !endpoint.path.startsWith('/')
48037
+ || endpoint.path.startsWith('//') || endpoint.path.includes('{') || !endpoint.path.endsWith('/capabilities'))
48038
+ continue;
48039
+ const value = endpoint.path.slice(0, -'/capabilities'.length);
48040
+ resources.set(value, { value, label: endpoint.resourceVisual?.title || endpoint.resourceKey });
48041
+ }
48042
+ this.selectorInputs = resources.size ? { metadata: {
48043
+ name: 'resourcePath', label: this.tx('resource'), type: 'string', controlType: 'select', searchable: true,
48044
+ selectOptions: [...resources.values()].sort((a, b) => a.label.localeCompare(b.label)),
48045
+ } } : undefined;
48046
+ }
48047
+ catch {
48048
+ this.catalogError = true;
48049
+ }
48050
+ finally {
48051
+ this.catalogLoading = false;
48052
+ this.cdr?.markForCheck();
48053
+ }
48054
+ }
48055
+ optionalInject(token) {
48056
+ try {
48057
+ return inject(token, { optional: true });
48058
+ }
48059
+ catch {
48060
+ return null;
48061
+ }
48062
+ }
47459
48063
  isDirty$ = new BehaviorSubject(false);
47460
48064
  isValid$ = new BehaviorSubject(false);
47461
48065
  isBusy$ = new BehaviorSubject(false);
@@ -47463,9 +48067,11 @@ class ResourceQuickConnectComponent {
47463
48067
  // When used standalone, consumers can bind [(resourcePath)].
47464
48068
  ngOnInit() {
47465
48069
  this.updateValidity();
48070
+ void this.loadCatalog();
47466
48071
  }
47467
48072
  ngOnChanges() {
47468
48073
  this.updateValidity();
48074
+ this.accessor?.writeValue(this.normalizedPath());
47469
48075
  }
47470
48076
  updateState() {
47471
48077
  this.isDirty$.next(true);
@@ -47501,57 +48107,54 @@ class ResourceQuickConnectComponent {
47501
48107
  return /^\/?[a-zA-Z0-9][a-zA-Z0-9/_-]*$/.test(value);
47502
48108
  }
47503
48109
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceQuickConnectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
47504
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: ResourceQuickConnectComponent, isStandalone: true, selector: "praxis-resource-quick-connect", inputs: { resourcePath: "resourcePath" }, usesOnChanges: true, ngImport: i0, template: `
48110
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: ResourceQuickConnectComponent, isStandalone: true, selector: "praxis-resource-quick-connect", inputs: { resourcePath: "resourcePath" }, providers: [providePraxisI18nConfig(RESOURCE_DISCOVERY_I18N_CONFIG)], viewQueries: [{ propertyName: "selector", first: true, predicate: NgComponentOutlet, descendants: true }], usesOnChanges: true, ngImport: i0, template: `
47505
48111
  <div class="pdx-quick-connect">
47506
- <mat-form-field appearance="outline">
47507
- <mat-label>Rota do recurso (API)</mat-label>
47508
- <input
47509
- matInput
47510
- [(ngModel)]="resourcePath"
47511
- (ngModelChange)="updateState()"
47512
- placeholder="ex.: human-resources/departamentos"
47513
- />
47514
- <mat-icon matSuffix [praxisIcon]="'link'"></mat-icon>
47515
- @if (showInvalid()) {
47516
- <mat-error>Use apenas letras, números, /, - ou _.</mat-error>
47517
- }
47518
- </mat-form-field>
47519
- <small class="pdx-quick-connect__hint">Conecte o componente à fonte de dados (ex.: /api/&lt;rota-do-recurso&gt;)</small>
47520
- @if (normalizedPath() && normalizedPath() !== resourcePath) {
47521
- <small class="pdx-quick-connect__hint">
47522
- Rota normalizada: {{ normalizedPath() }}
47523
- </small>
48112
+ @if (catalogLoading) { <p role="status">{{ tx('loading') }}</p> }
48113
+ @if (catalogError) { <p role="status">{{ tx('unavailable') }}</p><button type="button" (click)="loadCatalog()">{{ tx('retry') }}</button> }
48114
+ @if (selectorType && selectorInputs) {
48115
+ <ng-container *ngComponentOutlet="selectorType" />
48116
+ <small>{{ tx('hint') }}</small>
47524
48117
  }
48118
+ @if (!catalogLoading && !catalogError && !selectorInputs) { <p role="status">{{ tx('empty') }}</p> }
48119
+ <details [open]="!selectorType">
48120
+ <summary>{{ tx('advanced') }}</summary>
48121
+ <mat-form-field appearance="outline">
48122
+ <mat-label>{{ tx('path') }}</mat-label>
48123
+ <input matInput [(ngModel)]="resourcePath" (ngModelChange)="updateState()" />
48124
+ <mat-icon matSuffix [praxisIcon]="'link'"></mat-icon>
48125
+ @if (showInvalid()) { <mat-error>{{ tx('invalid') }}</mat-error> }
48126
+ </mat-form-field>
48127
+ </details>
47525
48128
  </div>
47526
- `, isInline: true, styles: [".pdx-quick-connect{display:grid;gap:12px;padding:12px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface)}.pdx-quick-connect__hint{color:var(--md-sys-color-on-surface-variant);font-size:.9rem}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i4.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }] });
48129
+ `, isInline: true, styles: [".pdx-quick-connect{display:grid;gap:12px;padding:12px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface)}.pdx-quick-connect__hint{color:var(--md-sys-color-on-surface-variant);font-size:.9rem}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: i1$1.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 });
47527
48130
  }
47528
48131
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceQuickConnectComponent, decorators: [{
47529
48132
  type: Component,
47530
- args: [{ selector: 'praxis-resource-quick-connect', standalone: true, imports: [FormsModule, MatFormFieldModule, MatInputModule, MatIconModule, PraxisIconDirective], template: `
48133
+ args: [{ selector: 'praxis-resource-quick-connect', changeDetection: ChangeDetectionStrategy.OnPush, providers: [providePraxisI18nConfig(RESOURCE_DISCOVERY_I18N_CONFIG)], imports: [NgComponentOutlet, FormsModule, MatFormFieldModule, MatInputModule, MatIconModule, PraxisIconDirective], template: `
47531
48134
  <div class="pdx-quick-connect">
47532
- <mat-form-field appearance="outline">
47533
- <mat-label>Rota do recurso (API)</mat-label>
47534
- <input
47535
- matInput
47536
- [(ngModel)]="resourcePath"
47537
- (ngModelChange)="updateState()"
47538
- placeholder="ex.: human-resources/departamentos"
47539
- />
47540
- <mat-icon matSuffix [praxisIcon]="'link'"></mat-icon>
47541
- @if (showInvalid()) {
47542
- <mat-error>Use apenas letras, números, /, - ou _.</mat-error>
47543
- }
47544
- </mat-form-field>
47545
- <small class="pdx-quick-connect__hint">Conecte o componente à fonte de dados (ex.: /api/&lt;rota-do-recurso&gt;)</small>
47546
- @if (normalizedPath() && normalizedPath() !== resourcePath) {
47547
- <small class="pdx-quick-connect__hint">
47548
- Rota normalizada: {{ normalizedPath() }}
47549
- </small>
48135
+ @if (catalogLoading) { <p role="status">{{ tx('loading') }}</p> }
48136
+ @if (catalogError) { <p role="status">{{ tx('unavailable') }}</p><button type="button" (click)="loadCatalog()">{{ tx('retry') }}</button> }
48137
+ @if (selectorType && selectorInputs) {
48138
+ <ng-container *ngComponentOutlet="selectorType" />
48139
+ <small>{{ tx('hint') }}</small>
47550
48140
  }
48141
+ @if (!catalogLoading && !catalogError && !selectorInputs) { <p role="status">{{ tx('empty') }}</p> }
48142
+ <details [open]="!selectorType">
48143
+ <summary>{{ tx('advanced') }}</summary>
48144
+ <mat-form-field appearance="outline">
48145
+ <mat-label>{{ tx('path') }}</mat-label>
48146
+ <input matInput [(ngModel)]="resourcePath" (ngModelChange)="updateState()" />
48147
+ <mat-icon matSuffix [praxisIcon]="'link'"></mat-icon>
48148
+ @if (showInvalid()) { <mat-error>{{ tx('invalid') }}</mat-error> }
48149
+ </mat-form-field>
48150
+ </details>
47551
48151
  </div>
47552
48152
  `, styles: [".pdx-quick-connect{display:grid;gap:12px;padding:12px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface)}.pdx-quick-connect__hint{color:var(--md-sys-color-on-surface-variant);font-size:.9rem}\n"] }]
47553
48153
  }], propDecorators: { resourcePath: [{
47554
48154
  type: Input
48155
+ }], selector: [{
48156
+ type: ViewChild,
48157
+ args: [NgComponentOutlet]
47555
48158
  }] } });
47556
48159
 
47557
48160
  /** Optional DI token used by SchemaViewer when input is not provided. */
@@ -48468,4 +49071,4 @@ function provideHookWhitelist(allowed) {
48468
49071
  * Generated bundle index. Do not edit.
48469
49072
  */
48470
49073
 
48471
- export { API_CONFIG_STORAGE_OPTIONS, API_URL, ASYNC_CONFIG_STORAGE, AllowedFileTypes, AnalyticsPresentationResolver, AnalyticsSchemaContractService, AnalyticsStatsRequestBuilderService, ApiConfigStorage, ApiEndpoint, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, BUILTIN_SHELL_PRESETS, COMPONENT_METADATA_REGISTRY_I18N_CONFIG, COMPONENT_METADATA_REGISTRY_I18N_NAMESPACE, CONFIG_STORAGE, CONNECTION_STORAGE, ComponentAuthoringManifestProjectionError, ComponentKeyService, ComponentMetadataRegistry, ComponentRuntimeProfileService, CompositionRuntimeFacade, CompositionValidatorService, ConsoleLoggerSink, CrudOperationResolutionService, DEFAULT_FIELD_SELECTOR_CONTROL_TYPE_MAP, DEFAULT_JSON_LOGIC_OPERATORS, DEFAULT_TABLE_CONFIG, DOMAIN_CATALOG_COMPONENT_CONTEXT_PACK, DOMAIN_CATALOG_CONTEXT_HINT_SCHEMA_VERSION, DYNAMIC_PAGE_AI_CAPABILITIES, DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK, DYNAMIC_PAGE_CONFIG_EDITOR, DYNAMIC_PAGE_SHELL_EDITOR, DefaultLoadingRenderer, DeferredAsyncConfigStorage, DomainCatalogService, DomainKnowledgeService, DomainRuleService, DynamicFormService, DynamicWidgetLoaderDirective, DynamicWidgetPageComponent, EDITORIAL_ALLOWED_CONTENT_FORMATS, EDITORIAL_COMPLIANCE_PRESETS, EDITORIAL_EXTERNAL_LINK_REL, EDITORIAL_FORM_TEMPLATE_CATALOG, EDITORIAL_HTML_ENABLED, EDITORIAL_MARKDOWN_IMAGES_ENABLED, EDITORIAL_SOLUTION_CATALOG, EDITORIAL_SOLUTION_PRESETS, EDITORIAL_THEME_PRESETS, EDITORIAL_WIDGET_CONVENTION_INPUTS, EDITORIAL_WIDGET_TAG, EMPLOYEE_ONBOARDING_EDITORIAL_SOLUTION, EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE, EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_SOLUTION, EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_TEMPLATE, EVENT_REGISTRATION_EDITORIAL_SOLUTION, EVENT_REGISTRATION_EDITORIAL_TEMPLATE, EmptyStateCardComponent, EnterpriseRuntimeContextService, ErrorMessageService, FIELD_METADATA_CAPABILITIES, FIELD_SELECTOR_REGISTRY_BASE, FIELD_SELECTOR_REGISTRY_DISABLE_DEFAULTS, FIELD_SELECTOR_REGISTRY_OVERRIDES, FORM_HOOKS, FORM_HOOKS_PRESETS, FORM_HOOKS_WHITELIST, FORM_HOOK_RESOLVERS, FieldControlType, FieldDataType, FieldSelectorRegistry, FormHooksRegistry, GLOBAL_ACTION_CATALOG, GLOBAL_ACTION_HANDLERS, GLOBAL_ACTION_UI_SCHEMAS, GLOBAL_ANALYTICS_SERVICE, GLOBAL_API_CLIENT, GLOBAL_CONFIG, GLOBAL_DIALOG_SERVICE, GLOBAL_ROUTE_GUARD_RESOLVER, GLOBAL_SURFACE_SERVICE, GLOBAL_TOAST_SERVICE, GenericCrudService, GlobalActionService, GlobalConfigService, INLINE_FILTER_ALIAS_TOKENS, INLINE_FILTER_CONTROL_TYPES, INLINE_FILTER_CONTROL_TYPE_SET, INLINE_FILTER_CONTROL_TYPE_VALUES, INLINE_FILTER_TOKEN_TO_BASE_CONTROL_TYPE, INLINE_FILTER_TOKEN_TO_CONTROL_TYPE, IconPickerService, IconPosition, IconSize, LOGGER_LEVEL_BY_ENV, LOGGER_LEVEL_PRIORITY, LoadingOrchestrator, LocalConnectionStorage, LocalStorageAsyncAdapter, LocalStorageCacheAdapter, LocalStorageConfigService, LoggerService, LoggerThrottleTracker, LoggerWarnOnceTracker, MemoryCacheAdapter, NestedPortCatalogService, NestedWidgetConfigAccessor, NumericFormat, OVERLAY_DECIDER_DEBUG, OVERLAY_DECISION_MATRIX, ObservabilityDashboardService, OverlayDeciderService, PRAXIS_ACTION_CONTROL_DEFAULTS, PRAXIS_ACTION_CONTROL_VARS, PRAXIS_COLLECTION_EXPORT_HTTP_OPTIONS, PRAXIS_COLLECTION_EXPORT_PROVIDER, PRAXIS_COLLECTION_SEARCH_DEFAULTS, PRAXIS_COLLECTION_SEARCH_VARS, PRAXIS_CORPORATE_SENSITIVE_KEYS, PRAXIS_DEFAULT_EXPORT_SECURITY_POLICY, PRAXIS_DEFAULT_OBSERVABILITY_ALERT_RULES, PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY, PRAXIS_EXPORT_FORMULA_PREFIXES, PRAXIS_EXPORT_SECURITY_POLICY, PRAXIS_FOOTER_LINKS_METADATA, PRAXIS_GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_OPTIONS, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_READY, PRAXIS_GLOBAL_CONFIG_TENANT_RESOLVER, PRAXIS_HERO_BANNER_METADATA, PRAXIS_I18N_CONFIG, PRAXIS_I18N_TRANSLATOR, PRAXIS_JSON_LOGIC_OPERATORS, PRAXIS_LAYER_SCALE_DEFAULTS, PRAXIS_LAYER_SCALE_VARS, PRAXIS_LEGAL_NOTICE_METADATA, PRAXIS_LOADING_CTX, PRAXIS_LOADING_RENDERER, PRAXIS_LOGGER_CONFIG, PRAXIS_LOGGER_SINKS, PRAXIS_OBSERVABILITY_DASHBOARD_OPTIONS, PRAXIS_QUERY_FILTER_EXPRESSION_SCHEMA_VERSION, PRAXIS_RELATED_RESOURCE_OUTLET_AUTHORING_MANIFEST, PRAXIS_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA, PRAXIS_RELATED_RESOURCE_OUTLET_PORTS, PRAXIS_RICH_TEXT_BLOCK_METADATA, PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS, PRAXIS_TABLE_DETAIL_INLINE_RENDERERS, PRAXIS_TABLE_DETAIL_RESOURCE_RESOLVER, PRAXIS_TELEMETRY_TRANSPORT, PRAXIS_THEME_SURFACE_DEFAULTS, PRAXIS_THEME_SURFACE_VARS, PRAXIS_USER_CONTEXT_SUMMARY_METADATA, PRIVACY_CONSENT_EDITORIAL_SOLUTION, PRIVACY_CONSENT_EDITORIAL_TEMPLATE, PraxisCollectionExportService, PraxisCore, PraxisFooterLinksComponent, PraxisGlobalErrorHandler, PraxisHeroBannerComponent, PraxisHttpCollectionExportProvider, PraxisI18nService, PraxisIconButtonComponent, PraxisIconDirective, PraxisIconPickerComponent, PraxisJsonLogicError, PraxisJsonLogicService, PraxisLayerScaleStyleService, PraxisLegalNoticeComponent, PraxisLoadingInterceptor, PraxisRelatedResourceOutletComponent, PraxisRelatedResourceOutletConfigEditorComponent, PraxisResourceIdentityComponent, PraxisRichTextBlockComponent, PraxisRuntimeComponentObservationRegistryService, PraxisSurfaceHostComponent, PraxisUserContextSummaryComponent, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, RULE_PROPERTY_SCHEMA, RelatedResourceSurfaceResolverService, RemoteConfigStorage, ResourceActionOpenAdapterService, ResourceDiscoveryService, ResourceQuickConnectComponent, ResourceRecordOpenError, ResourceRecordOpenService, ResourceSurfaceOpenAdapterService, SCHEMA_VIEWER_CONTEXT, SETTINGS_PANEL_BRIDGE, SETTINGS_PANEL_DATA, STEPPER_CONFIG_EDITOR, SURFACE_DRAWER_BRIDGE, SURFACE_DRAWER_CONTENT_DATA, SURFACE_DRAWER_REF, SURFACE_NAVIGATION_I18N_CONFIG, SURFACE_NAVIGATION_I18N_NAMESPACE, SURFACE_OPEN_I18N_CONFIG, SURFACE_OPEN_I18N_NAMESPACE, SURFACE_OPEN_PRESETS, SchemaMetadataClient, SchemaNormalizerService, SchemaViewerComponent, SurfaceBindingRuntimeService, SurfaceNavigationError, SurfaceOpenActionEditorComponent, SurfaceOpenMaterializerService, SurfaceOutletRegistryService, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageCompositionFactory, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, assertPraxisRuntimeComponentObservationSerializable, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisActionControlCss, buildPraxisCollectionSearchCss, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildPraxisThemeSurfaceCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, canonicalJsonSha256, canonicalJsonStringify, clampRange, classifyEntityLookupResult, clonePraxisRuntimeComponentObservation, cloneTableConfig, cnpjAlphaValidator, collapseWhitespace, composeHeadersWithVersion, conditionalAsyncValidator, convertFormLayoutToConfig, createCorporateLoggerConfig, createCorporateObservabilityOptions, createCpfCnpjValidator, createDefaultFormConfig, createDefaultTableConfig, createEmptyFormConfig, createEmptyRichContentDocument, createFieldLayoutItem, createPersistedPage, customAsyncValidatorFn, customValidatorFn, debounceAsyncValidator, deepMerge, domainKnowledgeTimelineToRichContentDocument, domainRuleTimelineToRichContentDocument, ensureIds, ensureNoConflictsHookFactory, ensurePageIds, escapePraxisExportCell, evaluateFieldAccess, extractNormalizedError, fetchWithETag, fileTypeValidator, fillUndefined, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionProviderEvidence, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getPraxisTableCellVisualizationConstraint, getPraxisTableCellVisualizationGuidance, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isDomainRuleSnapshotProblemResponse, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionProviderOperational, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isPraxisI18nMessageDescriptor, isPraxisPresentationVisualizationTableSafe, isPraxisRuntimeGlobalActionEffect, isProgrammaticDateRangePreset, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isStaticDateRangePreset, isSurfaceNavigationError, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, markGlobalActionProviderOperational, matchFieldValidator, materializeFormLayoutFromMetadata, materializeResourceIdentity, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, nestedPortPathIdentity, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldAccessMetadata, normalizeFieldConstraints, normalizeFieldPresentation, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef$1 as normalizeGlobalActionRef, normalizeLayoutPolicy, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizePraxisEffectPolicy, normalizePraxisPresentationVisualization, normalizePraxisQueryFilterExpression, normalizePraxisQueryFilterNode, normalizeReactiveDeterminations, normalizeResourceAvailabilityReasonCode, normalizeResourceIdentityContract, normalizeStart, normalizeSurfaceOperationContext, normalizeUnknownError, normalizeWidgetEventPath, notifySuccessHook, parseJsonResponseOrEmpty, praxisLoadingInterceptorFn, prefillFromContextHook, projectComponentAuthoringManifest, projectGroupedCommandPartialRows, provideDefaultFormHooks, provideFieldSelectorRegistryBase, provideFieldSelectorRegistryOverride, provideFieldSelectorRegistryRuntime, provideFormHookPresets, provideFormHooks, provideGlobalActionCatalog, provideGlobalActionHandler, provideGlobalConfig, provideGlobalConfigReady, provideGlobalConfigSeed, provideGlobalConfigTenant, provideHookResolvers, provideHookWhitelist, provideOverlayDecisionMatrix, providePraxisAnalyticsGlobalActions, providePraxisCollectionExportProvider, providePraxisDynamicPageMetadata, providePraxisEnterpriseRuntimeContext, providePraxisFooterLinksMetadata, providePraxisGlobalActionCatalog, providePraxisGlobalActions, providePraxisGlobalConfigBootstrap, providePraxisHeroBannerMetadata, providePraxisHttpCollectionExportProvider, providePraxisHttpLoading, providePraxisI18n, providePraxisI18nConfig, providePraxisI18nTranslator, providePraxisIconDefaults, providePraxisJsonLogicOperator, providePraxisJsonLogicOperatorOverride, providePraxisLegalNoticeMetadata, providePraxisLoadingDefaults, providePraxisLogging, providePraxisRelatedResourceOutletMetadata, providePraxisRichTextBlockMetadata, providePraxisTelemetry, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, registerPraxisRuntimeComponentObservation, removeDiacritics, renderPraxisPresentationVisualizationHtml, reportTelemetryHookFactory, requiredCheckedValidator, requiredPresenceValidator, resolveBuiltinPresets, resolveColumnTypeFromFieldDefinition, resolveControlTypeAlias, resolveDateRangeShortcutPreset, resolveDateRangeShortcutPresets, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveFieldPresentation, resolveGroupedCommandPartialRowSpans, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolvePraxisI18nDocument, resolveResourceAvailabilityReasonKey, resolveResourceIdentityContract, resolveSpan, resolveTextMaskFormat, resolveTextMaskFormatFromFieldDefinition, resolveValuePresentation, resolveValuePresentationLocale, serializeEntityLookupValueForPayload, serializeOptionSourceFilterRequest, serializePraxisCollectionToCsv, serializePraxisCollectionToExcel, serializePraxisCollectionToJson, slugify, staticDateRangePresetToPreset, stripMasksHook, supportsConfigDocuments, supportsImplicitValuePresentation, syncWithServerMetadata, textSha256, toCamel, toCapitalize, toKebab, toPascal, toSentenceCase, toSnake, toTitleCase, translateResourceAvailabilityReason, translateResourceDiscoveryText, translateSurfaceNavigationRejected, translateUnavailableWorkflowMessage, trim, uniqueAsyncValidator, urlValidator, validateGlobalActionRef, validateGlobalActionRefs, withFormConfigSections, withMessage, withPraxisHttpLoading };
49074
+ export { API_CONFIG_STORAGE_OPTIONS, API_URL, ASYNC_CONFIG_STORAGE, AllowedFileTypes, AnalyticsPresentationResolver, AnalyticsSchemaContractService, AnalyticsStatsRequestBuilderService, ApiConfigStorage, ApiEndpoint, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, BUILTIN_SHELL_PRESETS, COMPONENT_METADATA_REGISTRY_I18N_CONFIG, COMPONENT_METADATA_REGISTRY_I18N_NAMESPACE, CONFIG_STORAGE, CONNECTION_STORAGE, ComponentAuthoringManifestProjectionError, ComponentKeyService, ComponentMetadataRegistry, ComponentRuntimeProfileService, CompositionRuntimeFacade, CompositionValidatorService, ConsoleLoggerSink, CrudOperationResolutionService, DEFAULT_FIELD_SELECTOR_CONTROL_TYPE_MAP, DEFAULT_JSON_LOGIC_OPERATORS, DEFAULT_TABLE_CONFIG, DOMAIN_CATALOG_COMPONENT_CONTEXT_PACK, DOMAIN_CATALOG_CONTEXT_HINT_SCHEMA_VERSION, DYNAMIC_PAGE_AI_CAPABILITIES, DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK, DYNAMIC_PAGE_CONFIG_EDITOR, DYNAMIC_PAGE_SHELL_EDITOR, DefaultLoadingRenderer, DeferredAsyncConfigStorage, DomainCatalogService, DomainKnowledgeService, DomainRuleService, DynamicFormService, DynamicWidgetLoaderDirective, DynamicWidgetPageComponent, EDITORIAL_ALLOWED_CONTENT_FORMATS, EDITORIAL_COMPLIANCE_PRESETS, EDITORIAL_EXTERNAL_LINK_REL, EDITORIAL_FORM_TEMPLATE_CATALOG, EDITORIAL_HTML_ENABLED, EDITORIAL_MARKDOWN_IMAGES_ENABLED, EDITORIAL_SOLUTION_CATALOG, EDITORIAL_SOLUTION_PRESETS, EDITORIAL_THEME_PRESETS, EDITORIAL_WIDGET_CONVENTION_INPUTS, EDITORIAL_WIDGET_TAG, EMPLOYEE_ONBOARDING_EDITORIAL_SOLUTION, EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE, EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_SOLUTION, EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_TEMPLATE, EVENT_REGISTRATION_EDITORIAL_SOLUTION, EVENT_REGISTRATION_EDITORIAL_TEMPLATE, EmptyStateCardComponent, EnterpriseRuntimeContextService, ErrorMessageService, FIELD_METADATA_CAPABILITIES, FIELD_SELECTOR_REGISTRY_BASE, FIELD_SELECTOR_REGISTRY_DISABLE_DEFAULTS, FIELD_SELECTOR_REGISTRY_OVERRIDES, FORM_HOOKS, FORM_HOOKS_PRESETS, FORM_HOOKS_WHITELIST, FORM_HOOK_RESOLVERS, FieldControlType, FieldDataType, FieldSelectorRegistry, FormHooksRegistry, GLOBAL_ACTION_CATALOG, GLOBAL_ACTION_HANDLERS, GLOBAL_ACTION_UI_SCHEMAS, GLOBAL_ANALYTICS_SERVICE, GLOBAL_API_CLIENT, GLOBAL_CONFIG, GLOBAL_DIALOG_SERVICE, GLOBAL_ROUTE_GUARD_RESOLVER, GLOBAL_SURFACE_SERVICE, GLOBAL_TOAST_SERVICE, GOVERNED_COLOR_PALETTE_OPTIONS, GenericCrudService, GlobalActionService, GlobalConfigService, GovernedColorPaletteService, INLINE_FILTER_ALIAS_TOKENS, INLINE_FILTER_CONTROL_TYPES, INLINE_FILTER_CONTROL_TYPE_SET, INLINE_FILTER_CONTROL_TYPE_VALUES, INLINE_FILTER_TOKEN_TO_BASE_CONTROL_TYPE, INLINE_FILTER_TOKEN_TO_CONTROL_TYPE, IconPickerService, IconPosition, IconSize, LOGGER_LEVEL_BY_ENV, LOGGER_LEVEL_PRIORITY, LoadingOrchestrator, LocalConnectionStorage, LocalStorageAsyncAdapter, LocalStorageCacheAdapter, LocalStorageConfigService, LoggerService, LoggerThrottleTracker, LoggerWarnOnceTracker, MemoryCacheAdapter, NestedPortCatalogService, NestedWidgetConfigAccessor, NumericFormat, OVERLAY_DECIDER_DEBUG, OVERLAY_DECISION_MATRIX, ObservabilityDashboardService, OverlayDeciderService, PRAXIS_ACTION_CONTROL_DEFAULTS, PRAXIS_ACTION_CONTROL_VARS, PRAXIS_COLLECTION_EXPORT_HTTP_OPTIONS, PRAXIS_COLLECTION_EXPORT_PROVIDER, PRAXIS_COLLECTION_SEARCH_DEFAULTS, PRAXIS_COLLECTION_SEARCH_VARS, PRAXIS_CORPORATE_SENSITIVE_KEYS, PRAXIS_DEFAULT_EXPORT_SECURITY_POLICY, PRAXIS_DEFAULT_OBSERVABILITY_ALERT_RULES, PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY, PRAXIS_EXPORT_FORMULA_PREFIXES, PRAXIS_EXPORT_SECURITY_POLICY, PRAXIS_FOOTER_LINKS_METADATA, PRAXIS_GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_OPTIONS, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_READY, PRAXIS_GLOBAL_CONFIG_TENANT_RESOLVER, PRAXIS_HERO_BANNER_METADATA, PRAXIS_I18N_CONFIG, PRAXIS_I18N_TRANSLATOR, PRAXIS_JSON_LOGIC_OPERATORS, PRAXIS_LAYER_SCALE_DEFAULTS, PRAXIS_LAYER_SCALE_VARS, PRAXIS_LEGAL_NOTICE_METADATA, PRAXIS_LOADING_CTX, PRAXIS_LOADING_RENDERER, PRAXIS_LOGGER_CONFIG, PRAXIS_LOGGER_SINKS, PRAXIS_OBSERVABILITY_DASHBOARD_OPTIONS, PRAXIS_QUERY_FILTER_EXPRESSION_SCHEMA_VERSION, PRAXIS_RELATED_RESOURCE_OUTLET_AUTHORING_MANIFEST, PRAXIS_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA, PRAXIS_RELATED_RESOURCE_OUTLET_PORTS, PRAXIS_RICH_TEXT_BLOCK_METADATA, PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS, PRAXIS_TABLE_DETAIL_INLINE_RENDERERS, PRAXIS_TABLE_DETAIL_RESOURCE_RESOLVER, PRAXIS_TELEMETRY_TRANSPORT, PRAXIS_THEME_SURFACE_DEFAULTS, PRAXIS_THEME_SURFACE_VARS, PRAXIS_USER_CONTEXT_SUMMARY_METADATA, PRIVACY_CONSENT_EDITORIAL_SOLUTION, PRIVACY_CONSENT_EDITORIAL_TEMPLATE, PraxisCollectionExportService, PraxisCore, PraxisFooterLinksComponent, PraxisGlobalErrorHandler, PraxisHeroBannerComponent, PraxisHttpCollectionExportProvider, PraxisI18nService, PraxisIconButtonComponent, PraxisIconDirective, PraxisIconPickerComponent, PraxisJsonLogicError, PraxisJsonLogicService, PraxisLayerScaleStyleService, PraxisLegalNoticeComponent, PraxisLoadingInterceptor, PraxisRelatedResourceOutletComponent, PraxisRelatedResourceOutletConfigEditorComponent, PraxisResourceIdentityComponent, PraxisRichTextBlockComponent, PraxisRuntimeComponentObservationRegistryService, PraxisSurfaceHostComponent, PraxisUserContextSummaryComponent, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, RULE_PROPERTY_SCHEMA, RelatedResourceSurfaceResolverService, RemoteConfigStorage, ResourceActionOpenAdapterService, ResourceDiscoveryService, ResourceQuickConnectComponent, ResourceRecordOpenError, ResourceRecordOpenService, ResourceSurfaceOpenAdapterService, SCHEMA_VIEWER_CONTEXT, SETTINGS_PANEL_BRIDGE, SETTINGS_PANEL_DATA, STEPPER_CONFIG_EDITOR, SURFACE_DRAWER_BRIDGE, SURFACE_DRAWER_CONTENT_DATA, SURFACE_DRAWER_REF, SURFACE_NAVIGATION_I18N_CONFIG, SURFACE_NAVIGATION_I18N_NAMESPACE, SURFACE_OPEN_I18N_CONFIG, SURFACE_OPEN_I18N_NAMESPACE, SURFACE_OPEN_PRESETS, SchemaMetadataClient, SchemaNormalizerService, SchemaViewerComponent, SurfaceBindingRuntimeService, SurfaceNavigationError, SurfaceOpenActionEditorComponent, SurfaceOpenMaterializerService, SurfaceOutletRegistryService, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageCompositionFactory, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, assertPraxisRuntimeComponentObservationSerializable, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisActionControlCss, buildPraxisCollectionSearchCss, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildPraxisThemeSurfaceCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, canonicalJsonSha256, canonicalJsonStringify, clampRange, classifyEntityLookupResult, clonePraxisRuntimeComponentObservation, cloneTableConfig, cnpjAlphaValidator, collapseWhitespace, composeHeadersWithVersion, conditionalAsyncValidator, convertFormLayoutToConfig, createCorporateLoggerConfig, createCorporateObservabilityOptions, createCpfCnpjValidator, createDefaultFormConfig, createDefaultTableConfig, createEmptyFormConfig, createEmptyRichContentDocument, createFieldLayoutItem, createPersistedPage, customAsyncValidatorFn, customValidatorFn, debounceAsyncValidator, deepMerge, domainKnowledgeTimelineToRichContentDocument, domainRuleTimelineToRichContentDocument, ensureIds, ensureNoConflictsHookFactory, ensurePageIds, escapePraxisExportCell, evaluateFieldAccess, extractNormalizedError, fetchWithETag, fileTypeValidator, fillUndefined, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionProviderEvidence, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getPraxisTableCellVisualizationConstraint, getPraxisTableCellVisualizationGuidance, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isDomainRuleSnapshotProblemResponse, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionProviderOperational, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isPraxisI18nMessageDescriptor, isPraxisPresentationVisualizationTableSafe, isPraxisRuntimeGlobalActionEffect, isProgrammaticDateRangePreset, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isStaticDateRangePreset, isSurfaceNavigationError, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, markGlobalActionProviderOperational, matchFieldValidator, materializeFormLayoutFromMetadata, materializeGovernedPaletteColors, materializeGovernedPaletteEntries, materializeResourceIdentity, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, nestedPortPathIdentity, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldAccessMetadata, normalizeFieldConstraints, normalizeFieldPresentation, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef$1 as normalizeGlobalActionRef, normalizeLayoutPolicy, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizePraxisEffectPolicy, normalizePraxisPresentationVisualization, normalizePraxisQueryFilterExpression, normalizePraxisQueryFilterNode, normalizeReactiveDeterminations, normalizeResourceAvailabilityReasonCode, normalizeResourceIdentityContract, normalizeStart, normalizeSurfaceOperationContext, normalizeUnknownError, normalizeWidgetEventPath, notifySuccessHook, parseJsonResponseOrEmpty, praxisLoadingInterceptorFn, prefillFromContextHook, projectComponentAuthoringManifest, projectGroupedCommandPartialRows, provideDefaultFormHooks, provideFieldSelectorRegistryBase, provideFieldSelectorRegistryOverride, provideFieldSelectorRegistryRuntime, provideFormHookPresets, provideFormHooks, provideGlobalActionCatalog, provideGlobalActionHandler, provideGlobalConfig, provideGlobalConfigReady, provideGlobalConfigSeed, provideGlobalConfigTenant, provideHookResolvers, provideHookWhitelist, provideOverlayDecisionMatrix, providePraxisAnalyticsGlobalActions, providePraxisCollectionExportProvider, providePraxisDynamicPageMetadata, providePraxisEnterpriseRuntimeContext, providePraxisFooterLinksMetadata, providePraxisGlobalActionCatalog, providePraxisGlobalActions, providePraxisGlobalConfigBootstrap, providePraxisHeroBannerMetadata, providePraxisHttpCollectionExportProvider, providePraxisHttpLoading, providePraxisI18n, providePraxisI18nConfig, providePraxisI18nTranslator, providePraxisIconDefaults, providePraxisJsonLogicOperator, providePraxisJsonLogicOperatorOverride, providePraxisLegalNoticeMetadata, providePraxisLoadingDefaults, providePraxisLogging, providePraxisRelatedResourceOutletMetadata, providePraxisRichTextBlockMetadata, providePraxisTelemetry, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, registerPraxisRuntimeComponentObservation, removeDiacritics, renderPraxisPresentationVisualizationHtml, reportTelemetryHookFactory, requiredCheckedValidator, requiredPresenceValidator, resolveBuiltinPresets, resolveColumnTypeFromFieldDefinition, resolveControlTypeAlias, resolveDateRangeShortcutPreset, resolveDateRangeShortcutPresets, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveFieldPresentation, resolveGroupedCommandPartialRowSpans, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolvePraxisI18nDocument, resolveResourceAvailabilityReasonKey, resolveResourceIdentityContract, resolveSpan, resolveTextMaskFormat, resolveTextMaskFormatFromFieldDefinition, resolveValuePresentation, resolveValuePresentationLocale, serializeEntityLookupValueForPayload, serializeOptionSourceFilterRequest, serializePraxisCollectionToCsv, serializePraxisCollectionToExcel, serializePraxisCollectionToJson, slugify, staticDateRangePresetToPreset, stripMasksHook, supportsConfigDocuments, supportsImplicitValuePresentation, syncWithServerMetadata, textSha256, toCamel, toCapitalize, toKebab, toPascal, toSentenceCase, toSnake, toTitleCase, translateResourceAvailabilityReason, translateResourceDiscoveryText, translateSurfaceNavigationRejected, translateSurfaceOpenFailed, translateUnavailableWorkflowMessage, trim, uniqueAsyncValidator, urlValidator, validateGlobalActionRef, validateGlobalActionRefs, withFormConfigSections, withMessage, withPraxisHttpLoading };