@praxisui/core 8.0.0-beta.99 → 9.0.0-beta.0

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,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, InjectionToken, Injectable, inject, Inject, Optional, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, APP_INITIALIZER, ErrorHandler, EventEmitter, Output, Input, ChangeDetectionStrategy, Directive, SecurityContext, ViewContainerRef, inputBinding, ContentChild, HostBinding, signal, HostListener, ViewChild, computed } from '@angular/core';
2
+ import { Component, InjectionToken, Injectable, inject, Inject, Optional, makeEnvironmentProviders, signal, computed, DestroyRef, ENVIRONMENT_INITIALIZER, APP_INITIALIZER, ErrorHandler, EventEmitter, Output, Input, ChangeDetectionStrategy, Directive, SecurityContext, ViewContainerRef, SimpleChange, ContentChild, HostBinding, 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
5
  import { of, defer, throwError, from, EMPTY, BehaviorSubject, firstValueFrom, Subject, map as map$1, switchMap as switchMap$1 } from 'rxjs';
@@ -3085,6 +3085,7 @@ class GenericCrudService {
3085
3085
  endpoints = {}; // Stores user-defined custom endpoints
3086
3086
  apiUrlConfig;
3087
3087
  currentEndpointKey = ApiEndpoint.Default;
3088
+ currentApiUrlEntry = null;
3088
3089
  resourcePath;
3089
3090
  // Nova propriedade para armazenar a URL do schema
3090
3091
  _schemaUrl = null;
@@ -3185,19 +3186,22 @@ class GenericCrudService {
3185
3186
  if (this.configured &&
3186
3187
  this.apiUrl === nextApiUrl &&
3187
3188
  this.baseApiUrl === nextBaseApiUrl &&
3188
- this.currentEndpointKey === nextEndpointKey) {
3189
+ this.currentEndpointKey === nextEndpointKey &&
3190
+ this.currentApiUrlEntry === (configureOptions.apiUrlEntry ?? null)) {
3189
3191
  // No-op; already configured with same values
3190
3192
  // console.debug('[CRUD:Service] configure (no-op)', { resourcePath, baseApiUrl: nextBaseApiUrl });
3191
3193
  return;
3192
3194
  }
3193
3195
  // Apply new configuration
3194
3196
  this.currentEndpointKey = nextEndpointKey;
3197
+ this.currentApiUrlEntry = configureOptions.apiUrlEntry ?? null;
3195
3198
  this.baseApiUrl = nextBaseApiUrl;
3196
3199
  this.resourcePath = resource;
3197
3200
  this.apiUrl = nextApiUrl;
3198
3201
  this.configured = true;
3199
3202
  this._filterSchemaLoaded = false;
3200
3203
  this._rangeFilterFieldHints.clear();
3204
+ this._lastSchemaInfo = {};
3201
3205
  this._lastResourceMeta = {};
3202
3206
  this._lastResourceCapabilityDigest = null;
3203
3207
  console.debug('[CRUD:Service] configure', {
@@ -4280,6 +4284,10 @@ class GenericCrudService {
4280
4284
  }
4281
4285
  resolveEndpointEntry(key) {
4282
4286
  const cfgKey = key ?? this.currentEndpointKey;
4287
+ if (this.currentApiUrlEntry &&
4288
+ (!key || cfgKey === this.currentEndpointKey)) {
4289
+ return this.currentApiUrlEntry;
4290
+ }
4283
4291
  return this.apiUrlConfig[cfgKey] || this.apiUrlConfig['default'];
4284
4292
  }
4285
4293
  /**
@@ -6118,6 +6126,8 @@ class SurfaceBindingRuntimeService {
6118
6126
  if (!targetPath)
6119
6127
  continue;
6120
6128
  const value = this.resolveBindingValue(binding, context);
6129
+ if (value === undefined && binding.omitIfUndefined)
6130
+ continue;
6121
6131
  resolvedWidget = this.setValueAtPath(resolvedWidget, targetPath, value);
6122
6132
  }
6123
6133
  return resolvedWidget;
@@ -6130,6 +6140,8 @@ class SurfaceBindingRuntimeService {
6130
6140
  if (!rawTargetPath)
6131
6141
  continue;
6132
6142
  const value = this.resolveBindingValue(binding, context);
6143
+ if (value === undefined && binding.omitIfUndefined)
6144
+ continue;
6133
6145
  if (rawTargetPath.startsWith('widget.')) {
6134
6146
  resolvedPayload = {
6135
6147
  ...resolvedPayload,
@@ -6863,8 +6875,26 @@ class GlobalActionService {
6863
6875
  }
6864
6876
  const resolvedPayload = this.surfaceBindingRuntime.resolveSurfacePayload(surfacePayload, context, surfacePayload.context);
6865
6877
  const data = await this.surface.open(resolvedPayload, context);
6878
+ this.bindSurfaceResultAction(data, resolvedPayload, context);
6866
6879
  return { success: true, data };
6867
6880
  });
6881
+ this.register('surface.close', async (payload, context) => {
6882
+ const runtime = this.resolveSurfaceRuntime(context);
6883
+ if (typeof runtime?.close !== 'function') {
6884
+ return { success: false, error: 'Surface runtime not available' };
6885
+ }
6886
+ runtime.close(this.toSurfaceResult(payload, 'close'));
6887
+ return { success: true };
6888
+ });
6889
+ this.register('surface.result', async (payload, context) => {
6890
+ const runtime = this.resolveSurfaceRuntime(context);
6891
+ if (typeof runtime?.emitResult !== 'function') {
6892
+ return { success: false, error: 'Surface result runtime not available' };
6893
+ }
6894
+ runtime.emitResult(this.toSurfaceResult(payload, 'result'));
6895
+ return { success: true };
6896
+ });
6897
+ this.register('dynamicPage.composition.dispatch', async (payload, context) => this.handleCompositionDispatch(payload, context));
6868
6898
  this.register('toast.success', async (payload) => {
6869
6899
  const message = payload?.message || payload;
6870
6900
  if (!message)
@@ -6939,6 +6969,46 @@ class GlobalActionService {
6939
6969
  return { success: false, error: err?.message || String(err) };
6940
6970
  }
6941
6971
  }
6972
+ async handleCompositionDispatch(payload, context) {
6973
+ const dispatch = context?.runtime?.composition?.dispatch;
6974
+ if (typeof dispatch !== 'function') {
6975
+ return { success: false, error: 'Composition runtime not available' };
6976
+ }
6977
+ const source = payload?.source;
6978
+ if (!this.isCompositionEndpointRef(source)) {
6979
+ return { success: false, error: 'dynamicPage.composition.dispatch requires source endpoint' };
6980
+ }
6981
+ const eventPayload = payload && Object.prototype.hasOwnProperty.call(payload, 'payload')
6982
+ ? payload.payload
6983
+ : context?.payload;
6984
+ await dispatch({
6985
+ source,
6986
+ payload: eventPayload,
6987
+ ...(typeof payload?.occurredAt === 'string' ? { occurredAt: payload.occurredAt } : {}),
6988
+ });
6989
+ return {
6990
+ success: true,
6991
+ data: {
6992
+ source,
6993
+ payload: eventPayload,
6994
+ },
6995
+ };
6996
+ }
6997
+ isCompositionEndpointRef(value) {
6998
+ if (!value || typeof value !== 'object') {
6999
+ return false;
7000
+ }
7001
+ if (value.kind === 'component-port') {
7002
+ return !!value.ref?.widget && !!value.ref?.port && !!value.ref?.direction;
7003
+ }
7004
+ if (value.kind === 'state') {
7005
+ return !!value.ref?.path;
7006
+ }
7007
+ if (value.kind === 'global-action') {
7008
+ return !!value.ref?.actionId;
7009
+ }
7010
+ return false;
7011
+ }
6942
7012
  async handleNavigationOpenRoute(payload) {
6943
7013
  const url = this.buildNavigationUrl(payload);
6944
7014
  if (!url)
@@ -7077,6 +7147,51 @@ class GlobalActionService {
7077
7147
  return '';
7078
7148
  return `#${encodeURIComponent(raw.replace(/^#/, ''))}`;
7079
7149
  }
7150
+ resolveSurfaceRuntime(context) {
7151
+ return (context?.runtime?.state?.surfaceRuntime
7152
+ || context?.payload?.surfaceContext?.surfaceRuntime
7153
+ || context?.pageContext?.surfaceRuntime
7154
+ || null);
7155
+ }
7156
+ bindSurfaceResultAction(ref, payload, context) {
7157
+ const onResult = payload.onResult;
7158
+ if (!onResult || typeof ref?.result$?.subscribe !== 'function') {
7159
+ return;
7160
+ }
7161
+ ref.result$.subscribe((result) => {
7162
+ void this.executeRef(onResult, {
7163
+ ...context,
7164
+ payload: result,
7165
+ runtime: {
7166
+ ...(context?.runtime || {}),
7167
+ value: result,
7168
+ state: {
7169
+ ...(context?.runtime?.state || {}),
7170
+ surfaceResult: result,
7171
+ },
7172
+ },
7173
+ meta: {
7174
+ ...(context?.meta || {}),
7175
+ origin: 'surface.result',
7176
+ surfaceTitle: payload.title,
7177
+ surfacePresentation: payload.presentation,
7178
+ },
7179
+ });
7180
+ });
7181
+ }
7182
+ toSurfaceResult(payload, fallbackType) {
7183
+ if (payload && typeof payload === 'object' && ('type' in payload || 'data' in payload)) {
7184
+ return {
7185
+ type: String(payload.type || fallbackType),
7186
+ ...(Object.prototype.hasOwnProperty.call(payload, 'data')
7187
+ ? { data: payload.data }
7188
+ : {}),
7189
+ };
7190
+ }
7191
+ return payload === undefined
7192
+ ? { type: fallbackType }
7193
+ : { type: fallbackType, data: payload };
7194
+ }
7080
7195
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: GlobalActionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
7081
7196
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: GlobalActionService, providedIn: 'root' });
7082
7197
  }
@@ -8596,6 +8711,15 @@ function minWordsValidator(minWords, message) {
8596
8711
  function requiredCheckedValidator(message) {
8597
8712
  return withMessage(Validators.requiredTrue, 'requiredTrue', message);
8598
8713
  }
8714
+ function requiredPresenceValidator(message) {
8715
+ return (control) => {
8716
+ const value = control.value;
8717
+ if (value === null || value === undefined || value === '') {
8718
+ return toMessageError('required', { required: true }, message);
8719
+ }
8720
+ return null;
8721
+ };
8722
+ }
8599
8723
  function fileTypeValidator(allowed, message) {
8600
8724
  const normalized = (allowed || []).map((s) => String(s).toLowerCase());
8601
8725
  const hasExt = (s) => s.startsWith('.');
@@ -8919,8 +9043,11 @@ function buildAngularValidators(field) {
8919
9043
  const v = [];
8920
9044
  let av = [];
8921
9045
  // Required / requiredChecked
8922
- if (field.required)
8923
- v.push(withMessage(Validators.required, 'required', field.requiredMessage));
9046
+ if (field.required) {
9047
+ v.push(isBooleanRequiredField(field)
9048
+ ? requiredPresenceValidator(field.requiredMessage)
9049
+ : withMessage(Validators.required, 'required', field.requiredMessage));
9050
+ }
8924
9051
  if (field.requiredChecked)
8925
9052
  v.push(requiredCheckedValidator());
8926
9053
  // Length
@@ -8973,6 +9100,11 @@ function buildAngularValidators(field) {
8973
9100
  }
8974
9101
  return { validators: v, asyncValidators: av };
8975
9102
  }
9103
+ function isBooleanRequiredField(field) {
9104
+ const controlType = String(field.controlType ?? '').toLowerCase();
9105
+ const type = String(field.type ?? field.dataType ?? '').toLowerCase();
9106
+ return type === 'boolean' || controlType === 'checkbox' || controlType === 'toggle';
9107
+ }
8976
9108
  function buildValidatorsFromValidatorOptions(opts = {}, jsonLogic = DEFAULT_JSON_LOGIC$3) {
8977
9109
  const v = [];
8978
9110
  let av = [];
@@ -9661,15 +9793,98 @@ class DynamicFormService {
9661
9793
  return null;
9662
9794
  });
9663
9795
  }
9796
+ else if (this.isPhoneField(meta)) {
9797
+ const pattern = meta.validators?.pattern ?? meta.pattern;
9798
+ const patternMessage = meta.validators?.patternMessage ?? meta.patternMessage;
9799
+ if (pattern) {
9800
+ v.push(this.buildNormalizedPhonePatternValidator(pattern, patternMessage));
9801
+ }
9802
+ }
9664
9803
  return v;
9665
9804
  }
9666
9805
  /**
9667
9806
  * Indica se o campo deve ser tratado como seleção múltipla (valor padrão []).
9668
9807
  */
9669
9808
  isMultipleField(meta) {
9670
- return (meta.controlType === FieldControlType.CHECKBOX ||
9671
- meta.controlType === FieldControlType.MULTI_SELECT ||
9672
- meta.multiple === true);
9809
+ return (meta.controlType === FieldControlType.MULTI_SELECT ||
9810
+ meta.multiple === true ||
9811
+ (meta.controlType === FieldControlType.CHECKBOX &&
9812
+ this.hasCheckboxOptions(meta)));
9813
+ }
9814
+ isBooleanField(meta) {
9815
+ const controlType = String(meta?.controlType ?? '').toLowerCase();
9816
+ const type = String(meta?.type ?? meta?.dataType ?? '').toLowerCase();
9817
+ if (controlType === 'checkbox' && (this.isMultipleField(meta) || this.hasCheckboxOptions(meta))) {
9818
+ return false;
9819
+ }
9820
+ return type === 'boolean' || controlType === 'checkbox' || controlType === 'toggle';
9821
+ }
9822
+ hasCheckboxOptions(meta) {
9823
+ return (Array.isArray(meta.checkboxOptions) ||
9824
+ Array.isArray(meta.options));
9825
+ }
9826
+ isPhoneField(meta) {
9827
+ const controlType = String(meta?.controlType ?? '').toLowerCase();
9828
+ return controlType === 'phone' || controlType === 'phoneinput' || controlType === 'inlinephone';
9829
+ }
9830
+ buildNormalizedPhonePatternValidator(pattern, message) {
9831
+ const { regex, requiredPattern } = this.buildAngularCompatiblePattern(pattern);
9832
+ return withMessage((control) => {
9833
+ const value = control.value;
9834
+ if (value === null || value === undefined || value === '') {
9835
+ return null;
9836
+ }
9837
+ const normalized = String(value).replace(/[()\s-]/g, '');
9838
+ regex.lastIndex = 0;
9839
+ return regex.test(normalized)
9840
+ ? null
9841
+ : {
9842
+ pattern: {
9843
+ requiredPattern,
9844
+ actualValue: value,
9845
+ normalizedValue: normalized,
9846
+ },
9847
+ };
9848
+ }, 'pattern', message);
9849
+ }
9850
+ buildAngularCompatiblePattern(pattern) {
9851
+ if (typeof pattern !== 'string') {
9852
+ return { regex: pattern, requiredPattern: pattern.toString() };
9853
+ }
9854
+ let regexStr = '';
9855
+ if (pattern.charAt(0) !== '^') {
9856
+ regexStr += '^';
9857
+ }
9858
+ regexStr += pattern;
9859
+ if (pattern.charAt(pattern.length - 1) !== '$') {
9860
+ regexStr += '$';
9861
+ }
9862
+ return { regex: new RegExp(regexStr), requiredPattern: regexStr };
9863
+ }
9864
+ buildFromMetadata(meta) {
9865
+ const options = { ...(meta.validators ?? {}) };
9866
+ const required = meta.validators?.required === true ||
9867
+ meta.required === true;
9868
+ if (meta.required === true && options.required === undefined) {
9869
+ options.required = true;
9870
+ }
9871
+ if (meta.pattern && options.pattern === undefined) {
9872
+ options.pattern = meta.pattern;
9873
+ }
9874
+ if (meta.patternMessage && options.patternMessage === undefined) {
9875
+ options.patternMessage = meta.patternMessage;
9876
+ }
9877
+ if (this.isBooleanField(meta) && required) {
9878
+ options.required = false;
9879
+ }
9880
+ if (this.isPhoneField(meta) && options.pattern) {
9881
+ options.pattern = undefined;
9882
+ }
9883
+ const built = this.buildFromValidatorOptions(options);
9884
+ if (this.isBooleanField(meta) && required) {
9885
+ built.validators.unshift(requiredPresenceValidator(meta.validators?.requiredMessage ?? meta.requiredMessage));
9886
+ }
9887
+ return built;
9673
9888
  }
9674
9889
  isArrayMetadata(meta) {
9675
9890
  return (meta.controlType === FieldControlType.ARRAY_INPUT ||
@@ -9890,7 +10105,7 @@ class DynamicFormService {
9890
10105
  * - Valor inicial: [] para campos múltiplos quando ausente.
9891
10106
  */
9892
10107
  createControlFromMetadata(meta) {
9893
- const { validators, asyncValidators } = this.buildFromValidatorOptions(meta.validators);
10108
+ const { validators, asyncValidators } = this.buildFromMetadata(meta);
9894
10109
  const updateOn = this.getUpdateOnFromMetadata(meta);
9895
10110
  const initialValue = meta.defaultValue ?? null;
9896
10111
  const value = this.isMultipleField(meta) && initialValue == null ? [] : initialValue;
@@ -9971,7 +10186,7 @@ class DynamicFormService {
9971
10186
  control.updateValueAndValidity({ emitEvent: opts.emitEvent ?? false });
9972
10187
  return;
9973
10188
  }
9974
- const { validators, asyncValidators } = this.buildFromValidatorOptions(meta.validators);
10189
+ const { validators, asyncValidators } = this.buildFromMetadata(meta);
9975
10190
  control.setValidators(validators);
9976
10191
  control.setAsyncValidators(asyncValidators);
9977
10192
  control.addValidators(this.getUiSpecificValidators(meta));
@@ -10455,8 +10670,17 @@ function serializePraxisCollectionToCsv(request, policy = PRAXIS_DEFAULT_EXPORT_
10455
10670
  const fields = resolvePraxisExportFields(request);
10456
10671
  const items = resolvePraxisCollectionExportItems(request);
10457
10672
  const rows = [];
10673
+ const csvOptions = request.formatOptions?.csv;
10674
+ const locale = request.localization?.locale;
10675
+ const isPtBr = locale === 'pt-BR' || (typeof locale === 'string' && locale.toLowerCase().startsWith('pt'));
10676
+ const delimiter = csvOptions?.delimiter ?? (isPtBr ? ';' : ',');
10677
+ const includeBom = csvOptions?.includeBom ?? isPtBr;
10678
+ const includeSepDirective = csvOptions?.includeSepDirective ?? (csvOptions?.excelCompatibility && delimiter === ';');
10679
+ if (includeSepDirective) {
10680
+ rows.push(`sep=${delimiter}`);
10681
+ }
10458
10682
  if (request.includeHeaders !== false) {
10459
- rows.push(fields.map((field) => quoteCsvCell(field.label ?? field.key)).join(','));
10683
+ rows.push(fields.map((field) => quoteCsvCell(field.label ?? field.key)).join(delimiter));
10460
10684
  }
10461
10685
  for (const item of applyPraxisExportLimit(items, request.maxRows)) {
10462
10686
  const cells = fields.map((field) => {
@@ -10468,9 +10692,10 @@ function serializePraxisCollectionToCsv(request, policy = PRAXIS_DEFAULT_EXPORT_
10468
10692
  : rawValue;
10469
10693
  return quoteCsvCell(escapePraxisExportCell(formattedValue, policy));
10470
10694
  });
10471
- rows.push(cells.join(','));
10695
+ rows.push(cells.join(delimiter));
10472
10696
  }
10473
- return rows.join('\r\n');
10697
+ const csvContent = rows.join('\r\n');
10698
+ return includeBom ? `\uFEFF${csvContent}` : csvContent;
10474
10699
  }
10475
10700
  function serializePraxisCollectionToJson(request) {
10476
10701
  const fields = resolvePraxisExportFields(request);
@@ -11697,6 +11922,108 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
11697
11922
  args: [{ providedIn: 'any' }]
11698
11923
  }] });
11699
11924
 
11925
+ function clonePraxisRuntimeComponentObservation(observation) {
11926
+ assertPraxisRuntimeComponentObservationSerializable(observation);
11927
+ return JSON.parse(JSON.stringify(observation));
11928
+ }
11929
+ function assertPraxisRuntimeComponentObservationSerializable(observation) {
11930
+ assertSerializableValue(observation, 'observation', new WeakSet());
11931
+ }
11932
+ function assertSerializableValue(value, path, seen) {
11933
+ if (value === null ||
11934
+ typeof value === 'string' ||
11935
+ typeof value === 'number' ||
11936
+ typeof value === 'boolean' ||
11937
+ value === undefined) {
11938
+ return;
11939
+ }
11940
+ if (typeof value === 'function' ||
11941
+ typeof value === 'symbol' ||
11942
+ typeof value === 'bigint') {
11943
+ throw new Error(`Runtime observation contains a non-serializable value at ${path}.`);
11944
+ }
11945
+ if (typeof value !== 'object') {
11946
+ throw new Error(`Runtime observation contains an unsupported value at ${path}.`);
11947
+ }
11948
+ if (seen.has(value)) {
11949
+ throw new Error(`Runtime observation contains a circular reference at ${path}.`);
11950
+ }
11951
+ seen.add(value);
11952
+ if (Array.isArray(value)) {
11953
+ value.forEach((item, index) => {
11954
+ assertSerializableValue(item, `${path}[${index}]`, seen);
11955
+ });
11956
+ seen.delete(value);
11957
+ return;
11958
+ }
11959
+ Object.entries(value).forEach(([key, item]) => {
11960
+ assertSerializableValue(item, `${path}.${key}`, seen);
11961
+ });
11962
+ seen.delete(value);
11963
+ }
11964
+
11965
+ class PraxisRuntimeComponentObservationRegistryService {
11966
+ entriesSignal = signal([], ...(ngDevMode ? [{ debugName: "entriesSignal" }] : /* istanbul ignore next */ []));
11967
+ registeredCount = computed(() => this.entriesSignal().length, ...(ngDevMode ? [{ debugName: "registeredCount" }] : /* istanbul ignore next */ []));
11968
+ register(provider, options = {}) {
11969
+ const entry = {
11970
+ id: Symbol('praxis-runtime-component-observation'),
11971
+ provider,
11972
+ };
11973
+ let active = true;
11974
+ this.entriesSignal.update((entries) => [...entries, entry]);
11975
+ const destroy = () => {
11976
+ if (!active) {
11977
+ return;
11978
+ }
11979
+ active = false;
11980
+ this.entriesSignal.update((entries) => entries.filter((candidate) => candidate.id !== entry.id));
11981
+ };
11982
+ options.destroyRef?.onDestroy(destroy);
11983
+ return { destroy };
11984
+ }
11985
+ async listActive() {
11986
+ const settled = await Promise.allSettled(this.entriesSignal().map((entry) => this.resolveObservation(entry.provider)));
11987
+ return settled
11988
+ .filter((result) => result.status === 'fulfilled' && this.isActiveObservation(result.value))
11989
+ .map((result) => result.value);
11990
+ }
11991
+ async getByInstance(instanceId) {
11992
+ const normalizedInstanceId = instanceId.trim();
11993
+ if (!normalizedInstanceId) {
11994
+ return null;
11995
+ }
11996
+ const active = await this.listActive();
11997
+ return active.find((observation) => observation.identity.instanceId === normalizedInstanceId) ?? null;
11998
+ }
11999
+ async resolveObservation(provider) {
12000
+ const observation = await provider.getObservation();
12001
+ return clonePraxisRuntimeComponentObservation(observation);
12002
+ }
12003
+ isActiveObservation(observation) {
12004
+ if (!observation.lifecycle.active) {
12005
+ return false;
12006
+ }
12007
+ const ttlMs = observation.lifecycle.ttlMs;
12008
+ if (ttlMs === undefined || ttlMs < 0) {
12009
+ return true;
12010
+ }
12011
+ const capturedAt = Date.parse(observation.lifecycle.capturedAt);
12012
+ return Number.isFinite(capturedAt) && Date.now() - capturedAt <= ttlMs;
12013
+ }
12014
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisRuntimeComponentObservationRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
12015
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisRuntimeComponentObservationRegistryService, providedIn: 'root' });
12016
+ }
12017
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisRuntimeComponentObservationRegistryService, decorators: [{
12018
+ type: Injectable,
12019
+ args: [{ providedIn: 'root' }]
12020
+ }] });
12021
+ function registerPraxisRuntimeComponentObservation(provider, options = {}) {
12022
+ const registry = inject(PraxisRuntimeComponentObservationRegistryService);
12023
+ const destroyRef = options.destroyRef ?? inject(DestroyRef);
12024
+ return registry.register(provider, { ...options, destroyRef });
12025
+ }
12026
+
11700
12027
  const SURFACE_OPEN_PRESETS = [
11701
12028
  {
11702
12029
  id: 'praxis-dynamic-form',
@@ -11913,9 +12240,7 @@ class ResourceSurfaceOpenAdapterService {
11913
12240
  const resolvedSubmitUrl = this.isWritableFormSurface(surface.kind)
11914
12241
  ? this.discovery.resolveHref(surface.path, discoveryOptions)
11915
12242
  : null;
11916
- const resolvedReadUrl = this.isReadableItemSurface(surface)
11917
- ? this.discovery.resolveHref(surface.path, discoveryOptions)
11918
- : null;
12243
+ const resolvedReadUrl = this.resolveItemHydrationReadUrl(surface, resourcePath, discoveryOptions);
11919
12244
  const basePayload = this.buildBasePayload(surface);
11920
12245
  const payload = {
11921
12246
  ...basePayload,
@@ -11966,10 +12291,10 @@ class ResourceSurfaceOpenAdapterService {
11966
12291
  apiEndpointKey: options.endpointKey ?? null,
11967
12292
  apiUrlEntry: options.apiUrlEntry ?? resolvedApiEntry,
11968
12293
  };
11969
- if (surface.scope === 'ITEM' && this.isReadableFormSurface(surface.kind)) {
12294
+ if (surface.scope === 'ITEM' && resolvedReadUrl) {
11970
12295
  payload.widget.inputs['customEndpoints'] = {
11971
12296
  ...(payload.widget.inputs['customEndpoints'] || {}),
11972
- getById: this.discovery.resolveHref(surface.path, discoveryOptions),
12297
+ getById: resolvedReadUrl,
11973
12298
  };
11974
12299
  payload.widget.bindingOrder = this.withInputBefore(payload.widget.bindingOrder, 'customEndpoints', 'resourceId');
11975
12300
  }
@@ -12044,6 +12369,24 @@ class ResourceSurfaceOpenAdapterService {
12044
12369
  surface.method.toUpperCase() === 'GET' &&
12045
12370
  (surface.kind === 'VIEW' || surface.kind === 'READ_PROJECTION'));
12046
12371
  }
12372
+ isItemFormHydrationSurface(surface) {
12373
+ return surface.scope === 'ITEM'
12374
+ && (this.isReadableFormSurface(surface.kind) || this.isWritableFormSurface(surface.kind));
12375
+ }
12376
+ resolveItemHydrationReadUrl(surface, resourcePath, discoveryOptions) {
12377
+ if (!this.isItemFormHydrationSurface(surface)) {
12378
+ return null;
12379
+ }
12380
+ if (this.isReadableItemSurface(surface)) {
12381
+ return this.discovery.resolveHref(surface.path, discoveryOptions);
12382
+ }
12383
+ return this.discovery.resolveHref(this.buildCanonicalItemHref(resourcePath), discoveryOptions);
12384
+ }
12385
+ buildCanonicalItemHref(resourcePath) {
12386
+ const normalizedResourcePath = this.normalizeResourcePath(resourcePath);
12387
+ const itemHref = `${normalizedResourcePath}/{id}`;
12388
+ return normalizedResourcePath.startsWith('api/') ? `/${itemHref}` : itemHref;
12389
+ }
12047
12390
  buildIdBinding(idBindingPath) {
12048
12391
  return {
12049
12392
  from: idBindingPath,
@@ -12127,6 +12470,7 @@ class SurfaceOpenMaterializerService {
12127
12470
  if (data && typeof data === 'object' && !Array.isArray(data)) {
12128
12471
  const objectData = data;
12129
12472
  if (payload.widget.id === 'praxis-dynamic-form') {
12473
+ const schemaFields = await this.resolveSchemaFields(payload, discoveryOptions);
12130
12474
  return {
12131
12475
  ...payload,
12132
12476
  widget: {
@@ -12137,7 +12481,7 @@ class SurfaceOpenMaterializerService {
12137
12481
  mode: payload.widget.inputs?.['mode'] || 'view',
12138
12482
  initialValue: objectData,
12139
12483
  resourceId,
12140
- config: this.buildLocalFormConfig(objectData, payload.title),
12484
+ config: this.buildLocalFormConfig(objectData, schemaFields),
12141
12485
  },
12142
12486
  },
12143
12487
  context: this.mergeMaterializationContext(payload, {
@@ -12171,6 +12515,15 @@ class SurfaceOpenMaterializerService {
12171
12515
  const supported = new Set([
12172
12516
  'formId',
12173
12517
  'componentInstanceId',
12518
+ 'resourcePath',
12519
+ 'resourceId',
12520
+ 'apiEndpointKey',
12521
+ 'apiUrlEntry',
12522
+ 'submitUrl',
12523
+ 'submitMethod',
12524
+ 'responseSchemaUrl',
12525
+ 'customEndpoints',
12526
+ 'configPersistenceStrategy',
12174
12527
  'mode',
12175
12528
  'actions',
12176
12529
  'enableCustomization',
@@ -12191,41 +12544,146 @@ class SurfaceOpenMaterializerService {
12191
12544
  ]);
12192
12545
  return Object.fromEntries(Object.entries(inputs).filter(([key]) => supported.has(key)));
12193
12546
  }
12194
- buildLocalFormConfig(data, title) {
12195
- const fields = Object.entries(data)
12196
- .filter(([key, value]) => this.shouldRenderMaterializedFormField(key, value))
12197
- .map(([key, value]) => ({
12198
- name: key,
12199
- label: this.humanizeFieldName(key),
12200
- controlType: this.inferFormControlType(value),
12201
- readOnly: true,
12202
- }));
12203
- const fieldNames = fields.map((field) => field.name);
12204
- const rows = this.chunk(fieldNames, 2).map((names, index) => ({
12205
- id: `row-${index + 1}`,
12206
- columns: names.map((name) => ({
12207
- id: `col-${name}`,
12208
- fields: [name],
12209
- })),
12210
- }));
12547
+ buildLocalFormConfig(data, schemaFields = []) {
12548
+ const fields = this.buildMaterializedFormFields(data, schemaFields);
12549
+ const sections = this.buildMaterializedFormSections(fields);
12211
12550
  return {
12212
- sections: [
12213
- {
12214
- id: 'details',
12215
- title: title || 'Detalhes',
12216
- rows,
12217
- },
12218
- ],
12551
+ sections,
12219
12552
  fieldMetadata: fields,
12220
12553
  };
12221
12554
  }
12222
- shouldRenderMaterializedFormField(key, value) {
12555
+ buildMaterializedFormFields(data, schemaFields) {
12556
+ const schemaByName = new Map(schemaFields
12557
+ .filter((field) => !!field?.name)
12558
+ .map((field) => [field.name, field]));
12559
+ const orderedNames = schemaFields.length
12560
+ ? [
12561
+ ...schemaFields
12562
+ .filter((field) => field?.name && Object.prototype.hasOwnProperty.call(data, field.name))
12563
+ .sort((left, right) => (left.order ?? Number.MAX_SAFE_INTEGER) - (right.order ?? Number.MAX_SAFE_INTEGER))
12564
+ .map((field) => field.name),
12565
+ ...Object.keys(data).filter((key) => !schemaByName.has(key)),
12566
+ ]
12567
+ : Object.keys(data);
12568
+ return orderedNames
12569
+ .filter((key, index, keys) => keys.indexOf(key) === index)
12570
+ .filter((key) => this.shouldRenderMaterializedFormField(key, data[key], schemaByName.get(key), data))
12571
+ .map((key) => {
12572
+ const field = schemaByName.get(key);
12573
+ if (field) {
12574
+ return {
12575
+ ...mapFieldDefinitionToMetadata({
12576
+ ...field,
12577
+ hidden: false,
12578
+ formHidden: false,
12579
+ readOnly: true,
12580
+ }),
12581
+ readOnly: true,
12582
+ };
12583
+ }
12584
+ return {
12585
+ name: key,
12586
+ label: this.humanizeFieldName(key),
12587
+ controlType: this.inferFormControlType(data[key]),
12588
+ readOnly: true,
12589
+ };
12590
+ });
12591
+ }
12592
+ buildMaterializedFormSections(fields) {
12593
+ const groups = new Map();
12594
+ for (const field of fields) {
12595
+ const group = String(field.group || '').trim() || 'Detalhes';
12596
+ groups.set(group, [...(groups.get(group) || []), field]);
12597
+ }
12598
+ return Array.from(groups.entries()).map(([group, groupFields], sectionIndex) => {
12599
+ const fieldNames = groupFields.map((field) => field.name);
12600
+ const rows = this.chunk(fieldNames, 2).map((names, rowIndex) => ({
12601
+ id: `row-${sectionIndex + 1}-${rowIndex + 1}`,
12602
+ columns: names.map((name) => ({
12603
+ id: `col-${name}`,
12604
+ fields: [name],
12605
+ })),
12606
+ }));
12607
+ return {
12608
+ id: this.stableSectionId(group, sectionIndex),
12609
+ title: group,
12610
+ rows,
12611
+ };
12612
+ });
12613
+ }
12614
+ shouldRenderMaterializedFormField(key, value, field, data) {
12223
12615
  if (!key || key.startsWith('_'))
12224
12616
  return false;
12617
+ if (field?.hidden === true)
12618
+ return false;
12619
+ if (this.isTechnicalRelationIdField(key, field, data))
12620
+ return false;
12621
+ if (this.isDuplicateMediaUrlField(key, value, field, data))
12622
+ return false;
12623
+ if (field?.formHidden === true && !this.isResolvedDisplayCompanionField(key, data)) {
12624
+ return false;
12625
+ }
12225
12626
  if (value == null)
12226
12627
  return true;
12227
12628
  return typeof value !== 'object' || value instanceof Date;
12228
12629
  }
12630
+ isTechnicalRelationIdField(key, field, data) {
12631
+ if (key === 'id' || !/Id$/.test(key))
12632
+ return false;
12633
+ const base = key.slice(0, -2);
12634
+ const hasDisplayCompanion = this.hasDisplayCompanion(base, data);
12635
+ if (!hasDisplayCompanion)
12636
+ return false;
12637
+ const controlType = String(field?.controlType || '').toLowerCase();
12638
+ return Boolean(field?.endpoint
12639
+ || field?.resourcePath
12640
+ || field?.optionSource
12641
+ || controlType.includes('select')
12642
+ || field?.tableHidden === true);
12643
+ }
12644
+ isResolvedDisplayCompanionField(key, data) {
12645
+ const base = this.resolveDisplayCompanionBase(key);
12646
+ return !!base && Object.prototype.hasOwnProperty.call(data, `${base}Id`);
12647
+ }
12648
+ resolveDisplayCompanionBase(key) {
12649
+ const suffixes = ['Nome', 'Name', 'Label', 'Descricao', 'Description', 'Title', 'Text'];
12650
+ const suffix = suffixes.find((candidate) => key.endsWith(candidate));
12651
+ return suffix ? key.slice(0, -suffix.length) : null;
12652
+ }
12653
+ hasDisplayCompanion(base, data) {
12654
+ const suffixes = ['Nome', 'Name', 'Label', 'Descricao', 'Description', 'Title', 'Text'];
12655
+ return suffixes.some((suffix) => {
12656
+ const value = data[`${base}${suffix}`];
12657
+ return value != null && String(value).trim().length > 0;
12658
+ });
12659
+ }
12660
+ isDuplicateMediaUrlField(key, value, field, data) {
12661
+ if (typeof value !== 'string' || !this.looksLikeMediaUrlField(key, field)) {
12662
+ return false;
12663
+ }
12664
+ return Object.entries(data).some(([candidateKey, candidateValue]) => {
12665
+ if (candidateKey === key || candidateValue !== value) {
12666
+ return false;
12667
+ }
12668
+ return this.looksLikeAvatarFieldName(candidateKey);
12669
+ });
12670
+ }
12671
+ looksLikeMediaUrlField(key, field) {
12672
+ const type = String(field?.type || '').toLowerCase();
12673
+ const controlType = String(field?.controlType || '').toLowerCase();
12674
+ const normalized = key.toLowerCase();
12675
+ return Boolean(type === 'url'
12676
+ || controlType.includes('url')
12677
+ || normalized.includes('url')
12678
+ || normalized.includes('foto')
12679
+ || normalized.includes('photo')
12680
+ || normalized.includes('image')
12681
+ || normalized.includes('imagem'));
12682
+ }
12683
+ looksLikeAvatarFieldName(key) {
12684
+ const normalized = key.toLowerCase();
12685
+ return normalized.includes('avatar') || normalized.includes('portrait');
12686
+ }
12229
12687
  inferFormControlType(value) {
12230
12688
  if (typeof value === 'boolean')
12231
12689
  return 'checkbox';
@@ -12247,6 +12705,18 @@ class SurfaceOpenMaterializerService {
12247
12705
  .trim()
12248
12706
  .replace(/^./, (char) => char.toUpperCase());
12249
12707
  }
12708
+ stableSectionId(group, index) {
12709
+ if (group === 'Detalhes') {
12710
+ return 'details';
12711
+ }
12712
+ const normalized = group
12713
+ .normalize('NFD')
12714
+ .replace(/[\u0300-\u036f]/g, '')
12715
+ .toLowerCase()
12716
+ .replace(/[^a-z0-9]+/g, '-')
12717
+ .replace(/^-+|-+$/g, '');
12718
+ return normalized || `details-${index + 1}`;
12719
+ }
12250
12720
  chunk(items, size) {
12251
12721
  const result = [];
12252
12722
  for (let index = 0; index < items.length; index += size) {
@@ -14882,6 +15352,10 @@ const PRAXIS_GLOBAL_ACTION_CATALOG = [
14882
15352
  description: 'Bindings declarativos aplicados sobre widget.inputs.*. Prefira payload.* para o envelope canônico do evento e runtime.* para estado direto do host.',
14883
15353
  },
14884
15354
  context: { type: 'object', description: 'Contexto explícito adicional exposto ao runtime de bindings.' },
15355
+ onResult: {
15356
+ type: 'object',
15357
+ description: 'Ação estruturada executada quando a surface emite um resultado semântico via surface.result.',
15358
+ },
14885
15359
  },
14886
15360
  required: ['presentation', 'widget'],
14887
15361
  example: {
@@ -14902,6 +15376,60 @@ const PRAXIS_GLOBAL_ACTION_CATALOG = [
14902
15376
  },
14903
15377
  },
14904
15378
  },
15379
+ {
15380
+ id: 'surface.close',
15381
+ label: 'Fechar Surface',
15382
+ icon: 'close',
15383
+ description: 'Fecha a surface de runtime atual quando a ação é executada dentro de um host aberto por surface.open.',
15384
+ payloadSchema: {
15385
+ type: 'object',
15386
+ properties: {
15387
+ type: { type: 'string', description: 'Tipo semântico do fechamento.' },
15388
+ data: { type: 'object', description: 'Dados opcionais devolvidos ao host.' },
15389
+ },
15390
+ example: { type: 'done' },
15391
+ },
15392
+ },
15393
+ {
15394
+ id: 'surface.result',
15395
+ label: 'Emitir Resultado de Surface',
15396
+ icon: 'outbox',
15397
+ description: 'Emite um resultado semântico para a surface de runtime atual sem fechar o drawer.',
15398
+ payloadSchema: {
15399
+ type: 'object',
15400
+ properties: {
15401
+ type: { type: 'string', description: 'Tipo semântico do resultado.' },
15402
+ data: { type: 'object', description: 'Dados opcionais do resultado.' },
15403
+ },
15404
+ example: { type: 'selection', data: { id: 42 } },
15405
+ },
15406
+ },
15407
+ {
15408
+ id: 'dynamicPage.composition.dispatch',
15409
+ label: 'Despachar Evento de Composição',
15410
+ icon: 'hub',
15411
+ description: 'Publica um evento no runtime de composição da página atual para que links governados atualizem estado, widgets e projeções derivadas.',
15412
+ payloadSchema: {
15413
+ type: 'object',
15414
+ properties: {
15415
+ source: {
15416
+ type: 'object',
15417
+ description: 'Endpoint canônico que deve ser usado como origem do dispatch.',
15418
+ },
15419
+ payload: {
15420
+ type: 'object',
15421
+ description: 'Payload opcional do evento. Quando omitido, a ação usa o payload do contexto de execução.',
15422
+ },
15423
+ },
15424
+ required: ['source'],
15425
+ example: {
15426
+ source: {
15427
+ kind: 'global-action',
15428
+ ref: { actionId: 'peopleOps.decision.accepted' },
15429
+ },
15430
+ },
15431
+ },
15432
+ },
14905
15433
  {
14906
15434
  id: 'toast.success',
14907
15435
  label: 'Toast Sucesso',
@@ -23063,8 +23591,9 @@ class PraxisHeroBannerComponent {
23063
23591
  appearance = 'card';
23064
23592
  brandText;
23065
23593
  titleAccent;
23594
+ visualSummary;
23066
23595
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisHeroBannerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
23067
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisHeroBannerComponent, isStandalone: true, selector: "praxis-hero-banner", inputs: { instanceId: "instanceId", analyticsId: "analyticsId", ariaLabel: "ariaLabel", title: "title", subtitle: "subtitle", description: "description", imageUrl: "imageUrl", imageAlt: "imageAlt", badges: "badges", metaItems: "metaItems", variant: "variant", appearance: "appearance", brandText: "brandText", titleAccent: "titleAccent" }, host: { properties: { "attr.data-instance-id": "instanceId || null", "attr.data-analytics-id": "analyticsId || null", "attr.aria-label": "ariaLabel || null", "attr.role": "ariaLabel ? \"region\" : null", "attr.data-variant": "variant" }, classAttribute: "praxis-hero-banner" }, ngImport: i0, template: `
23596
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisHeroBannerComponent, isStandalone: true, selector: "praxis-hero-banner", inputs: { instanceId: "instanceId", analyticsId: "analyticsId", ariaLabel: "ariaLabel", title: "title", subtitle: "subtitle", description: "description", imageUrl: "imageUrl", imageAlt: "imageAlt", badges: "badges", metaItems: "metaItems", variant: "variant", appearance: "appearance", brandText: "brandText", titleAccent: "titleAccent", visualSummary: "visualSummary" }, host: { properties: { "attr.data-instance-id": "instanceId || null", "attr.data-analytics-id": "analyticsId || null", "attr.aria-label": "ariaLabel || null", "attr.role": "ariaLabel ? \"region\" : null", "attr.data-variant": "variant" }, classAttribute: "praxis-hero-banner" }, ngImport: i0, template: `
23068
23597
  <section
23069
23598
  class="phb-shell"
23070
23599
  [class.phb-event]="variant === 'event'"
@@ -23076,7 +23605,7 @@ class PraxisHeroBannerComponent {
23076
23605
  <p class="phb-brand">{{ brandText }}</p>
23077
23606
  }
23078
23607
 
23079
- @if (badges?.length) {
23608
+ @if (badges.length) {
23080
23609
  <div class="phb-badges">
23081
23610
  @for (badge of badges; track badge) {
23082
23611
  <span
@@ -23101,7 +23630,7 @@ class PraxisHeroBannerComponent {
23101
23630
  <span>{{ title }}</span>
23102
23631
  }
23103
23632
  @if (titleAccent) {
23104
- <span class="phb-title-accent">{{ titleAccent }}</span>
23633
+ <span class="phb-title-accent"> {{ titleAccent }}</span>
23105
23634
  }
23106
23635
  </h2>
23107
23636
  }
@@ -23110,7 +23639,7 @@ class PraxisHeroBannerComponent {
23110
23639
  }
23111
23640
  </div>
23112
23641
 
23113
- @if (metaItems?.length) {
23642
+ @if (metaItems.length) {
23114
23643
  <dl class="phb-meta">
23115
23644
  @for (item of metaItems; track item) {
23116
23645
  <div class="phb-meta-item">
@@ -23126,16 +23655,93 @@ class PraxisHeroBannerComponent {
23126
23655
  <div class="phb-visual">
23127
23656
  <img class="phb-image" [src]="imageUrl" [alt]="imageAlt || title || subtitle || 'Imagem do destaque'" />
23128
23657
  </div>
23658
+ } @else if (visualSummary) {
23659
+ <aside class="phb-visual phb-visual-summary" aria-label="Resumo visual">
23660
+ <div class="phb-summary-header">
23661
+ <div>
23662
+ @if (visualSummary.eyebrow) {
23663
+ <p class="phb-summary-eyebrow">{{ visualSummary.eyebrow }}</p>
23664
+ }
23665
+ @if (visualSummary.title) {
23666
+ <h3>{{ visualSummary.title }}</h3>
23667
+ }
23668
+ </div>
23669
+ @if (visualSummary.status) {
23670
+ <span
23671
+ class="phb-status"
23672
+ [class.phb-tone-success]="visualSummary.statusTone === 'success'"
23673
+ [class.phb-tone-warning]="visualSummary.statusTone === 'warning'"
23674
+ [class.phb-tone-danger]="visualSummary.statusTone === 'danger'"
23675
+ [class.phb-tone-info]="visualSummary.statusTone === 'info'"
23676
+ >
23677
+ {{ visualSummary.status }}
23678
+ </span>
23679
+ }
23680
+ </div>
23681
+
23682
+ @if (visualSummary.items?.length) {
23683
+ <dl class="phb-summary-grid">
23684
+ @for (item of visualSummary.items; track item) {
23685
+ <div
23686
+ class="phb-summary-item"
23687
+ [class.phb-tone-success]="item.tone === 'success'"
23688
+ [class.phb-tone-warning]="item.tone === 'warning'"
23689
+ [class.phb-tone-danger]="item.tone === 'danger'"
23690
+ [class.phb-tone-info]="item.tone === 'info'"
23691
+ >
23692
+ <dt>{{ item.label }}</dt>
23693
+ <dd>{{ item.value }}</dd>
23694
+ </div>
23695
+ }
23696
+ </dl>
23697
+ }
23698
+
23699
+ @if (visualSummary.events?.length) {
23700
+ <div class="phb-summary-events">
23701
+ @for (event of visualSummary.events; track event) {
23702
+ <div
23703
+ class="phb-summary-event"
23704
+ [class.phb-tone-success]="event.tone === 'success'"
23705
+ [class.phb-tone-warning]="event.tone === 'warning'"
23706
+ [class.phb-tone-danger]="event.tone === 'danger'"
23707
+ [class.phb-tone-info]="event.tone === 'info'"
23708
+ >
23709
+ <span>{{ event.label }}</span>
23710
+ @if (event.value) {
23711
+ <strong>{{ event.value }}</strong>
23712
+ }
23713
+ </div>
23714
+ }
23715
+ </div>
23716
+ }
23717
+ </aside>
23129
23718
  } @else {
23130
23719
  <div class="phb-visual phb-visual-fallback" aria-hidden="true">
23131
- <div class="phb-orb phb-orb-a"></div>
23132
- <div class="phb-orb phb-orb-b"></div>
23133
- <div class="phb-grid"></div>
23720
+ <div class="phb-preview">
23721
+ <div class="phb-preview-header"></div>
23722
+ <div class="phb-preview-kpis">
23723
+ <span></span>
23724
+ <span></span>
23725
+ <span></span>
23726
+ </div>
23727
+ <div class="phb-preview-chart">
23728
+ <span style="--bar-height: 42%"></span>
23729
+ <span style="--bar-height: 68%"></span>
23730
+ <span style="--bar-height: 54%"></span>
23731
+ <span style="--bar-height: 82%"></span>
23732
+ <span style="--bar-height: 62%"></span>
23733
+ </div>
23734
+ <div class="phb-preview-list">
23735
+ <span></span>
23736
+ <span></span>
23737
+ <span></span>
23738
+ </div>
23739
+ </div>
23134
23740
  </div>
23135
23741
  }
23136
23742
 
23137
23743
  </section>
23138
- `, isInline: true, styles: [":host{display:block;--phb-shell-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 60%, transparent);--phb-shell-shadow: 0 24px 60px color-mix(in srgb, var(--md-sys-color-shadow, #000) 10%, transparent);--phb-shell-bg: radial-gradient(circle at top right, color-mix(in srgb, var(--md-sys-color-primary) 14%, transparent), transparent 38%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 92%, var(--md-sys-color-primary-container) 8%) 0%, color-mix(in srgb, var(--md-sys-color-surface-container-low) 88%, var(--md-sys-color-primary-container) 12%) 54%, color-mix(in srgb, var(--md-sys-color-surface) 96%, var(--md-sys-color-surface-container) 4%) 100% );--phb-event-bg: radial-gradient(circle at top right, rgba(255, 184, 77, .24), transparent 34%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary-container) 16%, var(--md-sys-color-surface-container-lowest) 84%) 0%, color-mix(in srgb, var(--md-sys-color-primary-container) 24%, var(--md-sys-color-surface-container-low) 76%) 45%, color-mix(in srgb, var(--md-sys-color-surface) 92%, var(--md-sys-color-primary-container) 8%) 100% );--phb-institutional-bg: radial-gradient(circle at top right, rgba(17, 94, 89, .2), transparent 34%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-secondary-container) 18%, var(--md-sys-color-surface-container-lowest) 82%) 0%, color-mix(in srgb, var(--md-sys-color-secondary-container) 24%, var(--md-sys-color-surface-container-low) 76%) 48%, color-mix(in srgb, var(--md-sys-color-surface) 94%, var(--md-sys-color-secondary-container) 6%) 100% );--phb-brand-color: color-mix(in srgb, var(--md-sys-color-primary) 68%, var(--md-sys-color-on-surface) 32%);--phb-subtitle-color: color-mix(in srgb, var(--md-sys-color-primary) 52%, var(--md-sys-color-on-surface) 48%);--phb-title-color: var(--md-sys-color-on-surface);--phb-description-color: var(--md-sys-color-on-surface-variant);--phb-badge-bg: color-mix(in srgb, var(--md-sys-color-surface-container-high) 78%, transparent);--phb-badge-color: var(--md-sys-color-on-surface);--phb-badge-highlight-bg: color-mix(in srgb, var(--md-sys-color-primary-container) 78%, transparent);--phb-badge-highlight-color: var(--md-sys-color-on-primary-container);--phb-badge-muted-bg: color-mix(in srgb, var(--md-sys-color-surface-container-highest) 82%, transparent);--phb-badge-muted-color: var(--md-sys-color-on-surface-variant);--phb-badge-warning-bg: color-mix(in srgb, var(--md-sys-color-error-container) 74%, transparent);--phb-badge-warning-color: var(--md-sys-color-on-error-container);--phb-meta-bg: color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 72%, transparent);--phb-meta-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 48%, transparent);--phb-meta-label-color: var(--md-sys-color-on-surface-variant);--phb-meta-value-color: var(--md-sys-color-on-surface);--phb-visual-bg: linear-gradient( 160deg, color-mix(in srgb, var(--md-sys-color-surface-container-high) 90%, var(--md-sys-color-primary) 10%), color-mix(in srgb, var(--md-sys-color-surface-container-low) 88%, var(--md-sys-color-primary-container) 12%) );--phb-visual-fallback: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-surface-bright, var(--md-sys-color-surface-container-high)) 24%, transparent), color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 8%, transparent) ), linear-gradient( 145deg, color-mix(in srgb, var(--md-sys-color-primary) 18%, var(--md-sys-color-surface-container-high) 82%), color-mix(in srgb, var(--md-sys-color-primary-container) 18%, var(--md-sys-color-surface-container-low) 82%) );--phb-orb-a-bg: color-mix(in srgb, var(--md-sys-color-surface-bright, var(--md-sys-color-surface-container-high)) 68%, transparent);--phb-orb-b-bg: color-mix(in srgb, var(--md-sys-color-primary) 22%, transparent);--phb-grid-line: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent)}:host-context(.mdc-theme-dark),:host-context(.theme-dark){--phb-shell-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 84%, transparent);--phb-shell-shadow: 0 22px 54px rgba(0, 0, 0, .28);--phb-shell-bg: radial-gradient(circle at top right, color-mix(in srgb, var(--md-sys-color-primary) 16%, transparent), transparent 40%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 90%, var(--md-sys-color-primary-container) 10%) 0%, color-mix(in srgb, var(--md-sys-color-surface-container-low) 84%, var(--md-sys-color-primary-container) 16%) 54%, color-mix(in srgb, var(--md-sys-color-surface) 92%, var(--md-sys-color-primary-container) 8%) 100% );--phb-event-bg: radial-gradient(circle at top right, rgba(255, 184, 77, .18), transparent 36%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary-container) 16%, var(--md-sys-color-surface-container-lowest) 84%) 0%, color-mix(in srgb, var(--md-sys-color-primary-container) 22%, var(--md-sys-color-surface-container-low) 78%) 45%, color-mix(in srgb, var(--md-sys-color-surface-container) 90%, var(--md-sys-color-primary-container) 10%) 100% );--phb-institutional-bg: radial-gradient(circle at top right, rgba(17, 94, 89, .16), transparent 36%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-secondary-container) 16%, var(--md-sys-color-surface-container-lowest) 84%) 0%, color-mix(in srgb, var(--md-sys-color-secondary-container) 20%, var(--md-sys-color-surface-container-low) 80%) 48%, color-mix(in srgb, var(--md-sys-color-surface-container) 92%, var(--md-sys-color-secondary-container) 8%) 100% );--phb-meta-bg: color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 70%, transparent);--phb-meta-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 60%, transparent);--phb-visual-bg: linear-gradient( 160deg, color-mix(in srgb, var(--md-sys-color-surface-container-high) 88%, var(--md-sys-color-primary) 12%), color-mix(in srgb, var(--md-sys-color-surface-container) 82%, var(--md-sys-color-primary-container) 18%) );--phb-visual-fallback: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-surface-container-high) 22%, transparent), color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 8%, transparent) ), linear-gradient( 145deg, color-mix(in srgb, var(--md-sys-color-primary) 22%, var(--md-sys-color-surface-container-high) 78%), color-mix(in srgb, var(--md-sys-color-primary-container) 24%, var(--md-sys-color-surface-container-low) 76%) );--phb-orb-a-bg: color-mix(in srgb, var(--md-sys-color-surface-container-highest) 34%, transparent);--phb-orb-b-bg: color-mix(in srgb, var(--md-sys-color-primary) 26%, transparent);--phb-grid-line: color-mix(in srgb, var(--md-sys-color-on-surface) 10%, transparent)}.phb-shell{display:grid;grid-template-columns:minmax(0,1.45fr) minmax(240px,.95fr);gap:22px;align-items:stretch;padding:22px;border-radius:28px;overflow:hidden;background:var(--phb-shell-bg);border:1px solid var(--phb-shell-border);box-shadow:var(--phb-shell-shadow)}.phb-event{background:var(--phb-event-bg)}.phb-institutional{background:var(--phb-institutional-bg)}.phb-copy{display:grid;gap:18px;min-width:0}.phb-brand{margin:0;color:var(--phb-brand-color);font-size:.88rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.phb-badges{display:flex;flex-wrap:wrap;gap:8px}.phb-badge{display:inline-flex;align-items:center;min-height:28px;padding:0 12px;border-radius:999px;background:var(--phb-badge-bg);color:var(--phb-badge-color);font-size:.76rem;font-weight:700;letter-spacing:.02em}.phb-badge-highlight{background:var(--phb-badge-highlight-bg);color:var(--phb-badge-highlight-color)}.phb-badge-muted{background:var(--phb-badge-muted-bg);color:var(--phb-badge-muted-color)}.phb-badge-warning{background:var(--phb-badge-warning-bg);color:var(--phb-badge-warning-color)}.phb-text{display:grid;gap:8px}.phb-subtitle{margin:0;color:var(--phb-subtitle-color);font-size:.9rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em}.phb-title{margin:0;color:var(--phb-title-color);font-size:clamp(1.6rem,2.2vw,2.5rem);line-height:1.08;letter-spacing:-.03em}.phb-title-accent{display:inline;margin-left:.18em;background:linear-gradient(90deg,#4285f4,#6ea8ff 28%,#a142f4 62%,#ea4335);-webkit-background-clip:text;background-clip:text;color:transparent}.phb-description{margin:0;max-width:56ch;color:var(--phb-description-color);font-size:.98rem;line-height:1.65}.phb-meta{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin:0}.phb-meta-item{display:grid;gap:4px;padding:12px 14px;border-radius:16px;background:var(--phb-meta-bg);border:1px solid var(--phb-meta-border);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.phb-meta-item dt{margin:0;color:var(--phb-meta-label-color);font-size:.73rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em}.phb-meta-item dd{margin:0;color:var(--phb-meta-value-color);font-size:.92rem;line-height:1.45}.phb-visual{position:relative;min-height:220px;border-radius:22px;overflow:hidden;background:var(--phb-visual-bg)}.phb-image{display:block;width:100%;height:100%;object-fit:cover}.phb-visual-fallback{background:var(--phb-visual-fallback)}.phb-flat{padding:0 0 18px;border:0;border-radius:0;box-shadow:none;background:transparent;grid-template-columns:minmax(0,1.15fr) minmax(220px,.85fr);gap:18px}.phb-flat .phb-brand{color:var(--md-sys-color-primary)}.phb-flat .phb-badges{order:3}.phb-flat .phb-meta{grid-template-columns:1fr;gap:6px}.phb-flat .phb-meta-item{padding:0;border:0;border-radius:0;background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none}.phb-flat .phb-meta-item dt,.phb-flat .phb-meta-item dd{display:inline}.phb-flat .phb-meta-item dt{margin-right:6px}.phb-flat .phb-visual{min-height:190px;border-radius:26px}.phb-orb{position:absolute;border-radius:999px;filter:blur(2px)}.phb-orb-a{inset:24px auto auto 20px;width:86px;height:86px;background:var(--phb-orb-a-bg)}.phb-orb-b{inset:auto 16px 18px auto;width:132px;height:132px;background:var(--phb-orb-b-bg)}.phb-grid{position:absolute;inset:0;background-image:linear-gradient(var(--phb-grid-line) 1px,transparent 1px),linear-gradient(90deg,var(--phb-grid-line) 1px,transparent 1px);background-size:24px 24px;opacity:.5}@media(max-width:900px){.phb-shell{grid-template-columns:1fr;padding:18px}.phb-visual{order:-1;min-height:180px}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
23744
+ `, isInline: true, styles: [":host{display:block;--phb-shell-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 60%, transparent);--phb-shell-shadow: 0 24px 60px color-mix(in srgb, var(--md-sys-color-shadow, #000) 10%, transparent);--phb-shell-bg: radial-gradient(circle at top right, color-mix(in srgb, var(--md-sys-color-primary) 14%, transparent), transparent 38%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 92%, var(--md-sys-color-primary-container) 8%) 0%, color-mix(in srgb, var(--md-sys-color-surface-container-low) 88%, var(--md-sys-color-primary-container) 12%) 54%, color-mix(in srgb, var(--md-sys-color-surface) 96%, var(--md-sys-color-surface-container) 4%) 100% );--phb-event-bg: radial-gradient(circle at top right, rgba(255, 184, 77, .24), transparent 34%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary-container) 16%, var(--md-sys-color-surface-container-lowest) 84%) 0%, color-mix(in srgb, var(--md-sys-color-primary-container) 24%, var(--md-sys-color-surface-container-low) 76%) 45%, color-mix(in srgb, var(--md-sys-color-surface) 92%, var(--md-sys-color-primary-container) 8%) 100% );--phb-institutional-bg: radial-gradient(circle at top right, rgba(17, 94, 89, .2), transparent 34%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-secondary-container) 18%, var(--md-sys-color-surface-container-lowest) 82%) 0%, color-mix(in srgb, var(--md-sys-color-secondary-container) 24%, var(--md-sys-color-surface-container-low) 76%) 48%, color-mix(in srgb, var(--md-sys-color-surface) 94%, var(--md-sys-color-secondary-container) 6%) 100% );--phb-brand-color: color-mix(in srgb, var(--md-sys-color-primary) 68%, var(--md-sys-color-on-surface) 32%);--phb-subtitle-color: color-mix(in srgb, var(--md-sys-color-primary) 52%, var(--md-sys-color-on-surface) 48%);--phb-title-color: var(--md-sys-color-on-surface);--phb-description-color: var(--md-sys-color-on-surface-variant);--phb-badge-bg: color-mix(in srgb, var(--md-sys-color-surface-container-high) 78%, transparent);--phb-badge-color: var(--md-sys-color-on-surface);--phb-badge-highlight-bg: color-mix(in srgb, var(--md-sys-color-primary-container) 78%, transparent);--phb-badge-highlight-color: var(--md-sys-color-on-primary-container);--phb-badge-muted-bg: color-mix(in srgb, var(--md-sys-color-surface-container-highest) 82%, transparent);--phb-badge-muted-color: var(--md-sys-color-on-surface-variant);--phb-badge-warning-bg: color-mix(in srgb, var(--md-sys-color-error-container) 74%, transparent);--phb-badge-warning-color: var(--md-sys-color-on-error-container);--phb-meta-bg: color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 72%, transparent);--phb-meta-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 48%, transparent);--phb-meta-label-color: var(--md-sys-color-on-surface-variant);--phb-meta-value-color: var(--md-sys-color-on-surface);--phb-visual-bg: linear-gradient( 160deg, color-mix(in srgb, var(--md-sys-color-surface-container-high) 90%, var(--md-sys-color-primary) 10%), color-mix(in srgb, var(--md-sys-color-surface-container-low) 88%, var(--md-sys-color-primary-container) 12%) );--phb-visual-fallback: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-surface-bright, var(--md-sys-color-surface-container-high)) 24%, transparent), color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 8%, transparent) ), linear-gradient( 145deg, color-mix(in srgb, var(--md-sys-color-primary) 18%, var(--md-sys-color-surface-container-high) 82%), color-mix(in srgb, var(--md-sys-color-primary-container) 18%, var(--md-sys-color-surface-container-low) 82%) );--phb-orb-a-bg: color-mix(in srgb, var(--md-sys-color-surface-bright, var(--md-sys-color-surface-container-high)) 68%, transparent);--phb-orb-b-bg: color-mix(in srgb, var(--md-sys-color-primary) 22%, transparent);--phb-grid-line: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent)}:host-context(.mdc-theme-dark),:host-context(.theme-dark){--phb-shell-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 84%, transparent);--phb-shell-shadow: 0 22px 54px rgba(0, 0, 0, .28);--phb-shell-bg: radial-gradient(circle at top right, color-mix(in srgb, var(--md-sys-color-primary) 16%, transparent), transparent 40%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 90%, var(--md-sys-color-primary-container) 10%) 0%, color-mix(in srgb, var(--md-sys-color-surface-container-low) 84%, var(--md-sys-color-primary-container) 16%) 54%, color-mix(in srgb, var(--md-sys-color-surface) 92%, var(--md-sys-color-primary-container) 8%) 100% );--phb-event-bg: radial-gradient(circle at top right, rgba(255, 184, 77, .18), transparent 36%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary-container) 16%, var(--md-sys-color-surface-container-lowest) 84%) 0%, color-mix(in srgb, var(--md-sys-color-primary-container) 22%, var(--md-sys-color-surface-container-low) 78%) 45%, color-mix(in srgb, var(--md-sys-color-surface-container) 90%, var(--md-sys-color-primary-container) 10%) 100% );--phb-institutional-bg: radial-gradient(circle at top right, rgba(17, 94, 89, .16), transparent 36%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-secondary-container) 16%, var(--md-sys-color-surface-container-lowest) 84%) 0%, color-mix(in srgb, var(--md-sys-color-secondary-container) 20%, var(--md-sys-color-surface-container-low) 80%) 48%, color-mix(in srgb, var(--md-sys-color-surface-container) 92%, var(--md-sys-color-secondary-container) 8%) 100% );--phb-meta-bg: color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 70%, transparent);--phb-meta-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 60%, transparent);--phb-visual-bg: linear-gradient( 160deg, color-mix(in srgb, var(--md-sys-color-surface-container-high) 88%, var(--md-sys-color-primary) 12%), color-mix(in srgb, var(--md-sys-color-surface-container) 82%, var(--md-sys-color-primary-container) 18%) );--phb-visual-fallback: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-surface-container-high) 22%, transparent), color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 8%, transparent) ), linear-gradient( 145deg, color-mix(in srgb, var(--md-sys-color-primary) 22%, var(--md-sys-color-surface-container-high) 78%), color-mix(in srgb, var(--md-sys-color-primary-container) 24%, var(--md-sys-color-surface-container-low) 76%) );--phb-orb-a-bg: color-mix(in srgb, var(--md-sys-color-surface-container-highest) 34%, transparent);--phb-orb-b-bg: color-mix(in srgb, var(--md-sys-color-primary) 26%, transparent);--phb-grid-line: color-mix(in srgb, var(--md-sys-color-on-surface) 10%, transparent)}.phb-shell{display:grid;grid-template-columns:minmax(0,1.45fr) minmax(240px,.95fr);gap:22px;align-items:stretch;padding:22px;border-radius:28px;overflow:hidden;background:var(--phb-shell-bg);border:1px solid var(--phb-shell-border);box-shadow:var(--phb-shell-shadow)}.phb-event{background:var(--phb-event-bg)}.phb-institutional{background:var(--phb-institutional-bg)}.phb-copy{display:grid;gap:14px;min-width:0}.phb-brand{margin:0;color:var(--phb-brand-color);font-size:.88rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.phb-badges{display:flex;flex-wrap:wrap;gap:8px}.phb-badge{display:inline-flex;align-items:center;min-height:28px;padding:0 12px;border-radius:999px;background:var(--phb-badge-bg);color:var(--phb-badge-color);font-size:.76rem;font-weight:700;letter-spacing:.02em}.phb-badge-highlight{background:var(--phb-badge-highlight-bg);color:var(--phb-badge-highlight-color)}.phb-badge-muted{background:var(--phb-badge-muted-bg);color:var(--phb-badge-muted-color)}.phb-badge-warning{background:var(--phb-badge-warning-bg);color:var(--phb-badge-warning-color)}.phb-text{display:grid;gap:8px}.phb-subtitle{margin:0;color:var(--phb-subtitle-color);font-size:.9rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em}.phb-title{margin:0;color:var(--phb-title-color);font-size:clamp(1.6rem,2.2vw,2.5rem);line-height:1.08;letter-spacing:0}.phb-title-accent{display:inline;background:linear-gradient(90deg,#4285f4,#6ea8ff 28%,#a142f4 62%,#ea4335);-webkit-background-clip:text;background-clip:text;color:transparent}.phb-description{margin:0;max-width:56ch;color:var(--phb-description-color);font-size:.94rem;line-height:1.5}.phb-meta{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin:0}.phb-meta-item{display:grid;gap:4px;padding:12px 14px;border-radius:16px;background:var(--phb-meta-bg);border:1px solid var(--phb-meta-border);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.phb-meta-item dt{margin:0;color:var(--phb-meta-label-color);font-size:.73rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em}.phb-meta-item dd{margin:0;color:var(--phb-meta-value-color);font-size:.92rem;line-height:1.45}.phb-visual{position:relative;min-height:220px;border-radius:22px;overflow:hidden;background:var(--phb-visual-bg)}.phb-image{display:block;width:100%;height:100%;object-fit:cover}.phb-visual-fallback{background:var(--phb-visual-fallback)}.phb-visual-summary{display:grid;align-content:start;gap:10px;padding:14px;background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-surface-container-high) 92%,var(--md-sys-color-primary) 8%),color-mix(in srgb,var(--md-sys-color-surface-container-low) 88%,var(--md-sys-color-tertiary) 12%))}.phb-summary-header{display:flex;align-items:start;justify-content:space-between;gap:12px}.phb-summary-eyebrow{margin:0 0 4px;color:var(--md-sys-color-primary);font-size:.72rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.phb-summary-header h3{margin:0;color:var(--md-sys-color-on-surface);font-size:.95rem;line-height:1.25}.phb-status{display:inline-flex;align-items:center;min-height:26px;padding:0 10px;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-surface-container-highest) 74%,transparent);color:var(--md-sys-color-on-surface);font-size:.72rem;font-weight:800;white-space:nowrap}.phb-summary-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:0}.phb-summary-item{display:grid;gap:4px;min-height:56px;padding:9px 10px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 48%,transparent);border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 58%,transparent)}.phb-summary-item dt{margin:0;color:var(--md-sys-color-on-surface-variant);font-size:.64rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em}.phb-summary-item dd{margin:0;color:var(--md-sys-color-on-surface);font-size:1.08rem;font-weight:850;line-height:1.15}.phb-summary-events{display:grid;gap:6px}.phb-summary-event{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:28px;padding:6px 9px;border-radius:12px;background:color-mix(in srgb,var(--md-sys-color-surface-container) 68%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:.72rem}.phb-summary-event strong{color:var(--md-sys-color-on-surface);font-weight:800;white-space:nowrap}.phb-tone-success{--phb-tone-color: var(--md-sys-color-tertiary);border-color:color-mix(in srgb,var(--md-sys-color-tertiary) 34%,var(--md-sys-color-outline-variant))}.phb-tone-warning{--phb-tone-color: #d79921;border-color:color-mix(in srgb,#d79921 36%,var(--md-sys-color-outline-variant))}.phb-tone-danger{--phb-tone-color: var(--md-sys-color-error);border-color:color-mix(in srgb,var(--md-sys-color-error) 34%,var(--md-sys-color-outline-variant))}.phb-tone-info{--phb-tone-color: var(--md-sys-color-primary);border-color:color-mix(in srgb,var(--md-sys-color-primary) 34%,var(--md-sys-color-outline-variant))}.phb-summary-item.phb-tone-success dd,.phb-summary-item.phb-tone-warning dd,.phb-summary-item.phb-tone-danger dd,.phb-summary-item.phb-tone-info dd,.phb-status.phb-tone-success,.phb-status.phb-tone-warning,.phb-status.phb-tone-danger,.phb-status.phb-tone-info,.phb-summary-event.phb-tone-success strong,.phb-summary-event.phb-tone-warning strong,.phb-summary-event.phb-tone-danger strong,.phb-summary-event.phb-tone-info strong{color:var(--phb-tone-color)}.phb-flat{padding:0 0 18px;border:0;border-radius:0;box-shadow:none;background:transparent;grid-template-columns:minmax(0,1.15fr) minmax(220px,.85fr);gap:18px}.phb-flat .phb-brand{color:var(--md-sys-color-primary)}.phb-flat .phb-badges{order:3}.phb-flat .phb-meta{grid-template-columns:1fr;gap:6px}.phb-flat .phb-meta-item{padding:0;border:0;border-radius:0;background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none}.phb-flat .phb-meta-item dt,.phb-flat .phb-meta-item dd{display:inline}.phb-flat .phb-meta-item dt{margin-right:6px}.phb-flat .phb-visual{min-height:190px;border-radius:26px}.phb-preview{position:absolute;inset:18px;display:grid;grid-template-rows:18px 44px minmax(72px,1fr) 1fr;gap:12px;padding:16px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 50%,transparent);border-radius:18px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 62%,transparent);box-shadow:inset 0 1px color-mix(in srgb,var(--md-sys-color-surface-bright, #fff) 28%,transparent)}.phb-preview-header,.phb-preview-kpis span,.phb-preview-list span{border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-on-surface) 12%,transparent)}.phb-preview-header{width:46%}.phb-preview-kpis{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.phb-preview-kpis span{height:44px;border-radius:12px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 48%,var(--md-sys-color-surface-container-high) 52%)}.phb-preview-chart{display:grid;grid-template-columns:repeat(5,1fr);align-items:end;gap:8px;padding:12px;border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface-container) 74%,transparent)}.phb-preview-chart span{min-height:18px;height:var(--bar-height);border-radius:8px 8px 4px 4px;background:color-mix(in srgb,var(--md-sys-color-primary) 68%,var(--md-sys-color-tertiary) 32%)}.phb-preview-list{display:grid;gap:8px;align-content:start}.phb-preview-list span{height:10px}.phb-preview-list span:nth-child(2){width:74%}.phb-preview-list span:nth-child(3){width:58%}@media(max-width:900px){.phb-shell{grid-template-columns:1fr;padding:18px}.phb-visual{order:-1;min-height:180px}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
23139
23745
  }
23140
23746
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisHeroBannerComponent, decorators: [{
23141
23747
  type: Component,
@@ -23158,7 +23764,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
23158
23764
  <p class="phb-brand">{{ brandText }}</p>
23159
23765
  }
23160
23766
 
23161
- @if (badges?.length) {
23767
+ @if (badges.length) {
23162
23768
  <div class="phb-badges">
23163
23769
  @for (badge of badges; track badge) {
23164
23770
  <span
@@ -23183,7 +23789,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
23183
23789
  <span>{{ title }}</span>
23184
23790
  }
23185
23791
  @if (titleAccent) {
23186
- <span class="phb-title-accent">{{ titleAccent }}</span>
23792
+ <span class="phb-title-accent"> {{ titleAccent }}</span>
23187
23793
  }
23188
23794
  </h2>
23189
23795
  }
@@ -23192,7 +23798,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
23192
23798
  }
23193
23799
  </div>
23194
23800
 
23195
- @if (metaItems?.length) {
23801
+ @if (metaItems.length) {
23196
23802
  <dl class="phb-meta">
23197
23803
  @for (item of metaItems; track item) {
23198
23804
  <div class="phb-meta-item">
@@ -23208,16 +23814,93 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
23208
23814
  <div class="phb-visual">
23209
23815
  <img class="phb-image" [src]="imageUrl" [alt]="imageAlt || title || subtitle || 'Imagem do destaque'" />
23210
23816
  </div>
23817
+ } @else if (visualSummary) {
23818
+ <aside class="phb-visual phb-visual-summary" aria-label="Resumo visual">
23819
+ <div class="phb-summary-header">
23820
+ <div>
23821
+ @if (visualSummary.eyebrow) {
23822
+ <p class="phb-summary-eyebrow">{{ visualSummary.eyebrow }}</p>
23823
+ }
23824
+ @if (visualSummary.title) {
23825
+ <h3>{{ visualSummary.title }}</h3>
23826
+ }
23827
+ </div>
23828
+ @if (visualSummary.status) {
23829
+ <span
23830
+ class="phb-status"
23831
+ [class.phb-tone-success]="visualSummary.statusTone === 'success'"
23832
+ [class.phb-tone-warning]="visualSummary.statusTone === 'warning'"
23833
+ [class.phb-tone-danger]="visualSummary.statusTone === 'danger'"
23834
+ [class.phb-tone-info]="visualSummary.statusTone === 'info'"
23835
+ >
23836
+ {{ visualSummary.status }}
23837
+ </span>
23838
+ }
23839
+ </div>
23840
+
23841
+ @if (visualSummary.items?.length) {
23842
+ <dl class="phb-summary-grid">
23843
+ @for (item of visualSummary.items; track item) {
23844
+ <div
23845
+ class="phb-summary-item"
23846
+ [class.phb-tone-success]="item.tone === 'success'"
23847
+ [class.phb-tone-warning]="item.tone === 'warning'"
23848
+ [class.phb-tone-danger]="item.tone === 'danger'"
23849
+ [class.phb-tone-info]="item.tone === 'info'"
23850
+ >
23851
+ <dt>{{ item.label }}</dt>
23852
+ <dd>{{ item.value }}</dd>
23853
+ </div>
23854
+ }
23855
+ </dl>
23856
+ }
23857
+
23858
+ @if (visualSummary.events?.length) {
23859
+ <div class="phb-summary-events">
23860
+ @for (event of visualSummary.events; track event) {
23861
+ <div
23862
+ class="phb-summary-event"
23863
+ [class.phb-tone-success]="event.tone === 'success'"
23864
+ [class.phb-tone-warning]="event.tone === 'warning'"
23865
+ [class.phb-tone-danger]="event.tone === 'danger'"
23866
+ [class.phb-tone-info]="event.tone === 'info'"
23867
+ >
23868
+ <span>{{ event.label }}</span>
23869
+ @if (event.value) {
23870
+ <strong>{{ event.value }}</strong>
23871
+ }
23872
+ </div>
23873
+ }
23874
+ </div>
23875
+ }
23876
+ </aside>
23211
23877
  } @else {
23212
23878
  <div class="phb-visual phb-visual-fallback" aria-hidden="true">
23213
- <div class="phb-orb phb-orb-a"></div>
23214
- <div class="phb-orb phb-orb-b"></div>
23215
- <div class="phb-grid"></div>
23879
+ <div class="phb-preview">
23880
+ <div class="phb-preview-header"></div>
23881
+ <div class="phb-preview-kpis">
23882
+ <span></span>
23883
+ <span></span>
23884
+ <span></span>
23885
+ </div>
23886
+ <div class="phb-preview-chart">
23887
+ <span style="--bar-height: 42%"></span>
23888
+ <span style="--bar-height: 68%"></span>
23889
+ <span style="--bar-height: 54%"></span>
23890
+ <span style="--bar-height: 82%"></span>
23891
+ <span style="--bar-height: 62%"></span>
23892
+ </div>
23893
+ <div class="phb-preview-list">
23894
+ <span></span>
23895
+ <span></span>
23896
+ <span></span>
23897
+ </div>
23898
+ </div>
23216
23899
  </div>
23217
23900
  }
23218
23901
 
23219
23902
  </section>
23220
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;--phb-shell-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 60%, transparent);--phb-shell-shadow: 0 24px 60px color-mix(in srgb, var(--md-sys-color-shadow, #000) 10%, transparent);--phb-shell-bg: radial-gradient(circle at top right, color-mix(in srgb, var(--md-sys-color-primary) 14%, transparent), transparent 38%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 92%, var(--md-sys-color-primary-container) 8%) 0%, color-mix(in srgb, var(--md-sys-color-surface-container-low) 88%, var(--md-sys-color-primary-container) 12%) 54%, color-mix(in srgb, var(--md-sys-color-surface) 96%, var(--md-sys-color-surface-container) 4%) 100% );--phb-event-bg: radial-gradient(circle at top right, rgba(255, 184, 77, .24), transparent 34%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary-container) 16%, var(--md-sys-color-surface-container-lowest) 84%) 0%, color-mix(in srgb, var(--md-sys-color-primary-container) 24%, var(--md-sys-color-surface-container-low) 76%) 45%, color-mix(in srgb, var(--md-sys-color-surface) 92%, var(--md-sys-color-primary-container) 8%) 100% );--phb-institutional-bg: radial-gradient(circle at top right, rgba(17, 94, 89, .2), transparent 34%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-secondary-container) 18%, var(--md-sys-color-surface-container-lowest) 82%) 0%, color-mix(in srgb, var(--md-sys-color-secondary-container) 24%, var(--md-sys-color-surface-container-low) 76%) 48%, color-mix(in srgb, var(--md-sys-color-surface) 94%, var(--md-sys-color-secondary-container) 6%) 100% );--phb-brand-color: color-mix(in srgb, var(--md-sys-color-primary) 68%, var(--md-sys-color-on-surface) 32%);--phb-subtitle-color: color-mix(in srgb, var(--md-sys-color-primary) 52%, var(--md-sys-color-on-surface) 48%);--phb-title-color: var(--md-sys-color-on-surface);--phb-description-color: var(--md-sys-color-on-surface-variant);--phb-badge-bg: color-mix(in srgb, var(--md-sys-color-surface-container-high) 78%, transparent);--phb-badge-color: var(--md-sys-color-on-surface);--phb-badge-highlight-bg: color-mix(in srgb, var(--md-sys-color-primary-container) 78%, transparent);--phb-badge-highlight-color: var(--md-sys-color-on-primary-container);--phb-badge-muted-bg: color-mix(in srgb, var(--md-sys-color-surface-container-highest) 82%, transparent);--phb-badge-muted-color: var(--md-sys-color-on-surface-variant);--phb-badge-warning-bg: color-mix(in srgb, var(--md-sys-color-error-container) 74%, transparent);--phb-badge-warning-color: var(--md-sys-color-on-error-container);--phb-meta-bg: color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 72%, transparent);--phb-meta-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 48%, transparent);--phb-meta-label-color: var(--md-sys-color-on-surface-variant);--phb-meta-value-color: var(--md-sys-color-on-surface);--phb-visual-bg: linear-gradient( 160deg, color-mix(in srgb, var(--md-sys-color-surface-container-high) 90%, var(--md-sys-color-primary) 10%), color-mix(in srgb, var(--md-sys-color-surface-container-low) 88%, var(--md-sys-color-primary-container) 12%) );--phb-visual-fallback: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-surface-bright, var(--md-sys-color-surface-container-high)) 24%, transparent), color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 8%, transparent) ), linear-gradient( 145deg, color-mix(in srgb, var(--md-sys-color-primary) 18%, var(--md-sys-color-surface-container-high) 82%), color-mix(in srgb, var(--md-sys-color-primary-container) 18%, var(--md-sys-color-surface-container-low) 82%) );--phb-orb-a-bg: color-mix(in srgb, var(--md-sys-color-surface-bright, var(--md-sys-color-surface-container-high)) 68%, transparent);--phb-orb-b-bg: color-mix(in srgb, var(--md-sys-color-primary) 22%, transparent);--phb-grid-line: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent)}:host-context(.mdc-theme-dark),:host-context(.theme-dark){--phb-shell-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 84%, transparent);--phb-shell-shadow: 0 22px 54px rgba(0, 0, 0, .28);--phb-shell-bg: radial-gradient(circle at top right, color-mix(in srgb, var(--md-sys-color-primary) 16%, transparent), transparent 40%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 90%, var(--md-sys-color-primary-container) 10%) 0%, color-mix(in srgb, var(--md-sys-color-surface-container-low) 84%, var(--md-sys-color-primary-container) 16%) 54%, color-mix(in srgb, var(--md-sys-color-surface) 92%, var(--md-sys-color-primary-container) 8%) 100% );--phb-event-bg: radial-gradient(circle at top right, rgba(255, 184, 77, .18), transparent 36%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary-container) 16%, var(--md-sys-color-surface-container-lowest) 84%) 0%, color-mix(in srgb, var(--md-sys-color-primary-container) 22%, var(--md-sys-color-surface-container-low) 78%) 45%, color-mix(in srgb, var(--md-sys-color-surface-container) 90%, var(--md-sys-color-primary-container) 10%) 100% );--phb-institutional-bg: radial-gradient(circle at top right, rgba(17, 94, 89, .16), transparent 36%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-secondary-container) 16%, var(--md-sys-color-surface-container-lowest) 84%) 0%, color-mix(in srgb, var(--md-sys-color-secondary-container) 20%, var(--md-sys-color-surface-container-low) 80%) 48%, color-mix(in srgb, var(--md-sys-color-surface-container) 92%, var(--md-sys-color-secondary-container) 8%) 100% );--phb-meta-bg: color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 70%, transparent);--phb-meta-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 60%, transparent);--phb-visual-bg: linear-gradient( 160deg, color-mix(in srgb, var(--md-sys-color-surface-container-high) 88%, var(--md-sys-color-primary) 12%), color-mix(in srgb, var(--md-sys-color-surface-container) 82%, var(--md-sys-color-primary-container) 18%) );--phb-visual-fallback: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-surface-container-high) 22%, transparent), color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 8%, transparent) ), linear-gradient( 145deg, color-mix(in srgb, var(--md-sys-color-primary) 22%, var(--md-sys-color-surface-container-high) 78%), color-mix(in srgb, var(--md-sys-color-primary-container) 24%, var(--md-sys-color-surface-container-low) 76%) );--phb-orb-a-bg: color-mix(in srgb, var(--md-sys-color-surface-container-highest) 34%, transparent);--phb-orb-b-bg: color-mix(in srgb, var(--md-sys-color-primary) 26%, transparent);--phb-grid-line: color-mix(in srgb, var(--md-sys-color-on-surface) 10%, transparent)}.phb-shell{display:grid;grid-template-columns:minmax(0,1.45fr) minmax(240px,.95fr);gap:22px;align-items:stretch;padding:22px;border-radius:28px;overflow:hidden;background:var(--phb-shell-bg);border:1px solid var(--phb-shell-border);box-shadow:var(--phb-shell-shadow)}.phb-event{background:var(--phb-event-bg)}.phb-institutional{background:var(--phb-institutional-bg)}.phb-copy{display:grid;gap:18px;min-width:0}.phb-brand{margin:0;color:var(--phb-brand-color);font-size:.88rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.phb-badges{display:flex;flex-wrap:wrap;gap:8px}.phb-badge{display:inline-flex;align-items:center;min-height:28px;padding:0 12px;border-radius:999px;background:var(--phb-badge-bg);color:var(--phb-badge-color);font-size:.76rem;font-weight:700;letter-spacing:.02em}.phb-badge-highlight{background:var(--phb-badge-highlight-bg);color:var(--phb-badge-highlight-color)}.phb-badge-muted{background:var(--phb-badge-muted-bg);color:var(--phb-badge-muted-color)}.phb-badge-warning{background:var(--phb-badge-warning-bg);color:var(--phb-badge-warning-color)}.phb-text{display:grid;gap:8px}.phb-subtitle{margin:0;color:var(--phb-subtitle-color);font-size:.9rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em}.phb-title{margin:0;color:var(--phb-title-color);font-size:clamp(1.6rem,2.2vw,2.5rem);line-height:1.08;letter-spacing:-.03em}.phb-title-accent{display:inline;margin-left:.18em;background:linear-gradient(90deg,#4285f4,#6ea8ff 28%,#a142f4 62%,#ea4335);-webkit-background-clip:text;background-clip:text;color:transparent}.phb-description{margin:0;max-width:56ch;color:var(--phb-description-color);font-size:.98rem;line-height:1.65}.phb-meta{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin:0}.phb-meta-item{display:grid;gap:4px;padding:12px 14px;border-radius:16px;background:var(--phb-meta-bg);border:1px solid var(--phb-meta-border);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.phb-meta-item dt{margin:0;color:var(--phb-meta-label-color);font-size:.73rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em}.phb-meta-item dd{margin:0;color:var(--phb-meta-value-color);font-size:.92rem;line-height:1.45}.phb-visual{position:relative;min-height:220px;border-radius:22px;overflow:hidden;background:var(--phb-visual-bg)}.phb-image{display:block;width:100%;height:100%;object-fit:cover}.phb-visual-fallback{background:var(--phb-visual-fallback)}.phb-flat{padding:0 0 18px;border:0;border-radius:0;box-shadow:none;background:transparent;grid-template-columns:minmax(0,1.15fr) minmax(220px,.85fr);gap:18px}.phb-flat .phb-brand{color:var(--md-sys-color-primary)}.phb-flat .phb-badges{order:3}.phb-flat .phb-meta{grid-template-columns:1fr;gap:6px}.phb-flat .phb-meta-item{padding:0;border:0;border-radius:0;background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none}.phb-flat .phb-meta-item dt,.phb-flat .phb-meta-item dd{display:inline}.phb-flat .phb-meta-item dt{margin-right:6px}.phb-flat .phb-visual{min-height:190px;border-radius:26px}.phb-orb{position:absolute;border-radius:999px;filter:blur(2px)}.phb-orb-a{inset:24px auto auto 20px;width:86px;height:86px;background:var(--phb-orb-a-bg)}.phb-orb-b{inset:auto 16px 18px auto;width:132px;height:132px;background:var(--phb-orb-b-bg)}.phb-grid{position:absolute;inset:0;background-image:linear-gradient(var(--phb-grid-line) 1px,transparent 1px),linear-gradient(90deg,var(--phb-grid-line) 1px,transparent 1px);background-size:24px 24px;opacity:.5}@media(max-width:900px){.phb-shell{grid-template-columns:1fr;padding:18px}.phb-visual{order:-1;min-height:180px}}\n"] }]
23903
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;--phb-shell-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 60%, transparent);--phb-shell-shadow: 0 24px 60px color-mix(in srgb, var(--md-sys-color-shadow, #000) 10%, transparent);--phb-shell-bg: radial-gradient(circle at top right, color-mix(in srgb, var(--md-sys-color-primary) 14%, transparent), transparent 38%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 92%, var(--md-sys-color-primary-container) 8%) 0%, color-mix(in srgb, var(--md-sys-color-surface-container-low) 88%, var(--md-sys-color-primary-container) 12%) 54%, color-mix(in srgb, var(--md-sys-color-surface) 96%, var(--md-sys-color-surface-container) 4%) 100% );--phb-event-bg: radial-gradient(circle at top right, rgba(255, 184, 77, .24), transparent 34%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary-container) 16%, var(--md-sys-color-surface-container-lowest) 84%) 0%, color-mix(in srgb, var(--md-sys-color-primary-container) 24%, var(--md-sys-color-surface-container-low) 76%) 45%, color-mix(in srgb, var(--md-sys-color-surface) 92%, var(--md-sys-color-primary-container) 8%) 100% );--phb-institutional-bg: radial-gradient(circle at top right, rgba(17, 94, 89, .2), transparent 34%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-secondary-container) 18%, var(--md-sys-color-surface-container-lowest) 82%) 0%, color-mix(in srgb, var(--md-sys-color-secondary-container) 24%, var(--md-sys-color-surface-container-low) 76%) 48%, color-mix(in srgb, var(--md-sys-color-surface) 94%, var(--md-sys-color-secondary-container) 6%) 100% );--phb-brand-color: color-mix(in srgb, var(--md-sys-color-primary) 68%, var(--md-sys-color-on-surface) 32%);--phb-subtitle-color: color-mix(in srgb, var(--md-sys-color-primary) 52%, var(--md-sys-color-on-surface) 48%);--phb-title-color: var(--md-sys-color-on-surface);--phb-description-color: var(--md-sys-color-on-surface-variant);--phb-badge-bg: color-mix(in srgb, var(--md-sys-color-surface-container-high) 78%, transparent);--phb-badge-color: var(--md-sys-color-on-surface);--phb-badge-highlight-bg: color-mix(in srgb, var(--md-sys-color-primary-container) 78%, transparent);--phb-badge-highlight-color: var(--md-sys-color-on-primary-container);--phb-badge-muted-bg: color-mix(in srgb, var(--md-sys-color-surface-container-highest) 82%, transparent);--phb-badge-muted-color: var(--md-sys-color-on-surface-variant);--phb-badge-warning-bg: color-mix(in srgb, var(--md-sys-color-error-container) 74%, transparent);--phb-badge-warning-color: var(--md-sys-color-on-error-container);--phb-meta-bg: color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 72%, transparent);--phb-meta-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 48%, transparent);--phb-meta-label-color: var(--md-sys-color-on-surface-variant);--phb-meta-value-color: var(--md-sys-color-on-surface);--phb-visual-bg: linear-gradient( 160deg, color-mix(in srgb, var(--md-sys-color-surface-container-high) 90%, var(--md-sys-color-primary) 10%), color-mix(in srgb, var(--md-sys-color-surface-container-low) 88%, var(--md-sys-color-primary-container) 12%) );--phb-visual-fallback: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-surface-bright, var(--md-sys-color-surface-container-high)) 24%, transparent), color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 8%, transparent) ), linear-gradient( 145deg, color-mix(in srgb, var(--md-sys-color-primary) 18%, var(--md-sys-color-surface-container-high) 82%), color-mix(in srgb, var(--md-sys-color-primary-container) 18%, var(--md-sys-color-surface-container-low) 82%) );--phb-orb-a-bg: color-mix(in srgb, var(--md-sys-color-surface-bright, var(--md-sys-color-surface-container-high)) 68%, transparent);--phb-orb-b-bg: color-mix(in srgb, var(--md-sys-color-primary) 22%, transparent);--phb-grid-line: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent)}:host-context(.mdc-theme-dark),:host-context(.theme-dark){--phb-shell-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 84%, transparent);--phb-shell-shadow: 0 22px 54px rgba(0, 0, 0, .28);--phb-shell-bg: radial-gradient(circle at top right, color-mix(in srgb, var(--md-sys-color-primary) 16%, transparent), transparent 40%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 90%, var(--md-sys-color-primary-container) 10%) 0%, color-mix(in srgb, var(--md-sys-color-surface-container-low) 84%, var(--md-sys-color-primary-container) 16%) 54%, color-mix(in srgb, var(--md-sys-color-surface) 92%, var(--md-sys-color-primary-container) 8%) 100% );--phb-event-bg: radial-gradient(circle at top right, rgba(255, 184, 77, .18), transparent 36%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary-container) 16%, var(--md-sys-color-surface-container-lowest) 84%) 0%, color-mix(in srgb, var(--md-sys-color-primary-container) 22%, var(--md-sys-color-surface-container-low) 78%) 45%, color-mix(in srgb, var(--md-sys-color-surface-container) 90%, var(--md-sys-color-primary-container) 10%) 100% );--phb-institutional-bg: radial-gradient(circle at top right, rgba(17, 94, 89, .16), transparent 36%), linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-secondary-container) 16%, var(--md-sys-color-surface-container-lowest) 84%) 0%, color-mix(in srgb, var(--md-sys-color-secondary-container) 20%, var(--md-sys-color-surface-container-low) 80%) 48%, color-mix(in srgb, var(--md-sys-color-surface-container) 92%, var(--md-sys-color-secondary-container) 8%) 100% );--phb-meta-bg: color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 70%, transparent);--phb-meta-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 60%, transparent);--phb-visual-bg: linear-gradient( 160deg, color-mix(in srgb, var(--md-sys-color-surface-container-high) 88%, var(--md-sys-color-primary) 12%), color-mix(in srgb, var(--md-sys-color-surface-container) 82%, var(--md-sys-color-primary-container) 18%) );--phb-visual-fallback: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-surface-container-high) 22%, transparent), color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 8%, transparent) ), linear-gradient( 145deg, color-mix(in srgb, var(--md-sys-color-primary) 22%, var(--md-sys-color-surface-container-high) 78%), color-mix(in srgb, var(--md-sys-color-primary-container) 24%, var(--md-sys-color-surface-container-low) 76%) );--phb-orb-a-bg: color-mix(in srgb, var(--md-sys-color-surface-container-highest) 34%, transparent);--phb-orb-b-bg: color-mix(in srgb, var(--md-sys-color-primary) 26%, transparent);--phb-grid-line: color-mix(in srgb, var(--md-sys-color-on-surface) 10%, transparent)}.phb-shell{display:grid;grid-template-columns:minmax(0,1.45fr) minmax(240px,.95fr);gap:22px;align-items:stretch;padding:22px;border-radius:28px;overflow:hidden;background:var(--phb-shell-bg);border:1px solid var(--phb-shell-border);box-shadow:var(--phb-shell-shadow)}.phb-event{background:var(--phb-event-bg)}.phb-institutional{background:var(--phb-institutional-bg)}.phb-copy{display:grid;gap:14px;min-width:0}.phb-brand{margin:0;color:var(--phb-brand-color);font-size:.88rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.phb-badges{display:flex;flex-wrap:wrap;gap:8px}.phb-badge{display:inline-flex;align-items:center;min-height:28px;padding:0 12px;border-radius:999px;background:var(--phb-badge-bg);color:var(--phb-badge-color);font-size:.76rem;font-weight:700;letter-spacing:.02em}.phb-badge-highlight{background:var(--phb-badge-highlight-bg);color:var(--phb-badge-highlight-color)}.phb-badge-muted{background:var(--phb-badge-muted-bg);color:var(--phb-badge-muted-color)}.phb-badge-warning{background:var(--phb-badge-warning-bg);color:var(--phb-badge-warning-color)}.phb-text{display:grid;gap:8px}.phb-subtitle{margin:0;color:var(--phb-subtitle-color);font-size:.9rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em}.phb-title{margin:0;color:var(--phb-title-color);font-size:clamp(1.6rem,2.2vw,2.5rem);line-height:1.08;letter-spacing:0}.phb-title-accent{display:inline;background:linear-gradient(90deg,#4285f4,#6ea8ff 28%,#a142f4 62%,#ea4335);-webkit-background-clip:text;background-clip:text;color:transparent}.phb-description{margin:0;max-width:56ch;color:var(--phb-description-color);font-size:.94rem;line-height:1.5}.phb-meta{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin:0}.phb-meta-item{display:grid;gap:4px;padding:12px 14px;border-radius:16px;background:var(--phb-meta-bg);border:1px solid var(--phb-meta-border);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.phb-meta-item dt{margin:0;color:var(--phb-meta-label-color);font-size:.73rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em}.phb-meta-item dd{margin:0;color:var(--phb-meta-value-color);font-size:.92rem;line-height:1.45}.phb-visual{position:relative;min-height:220px;border-radius:22px;overflow:hidden;background:var(--phb-visual-bg)}.phb-image{display:block;width:100%;height:100%;object-fit:cover}.phb-visual-fallback{background:var(--phb-visual-fallback)}.phb-visual-summary{display:grid;align-content:start;gap:10px;padding:14px;background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-surface-container-high) 92%,var(--md-sys-color-primary) 8%),color-mix(in srgb,var(--md-sys-color-surface-container-low) 88%,var(--md-sys-color-tertiary) 12%))}.phb-summary-header{display:flex;align-items:start;justify-content:space-between;gap:12px}.phb-summary-eyebrow{margin:0 0 4px;color:var(--md-sys-color-primary);font-size:.72rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.phb-summary-header h3{margin:0;color:var(--md-sys-color-on-surface);font-size:.95rem;line-height:1.25}.phb-status{display:inline-flex;align-items:center;min-height:26px;padding:0 10px;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-surface-container-highest) 74%,transparent);color:var(--md-sys-color-on-surface);font-size:.72rem;font-weight:800;white-space:nowrap}.phb-summary-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:0}.phb-summary-item{display:grid;gap:4px;min-height:56px;padding:9px 10px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 48%,transparent);border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 58%,transparent)}.phb-summary-item dt{margin:0;color:var(--md-sys-color-on-surface-variant);font-size:.64rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em}.phb-summary-item dd{margin:0;color:var(--md-sys-color-on-surface);font-size:1.08rem;font-weight:850;line-height:1.15}.phb-summary-events{display:grid;gap:6px}.phb-summary-event{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:28px;padding:6px 9px;border-radius:12px;background:color-mix(in srgb,var(--md-sys-color-surface-container) 68%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:.72rem}.phb-summary-event strong{color:var(--md-sys-color-on-surface);font-weight:800;white-space:nowrap}.phb-tone-success{--phb-tone-color: var(--md-sys-color-tertiary);border-color:color-mix(in srgb,var(--md-sys-color-tertiary) 34%,var(--md-sys-color-outline-variant))}.phb-tone-warning{--phb-tone-color: #d79921;border-color:color-mix(in srgb,#d79921 36%,var(--md-sys-color-outline-variant))}.phb-tone-danger{--phb-tone-color: var(--md-sys-color-error);border-color:color-mix(in srgb,var(--md-sys-color-error) 34%,var(--md-sys-color-outline-variant))}.phb-tone-info{--phb-tone-color: var(--md-sys-color-primary);border-color:color-mix(in srgb,var(--md-sys-color-primary) 34%,var(--md-sys-color-outline-variant))}.phb-summary-item.phb-tone-success dd,.phb-summary-item.phb-tone-warning dd,.phb-summary-item.phb-tone-danger dd,.phb-summary-item.phb-tone-info dd,.phb-status.phb-tone-success,.phb-status.phb-tone-warning,.phb-status.phb-tone-danger,.phb-status.phb-tone-info,.phb-summary-event.phb-tone-success strong,.phb-summary-event.phb-tone-warning strong,.phb-summary-event.phb-tone-danger strong,.phb-summary-event.phb-tone-info strong{color:var(--phb-tone-color)}.phb-flat{padding:0 0 18px;border:0;border-radius:0;box-shadow:none;background:transparent;grid-template-columns:minmax(0,1.15fr) minmax(220px,.85fr);gap:18px}.phb-flat .phb-brand{color:var(--md-sys-color-primary)}.phb-flat .phb-badges{order:3}.phb-flat .phb-meta{grid-template-columns:1fr;gap:6px}.phb-flat .phb-meta-item{padding:0;border:0;border-radius:0;background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none}.phb-flat .phb-meta-item dt,.phb-flat .phb-meta-item dd{display:inline}.phb-flat .phb-meta-item dt{margin-right:6px}.phb-flat .phb-visual{min-height:190px;border-radius:26px}.phb-preview{position:absolute;inset:18px;display:grid;grid-template-rows:18px 44px minmax(72px,1fr) 1fr;gap:12px;padding:16px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 50%,transparent);border-radius:18px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 62%,transparent);box-shadow:inset 0 1px color-mix(in srgb,var(--md-sys-color-surface-bright, #fff) 28%,transparent)}.phb-preview-header,.phb-preview-kpis span,.phb-preview-list span{border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-on-surface) 12%,transparent)}.phb-preview-header{width:46%}.phb-preview-kpis{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.phb-preview-kpis span{height:44px;border-radius:12px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 48%,var(--md-sys-color-surface-container-high) 52%)}.phb-preview-chart{display:grid;grid-template-columns:repeat(5,1fr);align-items:end;gap:8px;padding:12px;border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface-container) 74%,transparent)}.phb-preview-chart span{min-height:18px;height:var(--bar-height);border-radius:8px 8px 4px 4px;background:color-mix(in srgb,var(--md-sys-color-primary) 68%,var(--md-sys-color-tertiary) 32%)}.phb-preview-list{display:grid;gap:8px;align-content:start}.phb-preview-list span{height:10px}.phb-preview-list span:nth-child(2){width:74%}.phb-preview-list span:nth-child(3){width:58%}@media(max-width:900px){.phb-shell{grid-template-columns:1fr;padding:18px}.phb-visual{order:-1;min-height:180px}}\n"] }]
23221
23904
  }], propDecorators: { instanceId: [{
23222
23905
  type: Input
23223
23906
  }], analyticsId: [{
@@ -23246,6 +23929,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
23246
23929
  type: Input
23247
23930
  }], titleAccent: [{
23248
23931
  type: Input
23932
+ }], visualSummary: [{
23933
+ type: Input
23249
23934
  }] } });
23250
23935
 
23251
23936
  const PRAXIS_HERO_BANNER_METADATA = {
@@ -23268,6 +23953,7 @@ const PRAXIS_HERO_BANNER_METADATA = {
23268
23953
  { name: 'imageAlt', type: 'string', label: 'Alt da imagem', description: 'Texto alternativo da imagem, quando presente.' },
23269
23954
  { name: 'badges', type: 'Array<{ label: string; tone?: "default" | "highlight" | "muted" | "warning" }>', label: 'Badges', description: 'Badges curatoriais no topo do hero.' },
23270
23955
  { name: 'metaItems', type: 'Array<{ label: string; value: string }>', label: 'Metadados', description: 'Metadados como data, local ou tenant.' },
23956
+ { name: 'visualSummary', type: 'HeroVisualSummary | null', label: 'Resumo visual', description: 'Painel opcional com evidências executivas, métricas e eventos para substituir a ilustração padrão.' },
23271
23957
  { name: 'variant', type: "'default' | 'event' | 'institutional'", label: 'Variante', description: 'Variante visual inicial do hero banner.', default: 'default' },
23272
23958
  { name: 'appearance', type: "'card' | 'flat'", label: 'Aparência', description: 'Controla se o hero usa cartão completo ou composição mais plana e leve.', default: 'card' },
23273
23959
  ],
@@ -23985,12 +24671,19 @@ class DynamicWidgetLoaderDirective {
23985
24671
  currentId;
23986
24672
  currentUsesInitialBindings = false;
23987
24673
  currentInitialBindingSignature = null;
24674
+ boundInputValues = {};
23988
24675
  outputSubs = [];
24676
+ destroyed = false;
23989
24677
  /** Dispatch a shell action to the inner widget instance when supported. */
23990
24678
  dispatchAction(action) {
23991
24679
  const instance = this.compRef?.instance;
23992
24680
  if (!instance)
23993
24681
  return false;
24682
+ if (action?.id === 'component-settings' &&
24683
+ typeof instance.openTableSettings === 'function') {
24684
+ instance.openTableSettings();
24685
+ return true;
24686
+ }
23994
24687
  if (typeof instance.handleShellAction === 'function') {
23995
24688
  instance.handleShellAction(action);
23996
24689
  return true;
@@ -24015,11 +24708,30 @@ class DynamicWidgetLoaderDirective {
24015
24708
  }
24016
24709
  }
24017
24710
  ngOnDestroy() {
24711
+ this.destroyed = true;
24018
24712
  this.destroyCurrent();
24019
24713
  }
24020
24714
  renderNow() {
24021
24715
  this.tryRender();
24022
24716
  }
24717
+ materializedInputSnapshot(inputNames) {
24718
+ const instance = this.compRef?.instance;
24719
+ if (!instance || !Array.isArray(inputNames) || !inputNames.length) {
24720
+ return {};
24721
+ }
24722
+ const snapshot = {};
24723
+ for (const name of inputNames) {
24724
+ const key = typeof name === 'string' ? name.trim() : '';
24725
+ if (!key) {
24726
+ continue;
24727
+ }
24728
+ const value = instance[key];
24729
+ if (value !== undefined && typeof value !== 'function') {
24730
+ snapshot[key] = this.cloneValue(value);
24731
+ }
24732
+ }
24733
+ return snapshot;
24734
+ }
24023
24735
  parseWidget(input) {
24024
24736
  if (!input)
24025
24737
  return null;
@@ -24035,6 +24747,8 @@ class DynamicWidgetLoaderDirective {
24035
24747
  return input;
24036
24748
  }
24037
24749
  tryRender() {
24750
+ if (this.destroyed)
24751
+ return;
24038
24752
  const def = this.parseWidget(this.widget);
24039
24753
  if (!def || !def.id)
24040
24754
  return;
@@ -24051,7 +24765,7 @@ class DynamicWidgetLoaderDirective {
24051
24765
  throw error;
24052
24766
  }
24053
24767
  // New component type? recreate; else just update inputs
24054
- const useInitialBindings = this.shouldUseInitialInputBindings(def.id, meta || undefined);
24768
+ const useInitialBindings = this.shouldUseInitialInputBindings(def.id, inputs, meta || undefined);
24055
24769
  const initialBindingSignature = useInitialBindings
24056
24770
  ? this.initialBindingSignature(def.id, inputs, def.bindingOrder, meta || undefined)
24057
24771
  : null;
@@ -24059,17 +24773,22 @@ class DynamicWidgetLoaderDirective {
24059
24773
  || def.id !== this.currentId
24060
24774
  || (useInitialBindings
24061
24775
  && initialBindingSignature !== this.currentInitialBindingSignature);
24776
+ let recreated = false;
24062
24777
  if (needsRecreate) {
24063
24778
  this.createComponent(def.id, inputs, def.bindingOrder, meta || undefined, useInitialBindings, initialBindingSignature);
24779
+ recreated = !!this.compRef;
24064
24780
  }
24065
24781
  if (this.compRef) {
24066
24782
  try {
24783
+ let inputsChanged = false;
24067
24784
  // Faz o binding com coerção de tipos quando possível
24068
24785
  if (!this.currentUsesInitialBindings) {
24069
- this.bindInputs(this.compRef, def.id, inputs, def.bindingOrder, meta || undefined);
24786
+ inputsChanged = this.bindInputs(this.compRef, def.id, inputs, def.bindingOrder, meta || undefined);
24070
24787
  }
24071
24788
  this.bindOutputs(this.compRef.instance, def.id, outputs, meta || undefined);
24072
- this.compRef.changeDetectorRef.detectChanges();
24789
+ if (recreated || inputsChanged) {
24790
+ this.compRef.changeDetectorRef.detectChanges();
24791
+ }
24073
24792
  this.widgetDiagnostic.emit({
24074
24793
  componentId: def.id,
24075
24794
  childWidgetKey: def.childWidgetKey,
@@ -24115,11 +24834,10 @@ class DynamicWidgetLoaderDirective {
24115
24834
  }
24116
24835
  this.vcRef.clear();
24117
24836
  try {
24118
- const initialBindings = useInitialBindings
24119
- ? this.orderedInputEntries(id, inputs, bindingOrder)
24120
- .map(([key, raw]) => inputBinding(key, () => this.resolveAndCoerceValue(key, raw, metaForInputs)))
24121
- : [];
24122
- this.compRef = this.vcRef.createComponent(cmp, initialBindings.length ? { bindings: initialBindings } : undefined);
24837
+ this.compRef = this.vcRef.createComponent(cmp);
24838
+ if (useInitialBindings) {
24839
+ this.bindInputs(this.compRef, id, inputs, bindingOrder, metaForInputs);
24840
+ }
24123
24841
  this.currentId = id;
24124
24842
  this.currentUsesInitialBindings = useInitialBindings;
24125
24843
  this.currentInitialBindingSignature = useInitialBindings ? initialBindingSignature : null;
@@ -24142,25 +24860,57 @@ class DynamicWidgetLoaderDirective {
24142
24860
  this.currentId = undefined;
24143
24861
  this.currentUsesInitialBindings = false;
24144
24862
  this.currentInitialBindingSignature = null;
24863
+ this.boundInputValues = {};
24145
24864
  }
24146
24865
  this.vcRef.clear();
24147
24866
  }
24148
- shouldUseInitialInputBindings(id, meta) {
24867
+ cloneValue(value) {
24868
+ if (value == null || typeof value !== 'object') {
24869
+ return value;
24870
+ }
24871
+ try {
24872
+ return JSON.parse(JSON.stringify(value));
24873
+ }
24874
+ catch {
24875
+ return value;
24876
+ }
24877
+ }
24878
+ shouldUseInitialInputBindings(id, inputs, meta) {
24879
+ const hasDetachedDynamicFormRuntimeInputs = id === 'praxis-dynamic-form'
24880
+ && Boolean(inputs['apiUrlEntry']
24881
+ || inputs['apiEndpointKey']
24882
+ || inputs['schemaUrl']
24883
+ || inputs['readUrl']
24884
+ || inputs['submitUrl']
24885
+ || inputs['customEndpoints']);
24886
+ const hasDetachedFilterRuntimeInputs = id === 'praxis-filter'
24887
+ && Boolean(inputs['apiUrlEntry']);
24149
24888
  return meta?.requiresInitialInputs === true
24150
- || id === 'praxis-chart';
24889
+ || id === 'praxis-chart'
24890
+ || hasDetachedDynamicFormRuntimeInputs
24891
+ || hasDetachedFilterRuntimeInputs;
24151
24892
  }
24152
24893
  bindInputs(compRef, id, inputs, bindingOrder, meta) {
24153
24894
  const prioritized = this.orderedInputEntries(id, inputs, bindingOrder);
24895
+ const changes = {};
24896
+ let changed = false;
24154
24897
  const apply = (key, raw) => {
24155
24898
  const value = this.resolveAndCoerceValue(key, raw, meta);
24156
24899
  try {
24157
- if (typeof compRef.setInput === 'function') {
24900
+ const hadPreviousValue = Object.prototype.hasOwnProperty.call(this.boundInputValues, key);
24901
+ const previousValue = this.boundInputValues[key];
24902
+ if (hadPreviousValue && Object.is(previousValue, value)) {
24903
+ return;
24904
+ }
24905
+ if (this.isSignalInput(compRef.instance, key)) {
24158
24906
  compRef.setInput(key, value);
24159
24907
  }
24160
24908
  else {
24161
- // Fallback assignment when setInput is unavailable
24162
24909
  compRef.instance[key] = value;
24163
24910
  }
24911
+ this.boundInputValues[key] = value;
24912
+ changes[key] = new SimpleChange(previousValue, value, !hadPreviousValue);
24913
+ changed = true;
24164
24914
  }
24165
24915
  catch (e) {
24166
24916
  console.warn(`[DynamicWidgetLoader] Failed to set input ${key}`, e);
@@ -24171,6 +24921,20 @@ class DynamicWidgetLoaderDirective {
24171
24921
  for (const [key, raw] of prioritized) {
24172
24922
  apply(key, raw);
24173
24923
  }
24924
+ if (changed && typeof compRef.instance?.ngOnChanges === 'function') {
24925
+ compRef.instance.ngOnChanges(changes);
24926
+ }
24927
+ return changed;
24928
+ }
24929
+ isSignalInput(instance, key) {
24930
+ try {
24931
+ const candidate = instance?.[key];
24932
+ return typeof candidate === 'function'
24933
+ && candidate.length === 0;
24934
+ }
24935
+ catch {
24936
+ return false;
24937
+ }
24174
24938
  }
24175
24939
  initialBindingSignature(id, inputs, bindingOrder, meta) {
24176
24940
  const resolvedEntries = this.orderedInputEntries(id, inputs, bindingOrder)
@@ -24179,7 +24943,7 @@ class DynamicWidgetLoaderDirective {
24179
24943
  }
24180
24944
  orderedInputEntries(id, inputs, bindingOrder) {
24181
24945
  const defaultOrderMap = {
24182
- 'praxis-table': ['tableId', 'componentInstanceId', 'resourcePath', 'data', 'config'],
24946
+ 'praxis-table': ['tableId', 'componentInstanceId', 'configPersistenceStrategy', 'resourcePath', 'data', 'config'],
24183
24947
  'praxis-crud': ['crudId', 'componentInstanceId', 'metadata'],
24184
24948
  'praxis-dynamic-form': ['formId', 'componentInstanceId', 'resourcePath'],
24185
24949
  'praxis-tabs': ['tabsId', 'componentInstanceId', 'configPersistenceStrategy', 'config'],
@@ -24282,8 +25046,11 @@ class DynamicWidgetLoaderDirective {
24282
25046
  this.outputSubs.forEach((u) => u());
24283
25047
  this.outputSubs = [];
24284
25048
  let keys = Object.keys(outputs || {});
24285
- if (this.autoWireOutputs && keys.length === 0 && meta?.outputs?.length) {
24286
- keys = meta.outputs.map((o) => o.name);
25049
+ if (this.autoWireOutputs && meta?.outputs?.length) {
25050
+ keys = Array.from(new Set([
25051
+ ...keys,
25052
+ ...meta.outputs.map((o) => o.name),
25053
+ ]));
24287
25054
  }
24288
25055
  if (!keys.includes('widgetEvent') && isSubscribableOutput(instance?.widgetEvent)) {
24289
25056
  keys = [...keys, 'widgetEvent'];
@@ -25243,22 +26010,69 @@ const BUILTIN_PAGE_THEME_PRESETS = {
25243
26010
  id: 'analytics-calm',
25244
26011
  label: 'Analytics Calm',
25245
26012
  description: 'Superfícies leves, ênfase clara em dados e motion sutil.',
26013
+ shellPreset: 'light-neutral',
26014
+ chartThemePreset: 'executive',
25246
26015
  density: 'comfortable',
25247
26016
  motion: 'subtle',
26017
+ tokens: {
26018
+ '--pdx-page-bg': 'var(--md-sys-color-surface)',
26019
+ '--pdx-page-surface': 'var(--md-sys-color-surface-container-lowest)',
26020
+ '--pdx-page-gap': '20px',
26021
+ '--pdx-page-card-radius': '14px',
26022
+ '--pdx-page-card-shadow': '0 10px 26px color-mix(in srgb, var(--md-sys-color-shadow, #000) 8%, transparent)',
26023
+ '--pdx-page-accent': 'var(--md-sys-color-primary)',
26024
+ },
25248
26025
  },
25249
26026
  'workspace-balanced': {
25250
26027
  id: 'workspace-balanced',
25251
26028
  label: 'Workspace Balanced',
25252
26029
  description: 'Equilíbrio entre densidade operacional e clareza visual.',
26030
+ shellPreset: 'light-neutral',
26031
+ chartThemePreset: 'default',
25253
26032
  density: 'comfortable',
25254
26033
  motion: 'subtle',
26034
+ tokens: {
26035
+ '--pdx-page-bg': 'color-mix(in srgb, var(--md-sys-color-surface) 88%, var(--md-sys-color-surface-container) 12%)',
26036
+ '--pdx-page-surface': 'var(--md-sys-color-surface)',
26037
+ '--pdx-page-gap': '18px',
26038
+ '--pdx-page-card-radius': '12px',
26039
+ '--pdx-page-card-shadow': '0 8px 22px color-mix(in srgb, var(--md-sys-color-shadow, #000) 7%, transparent)',
26040
+ '--pdx-page-accent': 'var(--md-sys-color-primary)',
26041
+ },
25255
26042
  },
25256
26043
  'ops-monitoring': {
25257
26044
  id: 'ops-monitoring',
25258
26045
  label: 'Ops Monitoring',
25259
26046
  description: 'Contraste um pouco maior para leitura rápida de status, filas e alertas.',
26047
+ shellPreset: 'graphite',
26048
+ chartThemePreset: 'compact',
26049
+ density: 'compact',
26050
+ motion: 'subtle',
26051
+ tokens: {
26052
+ '--pdx-page-bg': 'color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 70%, var(--md-sys-color-primary-container) 30%)',
26053
+ '--pdx-page-surface': 'var(--md-sys-color-surface)',
26054
+ '--pdx-page-gap': '14px',
26055
+ '--pdx-page-card-radius': '12px',
26056
+ '--pdx-page-card-shadow': '0 12px 30px color-mix(in srgb, var(--md-sys-color-shadow, #000) 12%, transparent)',
26057
+ '--pdx-page-accent': 'var(--md-sys-color-tertiary)',
26058
+ },
26059
+ },
26060
+ 'executive-command-center': {
26061
+ id: 'executive-command-center',
26062
+ label: 'Executive Command Center',
26063
+ description: 'Superfície premium para dashboards corporativos com hierarquia executiva, dados densos e ações de decisão.',
26064
+ shellPreset: 'graphite',
26065
+ chartThemePreset: 'executive',
25260
26066
  density: 'compact',
25261
26067
  motion: 'subtle',
26068
+ tokens: {
26069
+ '--pdx-page-bg': 'color-mix(in srgb, var(--md-sys-color-surface-container-lowest) 86%, var(--md-sys-color-primary-container) 14%)',
26070
+ '--pdx-page-surface': 'color-mix(in srgb, var(--md-sys-color-surface) 96%, var(--md-sys-color-surface-container-high) 4%)',
26071
+ '--pdx-page-gap': '12px',
26072
+ '--pdx-page-card-radius': '10px',
26073
+ '--pdx-page-card-shadow': '0 6px 18px color-mix(in srgb, var(--md-sys-color-shadow) 10%, transparent)',
26074
+ '--pdx-page-accent': 'var(--md-sys-color-primary)',
26075
+ },
25262
26076
  },
25263
26077
  };
25264
26078
 
@@ -29110,6 +29924,10 @@ class DynamicWidgetPageComponent {
29110
29924
  widgets = signal([], ...(ngDevMode ? [{ debugName: "widgets" }] : /* istanbul ignore next */ []));
29111
29925
  renderedGroups = signal([], ...(ngDevMode ? [{ debugName: "renderedGroups" }] : /* istanbul ignore next */ []));
29112
29926
  mergedContext = {};
29927
+ pageThemePresetId = null;
29928
+ pageThemeDensity = null;
29929
+ pageThemeMotion = null;
29930
+ pageThemeTokenStyle = {};
29113
29931
  pageGap = '16px';
29114
29932
  gridTemplateColumns = 'minmax(0, 1fr)';
29115
29933
  gridAutoRows = 'auto';
@@ -29130,13 +29948,14 @@ class DynamicWidgetPageComponent {
29130
29948
  pageColumnCount = 1;
29131
29949
  activeTabs = {};
29132
29950
  widgetDiagnostics = {};
29133
- selectedWidgetKey = null;
29951
+ selectedWidgetKeyState = signal(null, ...(ngDevMode ? [{ debugName: "selectedWidgetKeyState" }] : /* istanbul ignore next */ []));
29134
29952
  blockedCanvasWidgetKey = null;
29135
29953
  canvasPreviewState = signal(null, ...(ngDevMode ? [{ debugName: "canvasPreviewState" }] : /* istanbul ignore next */ []));
29136
29954
  canvasPreviewInvalidState = signal(false, ...(ngDevMode ? [{ debugName: "canvasPreviewInvalidState" }] : /* istanbul ignore next */ []));
29137
29955
  transientCanvasItemsState = signal({}, ...(ngDevMode ? [{ debugName: "transientCanvasItemsState" }] : /* istanbul ignore next */ []));
29138
29956
  activeCanvasInteraction = null;
29139
29957
  appliedPersisted = false;
29958
+ destroyed = false;
29140
29959
  isHydrating = false;
29141
29960
  persistenceReady = false;
29142
29961
  warnedMissingKey = false;
@@ -29151,6 +29970,7 @@ class DynamicWidgetPageComponent {
29151
29970
  componentMetadata = inject(ComponentMetadataRegistry, {
29152
29971
  optional: true,
29153
29972
  });
29973
+ runtimeObservationRegistry = inject(PraxisRuntimeComponentObservationRegistryService, { optional: true });
29154
29974
  i18n = inject(PraxisI18nService);
29155
29975
  route = (() => {
29156
29976
  try {
@@ -29172,8 +29992,15 @@ class DynamicWidgetPageComponent {
29172
29992
  defaultPageEditor = inject(DYNAMIC_PAGE_CONFIG_EDITOR, {
29173
29993
  optional: true,
29174
29994
  });
29175
- constructor() { }
29995
+ runtimeObservationRegistration = null;
29996
+ widgetLoaders;
29997
+ constructor() {
29998
+ this.registerRuntimeComponentObservationProvider();
29999
+ }
29176
30000
  ngOnDestroy() {
30001
+ this.destroyed = true;
30002
+ this.runtimeObservationRegistration?.destroy();
30003
+ this.runtimeObservationRegistration = null;
29177
30004
  this.compositionRuntime.destroy();
29178
30005
  }
29179
30006
  ngOnChanges(changes) {
@@ -29278,15 +30105,19 @@ class DynamicWidgetPageComponent {
29278
30105
  }
29279
30106
  applyWidgetInputPatchToPage(page, widgetKey, evt) {
29280
30107
  const payload = evt?.payload;
29281
- const inputPatch = this.extractWidgetInputPatch(payload);
30108
+ let inputPatch = this.extractWidgetInputPatch(payload);
29282
30109
  if (!inputPatch) {
29283
- return { page, changed: false };
30110
+ inputPatch = null;
29284
30111
  }
29285
30112
  const widgets = this.cloneWidgets(page.widgets || []);
29286
30113
  const widgetIndex = widgets.findIndex((widget) => widget.key === widgetKey);
29287
30114
  if (widgetIndex < 0) {
29288
30115
  return { page, changed: false };
29289
30116
  }
30117
+ inputPatch ??= this.extractImplicitInputPatchFromChangeOutput(evt, widgets[widgetIndex]);
30118
+ if (!inputPatch) {
30119
+ return { page, changed: false };
30120
+ }
29290
30121
  const nestedPath = this.resolveWidgetInputPatchNestedPath(widgets[widgetIndex], evt);
29291
30122
  if (nestedPath?.length) {
29292
30123
  let owner = widgets[widgetIndex];
@@ -29364,7 +30195,8 @@ class DynamicWidgetPageComponent {
29364
30195
  if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
29365
30196
  return null;
29366
30197
  }
29367
- const candidate = payload.inputPatch;
30198
+ const candidate = payload.inputPatch
30199
+ ?? payload.payload?.inputPatch;
29368
30200
  if (!candidate ||
29369
30201
  typeof candidate !== 'object' ||
29370
30202
  Array.isArray(candidate)) {
@@ -29372,6 +30204,26 @@ class DynamicWidgetPageComponent {
29372
30204
  }
29373
30205
  return candidate;
29374
30206
  }
30207
+ extractImplicitInputPatchFromChangeOutput(evt, widget) {
30208
+ const output = typeof evt?.output === 'string' ? evt.output.trim() : '';
30209
+ if (!output.endsWith('Change') || output.length <= 'Change'.length) {
30210
+ return null;
30211
+ }
30212
+ const inputName = output.slice(0, -'Change'.length);
30213
+ if (!inputName) {
30214
+ return null;
30215
+ }
30216
+ const declaredInputs = widget.definition?.inputs || {};
30217
+ const hasWidgetInput = Object.prototype.hasOwnProperty.call(declaredInputs, inputName);
30218
+ const hasMetadataInput = !!this.componentMetadata
30219
+ ?.get(widget.definition?.id || '')
30220
+ ?.inputs
30221
+ ?.some((input) => input.name === inputName);
30222
+ if (!hasWidgetInput && !hasMetadataInput) {
30223
+ return null;
30224
+ }
30225
+ return { [inputName]: this.cloneStateValues(evt.payload) };
30226
+ }
29375
30227
  buildStateRuntime(state, pageContext) {
29376
30228
  return this.stateRuntime.buildRuntimeSnapshot(state, this.buildStateContext(pageContext));
29377
30229
  }
@@ -29397,6 +30249,158 @@ class DynamicWidgetPageComponent {
29397
30249
  }).widgets;
29398
30250
  return this.applyRecordRelatedSurfaceAiContext(projected);
29399
30251
  }
30252
+ buildRuntimeComponentObservation() {
30253
+ const pageId = this.resolveRuntimePageId();
30254
+ const widgets = this.widgets();
30255
+ const widgetKeys = widgets.map((widget) => widget.key).filter(Boolean);
30256
+ const currentSelectedWidgetKey = this.selectedWidgetKeyState();
30257
+ const selectedWidgetKey = widgetKeys.includes(currentSelectedWidgetKey || '')
30258
+ ? currentSelectedWidgetKey
30259
+ : null;
30260
+ const warnings = [];
30261
+ if (currentSelectedWidgetKey && !selectedWidgetKey) {
30262
+ warnings.push('selectedWidgetKey omitted because it is not present in the active composition.');
30263
+ }
30264
+ const compositionLinks = this.compositionDefinition?.links || [];
30265
+ const compositionSurfaceRefs = this.getRuntimeCompositionSurfaceRefs(widgets);
30266
+ const activeSurfaceRefs = Array.from(new Set(compositionSurfaceRefs.map((surface) => surface.id).filter(Boolean)));
30267
+ const activeActionRefs = activeSurfaceRefs.length
30268
+ ? ['dynamicPage.surface.open']
30269
+ : undefined;
30270
+ const active = !!this.pageDefinition;
30271
+ const capturedAt = new Date().toISOString();
30272
+ return {
30273
+ schemaVersion: 'praxis-runtime-component-observation.v1',
30274
+ identity: {
30275
+ instanceId: this.resolveRuntimeComponentInstanceId(pageId),
30276
+ componentId: 'praxis-dynamic-page',
30277
+ componentType: 'dynamic-page',
30278
+ ownerPackage: '@praxisui/core',
30279
+ routeKey: this.pageIdentity?.routePath,
30280
+ },
30281
+ refs: {
30282
+ componentMetadataId: 'praxis-dynamic-page',
30283
+ authoringManifestRef: {
30284
+ componentId: 'praxis-dynamic-page',
30285
+ source: 'DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK',
30286
+ },
30287
+ pageId,
30288
+ },
30289
+ lifecycle: {
30290
+ active,
30291
+ visible: active && this.isRuntimeObservationVisible(),
30292
+ focused: !!selectedWidgetKey,
30293
+ capturedAt,
30294
+ ttlMs: 30_000,
30295
+ },
30296
+ snapshot: {
30297
+ stateDigest: {
30298
+ pageId,
30299
+ widgetCount: widgetKeys.length,
30300
+ activeWidgetKeys: widgetKeys.slice(0, 80),
30301
+ selectedWidgetKey,
30302
+ composition: {
30303
+ version: this.pageDefinition?.composition?.version
30304
+ || '1.0.0',
30305
+ linkCount: compositionLinks.length,
30306
+ linkIds: compositionLinks.map((link) => link.id).filter(Boolean).slice(0, 80),
30307
+ },
30308
+ relationSurfaceRefs: compositionSurfaceRefs.slice(0, 80),
30309
+ },
30310
+ dataProfileDigest: {
30311
+ source: active ? 'dynamic-page-composition' : 'empty',
30312
+ widgetCount: widgetKeys.length,
30313
+ selectedWidgetPresent: !!selectedWidgetKey,
30314
+ compositionLinkCount: compositionLinks.length,
30315
+ relationSurfaceCount: activeSurfaceRefs.length,
30316
+ },
30317
+ },
30318
+ affordances: {
30319
+ ...(activeSurfaceRefs.length ? { activeSurfaceRefs } : {}),
30320
+ ...(activeActionRefs ? { activeActionRefs } : {}),
30321
+ },
30322
+ claims: this.buildRuntimeObservationClaims({
30323
+ pageId,
30324
+ widgetKeys,
30325
+ activeSurfaceRefs,
30326
+ activeActionRefs,
30327
+ }),
30328
+ diagnostics: {
30329
+ redactionApplied: true,
30330
+ omittedFields: [
30331
+ 'widgetInputValues',
30332
+ 'stateValues',
30333
+ 'rawEvents',
30334
+ 'renderedDom',
30335
+ 'intentDecision',
30336
+ ],
30337
+ ...(warnings.length ? { warnings } : {}),
30338
+ },
30339
+ };
30340
+ }
30341
+ registerRuntimeComponentObservationProvider() {
30342
+ if (!this.runtimeObservationRegistry || this.runtimeObservationRegistration) {
30343
+ return;
30344
+ }
30345
+ this.runtimeObservationRegistration = this.runtimeObservationRegistry.register({
30346
+ getObservation: () => this.buildRuntimeComponentObservation(),
30347
+ });
30348
+ }
30349
+ resolveRuntimePageId() {
30350
+ const identityKey = this.pageIdentity ? buildPageKey(this.pageIdentity) : '';
30351
+ return this.componentInstanceId
30352
+ || identityKey
30353
+ || this.stringOrNull(this.pageDefinition?.context?.['pageId'])
30354
+ || 'dynamic-page:default';
30355
+ }
30356
+ resolveRuntimeComponentInstanceId(pageId) {
30357
+ return this.componentInstanceId
30358
+ || (pageId ? `dynamic-page:${pageId}` : 'dynamic-page:default');
30359
+ }
30360
+ isRuntimeObservationVisible() {
30361
+ const nativeElement = this.pageCanvasHost?.nativeElement;
30362
+ return nativeElement ? nativeElement.isConnected !== false : true;
30363
+ }
30364
+ getRuntimeCompositionSurfaceRefs(widgets) {
30365
+ const surfacesBySource = this.buildRecordRelatedSurfacesBySource(widgets);
30366
+ const refs = [];
30367
+ for (const surfaces of surfacesBySource.values()) {
30368
+ for (const surface of surfaces) {
30369
+ refs.push({
30370
+ id: surface.id,
30371
+ label: surface.label,
30372
+ sourceWidget: surface.source.widget,
30373
+ targetWidget: surface.target.widget,
30374
+ ...(surface.target.resourcePath ? { targetResourcePath: surface.target.resourcePath } : {}),
30375
+ ...(surface.runtimeSurfaceInstanceRef ? {
30376
+ runtimeSurfaceInstanceRef: surface.runtimeSurfaceInstanceRef,
30377
+ targetRuntimeSurfaceInstanceRef: surface.runtimeSurfaceInstanceRef,
30378
+ } : {}),
30379
+ statePath: surface.statePath,
30380
+ ...(surface.queryMapping ? { queryMapping: surface.queryMapping } : {}),
30381
+ operationId: surface.operationId,
30382
+ });
30383
+ }
30384
+ }
30385
+ return refs;
30386
+ }
30387
+ buildRuntimeObservationClaims(context) {
30388
+ const claims = [
30389
+ { kind: 'component', ref: 'praxis-dynamic-page', observed: true },
30390
+ { kind: 'stateDigest', ref: `page:${context.pageId}`, observed: true },
30391
+ { kind: 'dataDigest', ref: `page:${context.pageId}:composition`, observed: true },
30392
+ ];
30393
+ for (const widgetKey of context.widgetKeys.slice(0, 80)) {
30394
+ claims.push({ kind: 'component', ref: `widget:${widgetKey}`, observed: true });
30395
+ }
30396
+ for (const surfaceRef of context.activeSurfaceRefs.slice(0, 80)) {
30397
+ claims.push({ kind: 'surface', ref: surfaceRef, observed: true });
30398
+ }
30399
+ for (const actionRef of context.activeActionRefs || []) {
30400
+ claims.push({ kind: 'action', ref: actionRef, observed: true });
30401
+ }
30402
+ return claims;
30403
+ }
29400
30404
  applyRecordRelatedSurfaceAiContext(widgets) {
29401
30405
  const surfacesBySource = this.buildRecordRelatedSurfacesBySource(widgets);
29402
30406
  if (!surfacesBySource.size) {
@@ -29454,6 +30458,9 @@ class DynamicWidgetPageComponent {
29454
30458
  const statePath = sourceLink.to.kind === 'state' ? sourceLink.to.ref.path : '';
29455
30459
  if (!sourceRef || !statePath)
29456
30460
  continue;
30461
+ const sourceWidget = widgetByKey.get(sourceRef.widget);
30462
+ if (!sourceWidget)
30463
+ continue;
29457
30464
  const targets = stateToQueryLinks.filter((link) => link.from.kind === 'state'
29458
30465
  && link.from.ref.path === statePath
29459
30466
  && link.to.kind === 'component-port');
@@ -29466,6 +30473,8 @@ class DynamicWidgetPageComponent {
29466
30473
  continue;
29467
30474
  const targetRef = targetLink.to.ref;
29468
30475
  const targetWidget = widgetByKey.get(targetRef.widget);
30476
+ if (!targetWidget)
30477
+ continue;
29469
30478
  const targetDefinition = targetRef.nestedPath?.length && targetWidget
29470
30479
  ? this.nestedWidgetAccessor.resolveNestedWidget(targetWidget, targetRef.nestedPath)
29471
30480
  : targetWidget?.definition;
@@ -29473,11 +30482,13 @@ class DynamicWidgetPageComponent {
29473
30482
  if (!surfaceId)
29474
30483
  continue;
29475
30484
  const label = this.resolveRecordSurfaceLabel(targetRef, targetWidget, targetDefinition);
30485
+ const targetRuntimeSurfaceWidgetKey = this.resolveRuntimeSurfaceWidgetKey(targetRef, targetDefinition);
29476
30486
  const surface = {
29477
30487
  id: surfaceId,
29478
30488
  label,
29479
30489
  relation: 'record.related-surface',
29480
30490
  operationId: 'dynamicPage.surface.open',
30491
+ runtimeSurfaceInstanceRef: this.runtimeSurfaceInstanceRef(targetRuntimeSurfaceWidgetKey, targetRef.componentType, targetRuntimeSurfaceWidgetKey, this.stringOrNull(targetDefinition?.inputs?.['resourcePath'])),
29481
30492
  statePath,
29482
30493
  source: {
29483
30494
  widget: sourceRef.widget,
@@ -29496,6 +30507,10 @@ class DynamicWidgetPageComponent {
29496
30507
  },
29497
30508
  description: this.stringOrNull(targetDefinition?.inputs?.['config']?.['toolbar']?.['title']),
29498
30509
  };
30510
+ const queryMapping = this.resolveRecordSurfaceQueryMapping(sourceWidget, targetLink);
30511
+ if (queryMapping) {
30512
+ surface.queryMapping = queryMapping;
30513
+ }
29499
30514
  if (!existing.some((item) => item.id === surface.id)) {
29500
30515
  existing.push(surface);
29501
30516
  }
@@ -29506,6 +30521,39 @@ class DynamicWidgetPageComponent {
29506
30521
  }
29507
30522
  return surfacesBySource;
29508
30523
  }
30524
+ resolveRecordSurfaceQueryMapping(sourceWidget, targetLink) {
30525
+ const sourceField = this.stringOrNull(sourceWidget?.definition.inputs?.['config']?.['meta']?.['idField'])
30526
+ || this.stringOrNull(sourceWidget?.definition.inputs?.['config']?.['idField'])
30527
+ || this.stringOrNull(sourceWidget?.definition.inputs?.['idField']);
30528
+ const targetFilterField = this.resolveQueryContextFilterField(targetLink);
30529
+ if (!sourceField || !targetFilterField) {
30530
+ return undefined;
30531
+ }
30532
+ return {
30533
+ sourceField,
30534
+ targetFilterField,
30535
+ targetPath: `filters.${targetFilterField}`,
30536
+ valueSource: 'selectionDigest.selectedIds[0]',
30537
+ };
30538
+ }
30539
+ resolveQueryContextFilterField(link) {
30540
+ for (const step of link.transform?.steps || []) {
30541
+ if (step.kind !== 'object-template')
30542
+ continue;
30543
+ const template = step.config?.['template'];
30544
+ if (!template || typeof template !== 'object' || Array.isArray(template))
30545
+ continue;
30546
+ const filters = template['filters'];
30547
+ if (!filters || typeof filters !== 'object' || Array.isArray(filters))
30548
+ continue;
30549
+ for (const [field, value] of Object.entries(filters)) {
30550
+ if (value === '${source}') {
30551
+ return field;
30552
+ }
30553
+ }
30554
+ }
30555
+ return null;
30556
+ }
29509
30557
  isTableRowClickToStateLink(link) {
29510
30558
  return link.from.kind === 'component-port'
29511
30559
  && link.from.ref.componentType === 'praxis-table'
@@ -29536,6 +30584,11 @@ class DynamicWidgetPageComponent {
29536
30584
  const tab = [...(ref.nestedPath || [])].reverse().find((segment) => segment.kind === 'tab');
29537
30585
  return this.humanizeRecordSurfaceLabel(tab?.id || ref.widget);
29538
30586
  }
30587
+ resolveRuntimeSurfaceWidgetKey(targetRef, targetDefinition) {
30588
+ return this.stringOrNull(targetDefinition?.inputs?.['componentInstanceId'])
30589
+ || this.stringOrNull(targetDefinition?.inputs?.['tableId'])
30590
+ || targetRef.widget;
30591
+ }
29539
30592
  resolveRecordSurfaceTabLabel(ref, targetWidget) {
29540
30593
  const tab = [...(ref.nestedPath || [])].reverse().find((segment) => segment.kind === 'tab');
29541
30594
  if (!tab)
@@ -29561,6 +30614,23 @@ class DynamicWidgetPageComponent {
29561
30614
  .replace(/([a-z])([A-Z])/g, '$1 $2')
29562
30615
  .replace(/\b\w/g, (match) => match.toUpperCase());
29563
30616
  }
30617
+ runtimeSurfaceInstanceRef(widgetKey, componentId, surfaceRef, resourcePath) {
30618
+ const widget = this.safeRuntimeSurfaceRefSegment(widgetKey);
30619
+ const component = this.safeRuntimeSurfaceRefSegment(componentId || 'component');
30620
+ const surface = this.safeRuntimeSurfaceRefSegment(surfaceRef);
30621
+ const resource = this.safeRuntimeSurfaceRefSegment(resourcePath || 'resource');
30622
+ if (!widget || !surface) {
30623
+ return undefined;
30624
+ }
30625
+ return `runtime-surface:${widget}:${component}:${surface}:${resource}`;
30626
+ }
30627
+ safeRuntimeSurfaceRefSegment(value) {
30628
+ return String(value || '')
30629
+ .trim()
30630
+ .replace(/[^A-Za-z0-9._/-]+/g, '-')
30631
+ .replace(/^-+|-+$/g, '')
30632
+ .slice(0, 120);
30633
+ }
29564
30634
  resolveRecordSurfaceChildWidgetKey(path) {
29565
30635
  const widget = [...(path || [])].reverse().find((segment) => segment.kind === 'widget');
29566
30636
  return widget?.key;
@@ -29774,6 +30844,42 @@ class DynamicWidgetPageComponent {
29774
30844
  payload,
29775
30845
  });
29776
30846
  }
30847
+ dispatchRuntimeCompositionEvent(event) {
30848
+ const page = this.ensurePageDefinition();
30849
+ if (!this.compositionDefinition || !event?.source) {
30850
+ return;
30851
+ }
30852
+ let payload;
30853
+ try {
30854
+ payload = this.cloneStateValues(event.payload);
30855
+ }
30856
+ catch (error) {
30857
+ const message = 'DynamicWidgetPageComponent could not serialize global action payload for composition dispatch. ' +
30858
+ 'Composition links only support JSON-safe payloads.';
30859
+ const wrapped = new Error(message);
30860
+ wrapped.cause = error;
30861
+ throw wrapped;
30862
+ }
30863
+ const cycle = this.compositionRuntime.dispatch({
30864
+ eventId: this.buildRuntimeEventId('global-action', event.source.kind),
30865
+ source: event.source,
30866
+ payload,
30867
+ occurredAt: event.occurredAt,
30868
+ });
30869
+ if (!cycle.matchedLinkIds.length) {
30870
+ return;
30871
+ }
30872
+ const state = this.stateFromCompositionSnapshot(page.state, cycle.snapshot.state.primaryValues);
30873
+ let widgets = this.cloneWidgets(page.widgets || []);
30874
+ widgets = this.applyCompositionWidgetDeliveries(widgets, cycle).widgets;
30875
+ widgets = this.compositionRuntime.projectStateWidgetInputs(this.compositionDefinition, {
30876
+ widgets,
30877
+ state: cycle.snapshot.state,
30878
+ now: cycle.snapshot.generatedAt,
30879
+ }).widgets;
30880
+ const runtime = this.buildStateRuntime(state, page.context);
30881
+ this.applyPageUpdate({ ...page, widgets, state }, true, runtime, false, true);
30882
+ }
29777
30883
  matchesRuntimeSourceRef(endpoint, sourceRef) {
29778
30884
  return endpoint.kind === 'component-port'
29779
30885
  && endpoint.ref.widget === sourceRef.widget
@@ -29943,19 +31049,19 @@ class DynamicWidgetPageComponent {
29943
31049
  ...widget.definition,
29944
31050
  inputs: {
29945
31051
  ...(widget.definition.inputs || {}),
29946
- hostCapabilities: this.buildRichContentHostCapabilities(widget.key, runtime),
31052
+ hostCapabilities: this.buildRichContentHostCapabilities(widget.key, runtime, widget.definition.inputs?.['context']),
29947
31053
  },
29948
31054
  },
29949
31055
  };
29950
31056
  }
29951
- buildRichContentHostCapabilities(widgetKey, runtime) {
31057
+ buildRichContentHostCapabilities(widgetKey, runtime, widgetContext) {
29952
31058
  return {
29953
- dispatchAction: (actionId, payload) => this.dispatchRichContentAction(widgetKey, actionId, payload),
31059
+ dispatchAction: (actionId, payload) => this.dispatchRichContentAction(widgetKey, actionId, payload, widgetContext),
29954
31060
  isActionAvailable: (actionId) => this.isRichContentActionAvailable(widgetKey, actionId),
29955
31061
  hasCapability: (capabilityId) => this.hasRichContentCapability(widgetKey, capabilityId, runtime),
29956
31062
  };
29957
31063
  }
29958
- dispatchRichContentAction(widgetKey, actionId, payload) {
31064
+ dispatchRichContentAction(widgetKey, actionId, payload, widgetContext) {
29959
31065
  if (!actionId) {
29960
31066
  return;
29961
31067
  }
@@ -29969,6 +31075,14 @@ class DynamicWidgetPageComponent {
29969
31075
  payload,
29970
31076
  pageContext: this.mergedContext,
29971
31077
  pageState: this.cloneStateValues(this.pageRuntime?.effectiveValues || {}),
31078
+ richContentContext: widgetContext,
31079
+ },
31080
+ runtime: {
31081
+ widgetContext,
31082
+ pageState: this.cloneStateValues(this.pageRuntime?.effectiveValues || {}),
31083
+ composition: {
31084
+ dispatch: (event) => this.dispatchRuntimeCompositionEvent(event),
31085
+ },
29972
31086
  },
29973
31087
  meta: {
29974
31088
  origin: 'dynamic-page.rich-content',
@@ -30022,7 +31136,7 @@ class DynamicWidgetPageComponent {
30022
31136
  case 'page.autoPersist.disabled':
30023
31137
  return !this.autoPersist;
30024
31138
  case 'page.widget.selected':
30025
- return this.selectedWidgetKey === widgetKey;
31139
+ return this.selectedWidgetKeyState() === widgetKey;
30026
31140
  case 'page.widget.configurable': {
30027
31141
  const widget = this.widgets().find((candidate) => candidate.key === widgetKey);
30028
31142
  const widgetType = widget?.definition?.id || '';
@@ -30419,9 +31533,12 @@ class DynamicWidgetPageComponent {
30419
31533
  ref.saved$.subscribe((result) => this.applyWidgetShell(key, result, true));
30420
31534
  }
30421
31535
  openWidgetComponentSettings(key) {
31536
+ if (this.dispatchWidgetComponentSettingsToRuntime(key)) {
31537
+ return;
31538
+ }
30422
31539
  if (!this.settingsPanel)
30423
31540
  return;
30424
- const page = this.ensurePageDefinition();
31541
+ const page = this.materializeRuntimeInputsForWidget(this.ensurePageDefinition(), key);
30425
31542
  const widget = page.widgets.find((w) => w.key === key);
30426
31543
  if (!widget)
30427
31544
  return;
@@ -30446,6 +31563,54 @@ class DynamicWidgetPageComponent {
30446
31563
  ref.applied$.subscribe((result) => this.applyWidgetComponentInputs(key, result, false));
30447
31564
  ref.saved$.subscribe((result) => this.applyWidgetComponentInputs(key, result, true));
30448
31565
  }
31566
+ materializeRuntimeInputsForWidget(page, key) {
31567
+ const normalizedKey = String(key || '').trim();
31568
+ if (!normalizedKey) {
31569
+ return page;
31570
+ }
31571
+ const widget = page.widgets?.find((candidate) => candidate.key === normalizedKey);
31572
+ if (!widget) {
31573
+ return page;
31574
+ }
31575
+ const inputNames = this.componentMetadata
31576
+ ?.get(widget.definition?.id || '')
31577
+ ?.inputs
31578
+ ?.map((input) => input.name)
31579
+ ?.filter((name) => typeof name === 'string' && !!name.trim()) || [];
31580
+ if (!inputNames.length) {
31581
+ return page;
31582
+ }
31583
+ const loader = this.findWidgetLoader(normalizedKey);
31584
+ const materializedInputs = loader?.materializedInputSnapshot(inputNames) || {};
31585
+ if (!Object.keys(materializedInputs).length) {
31586
+ return page;
31587
+ }
31588
+ const result = this.applyWidgetInputPatchToPage(page, normalizedKey, {
31589
+ sourceComponentId: widget.definition?.id,
31590
+ output: 'runtimeInputSnapshot',
31591
+ payload: {
31592
+ inputPatch: materializedInputs,
31593
+ },
31594
+ });
31595
+ if (!result.changed) {
31596
+ return page;
31597
+ }
31598
+ this.applyPageUpdate(result.page, true, undefined, true, true);
31599
+ return result.page;
31600
+ }
31601
+ findWidgetLoader(key) {
31602
+ return this.widgetLoaders?.find((loader) => loader.ownerWidgetKey === key);
31603
+ }
31604
+ dispatchWidgetComponentSettingsToRuntime(key) {
31605
+ const loader = this.findWidgetLoader(String(key || '').trim());
31606
+ if (typeof loader?.dispatchAction !== 'function') {
31607
+ return false;
31608
+ }
31609
+ return loader?.dispatchAction({
31610
+ id: 'component-settings',
31611
+ command: 'component-settings',
31612
+ }) === true;
31613
+ }
30449
31614
  applyWidgetComponentInputs(key, result, persist) {
30450
31615
  if (!result || typeof result !== 'object' || Array.isArray(result))
30451
31616
  return;
@@ -30485,16 +31650,17 @@ class DynamicWidgetPageComponent {
30485
31650
  return;
30486
31651
  }
30487
31652
  this.applyPageUpdate(this.removeWidgetReferences(page, widgetKey), true);
30488
- if (this.selectedWidgetKey === widgetKey) {
30489
- this.selectedWidgetKey = null;
31653
+ if (this.selectedWidgetKeyState() === widgetKey) {
31654
+ this.selectedWidgetKeyState.set(null);
30490
31655
  this.widgetSelectionChange.emit(null);
30491
31656
  }
30492
31657
  }
30493
31658
  removeSelectedWidget() {
30494
- if (!this.selectedWidgetKey) {
31659
+ const selectedWidgetKey = this.selectedWidgetKeyState();
31660
+ if (!selectedWidgetKey) {
30495
31661
  return;
30496
31662
  }
30497
- void this.confirmAndRemoveWidget(this.selectedWidgetKey);
31663
+ void this.confirmAndRemoveWidget(selectedWidgetKey);
30498
31664
  }
30499
31665
  removeSelectedCanvasWidget() {
30500
31666
  this.removeSelectedWidget();
@@ -30725,7 +31891,7 @@ class DynamicWidgetPageComponent {
30725
31891
  const layoutPreset = pageDefinition
30726
31892
  ? this.resolveLayoutPresetDefinition(pageDefinition)
30727
31893
  : undefined;
30728
- return {
31894
+ const merged = {
30729
31895
  ...baseContext,
30730
31896
  ...(inputContext || {}),
30731
31897
  pageDeviceKind: this.resolveDeviceKind(),
@@ -30739,6 +31905,53 @@ class DynamicWidgetPageComponent {
30739
31905
  pageStateDerived: this.cloneStateValues(runtime.derivedValues),
30740
31906
  pageStateEffective: this.cloneStateValues(runtime.effectiveValues),
30741
31907
  };
31908
+ this.syncThemePresentation(themePreset);
31909
+ return this.projectThemeDefaultsIntoContext(merged, themePreset);
31910
+ }
31911
+ syncThemePresentation(themePreset) {
31912
+ this.pageThemePresetId = themePreset?.id || null;
31913
+ this.pageThemeDensity = themePreset?.density || null;
31914
+ this.pageThemeMotion = themePreset?.motion || null;
31915
+ this.pageThemeTokenStyle = this.normalizeThemeTokens(themePreset?.tokens);
31916
+ }
31917
+ normalizeThemeTokens(tokens) {
31918
+ if (!tokens)
31919
+ return {};
31920
+ const out = {};
31921
+ for (const [key, value] of Object.entries(tokens)) {
31922
+ if (!key.startsWith('--'))
31923
+ continue;
31924
+ if (typeof value !== 'string')
31925
+ continue;
31926
+ out[key] = value;
31927
+ }
31928
+ return out;
31929
+ }
31930
+ toPlainObject(value) {
31931
+ return value && typeof value === 'object' && !Array.isArray(value)
31932
+ ? { ...value }
31933
+ : {};
31934
+ }
31935
+ projectThemeDefaultsIntoContext(context, themePreset) {
31936
+ const shellPreset = themePreset?.shellPreset?.trim();
31937
+ if (!shellPreset)
31938
+ return context;
31939
+ const ui = this.toPlainObject(context['ui']);
31940
+ const shell = this.toPlainObject(ui['shell']);
31941
+ if (typeof shell['preset'] === 'string' && shell['preset'].trim()) {
31942
+ return context;
31943
+ }
31944
+ return {
31945
+ ...context,
31946
+ ui: {
31947
+ ...ui,
31948
+ shell: {
31949
+ ...shell,
31950
+ preset: shellPreset,
31951
+ presetSource: 'theme',
31952
+ },
31953
+ },
31954
+ };
30742
31955
  }
30743
31956
  onWindowResize() {
30744
31957
  if (!this.pageDefinition)
@@ -31011,8 +32224,8 @@ class DynamicWidgetPageComponent {
31011
32224
  selectWidget(widgetKey) {
31012
32225
  if (!this.enableCustomization)
31013
32226
  return;
31014
- if (this.selectedWidgetKey !== widgetKey) {
31015
- this.selectedWidgetKey = widgetKey;
32227
+ if (this.selectedWidgetKeyState() !== widgetKey) {
32228
+ this.selectedWidgetKeyState.set(widgetKey);
31016
32229
  this.widgetSelectionChange.emit(widgetKey);
31017
32230
  }
31018
32231
  if (this.blockedCanvasWidgetKey &&
@@ -31024,13 +32237,21 @@ class DynamicWidgetPageComponent {
31024
32237
  if (this.shouldPreserveInnerWidgetInteraction(event)) {
31025
32238
  return;
31026
32239
  }
32240
+ if (event.type === 'focusin') {
32241
+ setTimeout(() => {
32242
+ if (!this.destroyed) {
32243
+ this.selectWidget(widgetKey);
32244
+ }
32245
+ }, 0);
32246
+ return;
32247
+ }
31027
32248
  this.selectWidget(widgetKey);
31028
32249
  }
31029
32250
  isCanvasWidgetSelected(widgetKey) {
31030
32251
  return this.isWidgetSelected(widgetKey);
31031
32252
  }
31032
32253
  isWidgetSelected(widgetKey) {
31033
- return this.selectedWidgetKey === widgetKey;
32254
+ return this.selectedWidgetKeyState() === widgetKey;
31034
32255
  }
31035
32256
  shouldPreserveInnerWidgetInteraction(event) {
31036
32257
  if (!this.enableCustomization)
@@ -31974,8 +33195,15 @@ class DynamicWidgetPageComponent {
31974
33195
  throw new Error('DynamicWidgetPageComponent no longer accepts `page.connections`. Use `composition.links` only.');
31975
33196
  }
31976
33197
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicWidgetPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
31977
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicWidgetPageComponent, isStandalone: true, selector: "praxis-dynamic-page", inputs: { page: "page", context: "context", strictValidation: "strictValidation", enableCustomization: "enableCustomization", showPageSettingsButton: "showPageSettingsButton", shellEditorComponent: "shellEditorComponent", pageEditorComponent: "pageEditorComponent", autoPersist: "autoPersist", pageIdentity: "pageIdentity", componentInstanceId: "componentInstanceId", showWidgetAssistantButton: "showWidgetAssistantButton" }, outputs: { pageChange: "pageChange", widgetEvent: "widgetEvent", widgetSelectionChange: "widgetSelectionChange", widgetAssistantRequested: "widgetAssistantRequested", widgetDiagnosticsChange: "widgetDiagnosticsChange" }, host: { listeners: { "window:resize": "onWindowResize()", "window:pointermove": "onCanvasPointerMove($event)", "window:pointerup": "onCanvasPointerUp($event)", "window:pointercancel": "onCanvasPointerCancel($event)" } }, providers: [providePraxisI18nConfig(DYNAMIC_WIDGET_PAGE_I18N_CONFIG)], viewQueries: [{ propertyName: "pageCanvasHost", first: true, predicate: ["pageCanvasHost"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
31978
- <div class="pdx-page-wrapper" [class.editing]="enableCustomization">
33198
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicWidgetPageComponent, isStandalone: true, selector: "praxis-dynamic-page", inputs: { page: "page", context: "context", strictValidation: "strictValidation", enableCustomization: "enableCustomization", showPageSettingsButton: "showPageSettingsButton", shellEditorComponent: "shellEditorComponent", pageEditorComponent: "pageEditorComponent", autoPersist: "autoPersist", pageIdentity: "pageIdentity", componentInstanceId: "componentInstanceId", showWidgetAssistantButton: "showWidgetAssistantButton" }, outputs: { pageChange: "pageChange", widgetEvent: "widgetEvent", widgetSelectionChange: "widgetSelectionChange", widgetAssistantRequested: "widgetAssistantRequested", widgetDiagnosticsChange: "widgetDiagnosticsChange" }, host: { listeners: { "window:resize": "onWindowResize()", "window:pointermove": "onCanvasPointerMove($event)", "window:pointerup": "onCanvasPointerUp($event)", "window:pointercancel": "onCanvasPointerCancel($event)" } }, providers: [providePraxisI18nConfig(DYNAMIC_WIDGET_PAGE_I18N_CONFIG)], viewQueries: [{ propertyName: "pageCanvasHost", first: true, predicate: ["pageCanvasHost"], descendants: true }, { propertyName: "widgetLoaders", predicate: ["widgetLoader"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
33199
+ <div
33200
+ class="pdx-page-wrapper"
33201
+ [class.editing]="enableCustomization"
33202
+ [attr.data-theme-preset]="pageThemePresetId"
33203
+ [attr.data-density]="pageThemeDensity"
33204
+ [attr.data-motion]="pageThemeMotion"
33205
+ [ngStyle]="pageThemeTokenStyle"
33206
+ >
31979
33207
  @if (enableCustomization && showPageSettingsButton) {
31980
33208
  <button
31981
33209
  class="pdx-page-settings"
@@ -32001,6 +33229,7 @@ class DynamicWidgetPageComponent {
32001
33229
  @for (w of widgets(); track w.key) {
32002
33230
  <div
32003
33231
  class="pdx-widget pdx-widget--canvas"
33232
+ [attr.data-widget-key]="w.key"
32004
33233
  [class.pdx-widget--interactive]="enableCustomization"
32005
33234
  [class.pdx-widget--selected]="
32006
33235
  enableCustomization && isWidgetSelected(w.key)
@@ -32049,6 +33278,7 @@ class DynamicWidgetPageComponent {
32049
33278
  >
32050
33279
  <ng-container
32051
33280
  [dynamicWidgetLoader]="w.definition"
33281
+ #widgetLoader="dynamicWidgetLoader"
32052
33282
  [ownerWidgetKey]="w.key"
32053
33283
  [context]="mergedContext"
32054
33284
  [strictValidation]="strictValidation"
@@ -32137,6 +33367,7 @@ class DynamicWidgetPageComponent {
32137
33367
  @for (w of tab.widgets; track w.key) {
32138
33368
  <div
32139
33369
  class="pdx-widget"
33370
+ [attr.data-widget-key]="w.key"
32140
33371
  [class.pdx-widget--interactive]="enableCustomization"
32141
33372
  [class.pdx-widget--selected]="
32142
33373
  enableCustomization && isWidgetSelected(w.key)
@@ -32153,6 +33384,7 @@ class DynamicWidgetPageComponent {
32153
33384
  >
32154
33385
  <ng-container
32155
33386
  [dynamicWidgetLoader]="w.definition"
33387
+ #widgetLoader="dynamicWidgetLoader"
32156
33388
  [ownerWidgetKey]="w.key"
32157
33389
  [context]="mergedContext"
32158
33390
  [strictValidation]="strictValidation"
@@ -32201,6 +33433,7 @@ class DynamicWidgetPageComponent {
32201
33433
  @for (w of group.widgets; track w.key) {
32202
33434
  <div
32203
33435
  class="pdx-widget"
33436
+ [attr.data-widget-key]="w.key"
32204
33437
  [class.pdx-widget--interactive]="enableCustomization"
32205
33438
  [class.pdx-widget--selected]="
32206
33439
  enableCustomization && isWidgetSelected(w.key)
@@ -32217,6 +33450,7 @@ class DynamicWidgetPageComponent {
32217
33450
  >
32218
33451
  <ng-container
32219
33452
  [dynamicWidgetLoader]="w.definition"
33453
+ #widgetLoader="dynamicWidgetLoader"
32220
33454
  [ownerWidgetKey]="w.key"
32221
33455
  [context]="mergedContext"
32222
33456
  [strictValidation]="strictValidation"
@@ -32257,6 +33491,7 @@ class DynamicWidgetPageComponent {
32257
33491
  @for (w of widgets(); track w.key) {
32258
33492
  <div
32259
33493
  class="pdx-widget"
33494
+ [attr.data-widget-key]="w.key"
32260
33495
  [class.pdx-widget--interactive]="enableCustomization"
32261
33496
  [class.pdx-widget--selected]="
32262
33497
  enableCustomization && isWidgetSelected(w.key)
@@ -32273,6 +33508,7 @@ class DynamicWidgetPageComponent {
32273
33508
  >
32274
33509
  <ng-container
32275
33510
  [dynamicWidgetLoader]="w.definition"
33511
+ #widgetLoader="dynamicWidgetLoader"
32276
33512
  [ownerWidgetKey]="w.key"
32277
33513
  [context]="mergedContext"
32278
33514
  [strictValidation]="strictValidation"
@@ -32313,7 +33549,7 @@ class DynamicWidgetPageComponent {
32313
33549
  </div>
32314
33550
  }
32315
33551
  </div>
32316
- `, isInline: true, styles: [".pdx-page-wrapper{position:relative;display:block}.pdx-page{display:grid;gap:12px;grid-template-columns:minmax(0,1fr)}.pdx-page--canvas{align-items:start;grid-auto-flow:dense}.pdx-page-settings{position:sticky;top:8px;z-index:2;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);color:inherit;border-radius:12px;width:36px;height:36px;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-horizontal: linear-gradient( 90deg, 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-resize-gradient-vertical: linear-gradient( 180deg, 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-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-resize-gradient-diagonal-sw: linear-gradient( 225deg, 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:has(.pdx-canvas-resize:hover):after,.pdx-widget--canvas:has(.pdx-canvas-resize:focus-visible):after{opacity:.82}.pdx-widget--canvas:has(.pdx-canvas-resize--north:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-horizontal)}.pdx-widget--canvas:has(.pdx-canvas-resize--east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-vertical)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-sw)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize{position:absolute;z-index:7;border:0;padding:0;margin:0;background:transparent;touch-action:none;cursor:pointer;opacity:0;pointer-events:none;transform:scale(.94);transition:opacity .14s ease,transform .14s ease,filter .14s ease;filter:saturate(.9)}.pdx-widget--canvas:hover .pdx-canvas-resize,.pdx-widget--canvas:focus-within .pdx-canvas-resize,.pdx-widget--canvas-selected .pdx-canvas-resize{opacity:.88;pointer-events:auto;transform:scale(1);filter:saturate(1)}.pdx-widget--canvas:has(.pdx-shell.expanded) .pdx-canvas-resize,.pdx-widget--canvas:has(.pdx-shell.fullscreen) .pdx-canvas-resize{opacity:0;pointer-events:none;transform:scale(.94)}.pdx-canvas-resize-grip{display:block;width:9px;height:9px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 42%,var(--md-sys-color-outline-variant) 58%);background:color-mix(in srgb,var(--md-sys-color-surface) 92%,var(--md-sys-color-primary) 8%);box-shadow:0 1px 4px color-mix(in srgb,var(--md-sys-color-shadow) 10%,transparent);transition:transform .14s ease,border-color .14s ease,background .14s ease,box-shadow .14s ease}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:color-mix(in srgb,var(--md-sys-color-primary) 58%,var(--md-sys-color-outline-variant) 42%);background:color-mix(in srgb,var(--md-sys-color-surface) 84%,var(--md-sys-color-primary) 16%);box-shadow:0 2px 7px color-mix(in srgb,var(--md-sys-color-primary) 14%,transparent);transform:scale(1.04)}.pdx-canvas-resize--north,.pdx-canvas-resize--south{left:50%;width:40px;height:18px;margin-left:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north{top:-8px;cursor:ns-resize}.pdx-canvas-resize--south{bottom:-8px;cursor:ns-resize}.pdx-canvas-resize--east,.pdx-canvas-resize--west{top:50%;width:18px;height:40px;margin-top:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--east{right:-8px;cursor:ew-resize}.pdx-canvas-resize--west{left:-8px;cursor:ew-resize}.pdx-canvas-resize--north-east,.pdx-canvas-resize--north-west,.pdx-canvas-resize--south-east,.pdx-canvas-resize--south-west{width:18px;height:18px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north-east{top:-8px;right:-8px;cursor:nesw-resize}.pdx-canvas-resize--north-west{top:-8px;left:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-east{bottom:-8px;right:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-west{bottom:-8px;left:-8px;cursor:nesw-resize}.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%)}.pdx-canvas-resize:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:transparent;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 20%,transparent),var(--mat-elevation-level3)}.pdx-canvas-resize--north:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-horizontal)}.pdx-canvas-resize--east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-vertical)}.pdx-canvas-resize--north-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-sw)}.pdx-canvas-resize--north-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-west:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{transform:scale(1.08)}@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$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: DynamicWidgetContextToolbarComponent, selector: "praxis-dynamic-widget-context-toolbar", inputs: ["toolbarLabel", "contextLabel", "contextTooltip", "showAssistant", "assistantLabel", "assistantTooltip", "showComponentSettings", "componentSettingsLabel", "componentSettingsTooltip", "showShellSettings", "shellSettingsLabel", "shellSettingsTooltip", "moreActionsLabel", "removeLabel"], outputs: ["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"] }] });
33552
+ `, isInline: true, styles: [".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)}.pdx-page-settings{position:sticky;top:8px;z-index:2;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);color:inherit;border-radius:12px;width:36px;height:36px;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-horizontal: linear-gradient( 90deg, 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-resize-gradient-vertical: linear-gradient( 180deg, 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-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-resize-gradient-diagonal-sw: linear-gradient( 225deg, 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:has(.pdx-canvas-resize:hover):after,.pdx-widget--canvas:has(.pdx-canvas-resize:focus-visible):after{opacity:.82}.pdx-widget--canvas:has(.pdx-canvas-resize--north:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-horizontal)}.pdx-widget--canvas:has(.pdx-canvas-resize--east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-vertical)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-sw)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize{position:absolute;z-index:7;border:0;padding:0;margin:0;background:transparent;touch-action:none;cursor:pointer;opacity:0;pointer-events:none;transform:scale(.94);transition:opacity .14s ease,transform .14s ease,filter .14s ease;filter:saturate(.9)}.pdx-widget--canvas:hover .pdx-canvas-resize,.pdx-widget--canvas:focus-within .pdx-canvas-resize,.pdx-widget--canvas-selected .pdx-canvas-resize{opacity:.88;pointer-events:auto;transform:scale(1);filter:saturate(1)}.pdx-widget--canvas:has(.pdx-shell.expanded) .pdx-canvas-resize,.pdx-widget--canvas:has(.pdx-shell.fullscreen) .pdx-canvas-resize{opacity:0;pointer-events:none;transform:scale(.94)}.pdx-canvas-resize-grip{display:block;width:9px;height:9px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 42%,var(--md-sys-color-outline-variant) 58%);background:color-mix(in srgb,var(--md-sys-color-surface) 92%,var(--md-sys-color-primary) 8%);box-shadow:0 1px 4px color-mix(in srgb,var(--md-sys-color-shadow) 10%,transparent);transition:transform .14s ease,border-color .14s ease,background .14s ease,box-shadow .14s ease}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:color-mix(in srgb,var(--md-sys-color-primary) 58%,var(--md-sys-color-outline-variant) 42%);background:color-mix(in srgb,var(--md-sys-color-surface) 84%,var(--md-sys-color-primary) 16%);box-shadow:0 2px 7px color-mix(in srgb,var(--md-sys-color-primary) 14%,transparent);transform:scale(1.04)}.pdx-canvas-resize--north,.pdx-canvas-resize--south{left:50%;width:40px;height:18px;margin-left:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north{top:-8px;cursor:ns-resize}.pdx-canvas-resize--south{bottom:-8px;cursor:ns-resize}.pdx-canvas-resize--east,.pdx-canvas-resize--west{top:50%;width:18px;height:40px;margin-top:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--east{right:-8px;cursor:ew-resize}.pdx-canvas-resize--west{left:-8px;cursor:ew-resize}.pdx-canvas-resize--north-east,.pdx-canvas-resize--north-west,.pdx-canvas-resize--south-east,.pdx-canvas-resize--south-west{width:18px;height:18px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north-east{top:-8px;right:-8px;cursor:nesw-resize}.pdx-canvas-resize--north-west{top:-8px;left:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-east{bottom:-8px;right:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-west{bottom:-8px;left:-8px;cursor:nesw-resize}.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%)}.pdx-canvas-resize:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:transparent;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 20%,transparent),var(--mat-elevation-level3)}.pdx-canvas-resize--north:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-horizontal)}.pdx-canvas-resize--east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-vertical)}.pdx-canvas-resize--north-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-sw)}.pdx-canvas-resize--north-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-west:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{transform:scale(1.08)}@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$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { 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: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: DynamicWidgetContextToolbarComponent, selector: "praxis-dynamic-widget-context-toolbar", inputs: ["toolbarLabel", "contextLabel", "contextTooltip", "showAssistant", "assistantLabel", "assistantTooltip", "showComponentSettings", "componentSettingsLabel", "componentSettingsTooltip", "showShellSettings", "shellSettingsLabel", "shellSettingsTooltip", "moreActionsLabel", "removeLabel"], outputs: ["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"] }] });
32317
33553
  }
32318
33554
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicWidgetPageComponent, decorators: [{
32319
33555
  type: Component,
@@ -32326,7 +33562,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
32326
33562
  DynamicWidgetLoaderDirective,
32327
33563
  WidgetShellComponent,
32328
33564
  ], providers: [providePraxisI18nConfig(DYNAMIC_WIDGET_PAGE_I18N_CONFIG)], template: `
32329
- <div class="pdx-page-wrapper" [class.editing]="enableCustomization">
33565
+ <div
33566
+ class="pdx-page-wrapper"
33567
+ [class.editing]="enableCustomization"
33568
+ [attr.data-theme-preset]="pageThemePresetId"
33569
+ [attr.data-density]="pageThemeDensity"
33570
+ [attr.data-motion]="pageThemeMotion"
33571
+ [ngStyle]="pageThemeTokenStyle"
33572
+ >
32330
33573
  @if (enableCustomization && showPageSettingsButton) {
32331
33574
  <button
32332
33575
  class="pdx-page-settings"
@@ -32352,6 +33595,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
32352
33595
  @for (w of widgets(); track w.key) {
32353
33596
  <div
32354
33597
  class="pdx-widget pdx-widget--canvas"
33598
+ [attr.data-widget-key]="w.key"
32355
33599
  [class.pdx-widget--interactive]="enableCustomization"
32356
33600
  [class.pdx-widget--selected]="
32357
33601
  enableCustomization && isWidgetSelected(w.key)
@@ -32400,6 +33644,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
32400
33644
  >
32401
33645
  <ng-container
32402
33646
  [dynamicWidgetLoader]="w.definition"
33647
+ #widgetLoader="dynamicWidgetLoader"
32403
33648
  [ownerWidgetKey]="w.key"
32404
33649
  [context]="mergedContext"
32405
33650
  [strictValidation]="strictValidation"
@@ -32488,6 +33733,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
32488
33733
  @for (w of tab.widgets; track w.key) {
32489
33734
  <div
32490
33735
  class="pdx-widget"
33736
+ [attr.data-widget-key]="w.key"
32491
33737
  [class.pdx-widget--interactive]="enableCustomization"
32492
33738
  [class.pdx-widget--selected]="
32493
33739
  enableCustomization && isWidgetSelected(w.key)
@@ -32504,6 +33750,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
32504
33750
  >
32505
33751
  <ng-container
32506
33752
  [dynamicWidgetLoader]="w.definition"
33753
+ #widgetLoader="dynamicWidgetLoader"
32507
33754
  [ownerWidgetKey]="w.key"
32508
33755
  [context]="mergedContext"
32509
33756
  [strictValidation]="strictValidation"
@@ -32552,6 +33799,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
32552
33799
  @for (w of group.widgets; track w.key) {
32553
33800
  <div
32554
33801
  class="pdx-widget"
33802
+ [attr.data-widget-key]="w.key"
32555
33803
  [class.pdx-widget--interactive]="enableCustomization"
32556
33804
  [class.pdx-widget--selected]="
32557
33805
  enableCustomization && isWidgetSelected(w.key)
@@ -32568,6 +33816,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
32568
33816
  >
32569
33817
  <ng-container
32570
33818
  [dynamicWidgetLoader]="w.definition"
33819
+ #widgetLoader="dynamicWidgetLoader"
32571
33820
  [ownerWidgetKey]="w.key"
32572
33821
  [context]="mergedContext"
32573
33822
  [strictValidation]="strictValidation"
@@ -32608,6 +33857,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
32608
33857
  @for (w of widgets(); track w.key) {
32609
33858
  <div
32610
33859
  class="pdx-widget"
33860
+ [attr.data-widget-key]="w.key"
32611
33861
  [class.pdx-widget--interactive]="enableCustomization"
32612
33862
  [class.pdx-widget--selected]="
32613
33863
  enableCustomization && isWidgetSelected(w.key)
@@ -32624,6 +33874,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
32624
33874
  >
32625
33875
  <ng-container
32626
33876
  [dynamicWidgetLoader]="w.definition"
33877
+ #widgetLoader="dynamicWidgetLoader"
32627
33878
  [ownerWidgetKey]="w.key"
32628
33879
  [context]="mergedContext"
32629
33880
  [strictValidation]="strictValidation"
@@ -32664,7 +33915,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
32664
33915
  </div>
32665
33916
  }
32666
33917
  </div>
32667
- `, styles: [".pdx-page-wrapper{position:relative;display:block}.pdx-page{display:grid;gap:12px;grid-template-columns:minmax(0,1fr)}.pdx-page--canvas{align-items:start;grid-auto-flow:dense}.pdx-page-settings{position:sticky;top:8px;z-index:2;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);color:inherit;border-radius:12px;width:36px;height:36px;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-horizontal: linear-gradient( 90deg, 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-resize-gradient-vertical: linear-gradient( 180deg, 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-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-resize-gradient-diagonal-sw: linear-gradient( 225deg, 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:has(.pdx-canvas-resize:hover):after,.pdx-widget--canvas:has(.pdx-canvas-resize:focus-visible):after{opacity:.82}.pdx-widget--canvas:has(.pdx-canvas-resize--north:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-horizontal)}.pdx-widget--canvas:has(.pdx-canvas-resize--east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-vertical)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-sw)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize{position:absolute;z-index:7;border:0;padding:0;margin:0;background:transparent;touch-action:none;cursor:pointer;opacity:0;pointer-events:none;transform:scale(.94);transition:opacity .14s ease,transform .14s ease,filter .14s ease;filter:saturate(.9)}.pdx-widget--canvas:hover .pdx-canvas-resize,.pdx-widget--canvas:focus-within .pdx-canvas-resize,.pdx-widget--canvas-selected .pdx-canvas-resize{opacity:.88;pointer-events:auto;transform:scale(1);filter:saturate(1)}.pdx-widget--canvas:has(.pdx-shell.expanded) .pdx-canvas-resize,.pdx-widget--canvas:has(.pdx-shell.fullscreen) .pdx-canvas-resize{opacity:0;pointer-events:none;transform:scale(.94)}.pdx-canvas-resize-grip{display:block;width:9px;height:9px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 42%,var(--md-sys-color-outline-variant) 58%);background:color-mix(in srgb,var(--md-sys-color-surface) 92%,var(--md-sys-color-primary) 8%);box-shadow:0 1px 4px color-mix(in srgb,var(--md-sys-color-shadow) 10%,transparent);transition:transform .14s ease,border-color .14s ease,background .14s ease,box-shadow .14s ease}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:color-mix(in srgb,var(--md-sys-color-primary) 58%,var(--md-sys-color-outline-variant) 42%);background:color-mix(in srgb,var(--md-sys-color-surface) 84%,var(--md-sys-color-primary) 16%);box-shadow:0 2px 7px color-mix(in srgb,var(--md-sys-color-primary) 14%,transparent);transform:scale(1.04)}.pdx-canvas-resize--north,.pdx-canvas-resize--south{left:50%;width:40px;height:18px;margin-left:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north{top:-8px;cursor:ns-resize}.pdx-canvas-resize--south{bottom:-8px;cursor:ns-resize}.pdx-canvas-resize--east,.pdx-canvas-resize--west{top:50%;width:18px;height:40px;margin-top:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--east{right:-8px;cursor:ew-resize}.pdx-canvas-resize--west{left:-8px;cursor:ew-resize}.pdx-canvas-resize--north-east,.pdx-canvas-resize--north-west,.pdx-canvas-resize--south-east,.pdx-canvas-resize--south-west{width:18px;height:18px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north-east{top:-8px;right:-8px;cursor:nesw-resize}.pdx-canvas-resize--north-west{top:-8px;left:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-east{bottom:-8px;right:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-west{bottom:-8px;left:-8px;cursor:nesw-resize}.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%)}.pdx-canvas-resize:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:transparent;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 20%,transparent),var(--mat-elevation-level3)}.pdx-canvas-resize--north:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-horizontal)}.pdx-canvas-resize--east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-vertical)}.pdx-canvas-resize--north-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-sw)}.pdx-canvas-resize--north-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-west:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{transform:scale(1.08)}@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"] }]
33918
+ `, styles: [".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)}.pdx-page-settings{position:sticky;top:8px;z-index:2;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);color:inherit;border-radius:12px;width:36px;height:36px;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-horizontal: linear-gradient( 90deg, 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-resize-gradient-vertical: linear-gradient( 180deg, 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-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-resize-gradient-diagonal-sw: linear-gradient( 225deg, 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:has(.pdx-canvas-resize:hover):after,.pdx-widget--canvas:has(.pdx-canvas-resize:focus-visible):after{opacity:.82}.pdx-widget--canvas:has(.pdx-canvas-resize--north:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-horizontal)}.pdx-widget--canvas:has(.pdx-canvas-resize--east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-vertical)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-sw)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize{position:absolute;z-index:7;border:0;padding:0;margin:0;background:transparent;touch-action:none;cursor:pointer;opacity:0;pointer-events:none;transform:scale(.94);transition:opacity .14s ease,transform .14s ease,filter .14s ease;filter:saturate(.9)}.pdx-widget--canvas:hover .pdx-canvas-resize,.pdx-widget--canvas:focus-within .pdx-canvas-resize,.pdx-widget--canvas-selected .pdx-canvas-resize{opacity:.88;pointer-events:auto;transform:scale(1);filter:saturate(1)}.pdx-widget--canvas:has(.pdx-shell.expanded) .pdx-canvas-resize,.pdx-widget--canvas:has(.pdx-shell.fullscreen) .pdx-canvas-resize{opacity:0;pointer-events:none;transform:scale(.94)}.pdx-canvas-resize-grip{display:block;width:9px;height:9px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 42%,var(--md-sys-color-outline-variant) 58%);background:color-mix(in srgb,var(--md-sys-color-surface) 92%,var(--md-sys-color-primary) 8%);box-shadow:0 1px 4px color-mix(in srgb,var(--md-sys-color-shadow) 10%,transparent);transition:transform .14s ease,border-color .14s ease,background .14s ease,box-shadow .14s ease}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:color-mix(in srgb,var(--md-sys-color-primary) 58%,var(--md-sys-color-outline-variant) 42%);background:color-mix(in srgb,var(--md-sys-color-surface) 84%,var(--md-sys-color-primary) 16%);box-shadow:0 2px 7px color-mix(in srgb,var(--md-sys-color-primary) 14%,transparent);transform:scale(1.04)}.pdx-canvas-resize--north,.pdx-canvas-resize--south{left:50%;width:40px;height:18px;margin-left:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north{top:-8px;cursor:ns-resize}.pdx-canvas-resize--south{bottom:-8px;cursor:ns-resize}.pdx-canvas-resize--east,.pdx-canvas-resize--west{top:50%;width:18px;height:40px;margin-top:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--east{right:-8px;cursor:ew-resize}.pdx-canvas-resize--west{left:-8px;cursor:ew-resize}.pdx-canvas-resize--north-east,.pdx-canvas-resize--north-west,.pdx-canvas-resize--south-east,.pdx-canvas-resize--south-west{width:18px;height:18px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north-east{top:-8px;right:-8px;cursor:nesw-resize}.pdx-canvas-resize--north-west{top:-8px;left:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-east{bottom:-8px;right:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-west{bottom:-8px;left:-8px;cursor:nesw-resize}.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%)}.pdx-canvas-resize:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:transparent;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 20%,transparent),var(--mat-elevation-level3)}.pdx-canvas-resize--north:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-horizontal)}.pdx-canvas-resize--east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-vertical)}.pdx-canvas-resize--north-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-sw)}.pdx-canvas-resize--north-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-west:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{transform:scale(1.08)}@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"] }]
32668
33919
  }], ctorParameters: () => [], propDecorators: { pageCanvasHost: [{
32669
33920
  type: ViewChild,
32670
33921
  args: ['pageCanvasHost']
@@ -32700,6 +33951,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
32700
33951
  type: Output
32701
33952
  }], widgetDiagnosticsChange: [{
32702
33953
  type: Output
33954
+ }], widgetLoaders: [{
33955
+ type: ViewChildren,
33956
+ args: ['widgetLoader']
32703
33957
  }], onWindowResize: [{
32704
33958
  type: HostListener,
32705
33959
  args: ['window:resize']
@@ -32757,10 +34011,13 @@ function providePraxisDynamicPageMetadata() {
32757
34011
  }
32758
34012
 
32759
34013
  class PraxisSurfaceHostComponent {
34014
+ globalActions = inject(GlobalActionService);
32760
34015
  title;
32761
34016
  subtitle;
32762
34017
  icon;
34018
+ beforeWidget;
32763
34019
  widget;
34020
+ afterWidget;
32764
34021
  context = null;
32765
34022
  strictValidation = true;
32766
34023
  /**
@@ -32768,13 +34025,21 @@ class PraxisSurfaceHostComponent {
32768
34025
  * modal/drawer hosts. Inline consumers may opt into rendering it again.
32769
34026
  */
32770
34027
  renderTitleInsideBody = false;
32771
- widgetLoader;
34028
+ widgetEvent = new EventEmitter();
34029
+ beforeWidgetLoader;
34030
+ mainWidgetLoader;
34031
+ afterWidgetLoader;
32772
34032
  renderQueued = false;
34033
+ beforeWidgetKey = 'surface.before';
34034
+ mainWidgetKey = 'surface.main';
34035
+ afterWidgetKey = 'surface.after';
32773
34036
  ngAfterViewInit() {
32774
34037
  this.scheduleWidgetRender();
32775
34038
  }
32776
34039
  ngOnChanges(changes) {
32777
34040
  if (changes['widget']
34041
+ || changes['beforeWidget']
34042
+ || changes['afterWidget']
32778
34043
  || changes['context']
32779
34044
  || changes['strictValidation']) {
32780
34045
  this.scheduleWidgetRender();
@@ -32786,17 +34051,101 @@ class PraxisSurfaceHostComponent {
32786
34051
  this.renderQueued = true;
32787
34052
  queueMicrotask(() => {
32788
34053
  this.renderQueued = false;
32789
- const loader = this.widgetLoader;
32790
- if (!loader)
32791
- return;
32792
- loader.widget = this.widget;
32793
- loader.context = this.context;
32794
- loader.strictValidation = this.strictValidation;
32795
- loader.renderNow();
34054
+ this.renderLoader(this.beforeWidgetLoader, this.beforeWidget, this.beforeWidgetKey);
34055
+ this.renderLoader(this.mainWidgetLoader, this.widget, this.mainWidgetKey);
34056
+ this.renderLoader(this.afterWidgetLoader, this.afterWidget, this.afterWidgetKey);
34057
+ });
34058
+ }
34059
+ renderLoader(loader, widget, widgetKey) {
34060
+ if (!loader)
34061
+ return;
34062
+ loader.widget = this.enrichWidget(widget, widgetKey);
34063
+ loader.ownerWidgetKey = widgetKey;
34064
+ loader.context = this.context;
34065
+ loader.strictValidation = this.strictValidation;
34066
+ loader.renderNow();
34067
+ }
34068
+ enrichWidget(widget, widgetKey) {
34069
+ if (!widget || widget.id !== 'praxis-rich-content') {
34070
+ return widget;
34071
+ }
34072
+ return {
34073
+ ...widget,
34074
+ inputs: {
34075
+ ...(widget.inputs || {}),
34076
+ hostCapabilities: this.buildRichContentHostCapabilities(widgetKey, widget.inputs?.['context']),
34077
+ },
34078
+ };
34079
+ }
34080
+ buildRichContentHostCapabilities(widgetKey, widgetContext) {
34081
+ return {
34082
+ dispatchAction: (actionId, payload) => this.dispatchRichContentAction(widgetKey, actionId, payload, widgetContext),
34083
+ isActionAvailable: (actionId) => this.isRichContentActionAvailable(actionId),
34084
+ hasCapability: (capabilityId) => this.hasRichContentCapability(capabilityId),
34085
+ };
34086
+ }
34087
+ dispatchRichContentAction(widgetKey, actionId, payload, widgetContext) {
34088
+ if (!actionId) {
34089
+ return;
34090
+ }
34091
+ if (this.globalActions.has(actionId)) {
34092
+ void this.globalActions.execute(actionId, payload, {
34093
+ sourceId: widgetKey,
34094
+ widgetKey,
34095
+ payload: {
34096
+ widgetKey,
34097
+ actionId,
34098
+ payload,
34099
+ surfaceContext: this.context,
34100
+ richContentContext: widgetContext,
34101
+ },
34102
+ runtime: {
34103
+ widgetContext,
34104
+ state: this.context,
34105
+ },
34106
+ meta: {
34107
+ origin: 'surface.rich-content',
34108
+ componentId: 'praxis-surface-host',
34109
+ },
34110
+ });
34111
+ return;
34112
+ }
34113
+ this.widgetEvent.emit({
34114
+ ownerWidgetKey: widgetKey,
34115
+ sourceComponentId: 'praxis-rich-content',
34116
+ output: 'customAction',
34117
+ payload: {
34118
+ actionId,
34119
+ payload,
34120
+ globalAction: {
34121
+ actionId,
34122
+ payload,
34123
+ },
34124
+ },
34125
+ });
34126
+ }
34127
+ isRichContentActionAvailable(actionId) {
34128
+ return !!actionId;
34129
+ }
34130
+ hasRichContentCapability(capabilityId) {
34131
+ switch (capabilityId) {
34132
+ case 'surface.host':
34133
+ case 'surface.rich-content.actions':
34134
+ return true;
34135
+ case 'surface.context':
34136
+ return !!this.context;
34137
+ default:
34138
+ return false;
34139
+ }
34140
+ }
34141
+ onSlotWidgetEvent(ownerWidgetKey, event) {
34142
+ this.widgetEvent.emit({
34143
+ ...event,
34144
+ ownerWidgetKey: event.ownerWidgetKey || ownerWidgetKey,
32796
34145
  });
32797
34146
  }
32798
34147
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisSurfaceHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
32799
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisSurfaceHostComponent, isStandalone: true, selector: "praxis-surface-host", inputs: { title: "title", subtitle: "subtitle", icon: "icon", widget: "widget", context: "context", strictValidation: "strictValidation", renderTitleInsideBody: "renderTitleInsideBody" }, viewQueries: [{ propertyName: "widgetLoader", first: true, predicate: DynamicWidgetLoaderDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: `
34148
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisSurfaceHostComponent, isStandalone: true, selector: "praxis-surface-host", inputs: { title: "title", subtitle: "subtitle", icon: "icon", beforeWidget: "beforeWidget", widget: "widget", afterWidget: "afterWidget", context: "context", strictValidation: "strictValidation", renderTitleInsideBody: "renderTitleInsideBody" }, outputs: { widgetEvent: "widgetEvent" }, viewQueries: [{ propertyName: "beforeWidgetLoader", first: true, predicate: ["beforeWidgetLoader"], descendants: true, read: DynamicWidgetLoaderDirective }, { propertyName: "mainWidgetLoader", first: true, predicate: ["mainWidgetLoader"], descendants: true, read: DynamicWidgetLoaderDirective }, { propertyName: "afterWidgetLoader", first: true, predicate: ["afterWidgetLoader"], descendants: true, read: DynamicWidgetLoaderDirective }], usesOnChanges: true, ngImport: i0, template: `
32800
34149
  <div class="pdx-surface-host">
32801
34150
  @if (subtitle || (title && renderTitleInsideBody)) {
32802
34151
  <header class="pdx-surface-host__header">
@@ -32815,16 +34164,45 @@ class PraxisSurfaceHostComponent {
32815
34164
  }
32816
34165
 
32817
34166
  <section class="pdx-surface-host__body">
34167
+ @if (beforeWidget) {
34168
+ <div class="pdx-surface-host__slot pdx-surface-host__slot--before">
34169
+ <ng-container
34170
+ #beforeWidgetLoader
34171
+ [dynamicWidgetLoader]="beforeWidget"
34172
+ [ownerWidgetKey]="beforeWidgetKey"
34173
+ [context]="context"
34174
+ [strictValidation]="strictValidation"
34175
+ (widgetEvent)="onSlotWidgetEvent(beforeWidgetKey, $event)"
34176
+ ></ng-container>
34177
+ </div>
34178
+ }
34179
+
32818
34180
  @if (widget) {
32819
34181
  <ng-container
34182
+ #mainWidgetLoader
32820
34183
  [dynamicWidgetLoader]="widget"
34184
+ [ownerWidgetKey]="mainWidgetKey"
32821
34185
  [context]="context"
32822
34186
  [strictValidation]="strictValidation"
34187
+ (widgetEvent)="onSlotWidgetEvent(mainWidgetKey, $event)"
32823
34188
  ></ng-container>
32824
34189
  }
34190
+
34191
+ @if (afterWidget) {
34192
+ <div class="pdx-surface-host__slot pdx-surface-host__slot--after">
34193
+ <ng-container
34194
+ #afterWidgetLoader
34195
+ [dynamicWidgetLoader]="afterWidget"
34196
+ [ownerWidgetKey]="afterWidgetKey"
34197
+ [context]="context"
34198
+ [strictValidation]="strictValidation"
34199
+ (widgetEvent)="onSlotWidgetEvent(afterWidgetKey, $event)"
34200
+ ></ng-container>
34201
+ </div>
34202
+ }
32825
34203
  </section>
32826
34204
  </div>
32827
- `, isInline: true, styles: [":host{display:block;min-width:0}.pdx-surface-host{display:grid;gap:16px;min-width:0}.pdx-surface-host__header{display:grid;grid-template-columns:auto 1fr;gap:12px;align-items:start}.pdx-surface-host__icon{font-size:20px;line-height:20px;color:var(--md-sys-color-primary, currentColor)}.pdx-surface-host__copy{display:grid;gap:4px;min-width:0}.pdx-surface-host__title,.pdx-surface-host__subtitle{margin:0}.pdx-surface-host__title{font-size:1rem;font-weight:600}.pdx-surface-host__subtitle{color:var(--md-sys-color-on-surface-variant, rgba(0, 0, 0, .64));font-size:.9375rem}.pdx-surface-host__body{min-width:0}\n"], dependencies: [{ kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }] });
34205
+ `, isInline: true, styles: [":host{display:block;min-width:0}.pdx-surface-host{display:grid;gap:16px;min-width:0}.pdx-surface-host__header{display:grid;grid-template-columns:auto 1fr;gap:12px;align-items:start}.pdx-surface-host__icon{font-size:20px;line-height:20px;color:var(--md-sys-color-primary, currentColor)}.pdx-surface-host__copy{display:grid;gap:4px;min-width:0}.pdx-surface-host__title,.pdx-surface-host__subtitle{margin:0}.pdx-surface-host__title{font-size:1rem;font-weight:600}.pdx-surface-host__subtitle{color:var(--md-sys-color-on-surface-variant, rgba(0, 0, 0, .64));font-size:.9375rem}.pdx-surface-host__body{display:grid;gap:16px;min-width:0}.pdx-surface-host__slot{min-width:0}\n"], dependencies: [{ kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }] });
32828
34206
  }
32829
34207
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisSurfaceHostComponent, decorators: [{
32830
34208
  type: Component,
@@ -32847,33 +34225,74 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
32847
34225
  }
32848
34226
 
32849
34227
  <section class="pdx-surface-host__body">
34228
+ @if (beforeWidget) {
34229
+ <div class="pdx-surface-host__slot pdx-surface-host__slot--before">
34230
+ <ng-container
34231
+ #beforeWidgetLoader
34232
+ [dynamicWidgetLoader]="beforeWidget"
34233
+ [ownerWidgetKey]="beforeWidgetKey"
34234
+ [context]="context"
34235
+ [strictValidation]="strictValidation"
34236
+ (widgetEvent)="onSlotWidgetEvent(beforeWidgetKey, $event)"
34237
+ ></ng-container>
34238
+ </div>
34239
+ }
34240
+
32850
34241
  @if (widget) {
32851
34242
  <ng-container
34243
+ #mainWidgetLoader
32852
34244
  [dynamicWidgetLoader]="widget"
34245
+ [ownerWidgetKey]="mainWidgetKey"
32853
34246
  [context]="context"
32854
34247
  [strictValidation]="strictValidation"
34248
+ (widgetEvent)="onSlotWidgetEvent(mainWidgetKey, $event)"
32855
34249
  ></ng-container>
32856
34250
  }
34251
+
34252
+ @if (afterWidget) {
34253
+ <div class="pdx-surface-host__slot pdx-surface-host__slot--after">
34254
+ <ng-container
34255
+ #afterWidgetLoader
34256
+ [dynamicWidgetLoader]="afterWidget"
34257
+ [ownerWidgetKey]="afterWidgetKey"
34258
+ [context]="context"
34259
+ [strictValidation]="strictValidation"
34260
+ (widgetEvent)="onSlotWidgetEvent(afterWidgetKey, $event)"
34261
+ ></ng-container>
34262
+ </div>
34263
+ }
32857
34264
  </section>
32858
34265
  </div>
32859
- `, styles: [":host{display:block;min-width:0}.pdx-surface-host{display:grid;gap:16px;min-width:0}.pdx-surface-host__header{display:grid;grid-template-columns:auto 1fr;gap:12px;align-items:start}.pdx-surface-host__icon{font-size:20px;line-height:20px;color:var(--md-sys-color-primary, currentColor)}.pdx-surface-host__copy{display:grid;gap:4px;min-width:0}.pdx-surface-host__title,.pdx-surface-host__subtitle{margin:0}.pdx-surface-host__title{font-size:1rem;font-weight:600}.pdx-surface-host__subtitle{color:var(--md-sys-color-on-surface-variant, rgba(0, 0, 0, .64));font-size:.9375rem}.pdx-surface-host__body{min-width:0}\n"] }]
34266
+ `, styles: [":host{display:block;min-width:0}.pdx-surface-host{display:grid;gap:16px;min-width:0}.pdx-surface-host__header{display:grid;grid-template-columns:auto 1fr;gap:12px;align-items:start}.pdx-surface-host__icon{font-size:20px;line-height:20px;color:var(--md-sys-color-primary, currentColor)}.pdx-surface-host__copy{display:grid;gap:4px;min-width:0}.pdx-surface-host__title,.pdx-surface-host__subtitle{margin:0}.pdx-surface-host__title{font-size:1rem;font-weight:600}.pdx-surface-host__subtitle{color:var(--md-sys-color-on-surface-variant, rgba(0, 0, 0, .64));font-size:.9375rem}.pdx-surface-host__body{display:grid;gap:16px;min-width:0}.pdx-surface-host__slot{min-width:0}\n"] }]
32860
34267
  }], propDecorators: { title: [{
32861
34268
  type: Input
32862
34269
  }], subtitle: [{
32863
34270
  type: Input
32864
34271
  }], icon: [{
32865
34272
  type: Input
34273
+ }], beforeWidget: [{
34274
+ type: Input
32866
34275
  }], widget: [{
32867
34276
  type: Input
34277
+ }], afterWidget: [{
34278
+ type: Input
32868
34279
  }], context: [{
32869
34280
  type: Input
32870
34281
  }], strictValidation: [{
32871
34282
  type: Input
32872
34283
  }], renderTitleInsideBody: [{
32873
34284
  type: Input
32874
- }], widgetLoader: [{
34285
+ }], widgetEvent: [{
34286
+ type: Output
34287
+ }], beforeWidgetLoader: [{
32875
34288
  type: ViewChild,
32876
- args: [DynamicWidgetLoaderDirective]
34289
+ args: ['beforeWidgetLoader', { read: DynamicWidgetLoaderDirective }]
34290
+ }], mainWidgetLoader: [{
34291
+ type: ViewChild,
34292
+ args: ['mainWidgetLoader', { read: DynamicWidgetLoaderDirective }]
34293
+ }], afterWidgetLoader: [{
34294
+ type: ViewChild,
34295
+ args: ['afterWidgetLoader', { read: DynamicWidgetLoaderDirective }]
32877
34296
  }] } });
32878
34297
 
32879
34298
  class EmptyStateCardComponent {
@@ -34339,4 +35758,4 @@ function provideHookWhitelist(allowed) {
34339
35758
  * Generated bundle index. Do not edit.
34340
35759
  */
34341
35760
 
34342
- 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, CONFIG_STORAGE, CONNECTION_STORAGE, ComponentKeyService, ComponentMetadataRegistry, CompositionRuntimeFacade, 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, 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_COLLECTION_EXPORT_HTTP_OPTIONS, PRAXIS_COLLECTION_EXPORT_PROVIDER, PRAXIS_CORPORATE_SENSITIVE_KEYS, PRAXIS_DEFAULT_EXPORT_SECURITY_POLICY, PRAXIS_DEFAULT_OBSERVABILITY_ALERT_RULES, PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA, 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_RICH_TEXT_BLOCK_METADATA, PRAXIS_TELEMETRY_TRANSPORT, PRAXIS_USER_CONTEXT_SUMMARY_METADATA, PRIVACY_CONSENT_EDITORIAL_SOLUTION, PRIVACY_CONSENT_EDITORIAL_TEMPLATE, PraxisCollectionExportService, PraxisCore, PraxisFooterLinksComponent, PraxisGlobalErrorHandler, PraxisHeroBannerComponent, PraxisHttpCollectionExportProvider, PraxisI18nService, PraxisIconDirective, PraxisIconPickerComponent, PraxisJsonLogicError, PraxisJsonLogicService, PraxisLayerScaleStyleService, PraxisLegalNoticeComponent, PraxisLoadingInterceptor, PraxisRichTextBlockComponent, PraxisSurfaceHostComponent, PraxisUserContextSummaryComponent, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, RULE_PROPERTY_SCHEMA, RemoteConfigStorage, ResourceActionOpenAdapterService, ResourceDiscoveryService, ResourceQuickConnectComponent, ResourceSurfaceOpenAdapterService, SCHEMA_VIEWER_CONTEXT, SETTINGS_PANEL_BRIDGE, SETTINGS_PANEL_DATA, STEPPER_CONFIG_EDITOR, SURFACE_DRAWER_BRIDGE, SURFACE_OPEN_I18N_CONFIG, SURFACE_OPEN_I18N_NAMESPACE, SURFACE_OPEN_PRESETS, SchemaMetadataClient, SchemaNormalizerService, SchemaViewerComponent, SurfaceBindingRuntimeService, SurfaceOpenActionEditorComponent, SurfaceOpenMaterializerService, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, clampRange, classifyEntityLookupResult, 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, extractNormalizedError, fetchWithETag, fileTypeValidator, fillUndefined, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isPraxisRuntimeGlobalActionEffect, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, matchFieldValidator, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldConstraints, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef$1 as normalizeGlobalActionRef, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizePraxisEffectPolicy, normalizePraxisQueryFilterExpression, normalizePraxisQueryFilterNode, normalizeResourceAvailabilityReasonCode, normalizeStart, normalizeUnknownError, normalizeWidgetEventPath, notifySuccessHook, parseJsonResponseOrEmpty, praxisLoadingInterceptorFn, prefillFromContextHook, provideDefaultFormHooks, provideFieldSelectorRegistryBase, provideFieldSelectorRegistryOverride, provideFieldSelectorRegistryRuntime, provideFormHookPresets, provideFormHooks, provideGlobalActionCatalog, provideGlobalActionHandler, provideGlobalConfig, provideGlobalConfigReady, provideGlobalConfigSeed, provideGlobalConfigTenant, provideHookResolvers, provideHookWhitelist, provideOverlayDecisionMatrix, providePraxisAnalyticsGlobalActions, providePraxisCollectionExportProvider, providePraxisDynamicPageMetadata, providePraxisFooterLinksMetadata, providePraxisGlobalActionCatalog, providePraxisGlobalActions, providePraxisGlobalConfigBootstrap, providePraxisHeroBannerMetadata, providePraxisHttpCollectionExportProvider, providePraxisHttpLoading, providePraxisI18n, providePraxisI18nConfig, providePraxisI18nTranslator, providePraxisIconDefaults, providePraxisJsonLogicOperator, providePraxisJsonLogicOperatorOverride, providePraxisLegalNoticeMetadata, providePraxisLoadingDefaults, providePraxisLogging, providePraxisRichTextBlockMetadata, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, removeDiacritics, reportTelemetryHookFactory, requiredCheckedValidator, resolveBuiltinPresets, resolveControlTypeAlias, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolveResourceAvailabilityReasonKey, resolveSpan, resolveValuePresentation, resolveValuePresentationLocale, serializeEntityLookupValueForPayload, serializeOptionSourceFilterRequest, serializePraxisCollectionToCsv, serializePraxisCollectionToJson, slugify, stripMasksHook, supportsImplicitValuePresentation, syncWithServerMetadata, toCamel, toCapitalize, toKebab, toPascal, toSentenceCase, toSnake, toTitleCase, translateResourceAvailabilityReason, translateResourceDiscoveryText, translateUnavailableWorkflowMessage, trim, uniqueAsyncValidator, urlValidator, validateGlobalActionRef, validateGlobalActionRefs, withMessage, withPraxisHttpLoading };
35761
+ 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, CONFIG_STORAGE, CONNECTION_STORAGE, ComponentKeyService, ComponentMetadataRegistry, CompositionRuntimeFacade, 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, 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_COLLECTION_EXPORT_HTTP_OPTIONS, PRAXIS_COLLECTION_EXPORT_PROVIDER, PRAXIS_CORPORATE_SENSITIVE_KEYS, PRAXIS_DEFAULT_EXPORT_SECURITY_POLICY, PRAXIS_DEFAULT_OBSERVABILITY_ALERT_RULES, PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA, 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_RICH_TEXT_BLOCK_METADATA, PRAXIS_TELEMETRY_TRANSPORT, PRAXIS_USER_CONTEXT_SUMMARY_METADATA, PRIVACY_CONSENT_EDITORIAL_SOLUTION, PRIVACY_CONSENT_EDITORIAL_TEMPLATE, PraxisCollectionExportService, PraxisCore, PraxisFooterLinksComponent, PraxisGlobalErrorHandler, PraxisHeroBannerComponent, PraxisHttpCollectionExportProvider, PraxisI18nService, PraxisIconDirective, PraxisIconPickerComponent, PraxisJsonLogicError, PraxisJsonLogicService, PraxisLayerScaleStyleService, PraxisLegalNoticeComponent, PraxisLoadingInterceptor, PraxisRichTextBlockComponent, PraxisRuntimeComponentObservationRegistryService, PraxisSurfaceHostComponent, PraxisUserContextSummaryComponent, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, RULE_PROPERTY_SCHEMA, RemoteConfigStorage, ResourceActionOpenAdapterService, ResourceDiscoveryService, ResourceQuickConnectComponent, ResourceSurfaceOpenAdapterService, SCHEMA_VIEWER_CONTEXT, SETTINGS_PANEL_BRIDGE, SETTINGS_PANEL_DATA, STEPPER_CONFIG_EDITOR, SURFACE_DRAWER_BRIDGE, SURFACE_OPEN_I18N_CONFIG, SURFACE_OPEN_I18N_NAMESPACE, SURFACE_OPEN_PRESETS, SchemaMetadataClient, SchemaNormalizerService, SchemaViewerComponent, SurfaceBindingRuntimeService, SurfaceOpenActionEditorComponent, SurfaceOpenMaterializerService, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, assertPraxisRuntimeComponentObservationSerializable, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, 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, extractNormalizedError, fetchWithETag, fileTypeValidator, fillUndefined, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isPraxisRuntimeGlobalActionEffect, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, matchFieldValidator, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldConstraints, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef$1 as normalizeGlobalActionRef, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizePraxisEffectPolicy, normalizePraxisQueryFilterExpression, normalizePraxisQueryFilterNode, normalizeResourceAvailabilityReasonCode, normalizeStart, normalizeUnknownError, normalizeWidgetEventPath, notifySuccessHook, parseJsonResponseOrEmpty, praxisLoadingInterceptorFn, prefillFromContextHook, provideDefaultFormHooks, provideFieldSelectorRegistryBase, provideFieldSelectorRegistryOverride, provideFieldSelectorRegistryRuntime, provideFormHookPresets, provideFormHooks, provideGlobalActionCatalog, provideGlobalActionHandler, provideGlobalConfig, provideGlobalConfigReady, provideGlobalConfigSeed, provideGlobalConfigTenant, provideHookResolvers, provideHookWhitelist, provideOverlayDecisionMatrix, providePraxisAnalyticsGlobalActions, providePraxisCollectionExportProvider, providePraxisDynamicPageMetadata, providePraxisFooterLinksMetadata, providePraxisGlobalActionCatalog, providePraxisGlobalActions, providePraxisGlobalConfigBootstrap, providePraxisHeroBannerMetadata, providePraxisHttpCollectionExportProvider, providePraxisHttpLoading, providePraxisI18n, providePraxisI18nConfig, providePraxisI18nTranslator, providePraxisIconDefaults, providePraxisJsonLogicOperator, providePraxisJsonLogicOperatorOverride, providePraxisLegalNoticeMetadata, providePraxisLoadingDefaults, providePraxisLogging, providePraxisRichTextBlockMetadata, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, registerPraxisRuntimeComponentObservation, removeDiacritics, reportTelemetryHookFactory, requiredCheckedValidator, requiredPresenceValidator, resolveBuiltinPresets, resolveControlTypeAlias, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolveResourceAvailabilityReasonKey, resolveSpan, resolveValuePresentation, resolveValuePresentationLocale, serializeEntityLookupValueForPayload, serializeOptionSourceFilterRequest, serializePraxisCollectionToCsv, serializePraxisCollectionToJson, slugify, stripMasksHook, supportsImplicitValuePresentation, syncWithServerMetadata, toCamel, toCapitalize, toKebab, toPascal, toSentenceCase, toSnake, toTitleCase, translateResourceAvailabilityReason, translateResourceDiscoveryText, translateUnavailableWorkflowMessage, trim, uniqueAsyncValidator, urlValidator, validateGlobalActionRef, validateGlobalActionRefs, withMessage, withPraxisHttpLoading };