@praxisui/core 10.0.0-rc.4 → 10.0.0-rc.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ai/component-registry.json +4 -3
- package/fesm2022/praxisui-core-schema.mjs +2946 -0
- package/fesm2022/praxisui-core.mjs +3188 -106
- package/package.json +5 -1
- package/theming/_theming.scss +79 -1
- package/types/praxisui-core-schema.d.ts +4418 -0
- package/types/praxisui-core.d.ts +5920 -4834
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Component, InjectionToken, Injectable, inject, Inject, Optional, SkipSelf, makeEnvironmentProviders, APP_INITIALIZER, signal, computed, DestroyRef, ENVIRONMENT_INITIALIZER, ErrorHandler, isSignal, Input, Directive, input, booleanAttribute, ChangeDetectionStrategy, EventEmitter, Output, SecurityContext, ViewContainerRef, Injector, effect, SimpleChange, ElementRef, ChangeDetectorRef, afterEveryRender, contentChild, viewChild, HostBinding, output, afterNextRender, ViewChild, ViewEncapsulation, createEnvironmentInjector, EnvironmentInjector, reflectComponentType, HostListener, ViewChildren } from '@angular/core';
|
|
2
|
+
import { Component, InjectionToken, Injectable, inject, Inject, Optional, SkipSelf, makeEnvironmentProviders, APP_INITIALIZER, signal, computed, DestroyRef, ENVIRONMENT_INITIALIZER, ErrorHandler, isSignal, Input, Directive, input, booleanAttribute, ChangeDetectionStrategy, EventEmitter, Output, SecurityContext, ViewContainerRef, Injector, effect, SimpleChange, ElementRef, ChangeDetectorRef, afterEveryRender, contentChild, viewChild, HostBinding, output, afterNextRender, ViewChild, ViewEncapsulation, createEnvironmentInjector, EnvironmentInjector, reflectComponentType, HostListener, ViewChildren, TemplateRef, Renderer2 } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/common/http';
|
|
4
|
-
import { HttpHeaders, HttpClient, HttpParams, HttpResponse, HttpContextToken, HTTP_INTERCEPTORS, withInterceptors } from '@angular/common/http';
|
|
5
|
-
import { of, defer, throwError, from, EMPTY, BehaviorSubject, firstValueFrom, Subject, finalize as finalize$1, shareReplay as shareReplay$1, map as map$1, switchMap as switchMap$1, catchError as catchError$1, forkJoin, isObservable, combineLatest, merge, timeout } from 'rxjs';
|
|
6
|
-
import { switchMap, map, take, catchError, concatMap, tap, shareReplay, takeUntil, toArray, finalize } from 'rxjs/operators';
|
|
4
|
+
import { HttpHeaders, HttpClient, HttpParams, HttpResponse, HttpContextToken, HttpErrorResponse, HTTP_INTERCEPTORS, withInterceptors } from '@angular/common/http';
|
|
5
|
+
import { of, defer, throwError, from, EMPTY, BehaviorSubject, firstValueFrom, Subject, finalize as finalize$1, shareReplay as shareReplay$1, map as map$1, switchMap as switchMap$1, catchError as catchError$1, forkJoin, isObservable, combineLatest, merge, Subscription, timeout } from 'rxjs';
|
|
6
|
+
import { switchMap, map, take, catchError, concatMap, tap, shareReplay, takeUntil, toArray, finalize, filter } from 'rxjs/operators';
|
|
7
7
|
import * as i1$3 from '@angular/common';
|
|
8
8
|
import { Location, DOCUMENT, NgTemplateOutlet, CommonModule, NgComponentOutlet } from '@angular/common';
|
|
9
|
-
import { Router, ActivatedRoute } from '@angular/router';
|
|
9
|
+
import { Router, ActivatedRoute, RouterLink, RouterLinkActive } from '@angular/router';
|
|
10
10
|
import * as i1$2 from '@angular/forms';
|
|
11
11
|
import { Validators, FormGroup, FormControl, FormArray, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
12
12
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
@@ -32,7 +32,7 @@ import { Overlay, OverlayModule } from '@angular/cdk/overlay';
|
|
|
32
32
|
import { DomPortal } from '@angular/cdk/portal';
|
|
33
33
|
import * as i4 from '@angular/material/menu';
|
|
34
34
|
import { MAT_MENU_SCROLL_STRATEGY, MatMenuTrigger, MatMenuModule } from '@angular/material/menu';
|
|
35
|
-
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
35
|
+
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
36
36
|
import * as i5$1 from '@angular/material/radio';
|
|
37
37
|
import { MatRadioModule } from '@angular/material/radio';
|
|
38
38
|
import * as i3$1 from '@angular/material/progress-spinner';
|
|
@@ -1156,6 +1156,65 @@ function getPraxisTableCellVisualizationConstraint(kind) {
|
|
|
1156
1156
|
}
|
|
1157
1157
|
return null;
|
|
1158
1158
|
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Resolucao pura e canonica de tom semantico e rotulo acessivel para micro-visualizacoes.
|
|
1161
|
+
*
|
|
1162
|
+
* Precedencia de avaliacao:
|
|
1163
|
+
* 1. Correspondencia discreta (`equals`), tolerante a numeros e strings.
|
|
1164
|
+
* 2. Faixa numerica continua (`min` e `max`, inclusiva).
|
|
1165
|
+
* 3. Faixa aberta a direita (`min` ate infinito).
|
|
1166
|
+
* 4. Faixa aberta a esquerda (menos infinito ate `max`).
|
|
1167
|
+
* 5. Limiar de corte progressivo (`value`).
|
|
1168
|
+
* 6. Fallback estatico (`fallbackTone`).
|
|
1169
|
+
*/
|
|
1170
|
+
function resolvePraxisMicroVisualizationTone(value, thresholds, fallbackTone) {
|
|
1171
|
+
if (value === undefined || value === null || !Array.isArray(thresholds) || thresholds.length === 0) {
|
|
1172
|
+
return fallbackTone ? { tone: fallbackTone } : undefined;
|
|
1173
|
+
}
|
|
1174
|
+
const num = typeof value === 'number' ? value : Number(value);
|
|
1175
|
+
const isNum = Number.isFinite(num);
|
|
1176
|
+
// 1. Pass 1: Correspondencia discreta (equals) tem prioridade maxima
|
|
1177
|
+
for (const t of thresholds) {
|
|
1178
|
+
if (!t || !t.tone || t.equals === undefined) {
|
|
1179
|
+
continue;
|
|
1180
|
+
}
|
|
1181
|
+
if (t.equals === value || String(t.equals) === String(value)) {
|
|
1182
|
+
return { tone: t.tone, label: t.label, matchedThreshold: t };
|
|
1183
|
+
}
|
|
1184
|
+
if (isNum && Number.isFinite(Number(t.equals)) && Number(t.equals) === num) {
|
|
1185
|
+
return { tone: t.tone, label: t.label, matchedThreshold: t };
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
// 2. Pass 2: Faixas continuas ou limiares de corte
|
|
1189
|
+
if (isNum) {
|
|
1190
|
+
for (const t of thresholds) {
|
|
1191
|
+
if (!t || !t.tone) {
|
|
1192
|
+
continue;
|
|
1193
|
+
}
|
|
1194
|
+
const hasMin = t.min !== undefined && Number.isFinite(t.min);
|
|
1195
|
+
const hasMax = t.max !== undefined && Number.isFinite(t.max);
|
|
1196
|
+
if (hasMin && hasMax) {
|
|
1197
|
+
if (num >= t.min && num <= t.max) {
|
|
1198
|
+
return { tone: t.tone, label: t.label, matchedThreshold: t };
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
else if (hasMin) {
|
|
1202
|
+
if (num >= t.min) {
|
|
1203
|
+
return { tone: t.tone, label: t.label, matchedThreshold: t };
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
else if (hasMax) {
|
|
1207
|
+
if (num <= t.max) {
|
|
1208
|
+
return { tone: t.tone, label: t.label, matchedThreshold: t };
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
else if (t.value !== undefined && Number.isFinite(t.value) && num >= t.value) {
|
|
1212
|
+
return { tone: t.tone, label: t.label, matchedThreshold: t };
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
return fallbackTone ? { tone: fallbackTone } : undefined;
|
|
1217
|
+
}
|
|
1159
1218
|
function normalizePraxisPresentationVisualization(value) {
|
|
1160
1219
|
if (!value || typeof value !== 'object') {
|
|
1161
1220
|
return undefined;
|
|
@@ -1170,14 +1229,40 @@ function normalizePraxisPresentationVisualization(value) {
|
|
|
1170
1229
|
const tone = normalizeEnum$1(value.tone, VISUALIZATION_TONES);
|
|
1171
1230
|
const ariaLabel = normalizeText$2(value.ariaLabel);
|
|
1172
1231
|
const valueSuffix = normalizeText$2(value.valueSuffix);
|
|
1232
|
+
const thresholdsObj = normalizeThresholds(value.thresholds);
|
|
1233
|
+
let resolvedTone = tone;
|
|
1234
|
+
let resolvedAriaLabel = ariaLabel;
|
|
1235
|
+
if (!resolvedTone && thresholdsObj?.thresholds?.length) {
|
|
1236
|
+
let evalVal = value.value;
|
|
1237
|
+
if (evalVal === undefined && Array.isArray(value.points) && value.points.length > 0) {
|
|
1238
|
+
const last = value.points[value.points.length - 1];
|
|
1239
|
+
if (last && typeof last === 'object' && Number.isFinite(last.value)) {
|
|
1240
|
+
evalVal = last.value;
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
else if (Array.isArray(evalVal) && evalVal.length > 0) {
|
|
1244
|
+
const last = evalVal[evalVal.length - 1];
|
|
1245
|
+
evalVal = typeof last === 'object' && last !== null && 'value' in last ? last.value : last;
|
|
1246
|
+
}
|
|
1247
|
+
if (evalVal !== undefined && evalVal !== null) {
|
|
1248
|
+
const resolution = resolvePraxisMicroVisualizationTone(evalVal, thresholdsObj.thresholds);
|
|
1249
|
+
if (resolution?.tone) {
|
|
1250
|
+
resolvedTone = resolution.tone;
|
|
1251
|
+
}
|
|
1252
|
+
if (resolution?.label && !resolvedAriaLabel) {
|
|
1253
|
+
resolvedAriaLabel = `${fallbackText}: ${resolution.label}`;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1173
1257
|
return {
|
|
1174
1258
|
kind,
|
|
1175
1259
|
fallbackText,
|
|
1176
1260
|
...(surface ? { surface } : {}),
|
|
1177
1261
|
...(size ? { size } : {}),
|
|
1178
|
-
...(
|
|
1179
|
-
...(
|
|
1262
|
+
...(resolvedTone ? { tone: resolvedTone } : {}),
|
|
1263
|
+
...(resolvedAriaLabel ? { ariaLabel: resolvedAriaLabel } : {}),
|
|
1180
1264
|
...(valueSuffix ? { valueSuffix } : {}),
|
|
1265
|
+
...(typeof value.compactValue === 'boolean' ? { compactValue: value.compactValue } : {}),
|
|
1181
1266
|
...(Object.prototype.hasOwnProperty.call(value, 'value') ? { value: value.value } : {}),
|
|
1182
1267
|
...(normalizeExpression(value.valueExpr, 'valueExpr') ?? {}),
|
|
1183
1268
|
...(normalizeExpression(value.valueSuffixExpr, 'valueSuffixExpr') ?? {}),
|
|
@@ -1196,6 +1281,12 @@ function normalizePraxisPresentationVisualization(value) {
|
|
|
1196
1281
|
...(normalizeItems(value.items) ?? {}),
|
|
1197
1282
|
...(normalizeExpression(value.itemsExpr, 'itemsExpr') ?? {}),
|
|
1198
1283
|
...(normalizeExpression(value.toneExpr, 'toneExpr') ?? {}),
|
|
1284
|
+
...(value.stepLabelWidth !== undefined && (typeof value.stepLabelWidth === 'number' || typeof value.stepLabelWidth === 'string')
|
|
1285
|
+
? { stepLabelWidth: value.stepLabelWidth }
|
|
1286
|
+
: {}),
|
|
1287
|
+
...(typeof value.stepLabelLineClamp === 'number' && Number.isFinite(value.stepLabelLineClamp)
|
|
1288
|
+
? { stepLabelLineClamp: value.stepLabelLineClamp }
|
|
1289
|
+
: {}),
|
|
1199
1290
|
...(normalizeExpression(value.ariaLabelExpr, 'ariaLabelExpr') ?? {}),
|
|
1200
1291
|
...(normalizeExpression(value.fallbackTextExpr, 'fallbackTextExpr') ?? {}),
|
|
1201
1292
|
};
|
|
@@ -1284,12 +1375,15 @@ function renderStackedBarVisualizationHtml(visualization, options) {
|
|
|
1284
1375
|
}
|
|
1285
1376
|
function resolveBulletMax(visualization) {
|
|
1286
1377
|
const thresholds = visualization.thresholds ?? [];
|
|
1378
|
+
const thresholdValues = thresholds
|
|
1379
|
+
.map(t => t.value ?? t.max ?? t.min ?? 0)
|
|
1380
|
+
.filter((v) => Number.isFinite(v) && v > 0);
|
|
1287
1381
|
const values = [
|
|
1288
1382
|
toFiniteNumber(visualization.value) ?? 0,
|
|
1289
1383
|
visualization.target ?? 0,
|
|
1290
1384
|
visualization.total ?? 0,
|
|
1291
|
-
...
|
|
1292
|
-
].filter(v => Number.isFinite(v) && v > 0);
|
|
1385
|
+
...thresholdValues
|
|
1386
|
+
].filter((v) => Number.isFinite(v) && v > 0);
|
|
1293
1387
|
return Math.max(...values, 100);
|
|
1294
1388
|
}
|
|
1295
1389
|
function renderBulletVisualizationHtml(visualization, options) {
|
|
@@ -1301,11 +1395,17 @@ function renderBulletVisualizationHtml(visualization, options) {
|
|
|
1301
1395
|
const target = toFiniteNumber(visualization.target);
|
|
1302
1396
|
const targetLeft = target === undefined ? null : percent(target, max);
|
|
1303
1397
|
const isTable = visualization.surface === 'table-cell';
|
|
1304
|
-
// thresholds
|
|
1398
|
+
// thresholds: sort ascending by boundary value so bands draw continuously regardless of declaration order
|
|
1305
1399
|
const thresholds = visualization.thresholds ?? [];
|
|
1400
|
+
const sortedThresholds = [...thresholds].sort((a, b) => {
|
|
1401
|
+
const aVal = a.value ?? a.max ?? a.min ?? 0;
|
|
1402
|
+
const bVal = b.value ?? b.max ?? b.min ?? 0;
|
|
1403
|
+
return aVal - bVal;
|
|
1404
|
+
});
|
|
1306
1405
|
let previous = 0;
|
|
1307
|
-
const bands =
|
|
1308
|
-
const
|
|
1406
|
+
const bands = sortedThresholds.map(t => {
|
|
1407
|
+
const tVal = t.value ?? t.max ?? t.min ?? 0;
|
|
1408
|
+
const current = Math.max(tVal, previous);
|
|
1309
1409
|
const left = max > 0 ? percent(previous, max) : '0';
|
|
1310
1410
|
const width = max > 0 ? percent(current - previous, max) : '0';
|
|
1311
1411
|
previous = current;
|
|
@@ -1325,6 +1425,10 @@ function renderBulletVisualizationHtml(visualization, options) {
|
|
|
1325
1425
|
<span>${escapeHtml$1(formatMicroNumber(visualization.baseline ?? 0, options.locale))}</span>
|
|
1326
1426
|
<span>${escapeHtml$1(formatMicroNumber(max, options.locale))}</span>
|
|
1327
1427
|
</div>`;
|
|
1428
|
+
const showCompactValue = isTable && visualization.compactValue !== false;
|
|
1429
|
+
const compactValueHtml = showCompactValue
|
|
1430
|
+
? `<span class="pfx-micro-bullet__compact-value">${escapeHtml$1(formatMicroNumber(currentValue, options.locale))}${escapeHtml$1(visualization.valueSuffix ?? '')}</span>`
|
|
1431
|
+
: '';
|
|
1328
1432
|
return `
|
|
1329
1433
|
<span class="pfx-micro-viz pfx-micro-viz__bullet" data-tone="${escapeHtml$1(visualization.tone ?? 'info')}" role="img" aria-label="${escapeHtml$1(visualization.ariaLabel ?? visualization.fallbackText)}">
|
|
1330
1434
|
${topHtml}
|
|
@@ -1334,6 +1438,7 @@ function renderBulletVisualizationHtml(visualization, options) {
|
|
|
1334
1438
|
${targetLeft === null ? '' : `<span class="pfx-micro-bullet__target" style="left: ${targetLeft}%;"></span>`}
|
|
1335
1439
|
</span>
|
|
1336
1440
|
${bottomHtml}
|
|
1441
|
+
${compactValueHtml}
|
|
1337
1442
|
</span>`;
|
|
1338
1443
|
}
|
|
1339
1444
|
function renderDeltaVisualizationHtml(visualization, options) {
|
|
@@ -1395,7 +1500,32 @@ function normalizeSegments(value) {
|
|
|
1395
1500
|
return segments.length ? { segments } : undefined;
|
|
1396
1501
|
}
|
|
1397
1502
|
function normalizeThresholds(value) {
|
|
1398
|
-
|
|
1503
|
+
if (!Array.isArray(value)) {
|
|
1504
|
+
return undefined;
|
|
1505
|
+
}
|
|
1506
|
+
const thresholds = value
|
|
1507
|
+
.map((item) => {
|
|
1508
|
+
if (!item || typeof item !== 'object')
|
|
1509
|
+
return undefined;
|
|
1510
|
+
const numVal = toFiniteNumber(item.value);
|
|
1511
|
+
const minVal = toFiniteNumber(item.min);
|
|
1512
|
+
const maxVal = toFiniteNumber(item.max);
|
|
1513
|
+
const tone = normalizeEnum$1(item.tone, VISUALIZATION_TONES);
|
|
1514
|
+
const label = normalizeText$2(item.label);
|
|
1515
|
+
const hasCondition = numVal !== undefined || minVal !== undefined || maxVal !== undefined || item.equals !== undefined;
|
|
1516
|
+
if (!hasCondition) {
|
|
1517
|
+
return undefined;
|
|
1518
|
+
}
|
|
1519
|
+
return {
|
|
1520
|
+
...(label ? { label } : {}),
|
|
1521
|
+
...(numVal !== undefined ? { value: numVal } : {}),
|
|
1522
|
+
...(minVal !== undefined ? { min: minVal } : {}),
|
|
1523
|
+
...(maxVal !== undefined ? { max: maxVal } : {}),
|
|
1524
|
+
...(item.equals !== undefined ? { equals: item.equals } : {}),
|
|
1525
|
+
...(tone ? { tone } : {}),
|
|
1526
|
+
};
|
|
1527
|
+
})
|
|
1528
|
+
.filter((item) => !!item);
|
|
1399
1529
|
return thresholds.length ? { thresholds } : undefined;
|
|
1400
1530
|
}
|
|
1401
1531
|
function normalizeItems(value) {
|
|
@@ -1674,7 +1804,10 @@ function renderColumnVisualizationHtml(visualization, options) {
|
|
|
1674
1804
|
const x = padding + i * ((width - 2 * padding) / points.length) + 1;
|
|
1675
1805
|
const rectHeight = Math.max(2, ((p.value - minVal) / valRange) * (height - 2 * padding));
|
|
1676
1806
|
const rectY = height - padding - rectHeight;
|
|
1677
|
-
const itemTone = p.tone ??
|
|
1807
|
+
const itemTone = p.tone ??
|
|
1808
|
+
(visualization.thresholds?.length
|
|
1809
|
+
? resolvePraxisMicroVisualizationTone(p.value, visualization.thresholds)?.tone ?? tone
|
|
1810
|
+
: tone);
|
|
1678
1811
|
return `<rect class="pfx-micro-column__bar" x="${x.toFixed(1)}" y="${rectY.toFixed(1)}" width="${colWidth.toFixed(1)}" height="${rectHeight.toFixed(1)}" fill="currentColor" data-tone="${escapeHtml$1(itemTone)}" />`;
|
|
1679
1812
|
}).join('');
|
|
1680
1813
|
const isTable = visualization.surface === 'table-cell';
|
|
@@ -1709,12 +1842,23 @@ function renderProcessFlowVisualizationHtml(visualization, options) {
|
|
|
1709
1842
|
const isTable = visualization.surface === 'table-cell';
|
|
1710
1843
|
const stepLabels = items.map((item, index) => item.label ?? item.id ?? `${index + 1}`);
|
|
1711
1844
|
const aria = visualization.ariaLabel ?? `${visualization.fallbackText}: ${stepLabels.join(' > ')}`;
|
|
1845
|
+
const labelStyleAttr = [];
|
|
1846
|
+
if (visualization.stepLabelWidth !== undefined) {
|
|
1847
|
+
const widthVal = typeof visualization.stepLabelWidth === 'number'
|
|
1848
|
+
? `${visualization.stepLabelWidth}px`
|
|
1849
|
+
: String(visualization.stepLabelWidth);
|
|
1850
|
+
labelStyleAttr.push(`inline-size: ${escapeHtml$1(widthVal)}; max-width: ${escapeHtml$1(widthVal)};`);
|
|
1851
|
+
}
|
|
1852
|
+
if (visualization.stepLabelLineClamp !== undefined) {
|
|
1853
|
+
labelStyleAttr.push(`-webkit-line-clamp: ${visualization.stepLabelLineClamp};`);
|
|
1854
|
+
}
|
|
1855
|
+
const labelInlineStyle = labelStyleAttr.length ? ` style="${labelStyleAttr.join(' ')}"` : '';
|
|
1712
1856
|
const stepsHtml = items.map((item, index) => {
|
|
1713
1857
|
const itemTone = item.tone ?? 'neutral';
|
|
1714
1858
|
const itemState = item.state ?? '';
|
|
1715
1859
|
const isLast = index === items.length - 1;
|
|
1716
1860
|
const itemLabel = stepLabels[index];
|
|
1717
|
-
const label = !isTable && item.label ? `<span class="pfx-micro-step__label">${escapeHtml$1(item.label)}</span>` : '';
|
|
1861
|
+
const label = !isTable && item.label ? `<span class="pfx-micro-step__label"${labelInlineStyle}>${escapeHtml$1(item.label)}</span>` : '';
|
|
1718
1862
|
const connector = !isLast ? `<span class="pfx-micro-step__connector" data-tone="${escapeHtml$1(itemTone)}"></span>` : '';
|
|
1719
1863
|
const stepCircle = `
|
|
1720
1864
|
<span class="pfx-micro-step__node" data-tone="${escapeHtml$1(itemTone)}" aria-hidden="true">
|
|
@@ -1803,6 +1947,12 @@ function normalizeFieldPresentation(value) {
|
|
|
1803
1947
|
const tooltip = normalizeText$1(value.tooltip);
|
|
1804
1948
|
const prefix = normalizeText$1(value.prefix);
|
|
1805
1949
|
const suffix = normalizeText$1(value.suffix);
|
|
1950
|
+
const iconTrue = normalizeText$1(value.iconTrue);
|
|
1951
|
+
const iconFalse = normalizeText$1(value.iconFalse);
|
|
1952
|
+
const toneTrue = normalizeTone(value.toneTrue);
|
|
1953
|
+
const toneFalse = normalizeTone(value.toneFalse);
|
|
1954
|
+
const labelTrue = normalizeText$1(value.labelTrue);
|
|
1955
|
+
const labelFalse = normalizeText$1(value.labelFalse);
|
|
1806
1956
|
const visualization = normalizePraxisPresentationVisualization(value.visualization);
|
|
1807
1957
|
return {
|
|
1808
1958
|
...(presenter ? { presenter } : {}),
|
|
@@ -1814,6 +1964,12 @@ function normalizeFieldPresentation(value) {
|
|
|
1814
1964
|
...(tooltip ? { tooltip } : {}),
|
|
1815
1965
|
...(prefix ? { prefix } : {}),
|
|
1816
1966
|
...(suffix ? { suffix } : {}),
|
|
1967
|
+
...(iconTrue ? { iconTrue } : {}),
|
|
1968
|
+
...(iconFalse ? { iconFalse } : {}),
|
|
1969
|
+
...(toneTrue ? { toneTrue } : {}),
|
|
1970
|
+
...(toneFalse ? { toneFalse } : {}),
|
|
1971
|
+
...(labelTrue ? { labelTrue } : {}),
|
|
1972
|
+
...(labelFalse ? { labelFalse } : {}),
|
|
1817
1973
|
...(value.valuePresentation && typeof value.valuePresentation === 'object'
|
|
1818
1974
|
? { valuePresentation: value.valuePresentation }
|
|
1819
1975
|
: {}),
|
|
@@ -1941,9 +2097,10 @@ const LOOKUP_FILTER_OPERATORS = new Set([
|
|
|
1941
2097
|
'lte',
|
|
1942
2098
|
]);
|
|
1943
2099
|
/**
|
|
1944
|
-
*
|
|
2100
|
+
* SchemaNormalizationKernel (internal)
|
|
1945
2101
|
* -----------------------
|
|
1946
|
-
*
|
|
2102
|
+
* Cálculo compartilhado pelo serviço Angular, sem DI ou export público, que converte
|
|
2103
|
+
* um esquema bruto (OpenAPI + x-ui) em uma
|
|
1947
2104
|
* lista tipada de FieldDefinition consumida pelo restante do sistema
|
|
1948
2105
|
* (mapeadores de metadata, criador de FormGroup, carregador de campos dinâmicos, etc.).
|
|
1949
2106
|
*
|
|
@@ -1976,7 +2133,7 @@ const LOOKUP_FILTER_OPERATORS = new Set([
|
|
|
1976
2133
|
* const fields = normalizer.normalizeSchema(schema);
|
|
1977
2134
|
* // fields: [{ name: 'email', label: 'E-mail', type: 'string', controlType: 'input', required: true, email: true }]
|
|
1978
2135
|
*/
|
|
1979
|
-
class
|
|
2136
|
+
class SchemaNormalizationKernel {
|
|
1980
2137
|
clonePlain(value) {
|
|
1981
2138
|
if (value === undefined || value === null) {
|
|
1982
2139
|
return value;
|
|
@@ -2590,16 +2747,30 @@ class SchemaNormalizerService {
|
|
|
2590
2747
|
}
|
|
2591
2748
|
return Object.keys(filtering).length ? filtering : undefined;
|
|
2592
2749
|
}
|
|
2593
|
-
/** Parse option arrays into `{ key, value }` objects. */
|
|
2750
|
+
/** Parse option arrays into `{ key, value }` objects with label preservation. */
|
|
2594
2751
|
parseOptions(value) {
|
|
2595
2752
|
if (!Array.isArray(value)) {
|
|
2596
2753
|
return [];
|
|
2597
2754
|
}
|
|
2598
2755
|
return value.map((opt) => {
|
|
2599
|
-
if (typeof opt === 'object') {
|
|
2600
|
-
const k = opt.key ?? opt.value ?? opt.label ?? '';
|
|
2601
|
-
const
|
|
2602
|
-
|
|
2756
|
+
if (typeof opt === 'object' && opt !== null) {
|
|
2757
|
+
const k = opt.key ?? opt.value ?? opt.id ?? opt.label ?? '';
|
|
2758
|
+
const display = opt.label ??
|
|
2759
|
+
opt.text ??
|
|
2760
|
+
opt.title ??
|
|
2761
|
+
(opt.key !== undefined && opt.value !== undefined && opt.key !== opt.value
|
|
2762
|
+
? opt.value
|
|
2763
|
+
: undefined);
|
|
2764
|
+
const v = display ?? opt.value ?? opt.key ?? '';
|
|
2765
|
+
const result = {
|
|
2766
|
+
...opt,
|
|
2767
|
+
key: String(k),
|
|
2768
|
+
value: String(v),
|
|
2769
|
+
};
|
|
2770
|
+
if (display !== undefined && display !== null) {
|
|
2771
|
+
result.label = String(display);
|
|
2772
|
+
}
|
|
2773
|
+
return result;
|
|
2603
2774
|
}
|
|
2604
2775
|
return { key: String(opt), value: String(opt) };
|
|
2605
2776
|
});
|
|
@@ -3416,6 +3587,26 @@ class SchemaNormalizerService {
|
|
|
3416
3587
|
}
|
|
3417
3588
|
return undefined;
|
|
3418
3589
|
}
|
|
3590
|
+
}
|
|
3591
|
+
|
|
3592
|
+
/** Normalizes the exact schema/root object using the canonical Core calculation.
|
|
3593
|
+
* The caller must admit source, content and execution before invoking this function:
|
|
3594
|
+
* declared function expressions may execute during field construction.
|
|
3595
|
+
* This performs neither strict JSON parsing nor provenance/schema admission.
|
|
3596
|
+
*/
|
|
3597
|
+
function normalizeSchemaFields(schema) {
|
|
3598
|
+
return new SchemaNormalizationKernel().normalizeSchema(schema);
|
|
3599
|
+
}
|
|
3600
|
+
|
|
3601
|
+
/** Official Angular schema normalization facade.
|
|
3602
|
+
* The shared internal kernel owns the existing field semantics and local refs.
|
|
3603
|
+
* Origin/content and execution authority must be admitted before this call:
|
|
3604
|
+
* normalization can evaluate declared function expressions. This is not a sandbox.
|
|
3605
|
+
*/
|
|
3606
|
+
class SchemaNormalizerService {
|
|
3607
|
+
normalizeSchema(schema) {
|
|
3608
|
+
return normalizeSchemaFields(schema);
|
|
3609
|
+
}
|
|
3419
3610
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SchemaNormalizerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3420
3611
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SchemaNormalizerService, providedIn: 'root' });
|
|
3421
3612
|
}
|
|
@@ -4452,6 +4643,7 @@ class GenericCrudService {
|
|
|
4452
4643
|
_lastResourceCapabilityDigest = null;
|
|
4453
4644
|
_lastResourceIdentity = null;
|
|
4454
4645
|
_lastResourceIdentityDiagnostics = [];
|
|
4646
|
+
_lastResourceQuickFilters = null;
|
|
4455
4647
|
// Última informação do schema consumido (para auditoria/merge)
|
|
4456
4648
|
_lastSchemaInfo = {};
|
|
4457
4649
|
_resourceEtags = new Map();
|
|
@@ -4563,6 +4755,7 @@ class GenericCrudService {
|
|
|
4563
4755
|
this._lastResourceCapabilityDigest = null;
|
|
4564
4756
|
this._lastResourceIdentity = null;
|
|
4565
4757
|
this._lastResourceIdentityDiagnostics = [];
|
|
4758
|
+
this._lastResourceQuickFilters = null;
|
|
4566
4759
|
this._resourceEtags.clear();
|
|
4567
4760
|
debugCrudService('[CRUD:Service] configure', {
|
|
4568
4761
|
resourcePath, baseApiUrl: this.baseApiUrl,
|
|
@@ -4855,6 +5048,12 @@ class GenericCrudService {
|
|
|
4855
5048
|
filterExpressionSupported: canonicalOperations['filterExpression'] === true,
|
|
4856
5049
|
};
|
|
4857
5050
|
}
|
|
5051
|
+
if (Array.isArray(resource?.quickFilters)) {
|
|
5052
|
+
this._lastResourceQuickFilters = [...resource.quickFilters];
|
|
5053
|
+
}
|
|
5054
|
+
else {
|
|
5055
|
+
this._lastResourceQuickFilters = null;
|
|
5056
|
+
}
|
|
4858
5057
|
}
|
|
4859
5058
|
normalizeCanonicalCapabilities(value) {
|
|
4860
5059
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
@@ -4995,6 +5194,10 @@ class GenericCrudService {
|
|
|
4995
5194
|
: undefined,
|
|
4996
5195
|
}));
|
|
4997
5196
|
}
|
|
5197
|
+
/** Retorna os filtros rápidos canônicos descobertos no schema x-ui.resource.quickFilters. */
|
|
5198
|
+
getResourceQuickFilters() {
|
|
5199
|
+
return this._lastResourceQuickFilters ? [...this._lastResourceQuickFilters] : null;
|
|
5200
|
+
}
|
|
4998
5201
|
/** Retorna o último schemaId e hash conhecidos após getSchema()/getFilteredSchema(). */
|
|
4999
5202
|
getLastSchemaInfo() {
|
|
5000
5203
|
return { ...this._lastSchemaInfo };
|
|
@@ -7437,6 +7640,82 @@ function rotateRight(value, amount) {
|
|
|
7437
7640
|
return (value >>> amount) | (value << (32 - amount));
|
|
7438
7641
|
}
|
|
7439
7642
|
|
|
7643
|
+
/** Copy a raw authoring/patch object without JSON's silent omissions or coercions.
|
|
7644
|
+
* No schema, authority, merge, normalization or server quota is evaluated here.
|
|
7645
|
+
*/
|
|
7646
|
+
function cloneUiLayoutJsonDocument(value) {
|
|
7647
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
7648
|
+
throw invalid();
|
|
7649
|
+
return copyJson(value, false);
|
|
7650
|
+
}
|
|
7651
|
+
/** Local structural identity: null and array order count; object insertion order does not.
|
|
7652
|
+
* This is not a persisted hash or a native admission receipt.
|
|
7653
|
+
*/
|
|
7654
|
+
function uiLayoutJsonIdentity(value) {
|
|
7655
|
+
try {
|
|
7656
|
+
return JSON.stringify(copyJson(value, true));
|
|
7657
|
+
}
|
|
7658
|
+
catch {
|
|
7659
|
+
throw invalid();
|
|
7660
|
+
}
|
|
7661
|
+
}
|
|
7662
|
+
function copyJson(value, sorted) {
|
|
7663
|
+
const result = {};
|
|
7664
|
+
const parents = new Set();
|
|
7665
|
+
const stack = [{ value, parent: result, key: 'value' }];
|
|
7666
|
+
while (stack.length) {
|
|
7667
|
+
const task = stack.pop();
|
|
7668
|
+
const item = task.value;
|
|
7669
|
+
if (task.exit) {
|
|
7670
|
+
parents.delete(item);
|
|
7671
|
+
continue;
|
|
7672
|
+
}
|
|
7673
|
+
if (item === null || typeof item === 'string' || typeof item === 'boolean'
|
|
7674
|
+
|| typeof item === 'number' && Number.isFinite(item)) {
|
|
7675
|
+
put(task.parent, task.key, item);
|
|
7676
|
+
continue;
|
|
7677
|
+
}
|
|
7678
|
+
if (typeof item !== 'object' || item === null || parents.has(item)
|
|
7679
|
+
|| Object.getOwnPropertySymbols(item).length)
|
|
7680
|
+
throw invalid();
|
|
7681
|
+
const array = Array.isArray(item);
|
|
7682
|
+
if (!array && ![Object.prototype, null].includes(Object.getPrototypeOf(item)))
|
|
7683
|
+
throw invalid();
|
|
7684
|
+
const descriptors = Object.getOwnPropertyDescriptors(item);
|
|
7685
|
+
let keys = Object.keys(descriptors);
|
|
7686
|
+
if (array) {
|
|
7687
|
+
const length = descriptors['length'].value;
|
|
7688
|
+
if (keys.length !== length + 1)
|
|
7689
|
+
throw invalid();
|
|
7690
|
+
keys = keys.filter(key => key !== 'length');
|
|
7691
|
+
for (let index = 0; index < length; index++)
|
|
7692
|
+
if (!Object.hasOwn(descriptors, index))
|
|
7693
|
+
throw invalid();
|
|
7694
|
+
}
|
|
7695
|
+
else if (sorted)
|
|
7696
|
+
keys.sort();
|
|
7697
|
+
for (const key of keys) {
|
|
7698
|
+
const descriptor = descriptors[key];
|
|
7699
|
+
if (!descriptor.enumerable || !Object.hasOwn(descriptor, 'value'))
|
|
7700
|
+
throw invalid();
|
|
7701
|
+
}
|
|
7702
|
+
const copy = array ? [] : {};
|
|
7703
|
+
put(task.parent, task.key, copy);
|
|
7704
|
+
parents.add(item);
|
|
7705
|
+
stack.push({ ...task, exit: true });
|
|
7706
|
+
for (let index = keys.length - 1; index >= 0; index--) {
|
|
7707
|
+
const key = keys[index];
|
|
7708
|
+
stack.push({ value: descriptors[key].value, parent: copy, key });
|
|
7709
|
+
}
|
|
7710
|
+
}
|
|
7711
|
+
return result.value;
|
|
7712
|
+
}
|
|
7713
|
+
function put(target, key, value) {
|
|
7714
|
+
// Define data properties: __proto__ is JSON content, never a prototype setter.
|
|
7715
|
+
Object.defineProperty(target, key, { value, enumerable: true, configurable: true, writable: true });
|
|
7716
|
+
}
|
|
7717
|
+
function invalid() { return new TypeError('UI layout requires lossless JSON values.'); }
|
|
7718
|
+
|
|
7440
7719
|
const PRAXIS_I18N_CONFIG = new InjectionToken('PRAXIS_I18N_CONFIG', {
|
|
7441
7720
|
factory: () => ({}),
|
|
7442
7721
|
});
|
|
@@ -12189,14 +12468,18 @@ function mapFieldDefinitionsToMetadata(fields) {
|
|
|
12189
12468
|
return fields.map(mapFieldDefinitionToMetadata);
|
|
12190
12469
|
}
|
|
12191
12470
|
|
|
12471
|
+
const DEFAULT_DYNAMIC_FORM_SCHEMA_CACHE_TTL_MS = 10 * 60 * 1000; // 10 minutes
|
|
12472
|
+
const DEFAULT_DYNAMIC_FORM_SCHEMA_CACHE_MAX_ENTRIES = 100;
|
|
12192
12473
|
/**
|
|
12193
12474
|
* DynamicFormService
|
|
12194
12475
|
* -------------------
|
|
12195
12476
|
* Serviço utilitário central para criação e atualização de formulários dinâmicos
|
|
12196
12477
|
* (Reactive Forms) a partir de metadados corporativos (FieldMetadata) ou
|
|
12197
|
-
* definições do servidor (FieldDefinition)
|
|
12478
|
+
* definições do servidor (FieldDefinition), com cache de primeiro nível (L1) em
|
|
12479
|
+
* memória para esquemas OpenAPI compilados.
|
|
12198
12480
|
*
|
|
12199
12481
|
* Principais responsabilidades
|
|
12482
|
+
* - Cache L1 em memória para esquemas normalizados e compilados (Issue #2).
|
|
12200
12483
|
* - Converter ValidatorOptions/FieldDefinition em ValidatorFn/AsyncValidatorFn.
|
|
12201
12484
|
* - Aplicar updateOn por campo a partir de updateOn ou validationTrigger (change/blur/submit).
|
|
12202
12485
|
* - Injetar validadores específicos de UI conforme o controlType:
|
|
@@ -12210,6 +12493,7 @@ function mapFieldDefinitionsToMetadata(fields) {
|
|
|
12210
12493
|
* - createFormGroupFromMetadata(fields): cria FormGroup diretamente dos metadados normalizados.
|
|
12211
12494
|
* - createFormGroupFromFields(defs): cria FormGroup a partir de definições cruas do backend.
|
|
12212
12495
|
* - updateControlFromMetadata/Field: reavalia e aplica validadores/estado em controles existentes.
|
|
12496
|
+
* - getCompiledSchema / setCompiledSchema: recuperação e persistência em cache L1 para 0ms tab transitions.
|
|
12213
12497
|
*
|
|
12214
12498
|
* Boas práticas
|
|
12215
12499
|
* - Prefira trabalhar com FieldMetadata + ValidatorOptions (camada normalizada) no app.
|
|
@@ -12222,6 +12506,108 @@ function mapFieldDefinitionsToMetadata(fields) {
|
|
|
12222
12506
|
* dynamicForm.updateControlFromMetadata(group, { ...meta, validators: { ...meta.validators, required: true }});
|
|
12223
12507
|
*/
|
|
12224
12508
|
class DynamicFormService {
|
|
12509
|
+
global;
|
|
12510
|
+
compiledSchemaCache = new Map();
|
|
12511
|
+
constructor(global) {
|
|
12512
|
+
if (global !== undefined) {
|
|
12513
|
+
this.global = global;
|
|
12514
|
+
}
|
|
12515
|
+
else {
|
|
12516
|
+
try {
|
|
12517
|
+
this.global = inject(GlobalConfigService, { optional: true });
|
|
12518
|
+
}
|
|
12519
|
+
catch {
|
|
12520
|
+
this.global = null;
|
|
12521
|
+
}
|
|
12522
|
+
}
|
|
12523
|
+
}
|
|
12524
|
+
// ------------------- Schema L1 Cache -------------------
|
|
12525
|
+
/**
|
|
12526
|
+
* Constrói a chave estável de cache para um esquema com base nos parâmetros estruturais.
|
|
12527
|
+
*/
|
|
12528
|
+
buildSchemaCacheKey(params) {
|
|
12529
|
+
const schemaId = buildSchemaId(params);
|
|
12530
|
+
const prefix = params.baseUrl ? `${params.baseUrl}::` : '';
|
|
12531
|
+
const tenantPart = params.tenant ? `::tenant:${params.tenant}` : '';
|
|
12532
|
+
const localePart = params.locale ? `::locale:${params.locale}` : '';
|
|
12533
|
+
return `${prefix}${schemaId}${tenantPart}${localePart}`;
|
|
12534
|
+
}
|
|
12535
|
+
/**
|
|
12536
|
+
* Obtém um esquema compilado em cache L1 em memória, respeitando o TTL de expiração.
|
|
12537
|
+
*/
|
|
12538
|
+
getCompiledSchema(cacheKey) {
|
|
12539
|
+
const entry = this.compiledSchemaCache.get(cacheKey);
|
|
12540
|
+
if (!entry)
|
|
12541
|
+
return undefined;
|
|
12542
|
+
if (Date.now() > entry.expiresAt) {
|
|
12543
|
+
this.compiledSchemaCache.delete(cacheKey);
|
|
12544
|
+
return undefined;
|
|
12545
|
+
}
|
|
12546
|
+
return entry.compiled;
|
|
12547
|
+
}
|
|
12548
|
+
/**
|
|
12549
|
+
* Armazena um esquema compilado em cache L1 em memória com TTL governado.
|
|
12550
|
+
*/
|
|
12551
|
+
setCompiledSchema(cacheKey, compiled, customTtlMs) {
|
|
12552
|
+
const ttlMs = customTtlMs ?? this.resolveSchemaCacheTtlMs();
|
|
12553
|
+
const expiresAt = Date.now() + ttlMs;
|
|
12554
|
+
const maxEntries = this.resolveSchemaCacheMaxEntries();
|
|
12555
|
+
if (this.compiledSchemaCache.size >= maxEntries && !this.compiledSchemaCache.has(cacheKey)) {
|
|
12556
|
+
const oldestKey = this.compiledSchemaCache.keys().next().value;
|
|
12557
|
+
if (oldestKey)
|
|
12558
|
+
this.compiledSchemaCache.delete(oldestKey);
|
|
12559
|
+
}
|
|
12560
|
+
this.compiledSchemaCache.set(cacheKey, { compiled, expiresAt });
|
|
12561
|
+
}
|
|
12562
|
+
/**
|
|
12563
|
+
* Verifica se existe um esquema compilado válido e não-expirado em cache.
|
|
12564
|
+
*/
|
|
12565
|
+
hasCompiledSchema(cacheKey) {
|
|
12566
|
+
return this.getCompiledSchema(cacheKey) !== undefined;
|
|
12567
|
+
}
|
|
12568
|
+
/**
|
|
12569
|
+
* Invalida uma entrada específica ou todo o cache L1 de esquemas compilados.
|
|
12570
|
+
*/
|
|
12571
|
+
invalidateCompiledSchema(cacheKey) {
|
|
12572
|
+
if (cacheKey) {
|
|
12573
|
+
this.compiledSchemaCache.delete(cacheKey);
|
|
12574
|
+
}
|
|
12575
|
+
else {
|
|
12576
|
+
this.clearCompiledSchemaCache();
|
|
12577
|
+
}
|
|
12578
|
+
}
|
|
12579
|
+
/**
|
|
12580
|
+
* Limpa integralmente o cache L1 em memória.
|
|
12581
|
+
*/
|
|
12582
|
+
clearCompiledSchemaCache() {
|
|
12583
|
+
this.compiledSchemaCache.clear();
|
|
12584
|
+
}
|
|
12585
|
+
/**
|
|
12586
|
+
* Retorna a quantidade de entradas atualmente em cache L1.
|
|
12587
|
+
*/
|
|
12588
|
+
getCompiledSchemaCacheSize() {
|
|
12589
|
+
return this.compiledSchemaCache.size;
|
|
12590
|
+
}
|
|
12591
|
+
resolveSchemaCacheTtlMs() {
|
|
12592
|
+
try {
|
|
12593
|
+
const configured = this.global?.get('cache.schemaCacheTtlMs');
|
|
12594
|
+
if (typeof configured === 'number' && Number.isFinite(configured) && configured > 0) {
|
|
12595
|
+
return configured;
|
|
12596
|
+
}
|
|
12597
|
+
}
|
|
12598
|
+
catch { }
|
|
12599
|
+
return DEFAULT_DYNAMIC_FORM_SCHEMA_CACHE_TTL_MS;
|
|
12600
|
+
}
|
|
12601
|
+
resolveSchemaCacheMaxEntries() {
|
|
12602
|
+
try {
|
|
12603
|
+
const configured = this.global?.get('cache.schemaCacheMaxEntries');
|
|
12604
|
+
if (typeof configured === 'number' && Number.isFinite(configured) && configured > 0) {
|
|
12605
|
+
return configured;
|
|
12606
|
+
}
|
|
12607
|
+
}
|
|
12608
|
+
catch { }
|
|
12609
|
+
return DEFAULT_DYNAMIC_FORM_SCHEMA_CACHE_MAX_ENTRIES;
|
|
12610
|
+
}
|
|
12225
12611
|
// ------------------- Path helpers (nested groups) -------------------
|
|
12226
12612
|
isPath(name) {
|
|
12227
12613
|
return name.includes('.');
|
|
@@ -12817,13 +13203,15 @@ class DynamicFormService {
|
|
|
12817
13203
|
});
|
|
12818
13204
|
return root;
|
|
12819
13205
|
}
|
|
12820
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
13206
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormService, deps: [{ token: GlobalConfigService, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
12821
13207
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormService, providedIn: 'root' });
|
|
12822
13208
|
}
|
|
12823
13209
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormService, decorators: [{
|
|
12824
13210
|
type: Injectable,
|
|
12825
13211
|
args: [{ providedIn: 'root' }]
|
|
12826
|
-
}]
|
|
13212
|
+
}], ctorParameters: () => [{ type: GlobalConfigService, decorators: [{
|
|
13213
|
+
type: Optional
|
|
13214
|
+
}] }] });
|
|
12827
13215
|
|
|
12828
13216
|
/**
|
|
12829
13217
|
* Maps HTTP or network errors to user-friendly messages.
|
|
@@ -16417,15 +16805,7 @@ function providePraxisEnterpriseRuntimeContext(options = {}) {
|
|
|
16417
16805
|
{ provide: PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS, useValue: normalized },
|
|
16418
16806
|
{
|
|
16419
16807
|
provide: PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY,
|
|
16420
|
-
useFactory: (service) =>
|
|
16421
|
-
let promise = null;
|
|
16422
|
-
return () => {
|
|
16423
|
-
if (promise)
|
|
16424
|
-
return promise;
|
|
16425
|
-
promise = service.ready().then(() => undefined);
|
|
16426
|
-
return promise;
|
|
16427
|
-
};
|
|
16428
|
-
},
|
|
16808
|
+
useFactory: (service) => () => service.ready().then(() => undefined),
|
|
16429
16809
|
deps: [EnterpriseRuntimeContextService],
|
|
16430
16810
|
},
|
|
16431
16811
|
{
|
|
@@ -16437,6 +16817,18 @@ function providePraxisEnterpriseRuntimeContext(options = {}) {
|
|
|
16437
16817
|
];
|
|
16438
16818
|
}
|
|
16439
16819
|
|
|
16820
|
+
const CONTEXT_HEADERS = new Set([
|
|
16821
|
+
'x-tenant-id', 'x-tenant', 'x-user-id', 'x-env', 'x-updated-by',
|
|
16822
|
+
'x-praxis-profile-id', 'x-praxis-context-version',
|
|
16823
|
+
]);
|
|
16824
|
+
const EXPERIENCE_HEADERS = new Set(['accept-language', 'x-timezone', 'x-praxis-module-key']);
|
|
16825
|
+
/** A response for an older selection must never be presented as confirmed. */
|
|
16826
|
+
class EnterpriseRuntimeContextObsoleteError extends Error {
|
|
16827
|
+
constructor() {
|
|
16828
|
+
super('Runtime context changed before the switch was confirmed.');
|
|
16829
|
+
this.name = 'EnterpriseRuntimeContextObsoleteError';
|
|
16830
|
+
}
|
|
16831
|
+
}
|
|
16440
16832
|
class EnterpriseRuntimeContextService {
|
|
16441
16833
|
http = inject(HttpClient);
|
|
16442
16834
|
apiUrl = inject(API_URL, { optional: true });
|
|
@@ -16445,10 +16837,15 @@ class EnterpriseRuntimeContextService {
|
|
|
16445
16837
|
});
|
|
16446
16838
|
contextSubject = new BehaviorSubject(null);
|
|
16447
16839
|
loadPromise = null;
|
|
16840
|
+
contextRevision = 0;
|
|
16448
16841
|
contextChanges$ = this.contextSubject.asObservable();
|
|
16449
16842
|
get snapshot() {
|
|
16450
16843
|
return this.contextSubject.value;
|
|
16451
16844
|
}
|
|
16845
|
+
get effectiveContext() {
|
|
16846
|
+
const context = this.snapshot;
|
|
16847
|
+
return context?.state === 'ready' ? context.effectiveContext : null;
|
|
16848
|
+
}
|
|
16452
16849
|
ready() {
|
|
16453
16850
|
if (this.contextSubject.value) {
|
|
16454
16851
|
return Promise.resolve(this.contextSubject.value);
|
|
@@ -16456,7 +16853,9 @@ class EnterpriseRuntimeContextService {
|
|
|
16456
16853
|
if (this.loadPromise) {
|
|
16457
16854
|
return this.loadPromise;
|
|
16458
16855
|
}
|
|
16459
|
-
|
|
16856
|
+
const revision = this.contextRevision;
|
|
16857
|
+
let currentLoad;
|
|
16858
|
+
currentLoad = this.load(revision)
|
|
16460
16859
|
.catch((error) => {
|
|
16461
16860
|
if ((this.options?.errorPolicy ?? 'ignore') === 'fail') {
|
|
16462
16861
|
throw error;
|
|
@@ -16464,50 +16863,144 @@ class EnterpriseRuntimeContextService {
|
|
|
16464
16863
|
return null;
|
|
16465
16864
|
})
|
|
16466
16865
|
.finally(() => {
|
|
16467
|
-
this.loadPromise
|
|
16866
|
+
if (this.loadPromise === currentLoad)
|
|
16867
|
+
this.loadPromise = null;
|
|
16468
16868
|
});
|
|
16469
|
-
|
|
16869
|
+
this.loadPromise = currentLoad;
|
|
16870
|
+
return currentLoad;
|
|
16470
16871
|
}
|
|
16471
16872
|
refresh() {
|
|
16472
|
-
|
|
16473
|
-
|
|
16873
|
+
const revision = this.invalidateContext();
|
|
16874
|
+
let currentLoad;
|
|
16875
|
+
currentLoad = this.load(revision).catch((error) => {
|
|
16474
16876
|
if ((this.options?.errorPolicy ?? 'ignore') === 'fail') {
|
|
16475
16877
|
throw error;
|
|
16476
16878
|
}
|
|
16477
16879
|
return null;
|
|
16880
|
+
}).finally(() => {
|
|
16881
|
+
if (this.loadPromise === currentLoad)
|
|
16882
|
+
this.loadPromise = null;
|
|
16478
16883
|
});
|
|
16884
|
+
this.loadPromise = currentLoad;
|
|
16885
|
+
return currentLoad;
|
|
16886
|
+
}
|
|
16887
|
+
invalidate() {
|
|
16888
|
+
this.invalidateContext();
|
|
16479
16889
|
}
|
|
16890
|
+
/** Independent host tenant discovery; it never selects the runtime context. */
|
|
16480
16891
|
tenants() {
|
|
16481
16892
|
return this.getRuntimeSurface('tenants');
|
|
16482
16893
|
}
|
|
16894
|
+
choices(options = {}) {
|
|
16895
|
+
const pageSize = options.pageSize ?? 50;
|
|
16896
|
+
if (!Number.isInteger(pageSize) || pageSize < 1 || pageSize > 100) {
|
|
16897
|
+
return Promise.reject(new RangeError('pageSize must be an integer between 1 and 100.'));
|
|
16898
|
+
}
|
|
16899
|
+
let params = new HttpParams().set('pageSize', pageSize);
|
|
16900
|
+
if (options.cursor !== undefined)
|
|
16901
|
+
params = params.set('cursor', options.cursor);
|
|
16902
|
+
return firstValueFrom(this.http.get(this.endpoint('choices'), {
|
|
16903
|
+
headers: this.requestHeaders({ includeSnapshot: true }), params,
|
|
16904
|
+
}));
|
|
16905
|
+
}
|
|
16483
16906
|
navigation() {
|
|
16484
16907
|
return this.getRuntimeSurface('navigation');
|
|
16485
16908
|
}
|
|
16486
16909
|
securityEvents() {
|
|
16487
16910
|
return this.getRuntimeSurface('securityEvents');
|
|
16488
16911
|
}
|
|
16489
|
-
|
|
16490
|
-
const
|
|
16491
|
-
|
|
16492
|
-
|
|
16493
|
-
|
|
16494
|
-
this.
|
|
16495
|
-
|
|
16496
|
-
|
|
16912
|
+
switchContext(command) {
|
|
16913
|
+
const revision = this.invalidateContext();
|
|
16914
|
+
const operation = firstValueFrom(this.http.put(this.endpoint('context'), command, { headers: this.requestHeaders() })).then((response) => {
|
|
16915
|
+
if (revision !== this.contextRevision)
|
|
16916
|
+
throw new EnterpriseRuntimeContextObsoleteError();
|
|
16917
|
+
const context = this.normalizeContext(response);
|
|
16918
|
+
this.contextSubject.next(context);
|
|
16919
|
+
return context;
|
|
16920
|
+
});
|
|
16921
|
+
let currentSwitch;
|
|
16922
|
+
currentSwitch = operation.finally(() => {
|
|
16923
|
+
if (this.loadPromise === currentSwitch)
|
|
16924
|
+
this.loadPromise = null;
|
|
16925
|
+
});
|
|
16926
|
+
this.loadPromise = currentSwitch;
|
|
16927
|
+
return currentSwitch;
|
|
16497
16928
|
}
|
|
16498
16929
|
headers(fallback) {
|
|
16499
|
-
return
|
|
16930
|
+
return {
|
|
16931
|
+
...this.withoutContextHeaders(this.normalizeHeaders(fallback ?? {}), true),
|
|
16932
|
+
...this.normalizeHeaders(this.headersFromSnapshot(this.contextSubject.value)),
|
|
16933
|
+
};
|
|
16500
16934
|
}
|
|
16935
|
+
/** Preserve host authentication headers while removing unconfirmed contextual claims. */
|
|
16501
16936
|
effectiveRequestHeaders(fallback) {
|
|
16502
|
-
|
|
16937
|
+
const bootstrap = this.withoutContextHeaders(this.normalizeHeaders({
|
|
16938
|
+
...(this.options?.includeGlobalFetchHeaders ?? true ? this.globalFetchHeaders() : {}),
|
|
16939
|
+
...(this.options?.headersFactory?.() ?? {}),
|
|
16940
|
+
...(fallback ?? {}),
|
|
16941
|
+
}), true);
|
|
16942
|
+
const merged = { ...bootstrap, ...this.headersFromSnapshot(this.contextSubject.value) };
|
|
16943
|
+
const result = {};
|
|
16944
|
+
for (const [name, value] of Object.entries(merged)) {
|
|
16945
|
+
if (typeof value === 'string' && value.trim())
|
|
16946
|
+
result[name] = value;
|
|
16947
|
+
}
|
|
16948
|
+
return result;
|
|
16949
|
+
}
|
|
16950
|
+
/**
|
|
16951
|
+
* Applies the confirmed runtime snapshot to an existing request header set.
|
|
16952
|
+
* Contextual names are removed case-insensitively first, so nullable snapshot
|
|
16953
|
+
* fields cannot leave bootstrap or caller identity behind. Unrelated headers,
|
|
16954
|
+
* including repeated values, remain untouched.
|
|
16955
|
+
*/
|
|
16956
|
+
applyHeaders(headers) {
|
|
16957
|
+
if (!this.effectiveContext) {
|
|
16958
|
+
return headers;
|
|
16959
|
+
}
|
|
16960
|
+
let next = headers;
|
|
16961
|
+
for (const name of headers.keys()) {
|
|
16962
|
+
if (this.isContextualHeader(name)) {
|
|
16963
|
+
next = next.delete(name);
|
|
16964
|
+
}
|
|
16965
|
+
}
|
|
16966
|
+
for (const [name, value] of Object.entries(this.headersFromSnapshot(this.contextSubject.value))) {
|
|
16967
|
+
if (typeof value === 'string') {
|
|
16968
|
+
next = next.set(name, value);
|
|
16969
|
+
}
|
|
16970
|
+
}
|
|
16971
|
+
return next;
|
|
16972
|
+
}
|
|
16973
|
+
invalidateContext() {
|
|
16974
|
+
this.contextRevision += 1;
|
|
16975
|
+
this.loadPromise = null;
|
|
16976
|
+
this.contextSubject.next(null);
|
|
16977
|
+
return this.contextRevision;
|
|
16503
16978
|
}
|
|
16504
|
-
async load() {
|
|
16505
|
-
const
|
|
16979
|
+
async load(revision) {
|
|
16980
|
+
const response = await firstValueFrom(this.http.get(this.endpoint('context'), {
|
|
16506
16981
|
headers: this.requestHeaders(),
|
|
16507
16982
|
}));
|
|
16983
|
+
if (revision !== this.contextRevision)
|
|
16984
|
+
return null;
|
|
16985
|
+
const context = this.normalizeContext(response);
|
|
16508
16986
|
this.contextSubject.next(context ?? null);
|
|
16509
16987
|
return context ?? null;
|
|
16510
16988
|
}
|
|
16989
|
+
normalizeContext(context) {
|
|
16990
|
+
if (context.state !== 'ready' || !context.effectiveContext) {
|
|
16991
|
+
return context;
|
|
16992
|
+
}
|
|
16993
|
+
const effective = context.effectiveContext;
|
|
16994
|
+
return {
|
|
16995
|
+
...context,
|
|
16996
|
+
effectiveContext: {
|
|
16997
|
+
...effective,
|
|
16998
|
+
activeOrganizationId: effective.activeOrganizationId ?? null,
|
|
16999
|
+
capabilities: Array.isArray(effective.capabilities) ? effective.capabilities : [],
|
|
17000
|
+
authorities: Array.isArray(effective.authorities) ? effective.authorities : [],
|
|
17001
|
+
},
|
|
17002
|
+
};
|
|
17003
|
+
}
|
|
16511
17004
|
async getRuntimeSurface(surface) {
|
|
16512
17005
|
return firstValueFrom(this.http.get(this.endpoint(surface), {
|
|
16513
17006
|
headers: this.requestHeaders({ includeSnapshot: true }),
|
|
@@ -16542,6 +17035,8 @@ class EnterpriseRuntimeContextService {
|
|
|
16542
17035
|
return 'context';
|
|
16543
17036
|
case 'tenants':
|
|
16544
17037
|
return 'tenants';
|
|
17038
|
+
case 'choices':
|
|
17039
|
+
return 'context/choices';
|
|
16545
17040
|
case 'navigation':
|
|
16546
17041
|
return 'navigation';
|
|
16547
17042
|
case 'securityEvents':
|
|
@@ -16549,7 +17044,14 @@ class EnterpriseRuntimeContextService {
|
|
|
16549
17044
|
}
|
|
16550
17045
|
}
|
|
16551
17046
|
requestHeaders(options = {}) {
|
|
16552
|
-
const
|
|
17047
|
+
const bootstrap = this.withoutContextHeaders(this.normalizeHeaders({
|
|
17048
|
+
...(this.options?.includeGlobalFetchHeaders ?? true ? this.globalFetchHeaders() : {}),
|
|
17049
|
+
...(this.options?.headersFactory?.() ?? {}),
|
|
17050
|
+
}), options.includeSnapshot ?? false);
|
|
17051
|
+
const merged = {
|
|
17052
|
+
...bootstrap,
|
|
17053
|
+
...(options.includeSnapshot ? this.headersFromSnapshot(this.contextSubject.value) : {}),
|
|
17054
|
+
};
|
|
16553
17055
|
let headers = new HttpHeaders();
|
|
16554
17056
|
for (const [key, value] of Object.entries(merged)) {
|
|
16555
17057
|
if (value) {
|
|
@@ -16568,22 +17070,31 @@ class EnterpriseRuntimeContextService {
|
|
|
16568
17070
|
}
|
|
16569
17071
|
}
|
|
16570
17072
|
headersFromSnapshot(context) {
|
|
16571
|
-
if (!context) {
|
|
17073
|
+
if (context?.state !== 'ready' || !context.effectiveContext) {
|
|
16572
17074
|
return {};
|
|
16573
17075
|
}
|
|
17076
|
+
const effective = context.effectiveContext;
|
|
16574
17077
|
return {
|
|
16575
|
-
'X-
|
|
17078
|
+
'X-Praxis-Context-Version': effective.contextVersion,
|
|
17079
|
+
'X-Tenant-ID': effective.activeTenant?.tenantId,
|
|
16576
17080
|
'X-User-ID': context.user?.userId,
|
|
16577
|
-
'X-Env':
|
|
16578
|
-
'Accept-Language':
|
|
16579
|
-
'X-Timezone':
|
|
16580
|
-
'X-Praxis-Profile-ID':
|
|
16581
|
-
'X-Praxis-Module-Key':
|
|
17081
|
+
'X-Env': effective.environment ?? undefined,
|
|
17082
|
+
'Accept-Language': effective.locale ?? undefined,
|
|
17083
|
+
'X-Timezone': effective.timezone ?? undefined,
|
|
17084
|
+
'X-Praxis-Profile-ID': effective.activeProfileId ?? undefined,
|
|
17085
|
+
'X-Praxis-Module-Key': effective.activeModuleKey ?? undefined,
|
|
16582
17086
|
};
|
|
16583
17087
|
}
|
|
17088
|
+
withoutContextHeaders(headers, includeExperience) {
|
|
17089
|
+
return Object.fromEntries(Object.entries(headers).filter(([key]) => !CONTEXT_HEADERS.has(key.toLowerCase())
|
|
17090
|
+
&& (!includeExperience || !EXPERIENCE_HEADERS.has(key.toLowerCase()))));
|
|
17091
|
+
}
|
|
17092
|
+
isContextualHeader(name) {
|
|
17093
|
+
const normalized = name.toLowerCase();
|
|
17094
|
+
return CONTEXT_HEADERS.has(normalized) || EXPERIENCE_HEADERS.has(normalized);
|
|
17095
|
+
}
|
|
16584
17096
|
normalizeHeaders(headers) {
|
|
16585
17097
|
const normalized = {};
|
|
16586
|
-
const canonicalKeyByLowercase = new Map();
|
|
16587
17098
|
for (const [key, value] of Object.entries(headers)) {
|
|
16588
17099
|
if (typeof value !== 'string') {
|
|
16589
17100
|
continue;
|
|
@@ -16592,19 +17103,10 @@ class EnterpriseRuntimeContextService {
|
|
|
16592
17103
|
if (!trimmed) {
|
|
16593
17104
|
continue;
|
|
16594
17105
|
}
|
|
16595
|
-
const lowercase = key.toLowerCase();
|
|
16596
|
-
const previousKey = canonicalKeyByLowercase.get(lowercase);
|
|
16597
|
-
if (previousKey) {
|
|
16598
|
-
delete normalized[previousKey];
|
|
16599
|
-
}
|
|
16600
17106
|
normalized[key] = trimmed;
|
|
16601
|
-
canonicalKeyByLowercase.set(lowercase, key);
|
|
16602
17107
|
}
|
|
16603
17108
|
return normalized;
|
|
16604
17109
|
}
|
|
16605
|
-
mergeHeaders(...sources) {
|
|
16606
|
-
return this.normalizeHeaders(Object.assign({}, ...sources.map((source) => this.normalizeHeaders(source))));
|
|
16607
|
-
}
|
|
16608
17110
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EnterpriseRuntimeContextService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
16609
17111
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EnterpriseRuntimeContextService, providedIn: 'root' });
|
|
16610
17112
|
}
|
|
@@ -16613,6 +17115,537 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
16613
17115
|
args: [{ providedIn: 'root' }]
|
|
16614
17116
|
}] });
|
|
16615
17117
|
|
|
17118
|
+
/** B1b wire discriminator published by Config's effective-composition endpoint. */
|
|
17119
|
+
const EFFECTIVE_UI_LAYOUT_COMPOSITION_SCHEMA_VERSION = 'praxis.effective-ui-layout-composition/v1';
|
|
17120
|
+
|
|
17121
|
+
const PRAXIS_EFFECTIVE_UI_LAYOUT_OPTIONS = new InjectionToken('PRAXIS_EFFECTIVE_UI_LAYOUT_OPTIONS');
|
|
17122
|
+
|
|
17123
|
+
/** The effective-layout contract cannot be safely used for this request. */
|
|
17124
|
+
class EffectiveUiLayoutContractError extends Error {
|
|
17125
|
+
code;
|
|
17126
|
+
constructor(code) {
|
|
17127
|
+
super(`Effective UI layout contract error: ${code}.`);
|
|
17128
|
+
this.code = code;
|
|
17129
|
+
this.name = 'EffectiveUiLayoutContractError';
|
|
17130
|
+
}
|
|
17131
|
+
}
|
|
17132
|
+
/** Explicit Config read failure. Callers must render this state, never a local fallback. */
|
|
17133
|
+
class EffectiveUiLayoutHttpError extends Error {
|
|
17134
|
+
status;
|
|
17135
|
+
originalError;
|
|
17136
|
+
constructor(status, originalError) {
|
|
17137
|
+
super(`Effective UI layout request failed with HTTP ${status}.`);
|
|
17138
|
+
this.status = status;
|
|
17139
|
+
this.originalError = originalError;
|
|
17140
|
+
this.name = 'EffectiveUiLayoutHttpError';
|
|
17141
|
+
}
|
|
17142
|
+
}
|
|
17143
|
+
/**
|
|
17144
|
+
* Canonical conditional client for Config's read-only effective-layout surface.
|
|
17145
|
+
* It never calculates audience, precedence, permissions, hashes or local fallbacks.
|
|
17146
|
+
*/
|
|
17147
|
+
class EffectiveUiLayoutService {
|
|
17148
|
+
http = inject(HttpClient);
|
|
17149
|
+
apiUrl = inject(API_URL, { optional: true });
|
|
17150
|
+
options = inject(PRAXIS_EFFECTIVE_UI_LAYOUT_OPTIONS, {
|
|
17151
|
+
optional: true,
|
|
17152
|
+
});
|
|
17153
|
+
runtime = inject(EnterpriseRuntimeContextService);
|
|
17154
|
+
cache = new Map();
|
|
17155
|
+
compositionCache = new Map();
|
|
17156
|
+
compositionInFlight = new Map();
|
|
17157
|
+
contextRevision = 0;
|
|
17158
|
+
constructor() {
|
|
17159
|
+
this.runtime.contextChanges$.subscribe(() => {
|
|
17160
|
+
this.contextRevision += 1;
|
|
17161
|
+
this.cache.clear();
|
|
17162
|
+
this.compositionCache.clear();
|
|
17163
|
+
this.compositionInFlight.clear();
|
|
17164
|
+
});
|
|
17165
|
+
}
|
|
17166
|
+
async resolve(target) {
|
|
17167
|
+
const normalizedTarget = normalizeTarget$1(target);
|
|
17168
|
+
const context = this.runtime.snapshot ?? await this.runtime.ready();
|
|
17169
|
+
const contextVersion = context?.state === 'ready'
|
|
17170
|
+
? context.effectiveContext?.contextVersion
|
|
17171
|
+
: null;
|
|
17172
|
+
if (!contextVersion) {
|
|
17173
|
+
throw new EffectiveUiLayoutContractError('CONTEXT_NOT_READY');
|
|
17174
|
+
}
|
|
17175
|
+
const revision = this.contextRevision;
|
|
17176
|
+
const cacheKey = this.cacheKey(normalizedTarget, contextVersion);
|
|
17177
|
+
const cached = this.cache.get(cacheKey);
|
|
17178
|
+
let headers = this.requestHeaders();
|
|
17179
|
+
if (cached?.validator) {
|
|
17180
|
+
headers = headers.set('If-None-Match', cached.validator);
|
|
17181
|
+
}
|
|
17182
|
+
try {
|
|
17183
|
+
const httpResponse = await firstValueFrom(this.http.get(this.endpoint(), {
|
|
17184
|
+
headers,
|
|
17185
|
+
params: new HttpParams()
|
|
17186
|
+
.set('componentType', normalizedTarget.componentType)
|
|
17187
|
+
.set('componentId', normalizedTarget.componentId),
|
|
17188
|
+
observe: 'response',
|
|
17189
|
+
}));
|
|
17190
|
+
if (revision !== this.contextRevision) {
|
|
17191
|
+
throw new EffectiveUiLayoutContractError('CONTEXT_OBSOLETE');
|
|
17192
|
+
}
|
|
17193
|
+
const response = httpResponse.body;
|
|
17194
|
+
if (!response) {
|
|
17195
|
+
throw new EffectiveUiLayoutContractError('TARGET_MISMATCH');
|
|
17196
|
+
}
|
|
17197
|
+
this.assertCompatible(response, normalizedTarget, contextVersion);
|
|
17198
|
+
const validator = httpResponse.headers.get('ETag');
|
|
17199
|
+
if (!validator) {
|
|
17200
|
+
throw new EffectiveUiLayoutContractError('MISSING_VALIDATOR');
|
|
17201
|
+
}
|
|
17202
|
+
this.cache.set(cacheKey, {
|
|
17203
|
+
response: cloneLayoutResponse(response),
|
|
17204
|
+
validator,
|
|
17205
|
+
});
|
|
17206
|
+
return cloneLayoutResponse(response);
|
|
17207
|
+
}
|
|
17208
|
+
catch (error) {
|
|
17209
|
+
if (error instanceof EffectiveUiLayoutContractError) {
|
|
17210
|
+
throw error;
|
|
17211
|
+
}
|
|
17212
|
+
if (error instanceof HttpErrorResponse && error.status === 304) {
|
|
17213
|
+
if (revision !== this.contextRevision) {
|
|
17214
|
+
throw new EffectiveUiLayoutContractError('CONTEXT_OBSOLETE');
|
|
17215
|
+
}
|
|
17216
|
+
if (!cached) {
|
|
17217
|
+
throw new EffectiveUiLayoutContractError('CACHE_MISS_304');
|
|
17218
|
+
}
|
|
17219
|
+
this.assertCompatible(cached.response, normalizedTarget, contextVersion);
|
|
17220
|
+
return cloneLayoutResponse(cached.response);
|
|
17221
|
+
}
|
|
17222
|
+
if (error instanceof HttpErrorResponse) {
|
|
17223
|
+
throw new EffectiveUiLayoutHttpError(error.status, error);
|
|
17224
|
+
}
|
|
17225
|
+
throw error;
|
|
17226
|
+
}
|
|
17227
|
+
}
|
|
17228
|
+
/**
|
|
17229
|
+
* Reads one coherent server-resolved composition. This intentionally does
|
|
17230
|
+
* not fan out into unit effective-layout requests or infer membership.
|
|
17231
|
+
*/
|
|
17232
|
+
async resolveComposition(rootTarget) {
|
|
17233
|
+
const normalizedRoot = normalizeTarget$1(rootTarget);
|
|
17234
|
+
const context = this.runtime.snapshot ?? await this.runtime.ready();
|
|
17235
|
+
const contextVersion = context?.state === 'ready'
|
|
17236
|
+
? context.effectiveContext?.contextVersion
|
|
17237
|
+
: null;
|
|
17238
|
+
if (!contextVersion) {
|
|
17239
|
+
throw new EffectiveUiLayoutContractError('CONTEXT_NOT_READY');
|
|
17240
|
+
}
|
|
17241
|
+
const revision = this.contextRevision;
|
|
17242
|
+
const cacheKey = this.compositionCacheKey(normalizedRoot, contextVersion);
|
|
17243
|
+
const inFlight = this.compositionInFlight.get(cacheKey);
|
|
17244
|
+
if (inFlight) {
|
|
17245
|
+
return cloneCompositionResponse(await inFlight);
|
|
17246
|
+
}
|
|
17247
|
+
const request = this.requestComposition(normalizedRoot, contextVersion, revision, cacheKey);
|
|
17248
|
+
this.compositionInFlight.set(cacheKey, request);
|
|
17249
|
+
try {
|
|
17250
|
+
return cloneCompositionResponse(await request);
|
|
17251
|
+
}
|
|
17252
|
+
finally {
|
|
17253
|
+
if (this.compositionInFlight.get(cacheKey) === request) {
|
|
17254
|
+
this.compositionInFlight.delete(cacheKey);
|
|
17255
|
+
}
|
|
17256
|
+
}
|
|
17257
|
+
}
|
|
17258
|
+
endpoint() {
|
|
17259
|
+
const configured = this.options?.endpoint?.trim().replace(/\/+$/, '');
|
|
17260
|
+
if (configured)
|
|
17261
|
+
return configured;
|
|
17262
|
+
const entry = this.apiUrl?.['default'];
|
|
17263
|
+
const base = entry ? buildApiUrl(entry) : '';
|
|
17264
|
+
return base
|
|
17265
|
+
? `${base}/praxis/config/ui-layouts/effective`
|
|
17266
|
+
: '/api/praxis/config/ui-layouts/effective';
|
|
17267
|
+
}
|
|
17268
|
+
compositionEndpoint() {
|
|
17269
|
+
const configured = this.options?.compositionEndpoint?.trim().replace(/\/+$/, '');
|
|
17270
|
+
if (configured)
|
|
17271
|
+
return configured;
|
|
17272
|
+
const entry = this.apiUrl?.['default'];
|
|
17273
|
+
const base = entry ? buildApiUrl(entry) : '';
|
|
17274
|
+
return base
|
|
17275
|
+
? `${base}/praxis/config/ui-layouts/effective-composition`
|
|
17276
|
+
: '/api/praxis/config/ui-layouts/effective-composition';
|
|
17277
|
+
}
|
|
17278
|
+
requestHeaders() {
|
|
17279
|
+
const entryHeaders = this.apiUrl?.['default']
|
|
17280
|
+
? buildHeaders(this.apiUrl['default'])
|
|
17281
|
+
: undefined;
|
|
17282
|
+
return this.runtime.applyHeaders(entryHeaders ?? new HttpHeaders());
|
|
17283
|
+
}
|
|
17284
|
+
cacheKey(target, contextVersion) {
|
|
17285
|
+
return `${contextVersion}\u0000${target.componentType}\u0000${target.componentId}`;
|
|
17286
|
+
}
|
|
17287
|
+
compositionCacheKey(rootTarget, contextVersion) {
|
|
17288
|
+
return `composition\u0000${contextVersion}\u0000${rootTarget.componentType}\u0000${rootTarget.componentId}`;
|
|
17289
|
+
}
|
|
17290
|
+
async requestComposition(rootTarget, contextVersion, revision, cacheKey) {
|
|
17291
|
+
const cached = this.compositionCache.get(cacheKey);
|
|
17292
|
+
let headers = this.requestHeaders();
|
|
17293
|
+
if (cached?.validator) {
|
|
17294
|
+
headers = headers.set('If-None-Match', cached.validator);
|
|
17295
|
+
}
|
|
17296
|
+
try {
|
|
17297
|
+
const httpResponse = await firstValueFrom(this.http.get(this.compositionEndpoint(), {
|
|
17298
|
+
headers,
|
|
17299
|
+
params: new HttpParams()
|
|
17300
|
+
.set('rootComponentType', rootTarget.componentType)
|
|
17301
|
+
.set('rootComponentId', rootTarget.componentId),
|
|
17302
|
+
observe: 'response',
|
|
17303
|
+
}));
|
|
17304
|
+
if (revision !== this.contextRevision) {
|
|
17305
|
+
throw new EffectiveUiLayoutContractError('CONTEXT_OBSOLETE');
|
|
17306
|
+
}
|
|
17307
|
+
const response = httpResponse.body;
|
|
17308
|
+
if (!response) {
|
|
17309
|
+
throw new EffectiveUiLayoutContractError('COMPOSITION_ROOT_MISMATCH');
|
|
17310
|
+
}
|
|
17311
|
+
this.assertCompositionCompatible(response, rootTarget, contextVersion);
|
|
17312
|
+
const validator = httpResponse.headers.get('ETag');
|
|
17313
|
+
if (!validator) {
|
|
17314
|
+
throw new EffectiveUiLayoutContractError('MISSING_VALIDATOR');
|
|
17315
|
+
}
|
|
17316
|
+
this.compositionCache.set(cacheKey, {
|
|
17317
|
+
response: cloneCompositionResponse(response),
|
|
17318
|
+
validator,
|
|
17319
|
+
});
|
|
17320
|
+
return response;
|
|
17321
|
+
}
|
|
17322
|
+
catch (error) {
|
|
17323
|
+
if (error instanceof EffectiveUiLayoutContractError) {
|
|
17324
|
+
throw error;
|
|
17325
|
+
}
|
|
17326
|
+
if (error instanceof HttpErrorResponse && error.status === 304) {
|
|
17327
|
+
if (revision !== this.contextRevision) {
|
|
17328
|
+
throw new EffectiveUiLayoutContractError('CONTEXT_OBSOLETE');
|
|
17329
|
+
}
|
|
17330
|
+
if (!cached) {
|
|
17331
|
+
throw new EffectiveUiLayoutContractError('CACHE_MISS_304');
|
|
17332
|
+
}
|
|
17333
|
+
this.assertCompositionCompatible(cached.response, rootTarget, contextVersion);
|
|
17334
|
+
return cloneCompositionResponse(cached.response);
|
|
17335
|
+
}
|
|
17336
|
+
if (error instanceof HttpErrorResponse) {
|
|
17337
|
+
throw new EffectiveUiLayoutHttpError(error.status, error);
|
|
17338
|
+
}
|
|
17339
|
+
throw error;
|
|
17340
|
+
}
|
|
17341
|
+
}
|
|
17342
|
+
assertCompatible(response, target, contextVersion) {
|
|
17343
|
+
if (response.target?.componentType !== target.componentType
|
|
17344
|
+
|| response.target?.componentId !== target.componentId) {
|
|
17345
|
+
throw new EffectiveUiLayoutContractError('TARGET_MISMATCH');
|
|
17346
|
+
}
|
|
17347
|
+
if (response.contextVersion !== contextVersion) {
|
|
17348
|
+
throw new EffectiveUiLayoutContractError('CONTEXT_MISMATCH');
|
|
17349
|
+
}
|
|
17350
|
+
}
|
|
17351
|
+
assertCompositionCompatible(response, rootTarget, contextVersion) {
|
|
17352
|
+
if (!response
|
|
17353
|
+
|| response.schemaVersion !== EFFECTIVE_UI_LAYOUT_COMPOSITION_SCHEMA_VERSION) {
|
|
17354
|
+
throw new EffectiveUiLayoutContractError('COMPOSITION_SCHEMA_MISMATCH');
|
|
17355
|
+
}
|
|
17356
|
+
if (!sameTarget(response.rootTarget, rootTarget)) {
|
|
17357
|
+
throw new EffectiveUiLayoutContractError('COMPOSITION_ROOT_MISMATCH');
|
|
17358
|
+
}
|
|
17359
|
+
if (response.contextVersion !== contextVersion) {
|
|
17360
|
+
throw new EffectiveUiLayoutContractError('CONTEXT_MISMATCH');
|
|
17361
|
+
}
|
|
17362
|
+
if (!Array.isArray(response.members)) {
|
|
17363
|
+
throw new EffectiveUiLayoutContractError('COMPOSITION_MEMBER_INVALID');
|
|
17364
|
+
}
|
|
17365
|
+
const memberTargets = new Set();
|
|
17366
|
+
for (const [index, member] of response.members.entries()) {
|
|
17367
|
+
const target = member?.target;
|
|
17368
|
+
const memberOrder = member?.memberOrder;
|
|
17369
|
+
if (!member
|
|
17370
|
+
|| !target
|
|
17371
|
+
|| !target.componentType?.trim()
|
|
17372
|
+
|| !target.componentId?.trim()
|
|
17373
|
+
|| memberOrder !== index
|
|
17374
|
+
|| !Array.isArray(member.appliedContributions)
|
|
17375
|
+
|| !Object.hasOwn(member, 'effectiveLayout')
|
|
17376
|
+
|| (member.effectiveLayout !== null && typeof member.effectiveLayout !== 'object')
|
|
17377
|
+
|| (index === 0 && !sameTarget(target, rootTarget))) {
|
|
17378
|
+
throw new EffectiveUiLayoutContractError('COMPOSITION_MEMBER_INVALID');
|
|
17379
|
+
}
|
|
17380
|
+
const targetKey = `${target.componentType}\u0000${target.componentId}`;
|
|
17381
|
+
if (memberTargets.has(targetKey)) {
|
|
17382
|
+
throw new EffectiveUiLayoutContractError('COMPOSITION_MEMBER_INVALID');
|
|
17383
|
+
}
|
|
17384
|
+
memberTargets.add(targetKey);
|
|
17385
|
+
if (member.effectiveLayout !== null) {
|
|
17386
|
+
this.assertCompatible(member.effectiveLayout, target, contextVersion);
|
|
17387
|
+
}
|
|
17388
|
+
}
|
|
17389
|
+
if (response.members.length === 0) {
|
|
17390
|
+
throw new EffectiveUiLayoutContractError('COMPOSITION_MEMBER_INVALID');
|
|
17391
|
+
}
|
|
17392
|
+
}
|
|
17393
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EffectiveUiLayoutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
17394
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EffectiveUiLayoutService, providedIn: 'root' });
|
|
17395
|
+
}
|
|
17396
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EffectiveUiLayoutService, decorators: [{
|
|
17397
|
+
type: Injectable,
|
|
17398
|
+
args: [{ providedIn: 'root' }]
|
|
17399
|
+
}], ctorParameters: () => [] });
|
|
17400
|
+
function cloneLayoutResponse(response) {
|
|
17401
|
+
return structuredClone(response);
|
|
17402
|
+
}
|
|
17403
|
+
function cloneCompositionResponse(response) {
|
|
17404
|
+
return structuredClone(response);
|
|
17405
|
+
}
|
|
17406
|
+
function sameTarget(left, right) {
|
|
17407
|
+
return left?.componentType === right.componentType && left?.componentId === right.componentId;
|
|
17408
|
+
}
|
|
17409
|
+
function normalizeTarget$1(target) {
|
|
17410
|
+
const componentType = target?.componentType?.trim();
|
|
17411
|
+
const componentId = target?.componentId?.trim();
|
|
17412
|
+
if (!componentType || !componentId || componentType.length > 64 || componentId.length > 255) {
|
|
17413
|
+
throw new EffectiveUiLayoutContractError('INVALID_TARGET');
|
|
17414
|
+
}
|
|
17415
|
+
return { componentType, componentId };
|
|
17416
|
+
}
|
|
17417
|
+
|
|
17418
|
+
class UiLayoutLifecycleContractError extends Error {
|
|
17419
|
+
code;
|
|
17420
|
+
constructor(code) {
|
|
17421
|
+
super(`UI layout lifecycle contract error: ${code}.`);
|
|
17422
|
+
this.code = code;
|
|
17423
|
+
this.name = 'UiLayoutLifecycleContractError';
|
|
17424
|
+
}
|
|
17425
|
+
}
|
|
17426
|
+
/** Sanitized transport failure: original problem details are intentionally not re-exposed. */
|
|
17427
|
+
class UiLayoutLifecycleHttpError extends Error {
|
|
17428
|
+
status;
|
|
17429
|
+
category;
|
|
17430
|
+
constructor(status, category) {
|
|
17431
|
+
super(`UI layout lifecycle request failed: ${category} (${status}).`);
|
|
17432
|
+
this.status = status;
|
|
17433
|
+
this.category = category;
|
|
17434
|
+
this.name = 'UiLayoutLifecycleHttpError';
|
|
17435
|
+
}
|
|
17436
|
+
}
|
|
17437
|
+
/**
|
|
17438
|
+
* Typed B1c transport client. It never derives admission, actor, tenant,
|
|
17439
|
+
* authority, lifecycle state, selector semantics or retry policy.
|
|
17440
|
+
*/
|
|
17441
|
+
class UiLayoutLifecycleService {
|
|
17442
|
+
http = inject(HttpClient);
|
|
17443
|
+
apiUrl = inject(API_URL, { optional: true });
|
|
17444
|
+
runtime = inject(EnterpriseRuntimeContextService);
|
|
17445
|
+
contextRevision = 0;
|
|
17446
|
+
constructor() {
|
|
17447
|
+
this.runtime.contextChanges$.subscribe(() => this.contextRevision += 1);
|
|
17448
|
+
}
|
|
17449
|
+
/** Reads a creation association only. A missing association never authorizes automatic recreation. */
|
|
17450
|
+
async readDraftByCreationKey(target, creationKey) {
|
|
17451
|
+
const key = requireIdempotencyKey(creationKey);
|
|
17452
|
+
const admitted = await this.admit(target);
|
|
17453
|
+
const headers = admitted.headers.delete('If-Match').delete('If-None-Match').delete('Idempotency-Key').set('Idempotency-Key', key);
|
|
17454
|
+
this.assertDispatchContext(admitted.revision);
|
|
17455
|
+
try {
|
|
17456
|
+
const response = await firstValueFrom(this.http.get(`${this.root()}/drafts/by-creation-key`, {
|
|
17457
|
+
headers, params: admitted.params, observe: 'response',
|
|
17458
|
+
}));
|
|
17459
|
+
this.assertCurrent(admitted.revision, false);
|
|
17460
|
+
return this.receipt(response.body, response.headers);
|
|
17461
|
+
}
|
|
17462
|
+
catch (error) {
|
|
17463
|
+
throw this.normalizeError(error, admitted.revision, false);
|
|
17464
|
+
}
|
|
17465
|
+
}
|
|
17466
|
+
readDraft(target, draftId, ifNoneMatch) {
|
|
17467
|
+
return this.read(`${this.root()}/drafts/${encodeURIComponent(draftId)}`, target, ifNoneMatch);
|
|
17468
|
+
}
|
|
17469
|
+
readReview(target, releaseId, ifNoneMatch) {
|
|
17470
|
+
return this.read(`${this.root()}/releases/${encodeURIComponent(releaseId)}/review`, target, ifNoneMatch);
|
|
17471
|
+
}
|
|
17472
|
+
readHead(target, ifNoneMatch) {
|
|
17473
|
+
return this.read(`${this.root()}/release-head`, target, ifNoneMatch);
|
|
17474
|
+
}
|
|
17475
|
+
createDraft(target, idempotencyKey) {
|
|
17476
|
+
return this.write('POST', `${this.root()}/drafts`, target, null, undefined, idempotencyKey);
|
|
17477
|
+
}
|
|
17478
|
+
createRevision(target, draftId, draftEtag, command) {
|
|
17479
|
+
// Snapshot before asynchronous context admission; mutations cannot change the submitted intent.
|
|
17480
|
+
const snapshot = cloneUiLayoutJsonDocument(command);
|
|
17481
|
+
return this.write('POST', `${this.root()}/drafts/${encodeURIComponent(draftId)}/revisions`, target, snapshot, this.strongMatch(draftEtag));
|
|
17482
|
+
}
|
|
17483
|
+
createAssignment(target, draftId, draftEtag, command) {
|
|
17484
|
+
return this.write('POST', `${this.root()}/drafts/${encodeURIComponent(draftId)}/assignments`, target, command, this.strongMatch(draftEtag));
|
|
17485
|
+
}
|
|
17486
|
+
freezeRelease(target, draftId, draftEtag, command) {
|
|
17487
|
+
return this.write('POST', `${this.root()}/drafts/${encodeURIComponent(draftId)}/releases`, target, command, this.strongMatch(draftEtag));
|
|
17488
|
+
}
|
|
17489
|
+
submit(target, releaseId, reviewEtag) {
|
|
17490
|
+
return this.write('POST', `${this.root()}/releases/${encodeURIComponent(releaseId)}/submit`, target, null, this.strongMatch(reviewEtag));
|
|
17491
|
+
}
|
|
17492
|
+
approve(target, releaseId, reviewEtag, command) {
|
|
17493
|
+
return this.write('POST', `${this.root()}/releases/${encodeURIComponent(releaseId)}/approve`, target, command, this.strongMatch(reviewEtag));
|
|
17494
|
+
}
|
|
17495
|
+
publish(target, condition, command) {
|
|
17496
|
+
return this.write('POST', `${this.root()}/release-head/publish`, target, command, condition);
|
|
17497
|
+
}
|
|
17498
|
+
withdraw(target, headEtag, command) {
|
|
17499
|
+
return this.write('POST', `${this.root()}/release-head/withdraw`, target, command, this.strongMatch(headEtag));
|
|
17500
|
+
}
|
|
17501
|
+
rollback(target, headEtag, command) {
|
|
17502
|
+
return this.write('POST', `${this.root()}/release-head/rollback`, target, command, this.strongMatch(headEtag));
|
|
17503
|
+
}
|
|
17504
|
+
async read(url, target, ifNoneMatch) {
|
|
17505
|
+
const admitted = await this.admit(target);
|
|
17506
|
+
let headers = admitted.headers.delete('If-Match').delete('If-None-Match').delete('Idempotency-Key');
|
|
17507
|
+
if (ifNoneMatch)
|
|
17508
|
+
headers = headers.set('If-None-Match', ifNoneMatch);
|
|
17509
|
+
this.assertDispatchContext(admitted.revision);
|
|
17510
|
+
try {
|
|
17511
|
+
const response = await firstValueFrom(this.http.get(url, { headers, params: admitted.params, observe: 'response' }));
|
|
17512
|
+
this.assertCurrent(admitted.revision, false);
|
|
17513
|
+
return this.receipt(response.body, response.headers ?? new HttpHeaders());
|
|
17514
|
+
}
|
|
17515
|
+
catch (error) {
|
|
17516
|
+
if (error instanceof HttpErrorResponse && error.status === 304) {
|
|
17517
|
+
this.assertCurrent(admitted.revision, false);
|
|
17518
|
+
const etag = error.headers.get('ETag');
|
|
17519
|
+
if (!etag)
|
|
17520
|
+
throw new UiLayoutLifecycleContractError('NOT_MODIFIED_WITHOUT_ETAG');
|
|
17521
|
+
return { status: 'not-modified', etag };
|
|
17522
|
+
}
|
|
17523
|
+
throw this.normalizeError(error, admitted.revision, false);
|
|
17524
|
+
}
|
|
17525
|
+
}
|
|
17526
|
+
async write(method, url, target, body, condition, idempotencyKey) {
|
|
17527
|
+
const admitted = await this.admit(target);
|
|
17528
|
+
const headers = this.writeHeaders(admitted.headers, condition, idempotencyKey);
|
|
17529
|
+
this.assertDispatchContext(admitted.revision);
|
|
17530
|
+
let responseReceived = false;
|
|
17531
|
+
try {
|
|
17532
|
+
const response = await firstValueFrom(this.http.request(method, url, { body, headers, params: admitted.params, observe: 'response' }));
|
|
17533
|
+
responseReceived = true;
|
|
17534
|
+
this.assertCurrent(admitted.revision, true);
|
|
17535
|
+
return this.receipt(response.body, response.headers ?? new HttpHeaders());
|
|
17536
|
+
}
|
|
17537
|
+
catch (error) {
|
|
17538
|
+
if (responseReceived) {
|
|
17539
|
+
throw new UiLayoutLifecycleContractError('COMMAND_OUTCOME_UNCERTAIN');
|
|
17540
|
+
}
|
|
17541
|
+
throw this.normalizeError(error, admitted.revision, true);
|
|
17542
|
+
}
|
|
17543
|
+
}
|
|
17544
|
+
async admit(target) {
|
|
17545
|
+
const normalized = normalizeTarget(target);
|
|
17546
|
+
const revision = this.contextRevision;
|
|
17547
|
+
const context = this.runtime.snapshot ?? await this.runtime.ready();
|
|
17548
|
+
if (revision !== this.contextRevision)
|
|
17549
|
+
throw new UiLayoutLifecycleContractError('CONTEXT_OBSOLETE');
|
|
17550
|
+
if (context?.state !== 'ready' || !context.effectiveContext?.contextVersion) {
|
|
17551
|
+
throw new UiLayoutLifecycleContractError('CONTEXT_NOT_READY');
|
|
17552
|
+
}
|
|
17553
|
+
const entryHeaders = this.apiUrl?.['default'] ? (buildHeaders(this.apiUrl['default']) ?? new HttpHeaders()) : new HttpHeaders();
|
|
17554
|
+
return {
|
|
17555
|
+
revision,
|
|
17556
|
+
headers: this.runtime.applyHeaders(entryHeaders),
|
|
17557
|
+
params: new HttpParams().set('rootComponentType', normalized.componentType).set('rootComponentId', normalized.componentId),
|
|
17558
|
+
};
|
|
17559
|
+
}
|
|
17560
|
+
writeHeaders(headers, condition, idempotencyKey) {
|
|
17561
|
+
let unconditional = headers.delete('If-Match').delete('If-None-Match').delete('Idempotency-Key');
|
|
17562
|
+
if (idempotencyKey !== undefined)
|
|
17563
|
+
unconditional = unconditional.set('Idempotency-Key', requireIdempotencyKey(idempotencyKey));
|
|
17564
|
+
if (!condition)
|
|
17565
|
+
return unconditional;
|
|
17566
|
+
if (condition.kind === 'first-publish')
|
|
17567
|
+
return unconditional.set('If-None-Match', '*');
|
|
17568
|
+
return unconditional.set('If-Match', requireStrongEtag(condition.etag));
|
|
17569
|
+
}
|
|
17570
|
+
strongMatch(etag) {
|
|
17571
|
+
return { kind: 'match', etag: requireStrongEtag(etag) };
|
|
17572
|
+
}
|
|
17573
|
+
receipt(body, headers) {
|
|
17574
|
+
const etag = headers.get('ETag');
|
|
17575
|
+
if (!etag || body === null || body === undefined)
|
|
17576
|
+
throw new UiLayoutLifecycleContractError('MISSING_ETAG');
|
|
17577
|
+
return { body, etag, location: headers.get('Location') };
|
|
17578
|
+
}
|
|
17579
|
+
assertCurrent(revision, write) {
|
|
17580
|
+
if (revision !== this.contextRevision) {
|
|
17581
|
+
throw new UiLayoutLifecycleContractError(write ? 'COMMAND_OUTCOME_UNCERTAIN' : 'CONTEXT_OBSOLETE');
|
|
17582
|
+
}
|
|
17583
|
+
}
|
|
17584
|
+
assertDispatchContext(revision) {
|
|
17585
|
+
if (revision !== this.contextRevision) {
|
|
17586
|
+
throw new UiLayoutLifecycleContractError('CONTEXT_OBSOLETE');
|
|
17587
|
+
}
|
|
17588
|
+
}
|
|
17589
|
+
normalizeError(error, revision, write) {
|
|
17590
|
+
if (error instanceof UiLayoutLifecycleContractError)
|
|
17591
|
+
return error;
|
|
17592
|
+
if (revision !== this.contextRevision)
|
|
17593
|
+
return new UiLayoutLifecycleContractError(write ? 'COMMAND_OUTCOME_UNCERTAIN' : 'CONTEXT_OBSOLETE');
|
|
17594
|
+
if (error instanceof HttpErrorResponse && write && [0, 502, 504].includes(error.status)) {
|
|
17595
|
+
return new UiLayoutLifecycleContractError('COMMAND_OUTCOME_UNCERTAIN');
|
|
17596
|
+
}
|
|
17597
|
+
if (error instanceof HttpErrorResponse)
|
|
17598
|
+
return new UiLayoutLifecycleHttpError(error.status, categoryFor(error.status));
|
|
17599
|
+
return new UiLayoutLifecycleHttpError(0, 'HTTP_FAILURE');
|
|
17600
|
+
}
|
|
17601
|
+
root() {
|
|
17602
|
+
const entry = this.apiUrl?.['default'];
|
|
17603
|
+
const base = entry ? buildApiUrl(entry) : '';
|
|
17604
|
+
return base ? `${base}/praxis/config/ui-layouts` : '/api/praxis/config/ui-layouts';
|
|
17605
|
+
}
|
|
17606
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: UiLayoutLifecycleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
17607
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: UiLayoutLifecycleService, providedIn: 'root' });
|
|
17608
|
+
}
|
|
17609
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: UiLayoutLifecycleService, decorators: [{
|
|
17610
|
+
type: Injectable,
|
|
17611
|
+
args: [{ providedIn: 'root' }]
|
|
17612
|
+
}], ctorParameters: () => [] });
|
|
17613
|
+
function normalizeTarget(target) {
|
|
17614
|
+
const componentType = target?.componentType?.trim();
|
|
17615
|
+
const componentId = target?.componentId?.trim();
|
|
17616
|
+
if (!componentType || !componentId || componentType.length > 64 || componentId.length > 255) {
|
|
17617
|
+
throw new UiLayoutLifecycleContractError('INVALID_TARGET');
|
|
17618
|
+
}
|
|
17619
|
+
return { componentType, componentId };
|
|
17620
|
+
}
|
|
17621
|
+
function requireStrongEtag(etag) {
|
|
17622
|
+
const normalized = String(etag ?? '').trim();
|
|
17623
|
+
if (!/^"[^"\\]+"$/.test(normalized))
|
|
17624
|
+
throw new UiLayoutLifecycleContractError('INVALID_STRONG_ETAG');
|
|
17625
|
+
return normalized;
|
|
17626
|
+
}
|
|
17627
|
+
function requireIdempotencyKey(value) {
|
|
17628
|
+
const normalized = String(value ?? '').trim();
|
|
17629
|
+
if (!normalized || normalized.length > 180) {
|
|
17630
|
+
throw new UiLayoutLifecycleContractError('INVALID_IDEMPOTENCY_KEY');
|
|
17631
|
+
}
|
|
17632
|
+
return normalized;
|
|
17633
|
+
}
|
|
17634
|
+
function categoryFor(status) {
|
|
17635
|
+
switch (status) {
|
|
17636
|
+
case 400: return 'BAD_REQUEST';
|
|
17637
|
+
case 401: return 'UNAUTHENTICATED';
|
|
17638
|
+
case 403: return 'DENIED';
|
|
17639
|
+
case 404: return 'NOT_FOUND';
|
|
17640
|
+
case 409: return 'CONFLICT';
|
|
17641
|
+
case 412: return 'PRECONDITION';
|
|
17642
|
+
case 413: return 'PAYLOAD_TOO_LARGE';
|
|
17643
|
+
case 422: return 'UNPROCESSABLE';
|
|
17644
|
+
case 503: return 'UNAVAILABLE';
|
|
17645
|
+
default: return 'HTTP_FAILURE';
|
|
17646
|
+
}
|
|
17647
|
+
}
|
|
17648
|
+
|
|
16616
17649
|
function clonePraxisRuntimeComponentObservation(observation) {
|
|
16617
17650
|
assertPraxisRuntimeComponentObservationSerializable(observation);
|
|
16618
17651
|
return JSON.parse(JSON.stringify(observation));
|
|
@@ -21651,6 +22684,24 @@ const FieldDataType = {
|
|
|
21651
22684
|
* - Supports Material Design 3 specifications
|
|
21652
22685
|
*/
|
|
21653
22686
|
|
|
22687
|
+
/**
|
|
22688
|
+
* Normalizes user/schema declared aspect ratio strings (such as "16:9")
|
|
22689
|
+
* into valid CSS aspect-ratio values ("16 / 9").
|
|
22690
|
+
*/
|
|
22691
|
+
function normalizeCardMediaAspectRatio(aspectRatio) {
|
|
22692
|
+
if (!aspectRatio || typeof aspectRatio !== 'string')
|
|
22693
|
+
return null;
|
|
22694
|
+
const trimmed = aspectRatio.trim();
|
|
22695
|
+
if (!trimmed)
|
|
22696
|
+
return null;
|
|
22697
|
+
if (trimmed === 'auto')
|
|
22698
|
+
return 'auto';
|
|
22699
|
+
const ratioMatch = trimmed.match(/^(\d+(?:\.\d+)?)\s*[:/]\s*(\d+(?:\.\d+)?)$/);
|
|
22700
|
+
if (ratioMatch) {
|
|
22701
|
+
return `${ratioMatch[1]} / ${ratioMatch[2]}`;
|
|
22702
|
+
}
|
|
22703
|
+
return trimmed;
|
|
22704
|
+
}
|
|
21654
22705
|
function createEmptyRichContentDocument() {
|
|
21655
22706
|
return {
|
|
21656
22707
|
kind: 'praxis.rich-content',
|
|
@@ -22554,6 +23605,76 @@ function hasOnlyKeys(value, allowed) {
|
|
|
22554
23605
|
return Object.keys(value).every((key) => allowedSet.has(key));
|
|
22555
23606
|
}
|
|
22556
23607
|
|
|
23608
|
+
/** Does not mutate input, synthesize IDs, or attest a historical upgrade baseline. */
|
|
23609
|
+
function formIdentityIssues(config) {
|
|
23610
|
+
const issues = [];
|
|
23611
|
+
const record = (value) => value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
23612
|
+
const list = (value) => Array.isArray(value) ? value : [];
|
|
23613
|
+
const root = record(config);
|
|
23614
|
+
const add = (level, code, path, message) => issues.push({ level, code, path, message });
|
|
23615
|
+
const identity = (value, path, seen, optional) => {
|
|
23616
|
+
if (value === undefined && optional) {
|
|
23617
|
+
add('warning', 'unattested', path, 'Missing identity can be assigned during creation but does not attest historical identity.');
|
|
23618
|
+
}
|
|
23619
|
+
else if (typeof value !== 'string' || !value || value.trim() !== value) {
|
|
23620
|
+
add('error', 'invalid', path, 'Identity must be a non-empty string without surrounding whitespace.');
|
|
23621
|
+
}
|
|
23622
|
+
else if (seen.has(value)) {
|
|
23623
|
+
add('error', 'duplicate', path, 'Identity is duplicated within its container.');
|
|
23624
|
+
}
|
|
23625
|
+
else {
|
|
23626
|
+
seen.add(value);
|
|
23627
|
+
}
|
|
23628
|
+
};
|
|
23629
|
+
const fields = new Set();
|
|
23630
|
+
list(root['fieldMetadata']).forEach((field, index) => identity(record(field)['name'], `fieldMetadata[${index}].name`, fields, false));
|
|
23631
|
+
const hasCatalog = Array.isArray(root['fieldMetadata']);
|
|
23632
|
+
const reference = (value, path) => {
|
|
23633
|
+
if (typeof value !== 'string' || !value || value.trim() !== value) {
|
|
23634
|
+
add('error', 'invalid', path, 'Field reference must be a non-empty canonical field name.');
|
|
23635
|
+
}
|
|
23636
|
+
else if (!hasCatalog) {
|
|
23637
|
+
add('warning', 'catalog-missing', path, 'Field reference cannot be verified without the field catalog.');
|
|
23638
|
+
}
|
|
23639
|
+
else if (!fields.has(value)) {
|
|
23640
|
+
add('error', 'reference-missing', path, 'Field reference is absent from the declared field catalog.');
|
|
23641
|
+
}
|
|
23642
|
+
};
|
|
23643
|
+
const sections = new Set();
|
|
23644
|
+
list(root['sections']).forEach((section, si) => {
|
|
23645
|
+
const s = record(section), sp = `sections[${si}]`, rows = new Set();
|
|
23646
|
+
identity(s['id'], `${sp}.id`, sections, true);
|
|
23647
|
+
list(s['rows']).forEach((row, ri) => {
|
|
23648
|
+
const r = record(row), rp = `${sp}.rows[${ri}]`, columns = new Set();
|
|
23649
|
+
identity(r['id'], `${rp}.id`, rows, true);
|
|
23650
|
+
list(r['columns']).forEach((column, ci) => {
|
|
23651
|
+
const c = record(column), cp = `${rp}.columns[${ci}]`, items = new Set();
|
|
23652
|
+
identity(c['id'], `${cp}.id`, columns, true);
|
|
23653
|
+
if (c['items'] !== undefined && !Array.isArray(c['items'])) {
|
|
23654
|
+
add('error', 'invalid', `${cp}.items`, 'Canonical layout items must be an array.');
|
|
23655
|
+
}
|
|
23656
|
+
else if (Array.isArray(c['items'])) {
|
|
23657
|
+
c['items'].forEach((item, ii) => {
|
|
23658
|
+
const i = record(item), ip = `${cp}.items[${ii}]`;
|
|
23659
|
+
identity(i['id'], `${ip}.id`, items, true);
|
|
23660
|
+
if (i['kind'] === 'field')
|
|
23661
|
+
reference(i['fieldName'], `${ip}.fieldName`);
|
|
23662
|
+
else if (i['kind'] !== 'richContent')
|
|
23663
|
+
add('error', 'invalid', `${ip}.kind`, 'Layout item kind must be field or richContent.');
|
|
23664
|
+
else if (!i['document'] || typeof i['document'] !== 'object' || Array.isArray(i['document'])) {
|
|
23665
|
+
add('error', 'invalid', `${ip}.document`, 'Rich content item requires a document object.');
|
|
23666
|
+
}
|
|
23667
|
+
});
|
|
23668
|
+
}
|
|
23669
|
+
else {
|
|
23670
|
+
list(c['fields']).forEach((field, fi) => reference(typeof field === 'string' ? field : record(field)['name'], `${cp}.fields[${fi}]`));
|
|
23671
|
+
}
|
|
23672
|
+
});
|
|
23673
|
+
});
|
|
23674
|
+
});
|
|
23675
|
+
return issues;
|
|
23676
|
+
}
|
|
23677
|
+
|
|
22557
23678
|
/**
|
|
22558
23679
|
* Materializes a concrete FormConfig from a reusable editorial template.
|
|
22559
23680
|
*
|
|
@@ -27144,6 +28265,652 @@ function resolveBuiltinPresets(locale, dateAdapter, opts = {}) {
|
|
|
27144
28265
|
return presets;
|
|
27145
28266
|
}
|
|
27146
28267
|
|
|
28268
|
+
const DEFAULT_FUNCTIONS = {
|
|
28269
|
+
round: (v) => Math.round(Number(v)),
|
|
28270
|
+
ceil: (v) => Math.ceil(Number(v)),
|
|
28271
|
+
floor: (v) => Math.floor(Number(v)),
|
|
28272
|
+
abs: (v) => Math.abs(Number(v)),
|
|
28273
|
+
min: (...vals) => Math.min(...vals.map((v) => Number(v))),
|
|
28274
|
+
max: (...vals) => Math.max(...vals.map((v) => Number(v))),
|
|
28275
|
+
now: () => Date.now(),
|
|
28276
|
+
date: (v) => {
|
|
28277
|
+
if (v == null)
|
|
28278
|
+
return null;
|
|
28279
|
+
const d = v instanceof Date ? v : new Date(v);
|
|
28280
|
+
const ts = d.getTime();
|
|
28281
|
+
return isNaN(ts) ? null : ts;
|
|
28282
|
+
},
|
|
28283
|
+
yearsSince: (v) => {
|
|
28284
|
+
const ts = DEFAULT_FUNCTIONS.date(v);
|
|
28285
|
+
if (ts == null)
|
|
28286
|
+
return null;
|
|
28287
|
+
const diff = Date.now() - ts;
|
|
28288
|
+
if (!isFinite(diff))
|
|
28289
|
+
return null;
|
|
28290
|
+
return Math.floor(diff / 31557600000);
|
|
28291
|
+
},
|
|
28292
|
+
monthsSince: (v) => {
|
|
28293
|
+
const ts = DEFAULT_FUNCTIONS.date(v);
|
|
28294
|
+
if (ts == null)
|
|
28295
|
+
return null;
|
|
28296
|
+
const diff = Date.now() - ts;
|
|
28297
|
+
if (!isFinite(diff))
|
|
28298
|
+
return null;
|
|
28299
|
+
return Math.floor(diff / 2629800000);
|
|
28300
|
+
},
|
|
28301
|
+
daysSince: (v) => {
|
|
28302
|
+
const ts = DEFAULT_FUNCTIONS.date(v);
|
|
28303
|
+
if (ts == null)
|
|
28304
|
+
return null;
|
|
28305
|
+
const diff = Date.now() - ts;
|
|
28306
|
+
if (!isFinite(diff))
|
|
28307
|
+
return null;
|
|
28308
|
+
return Math.floor(diff / 86400000);
|
|
28309
|
+
},
|
|
28310
|
+
coalesce: (...vals) => {
|
|
28311
|
+
for (const v of vals) {
|
|
28312
|
+
if (v !== null && v !== undefined && v !== '')
|
|
28313
|
+
return v;
|
|
28314
|
+
}
|
|
28315
|
+
return null;
|
|
28316
|
+
},
|
|
28317
|
+
len: (v) => {
|
|
28318
|
+
if (v == null)
|
|
28319
|
+
return 0;
|
|
28320
|
+
if (typeof v === 'string' || Array.isArray(v))
|
|
28321
|
+
return v.length;
|
|
28322
|
+
return 0;
|
|
28323
|
+
},
|
|
28324
|
+
toNumber: (v) => {
|
|
28325
|
+
const n = Number(v);
|
|
28326
|
+
return Number.isFinite(n) ? n : null;
|
|
28327
|
+
},
|
|
28328
|
+
toString: (v) => (v == null ? '' : String(v)),
|
|
28329
|
+
if: (condition, truthyVal, falsyVal) => (Boolean(condition) ? truthyVal : falsyVal),
|
|
28330
|
+
};
|
|
28331
|
+
const DEFAULT_FUNCTION_ARITY = {
|
|
28332
|
+
round: { minArgs: 1, maxArgs: 1 },
|
|
28333
|
+
ceil: { minArgs: 1, maxArgs: 1 },
|
|
28334
|
+
floor: { minArgs: 1, maxArgs: 1 },
|
|
28335
|
+
abs: { minArgs: 1, maxArgs: 1 },
|
|
28336
|
+
min: { minArgs: 1, maxArgs: Number.MAX_SAFE_INTEGER },
|
|
28337
|
+
max: { minArgs: 1, maxArgs: Number.MAX_SAFE_INTEGER },
|
|
28338
|
+
now: { minArgs: 0, maxArgs: 0 },
|
|
28339
|
+
date: { minArgs: 1, maxArgs: 1 },
|
|
28340
|
+
yearsSince: { minArgs: 1, maxArgs: 1 },
|
|
28341
|
+
monthsSince: { minArgs: 1, maxArgs: 1 },
|
|
28342
|
+
daysSince: { minArgs: 1, maxArgs: 1 },
|
|
28343
|
+
coalesce: { minArgs: 1, maxArgs: Number.MAX_SAFE_INTEGER },
|
|
28344
|
+
len: { minArgs: 1, maxArgs: 1 },
|
|
28345
|
+
toNumber: { minArgs: 1, maxArgs: 1 },
|
|
28346
|
+
toString: { minArgs: 1, maxArgs: 1 },
|
|
28347
|
+
if: { minArgs: 3, maxArgs: 3 },
|
|
28348
|
+
};
|
|
28349
|
+
const BLOCKED_KEYS$1 = new Set(['__proto__', 'prototype', 'constructor']);
|
|
28350
|
+
class Tokenizer {
|
|
28351
|
+
input;
|
|
28352
|
+
i = 0;
|
|
28353
|
+
len;
|
|
28354
|
+
constructor(input) {
|
|
28355
|
+
this.input = input;
|
|
28356
|
+
this.len = input.length;
|
|
28357
|
+
}
|
|
28358
|
+
tokenize() {
|
|
28359
|
+
const tokens = [];
|
|
28360
|
+
while (this.i < this.len) {
|
|
28361
|
+
const ch = this.input[this.i];
|
|
28362
|
+
if (this.isWhitespace(ch)) {
|
|
28363
|
+
this.i += 1;
|
|
28364
|
+
continue;
|
|
28365
|
+
}
|
|
28366
|
+
const pos = this.i;
|
|
28367
|
+
if (this.isDigit(ch) || (ch === '.' && this.isDigit(this.peek()))) {
|
|
28368
|
+
tokens.push(this.readNumber(pos));
|
|
28369
|
+
continue;
|
|
28370
|
+
}
|
|
28371
|
+
if (ch === '"' || ch === "'") {
|
|
28372
|
+
tokens.push(this.readString(pos, ch));
|
|
28373
|
+
continue;
|
|
28374
|
+
}
|
|
28375
|
+
if (this.isIdentifierStart(ch)) {
|
|
28376
|
+
tokens.push(this.readIdentifier(pos));
|
|
28377
|
+
continue;
|
|
28378
|
+
}
|
|
28379
|
+
const op = this.readOperator();
|
|
28380
|
+
if (op) {
|
|
28381
|
+
tokens.push({ type: 'operator', value: op, pos });
|
|
28382
|
+
continue;
|
|
28383
|
+
}
|
|
28384
|
+
if (ch === '(' || ch === ')') {
|
|
28385
|
+
tokens.push({ type: 'paren', value: ch, pos });
|
|
28386
|
+
this.i += 1;
|
|
28387
|
+
continue;
|
|
28388
|
+
}
|
|
28389
|
+
if (ch === ',') {
|
|
28390
|
+
tokens.push({ type: 'comma', value: ch, pos });
|
|
28391
|
+
this.i += 1;
|
|
28392
|
+
continue;
|
|
28393
|
+
}
|
|
28394
|
+
if (ch === '.') {
|
|
28395
|
+
tokens.push({ type: 'dot', value: ch, pos });
|
|
28396
|
+
this.i += 1;
|
|
28397
|
+
continue;
|
|
28398
|
+
}
|
|
28399
|
+
throw new Error(`Unexpected character "${ch}"`);
|
|
28400
|
+
}
|
|
28401
|
+
tokens.push({ type: 'eof', value: '', pos: this.i });
|
|
28402
|
+
return tokens;
|
|
28403
|
+
}
|
|
28404
|
+
readNumber(pos) {
|
|
28405
|
+
let hasDot = false;
|
|
28406
|
+
let value = '';
|
|
28407
|
+
while (this.i < this.len) {
|
|
28408
|
+
const ch = this.input[this.i];
|
|
28409
|
+
if (this.isDigit(ch)) {
|
|
28410
|
+
value += ch;
|
|
28411
|
+
this.i += 1;
|
|
28412
|
+
continue;
|
|
28413
|
+
}
|
|
28414
|
+
if (ch === '.' && !hasDot && this.isDigit(this.peek())) {
|
|
28415
|
+
hasDot = true;
|
|
28416
|
+
value += ch;
|
|
28417
|
+
this.i += 1;
|
|
28418
|
+
continue;
|
|
28419
|
+
}
|
|
28420
|
+
break;
|
|
28421
|
+
}
|
|
28422
|
+
return { type: 'number', value, pos };
|
|
28423
|
+
}
|
|
28424
|
+
readString(pos, quote) {
|
|
28425
|
+
let value = '';
|
|
28426
|
+
this.i += 1; // skip quote
|
|
28427
|
+
while (this.i < this.len) {
|
|
28428
|
+
const ch = this.input[this.i];
|
|
28429
|
+
if (ch === '\\') {
|
|
28430
|
+
const next = this.peek();
|
|
28431
|
+
if (next) {
|
|
28432
|
+
value += next;
|
|
28433
|
+
this.i += 2;
|
|
28434
|
+
continue;
|
|
28435
|
+
}
|
|
28436
|
+
}
|
|
28437
|
+
if (ch === quote) {
|
|
28438
|
+
this.i += 1;
|
|
28439
|
+
return { type: 'string', value, pos };
|
|
28440
|
+
}
|
|
28441
|
+
value += ch;
|
|
28442
|
+
this.i += 1;
|
|
28443
|
+
}
|
|
28444
|
+
throw new Error('Unterminated string');
|
|
28445
|
+
}
|
|
28446
|
+
readIdentifier(pos) {
|
|
28447
|
+
let value = '';
|
|
28448
|
+
while (this.i < this.len) {
|
|
28449
|
+
const ch = this.input[this.i];
|
|
28450
|
+
if (this.isIdentifierPart(ch)) {
|
|
28451
|
+
value += ch;
|
|
28452
|
+
this.i += 1;
|
|
28453
|
+
continue;
|
|
28454
|
+
}
|
|
28455
|
+
break;
|
|
28456
|
+
}
|
|
28457
|
+
return { type: 'identifier', value, pos };
|
|
28458
|
+
}
|
|
28459
|
+
readOperator() {
|
|
28460
|
+
const two = this.input.slice(this.i, this.i + 2);
|
|
28461
|
+
const three = this.input.slice(this.i, this.i + 3);
|
|
28462
|
+
const ops = ['===', '!==', '==', '!=', '>=', '<='];
|
|
28463
|
+
if (ops.includes(three)) {
|
|
28464
|
+
this.i += 3;
|
|
28465
|
+
return three;
|
|
28466
|
+
}
|
|
28467
|
+
if (ops.includes(two)) {
|
|
28468
|
+
this.i += 2;
|
|
28469
|
+
return two;
|
|
28470
|
+
}
|
|
28471
|
+
const ch = this.input[this.i];
|
|
28472
|
+
if ('+-*/><?:'.includes(ch)) {
|
|
28473
|
+
this.i += 1;
|
|
28474
|
+
return ch;
|
|
28475
|
+
}
|
|
28476
|
+
return null;
|
|
28477
|
+
}
|
|
28478
|
+
peek() {
|
|
28479
|
+
return this.input[this.i + 1] || '';
|
|
28480
|
+
}
|
|
28481
|
+
isWhitespace(ch) {
|
|
28482
|
+
return ch === ' ' || ch === '\n' || ch === '\r' || ch === '\t';
|
|
28483
|
+
}
|
|
28484
|
+
isDigit(ch) {
|
|
28485
|
+
return ch >= '0' && ch <= '9';
|
|
28486
|
+
}
|
|
28487
|
+
isIdentifierStart(ch) {
|
|
28488
|
+
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '_';
|
|
28489
|
+
}
|
|
28490
|
+
isIdentifierPart(ch) {
|
|
28491
|
+
return this.isIdentifierStart(ch) || this.isDigit(ch);
|
|
28492
|
+
}
|
|
28493
|
+
}
|
|
28494
|
+
class Parser {
|
|
28495
|
+
tokens;
|
|
28496
|
+
opts;
|
|
28497
|
+
current = 0;
|
|
28498
|
+
opCount = 0;
|
|
28499
|
+
depth = 0;
|
|
28500
|
+
constructor(tokens, opts) {
|
|
28501
|
+
this.tokens = tokens;
|
|
28502
|
+
this.opts = opts;
|
|
28503
|
+
}
|
|
28504
|
+
parse() {
|
|
28505
|
+
const expr = this.parseTernary();
|
|
28506
|
+
this.consume('eof');
|
|
28507
|
+
if (this.opCount > this.opts.maxTokens) {
|
|
28508
|
+
throw new Error('Expression too complex');
|
|
28509
|
+
}
|
|
28510
|
+
return expr;
|
|
28511
|
+
}
|
|
28512
|
+
parseTernary() {
|
|
28513
|
+
let expr = this.parseComparison();
|
|
28514
|
+
if (this.matchOperator('?')) {
|
|
28515
|
+
this.enterDepth();
|
|
28516
|
+
const whenTrue = this.parseTernary();
|
|
28517
|
+
this.consumeOperator(':');
|
|
28518
|
+
const whenFalse = this.parseTernary();
|
|
28519
|
+
this.exitDepth();
|
|
28520
|
+
this.opCount += 2;
|
|
28521
|
+
return { kind: 'call', name: 'if', args: [expr, whenTrue, whenFalse] };
|
|
28522
|
+
}
|
|
28523
|
+
return expr;
|
|
28524
|
+
}
|
|
28525
|
+
parseComparison() {
|
|
28526
|
+
let expr = this.parseAdditive();
|
|
28527
|
+
while (this.matchOperator('==', '!=', '===', '!==', '>=', '<=', '>', '<')) {
|
|
28528
|
+
if (!this.opts.allowComparisons) {
|
|
28529
|
+
throw new Error('Comparisons not allowed');
|
|
28530
|
+
}
|
|
28531
|
+
const op = this.previous().value;
|
|
28532
|
+
const right = this.parseAdditive();
|
|
28533
|
+
expr = this.makeBinary(op, expr, right);
|
|
28534
|
+
}
|
|
28535
|
+
return expr;
|
|
28536
|
+
}
|
|
28537
|
+
parseAdditive() {
|
|
28538
|
+
let expr = this.parseMultiplicative();
|
|
28539
|
+
while (this.matchOperator('+', '-')) {
|
|
28540
|
+
const op = this.previous().value;
|
|
28541
|
+
const right = this.parseMultiplicative();
|
|
28542
|
+
expr = this.makeBinary(op, expr, right);
|
|
28543
|
+
}
|
|
28544
|
+
return expr;
|
|
28545
|
+
}
|
|
28546
|
+
parseMultiplicative() {
|
|
28547
|
+
let expr = this.parseUnary();
|
|
28548
|
+
while (this.matchOperator('*', '/')) {
|
|
28549
|
+
const op = this.previous().value;
|
|
28550
|
+
const right = this.parseUnary();
|
|
28551
|
+
expr = this.makeBinary(op, expr, right);
|
|
28552
|
+
}
|
|
28553
|
+
return expr;
|
|
28554
|
+
}
|
|
28555
|
+
parseUnary() {
|
|
28556
|
+
if (this.matchOperator('+', '-')) {
|
|
28557
|
+
const op = this.previous().value;
|
|
28558
|
+
const expr = this.parseUnary();
|
|
28559
|
+
this.opCount += 1;
|
|
28560
|
+
return { kind: 'unary', op, expr };
|
|
28561
|
+
}
|
|
28562
|
+
return this.parsePrimary();
|
|
28563
|
+
}
|
|
28564
|
+
parsePrimary() {
|
|
28565
|
+
if (this.match('number')) {
|
|
28566
|
+
return { kind: 'literal', value: Number(this.previous().value) };
|
|
28567
|
+
}
|
|
28568
|
+
if (this.match('string')) {
|
|
28569
|
+
return { kind: 'literal', value: this.previous().value };
|
|
28570
|
+
}
|
|
28571
|
+
if (this.match('identifier')) {
|
|
28572
|
+
const name = this.previous().value;
|
|
28573
|
+
if (name === 'true' || name === 'false') {
|
|
28574
|
+
return { kind: 'literal', value: name === 'true' };
|
|
28575
|
+
}
|
|
28576
|
+
if (this.matchValue('paren', '(')) {
|
|
28577
|
+
const args = this.parseArguments();
|
|
28578
|
+
return { kind: 'call', name, args };
|
|
28579
|
+
}
|
|
28580
|
+
const path = [name];
|
|
28581
|
+
while (this.matchValue('dot', '.')) {
|
|
28582
|
+
const seg = this.consume('identifier').value;
|
|
28583
|
+
path.push(seg);
|
|
28584
|
+
}
|
|
28585
|
+
if ((name === 'row' || name === 'rowData') && path.length === 1) {
|
|
28586
|
+
throw new Error('row reference must access a field');
|
|
28587
|
+
}
|
|
28588
|
+
return { kind: 'field', path };
|
|
28589
|
+
}
|
|
28590
|
+
if (this.matchValue('paren', '(')) {
|
|
28591
|
+
this.enterDepth();
|
|
28592
|
+
const expr = this.parseTernary();
|
|
28593
|
+
this.consumeValue('paren', ')');
|
|
28594
|
+
this.exitDepth();
|
|
28595
|
+
return expr;
|
|
28596
|
+
}
|
|
28597
|
+
throw new Error('Unexpected token');
|
|
28598
|
+
}
|
|
28599
|
+
parseArguments() {
|
|
28600
|
+
const args = [];
|
|
28601
|
+
if (this.checkValue('paren', ')')) {
|
|
28602
|
+
this.consumeValue('paren', ')');
|
|
28603
|
+
return args;
|
|
28604
|
+
}
|
|
28605
|
+
do {
|
|
28606
|
+
if (args.length >= this.opts.maxArgs) {
|
|
28607
|
+
throw new Error('Too many arguments');
|
|
28608
|
+
}
|
|
28609
|
+
args.push(this.parseTernary());
|
|
28610
|
+
} while (this.matchValue('comma', ','));
|
|
28611
|
+
this.consumeValue('paren', ')');
|
|
28612
|
+
return args;
|
|
28613
|
+
}
|
|
28614
|
+
consumeOperator(op) {
|
|
28615
|
+
if (this.check('operator') && this.peek().value === op) {
|
|
28616
|
+
return this.advance();
|
|
28617
|
+
}
|
|
28618
|
+
throw new Error(`Expected operator "${op}"`);
|
|
28619
|
+
}
|
|
28620
|
+
makeBinary(op, left, right) {
|
|
28621
|
+
this.opCount += 1;
|
|
28622
|
+
return { kind: 'binary', op, left, right };
|
|
28623
|
+
}
|
|
28624
|
+
enterDepth() {
|
|
28625
|
+
this.depth += 1;
|
|
28626
|
+
if (this.depth > this.opts.maxDepth) {
|
|
28627
|
+
throw new Error('Expression too deep');
|
|
28628
|
+
}
|
|
28629
|
+
}
|
|
28630
|
+
exitDepth() {
|
|
28631
|
+
this.depth = Math.max(0, this.depth - 1);
|
|
28632
|
+
}
|
|
28633
|
+
match(type) {
|
|
28634
|
+
if (this.check(type)) {
|
|
28635
|
+
this.current += 1;
|
|
28636
|
+
return true;
|
|
28637
|
+
}
|
|
28638
|
+
return false;
|
|
28639
|
+
}
|
|
28640
|
+
matchValue(type, value) {
|
|
28641
|
+
if (this.checkValue(type, value)) {
|
|
28642
|
+
this.current += 1;
|
|
28643
|
+
return true;
|
|
28644
|
+
}
|
|
28645
|
+
return false;
|
|
28646
|
+
}
|
|
28647
|
+
matchOperator(...ops) {
|
|
28648
|
+
if (this.check('operator') && ops.includes(this.peek().value)) {
|
|
28649
|
+
this.current += 1;
|
|
28650
|
+
return true;
|
|
28651
|
+
}
|
|
28652
|
+
return false;
|
|
28653
|
+
}
|
|
28654
|
+
consume(type) {
|
|
28655
|
+
if (this.check(type))
|
|
28656
|
+
return this.advance();
|
|
28657
|
+
throw new Error(`Expected ${type}`);
|
|
28658
|
+
}
|
|
28659
|
+
consumeValue(type, value) {
|
|
28660
|
+
if (this.checkValue(type, value))
|
|
28661
|
+
return this.advance();
|
|
28662
|
+
throw new Error(`Expected ${value}`);
|
|
28663
|
+
}
|
|
28664
|
+
check(type) {
|
|
28665
|
+
return this.peek().type === type;
|
|
28666
|
+
}
|
|
28667
|
+
checkValue(type, value) {
|
|
28668
|
+
const tk = this.peek();
|
|
28669
|
+
return tk.type === type && tk.value === value;
|
|
28670
|
+
}
|
|
28671
|
+
advance() {
|
|
28672
|
+
if (!this.isAtEnd())
|
|
28673
|
+
this.current += 1;
|
|
28674
|
+
return this.previous();
|
|
28675
|
+
}
|
|
28676
|
+
isAtEnd() {
|
|
28677
|
+
return this.peek().type === 'eof';
|
|
28678
|
+
}
|
|
28679
|
+
peek() {
|
|
28680
|
+
return this.tokens[this.current];
|
|
28681
|
+
}
|
|
28682
|
+
previous() {
|
|
28683
|
+
return this.tokens[this.current - 1];
|
|
28684
|
+
}
|
|
28685
|
+
}
|
|
28686
|
+
class SafeExpressionEvaluator {
|
|
28687
|
+
cache = new Map();
|
|
28688
|
+
opts;
|
|
28689
|
+
functions;
|
|
28690
|
+
functionArity;
|
|
28691
|
+
constructor(options = {}) {
|
|
28692
|
+
this.opts = {
|
|
28693
|
+
maxLength: options.maxLength ?? 200,
|
|
28694
|
+
maxTokens: options.maxTokens ?? 80,
|
|
28695
|
+
maxDepth: options.maxDepth ?? 12,
|
|
28696
|
+
maxArgs: options.maxArgs ?? 6,
|
|
28697
|
+
allowComparisons: options.allowComparisons ?? true,
|
|
28698
|
+
allowedFunctions: options.allowedFunctions ?? DEFAULT_FUNCTIONS,
|
|
28699
|
+
allowedFunctionArity: options.allowedFunctionArity ?? DEFAULT_FUNCTION_ARITY,
|
|
28700
|
+
};
|
|
28701
|
+
this.functions = this.opts.allowedFunctions;
|
|
28702
|
+
this.functionArity = this.resolveFunctionArity();
|
|
28703
|
+
}
|
|
28704
|
+
evaluate(expression, row) {
|
|
28705
|
+
const normalized = this.normalize(expression);
|
|
28706
|
+
if (!normalized)
|
|
28707
|
+
return { value: null, error: 'empty' };
|
|
28708
|
+
if (normalized.length > this.opts.maxLength)
|
|
28709
|
+
return { value: null, error: 'too_long' };
|
|
28710
|
+
const node = this.getOrParse(normalized);
|
|
28711
|
+
if (!node)
|
|
28712
|
+
return { value: null, error: 'parse' };
|
|
28713
|
+
try {
|
|
28714
|
+
return { value: this.evalNode(node, row) };
|
|
28715
|
+
}
|
|
28716
|
+
catch {
|
|
28717
|
+
return { value: null, error: 'eval' };
|
|
28718
|
+
}
|
|
28719
|
+
}
|
|
28720
|
+
getOrParse(expression) {
|
|
28721
|
+
if (this.cache.has(expression))
|
|
28722
|
+
return this.cache.get(expression) || null;
|
|
28723
|
+
try {
|
|
28724
|
+
const tokenizer = new Tokenizer(expression);
|
|
28725
|
+
const tokens = tokenizer.tokenize();
|
|
28726
|
+
if (tokens.length > this.opts.maxTokens) {
|
|
28727
|
+
throw new Error('Expression too complex');
|
|
28728
|
+
}
|
|
28729
|
+
const parser = new Parser(tokens, this.opts);
|
|
28730
|
+
const ast = parser.parse();
|
|
28731
|
+
this.cache.set(expression, ast);
|
|
28732
|
+
return ast;
|
|
28733
|
+
}
|
|
28734
|
+
catch {
|
|
28735
|
+
this.cache.set(expression, null);
|
|
28736
|
+
return null;
|
|
28737
|
+
}
|
|
28738
|
+
}
|
|
28739
|
+
normalize(expression) {
|
|
28740
|
+
if (typeof expression !== 'string')
|
|
28741
|
+
return null;
|
|
28742
|
+
let out = expression.trim();
|
|
28743
|
+
if (!out)
|
|
28744
|
+
return null;
|
|
28745
|
+
if (out.startsWith('='))
|
|
28746
|
+
out = out.replace(/^=+/, '').trim();
|
|
28747
|
+
return out || null;
|
|
28748
|
+
}
|
|
28749
|
+
evalNode(node, row) {
|
|
28750
|
+
switch (node.kind) {
|
|
28751
|
+
case 'literal':
|
|
28752
|
+
return node.value;
|
|
28753
|
+
case 'field':
|
|
28754
|
+
return this.resolvePath(row, node.path);
|
|
28755
|
+
case 'unary': {
|
|
28756
|
+
const val = this.evalNode(node.expr, row);
|
|
28757
|
+
const num = this.toNumber(val);
|
|
28758
|
+
return num == null ? null : (node.op === '-' ? -num : num);
|
|
28759
|
+
}
|
|
28760
|
+
case 'binary':
|
|
28761
|
+
return this.evalBinary(node, row);
|
|
28762
|
+
case 'call':
|
|
28763
|
+
return this.evalCall(node, row);
|
|
28764
|
+
default:
|
|
28765
|
+
return null;
|
|
28766
|
+
}
|
|
28767
|
+
}
|
|
28768
|
+
evalBinary(node, row) {
|
|
28769
|
+
const left = this.evalNode(node.left, row);
|
|
28770
|
+
const right = this.evalNode(node.right, row);
|
|
28771
|
+
switch (node.op) {
|
|
28772
|
+
case '+':
|
|
28773
|
+
const leftNum = this.toNumber(left);
|
|
28774
|
+
const rightNum = this.toNumber(right);
|
|
28775
|
+
if (leftNum != null && rightNum != null) {
|
|
28776
|
+
return leftNum + rightNum;
|
|
28777
|
+
}
|
|
28778
|
+
if (typeof left === 'string' || typeof right === 'string') {
|
|
28779
|
+
return String(left ?? '') + String(right ?? '');
|
|
28780
|
+
}
|
|
28781
|
+
return this.applyNumberOp(left, right, (a, b) => a + b);
|
|
28782
|
+
case '-':
|
|
28783
|
+
return this.applyNumberOp(left, right, (a, b) => a - b);
|
|
28784
|
+
case '*':
|
|
28785
|
+
return this.applyNumberOp(left, right, (a, b) => a * b);
|
|
28786
|
+
case '/':
|
|
28787
|
+
return this.applyNumberOp(left, right, (a, b) => (b === 0 ? null : a / b));
|
|
28788
|
+
case '>':
|
|
28789
|
+
case '>=':
|
|
28790
|
+
case '<':
|
|
28791
|
+
case '<=':
|
|
28792
|
+
case '==':
|
|
28793
|
+
case '!=':
|
|
28794
|
+
case '===':
|
|
28795
|
+
case '!==':
|
|
28796
|
+
return this.applyComparison(left, right, node.op);
|
|
28797
|
+
default:
|
|
28798
|
+
return null;
|
|
28799
|
+
}
|
|
28800
|
+
}
|
|
28801
|
+
evalCall(node, row) {
|
|
28802
|
+
const fn = this.functions[node.name];
|
|
28803
|
+
if (!fn) {
|
|
28804
|
+
throw new Error(`Function "${node.name}" is not allowlisted`);
|
|
28805
|
+
}
|
|
28806
|
+
const arity = this.functionArity[node.name];
|
|
28807
|
+
if (!arity) {
|
|
28808
|
+
throw new Error(`Function "${node.name}" has no arity contract`);
|
|
28809
|
+
}
|
|
28810
|
+
if (node.name === 'if' && fn === DEFAULT_FUNCTIONS['if']) {
|
|
28811
|
+
if (node.args.length !== 3) {
|
|
28812
|
+
throw new Error('Function "if" called with invalid arity');
|
|
28813
|
+
}
|
|
28814
|
+
const cond = this.evalNode(node.args[0], row);
|
|
28815
|
+
const branch = Boolean(cond) ? node.args[1] : node.args[2];
|
|
28816
|
+
return this.evalNode(branch, row);
|
|
28817
|
+
}
|
|
28818
|
+
const args = node.args.map((arg) => this.evalNode(arg, row));
|
|
28819
|
+
if (args.length < arity.minArgs || args.length > arity.maxArgs) {
|
|
28820
|
+
throw new Error(`Function "${node.name}" called with invalid arity`);
|
|
28821
|
+
}
|
|
28822
|
+
const value = fn(...args);
|
|
28823
|
+
if (typeof value === 'number' && !Number.isFinite(value)) {
|
|
28824
|
+
throw new Error(`Function "${node.name}" returned non-finite number`);
|
|
28825
|
+
}
|
|
28826
|
+
return value;
|
|
28827
|
+
}
|
|
28828
|
+
resolveFunctionArity() {
|
|
28829
|
+
const out = {};
|
|
28830
|
+
const userMap = this.opts.allowedFunctionArity || {};
|
|
28831
|
+
for (const [name, fn] of Object.entries(this.functions)) {
|
|
28832
|
+
const raw = userMap[name];
|
|
28833
|
+
const minFromFn = Number.isInteger(fn.length) && fn.length >= 0 ? fn.length : 0;
|
|
28834
|
+
const minRaw = Number(raw?.minArgs);
|
|
28835
|
+
const min = Number.isFinite(minRaw) && minRaw >= 0 ? Math.floor(minRaw) : minFromFn;
|
|
28836
|
+
const maxRaw = Number(raw?.maxArgs);
|
|
28837
|
+
let maxBase = this.opts.maxArgs;
|
|
28838
|
+
if (raw && Object.prototype.hasOwnProperty.call(raw, 'maxArgs')) {
|
|
28839
|
+
maxBase = Number.isFinite(maxRaw) && maxRaw >= min
|
|
28840
|
+
? Math.floor(maxRaw)
|
|
28841
|
+
: min;
|
|
28842
|
+
}
|
|
28843
|
+
const max = Math.max(min, Math.min(maxBase, this.opts.maxArgs));
|
|
28844
|
+
out[name] = { minArgs: min, maxArgs: max };
|
|
28845
|
+
}
|
|
28846
|
+
return out;
|
|
28847
|
+
}
|
|
28848
|
+
applyNumberOp(left, right, op) {
|
|
28849
|
+
const a = this.toNumber(left);
|
|
28850
|
+
const b = this.toNumber(right);
|
|
28851
|
+
if (a == null || b == null)
|
|
28852
|
+
return null;
|
|
28853
|
+
const out = op(a, b);
|
|
28854
|
+
return typeof out === 'number' && isFinite(out) ? out : null;
|
|
28855
|
+
}
|
|
28856
|
+
applyComparison(left, right, op) {
|
|
28857
|
+
switch (op) {
|
|
28858
|
+
case '==':
|
|
28859
|
+
case '===':
|
|
28860
|
+
return left === right;
|
|
28861
|
+
case '!=':
|
|
28862
|
+
case '!==':
|
|
28863
|
+
return left !== right;
|
|
28864
|
+
case '>':
|
|
28865
|
+
return this.toComparable(left) > this.toComparable(right);
|
|
28866
|
+
case '>=':
|
|
28867
|
+
return this.toComparable(left) >= this.toComparable(right);
|
|
28868
|
+
case '<':
|
|
28869
|
+
return this.toComparable(left) < this.toComparable(right);
|
|
28870
|
+
case '<=':
|
|
28871
|
+
return this.toComparable(left) <= this.toComparable(right);
|
|
28872
|
+
default:
|
|
28873
|
+
return false;
|
|
28874
|
+
}
|
|
28875
|
+
}
|
|
28876
|
+
toComparable(value) {
|
|
28877
|
+
const num = this.toNumber(value);
|
|
28878
|
+
if (num != null)
|
|
28879
|
+
return num;
|
|
28880
|
+
return String(value ?? '');
|
|
28881
|
+
}
|
|
28882
|
+
toNumber(value) {
|
|
28883
|
+
if (value == null || value === '')
|
|
28884
|
+
return 0;
|
|
28885
|
+
const num = Number(value);
|
|
28886
|
+
return isFinite(num) ? num : null;
|
|
28887
|
+
}
|
|
28888
|
+
resolvePath(row, path) {
|
|
28889
|
+
if (!Array.isArray(path) || !path.length)
|
|
28890
|
+
return undefined;
|
|
28891
|
+
let effectivePath = path;
|
|
28892
|
+
if ((path[0] === 'row' || path[0] === 'rowData') &&
|
|
28893
|
+
row != null &&
|
|
28894
|
+
typeof row === 'object' &&
|
|
28895
|
+
!(path[0] in row)) {
|
|
28896
|
+
effectivePath = path.slice(1);
|
|
28897
|
+
}
|
|
28898
|
+
if (!effectivePath.length)
|
|
28899
|
+
return undefined;
|
|
28900
|
+
let current = row;
|
|
28901
|
+
for (let i = 0; i < effectivePath.length; i += 1) {
|
|
28902
|
+
const key = effectivePath[i];
|
|
28903
|
+
if (!key || BLOCKED_KEYS$1.has(key))
|
|
28904
|
+
return undefined;
|
|
28905
|
+
if (current == null || (typeof current !== 'object' && typeof current !== 'function')) {
|
|
28906
|
+
return undefined;
|
|
28907
|
+
}
|
|
28908
|
+
current = current[key];
|
|
28909
|
+
}
|
|
28910
|
+
return current;
|
|
28911
|
+
}
|
|
28912
|
+
}
|
|
28913
|
+
|
|
27147
28914
|
/**
|
|
27148
28915
|
* Binds a stored icon string to a mat-icon element supporting:
|
|
27149
28916
|
* - Material Icons (classic ligatures): "mi:pending"
|
|
@@ -29930,7 +31697,7 @@ const ENUMS = {
|
|
|
29930
31697
|
layoutOrientation: ['vertical', 'columns'],
|
|
29931
31698
|
canvasMode: ['grid'],
|
|
29932
31699
|
canvasAutoRows: ['fixed', 'content'],
|
|
29933
|
-
canvasCollisionPolicy: ['block', 'swap'],
|
|
31700
|
+
canvasCollisionPolicy: ['block', 'swap', 'push-down'],
|
|
29934
31701
|
groupingKind: ['section', 'tabs', 'hero', 'rail'],
|
|
29935
31702
|
groupingLayout: ['stack', 'grid', 'row'],
|
|
29936
31703
|
heroEmphasis: ['high', 'medium'],
|
|
@@ -33824,6 +35591,19 @@ class DynamicWidgetLoaderDirective {
|
|
|
33824
35591
|
}
|
|
33825
35592
|
return false;
|
|
33826
35593
|
}
|
|
35594
|
+
/**
|
|
35595
|
+
* Resets any active visual selection on the hosted component instance if supported (e.g. PraxisChartComponent).
|
|
35596
|
+
*/
|
|
35597
|
+
clearSelection() {
|
|
35598
|
+
const instance = this.compRef?.instance;
|
|
35599
|
+
if (!instance || this.destroyed)
|
|
35600
|
+
return false;
|
|
35601
|
+
if (typeof instance.clearSelection === 'function') {
|
|
35602
|
+
instance.clearSelection();
|
|
35603
|
+
return true;
|
|
35604
|
+
}
|
|
35605
|
+
return false;
|
|
35606
|
+
}
|
|
33827
35607
|
ngOnInit() {
|
|
33828
35608
|
this.tryRender();
|
|
33829
35609
|
}
|
|
@@ -41822,6 +43602,188 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
41822
43602
|
`, styles: [":host{display:block;min-width:0;color:var(--md-sys-color-on-surface)}.size-editor{display:grid;gap:var(--pdx-editor-gap, 20px)}.context{display:grid;gap:4px;overflow-wrap:anywhere}.context span,.hint,.preset-unit{color:var(--md-sys-color-on-surface-variant);font-size:12px}p,h3{margin:0}h3,.section-label{font-size:14px;font-weight:500}.dimensions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:start}mat-form-field{min-width:0}mat-hint{color:var(--md-sys-color-on-surface-variant)}.presets{display:flex;flex-wrap:wrap;gap:8px}.presets button{min-height:44px}.preset-unit{margin-inline-start:8px}.preset-section .presets{display:grid;grid-template-columns:repeat(4,minmax(0,1fr))}.preset-section .presets button{height:auto;min-height:60px;padding:8px}.preset-section .presets strong,.preset-section .preset-unit{display:block;margin:0}.preset-copy{display:grid;gap:4px;text-align:center;white-space:normal}.preset-section,.fill-section{display:grid;gap:10px}.direction-grid{display:grid;grid-template-columns:repeat(3,minmax(44px,72px));gap:6px;justify-content:center}.direction-cell{display:block}.direction-cell button{width:100%;min-width:44px;height:44px;padding:0;font-size:24px}.direction-cell button.selected{background:var(--md-sys-color-secondary-container);color:var(--md-sys-color-on-secondary-container);border-color:var(--md-sys-color-primary)}.direction-cell button:disabled{background:transparent;color:var(--md-sys-color-on-surface);opacity:.38}.direction-center{display:grid;place-items:center;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.selection-summary{text-align:center;font-size:14px;font-weight:500}.hint{line-height:1.5}summary{cursor:pointer;padding-block:8px;font-weight:500}.advanced-content{display:grid;gap:16px;padding-block:8px}mat-radio-group{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}.recovery{display:grid;gap:4px;justify-items:start}.error{color:var(--md-sys-color-error);font-size:12px}.layout-preview{display:grid;gap:8px}.layout-comparison{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.layout-map{position:relative;height:112px;margin-block-start:6px;background:var(--md-sys-color-surface-container)}.layout-block{position:absolute;box-sizing:border-box;border:2px solid var(--md-sys-color-surface-container);padding:4px;background:var(--md-sys-color-surface-container-highest);color:var(--md-sys-color-on-surface-variant);font-size:11px;overflow:hidden}.layout-block.target{background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container);font-weight:600}.layout-block.changed{outline:1px dashed var(--md-sys-color-primary);outline-offset:-3px}.changed-neighbors{margin:0;padding-inline-start:20px;font-size:12px}.direction-reasons{margin:0;padding-inline-start:20px;color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.5}.direction-reasons li+li{margin-block-start:8px}@media(max-width:480px){.dimensions{grid-template-columns:minmax(0,1fr)}.preset-section .presets{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:380px){mat-radio-group{grid-template-columns:minmax(0,1fr)}}\n"] }]
|
|
41823
43603
|
}], propDecorators: { layoutItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "layoutItems", required: false }] }], resetRevision: [{ type: i0.Input, args: [{ isSignal: true, alias: "resetRevision", required: false }] }], restoredValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "restoredValue", required: false }] }], state: [{ type: i0.Output, args: ["state"] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], freeSpaceWidths: [{ type: i0.Input, args: [{ isSignal: true, alias: "freeSpaceWidths", required: false }] }], northFreeSpaceHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "northFreeSpaceHeight", required: false }] }], northUnavailable: [{ type: i0.Input, args: [{ isSignal: true, alias: "northUnavailable", required: false }] }], southFreeSpaceHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "southFreeSpaceHeight", required: false }] }], southUnavailable: [{ type: i0.Input, args: [{ isSignal: true, alias: "southUnavailable", required: false }] }], cornerFreeSpaceSizes: [{ type: i0.Input, args: [{ isSignal: true, alias: "cornerFreeSpaceSizes", required: false }] }], cornerUnavailable: [{ type: i0.Input, args: [{ isSignal: true, alias: "cornerUnavailable", required: false }] }], expandWidths: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandWidths", required: false }] }], notice: [{ type: i0.Input, args: [{ isSignal: true, alias: "notice", required: false }] }], hasUndo: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasUndo", required: false }] }], canUndo: [{ type: i0.Input, args: [{ isSignal: true, alias: "canUndo", required: false }] }], undo: [{ type: i0.Output, args: ["undo"] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: true }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: true }] }], contentRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentRows", required: false }] }], rowSpan: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowSpan", required: false }] }], widgetLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "widgetLabel", required: true }] }], scopeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "scopeLabel", required: true }] }], previewPending: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewPending", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], preview: [{ type: i0.Output, args: ["preview"] }], apply: [{ type: i0.Output, args: ["apply"] }], cancel: [{ type: i0.Output, args: ["cancel"] }] } });
|
|
41824
43604
|
|
|
43605
|
+
let eventCounter = 0;
|
|
43606
|
+
/**
|
|
43607
|
+
* Praxis UI Platform — Canonical Widget Event Bus (Issue #3)
|
|
43608
|
+
*
|
|
43609
|
+
* Barramento centralizado e desacoplado para comunicação declarativa
|
|
43610
|
+
* entre widgets heterogêneos de páginas ricas e dashboards.
|
|
43611
|
+
*/
|
|
43612
|
+
class PraxisWidgetEventBus {
|
|
43613
|
+
eventSubject$ = new Subject();
|
|
43614
|
+
internalSubs = new Subscription();
|
|
43615
|
+
parentBus;
|
|
43616
|
+
scopeId;
|
|
43617
|
+
constructor() {
|
|
43618
|
+
this.scopeId = `scope-${Date.now()}-${++eventCounter}`;
|
|
43619
|
+
}
|
|
43620
|
+
/**
|
|
43621
|
+
* Publica um evento no barramento.
|
|
43622
|
+
*/
|
|
43623
|
+
publish(event) {
|
|
43624
|
+
const enriched = {
|
|
43625
|
+
id: event.id || `evt-${Date.now()}-${++eventCounter}`,
|
|
43626
|
+
timestamp: event.timestamp || Date.now(),
|
|
43627
|
+
...event,
|
|
43628
|
+
metadata: {
|
|
43629
|
+
scopeId: this.scopeId,
|
|
43630
|
+
...(event.metadata || {}),
|
|
43631
|
+
},
|
|
43632
|
+
};
|
|
43633
|
+
this.eventSubject$.next(enriched);
|
|
43634
|
+
// Propaga para o escopo pai caso exista
|
|
43635
|
+
if (this.parentBus) {
|
|
43636
|
+
this.parentBus.publish(enriched);
|
|
43637
|
+
}
|
|
43638
|
+
}
|
|
43639
|
+
/**
|
|
43640
|
+
* Escuta eventos filtrados por tipo semântico e/ou widget destinatário.
|
|
43641
|
+
*/
|
|
43642
|
+
on(eventType, targetWidgetId) {
|
|
43643
|
+
return this.eventSubject$.asObservable().pipe(filter((evt) => {
|
|
43644
|
+
if (eventType && evt.eventType !== eventType) {
|
|
43645
|
+
return false;
|
|
43646
|
+
}
|
|
43647
|
+
if (targetWidgetId) {
|
|
43648
|
+
return (!evt.targetWidgetId ||
|
|
43649
|
+
evt.targetWidgetId === '*' ||
|
|
43650
|
+
evt.targetWidgetId === targetWidgetId);
|
|
43651
|
+
}
|
|
43652
|
+
return true;
|
|
43653
|
+
}));
|
|
43654
|
+
}
|
|
43655
|
+
/**
|
|
43656
|
+
* Helper conveniente para escutar mutações de filtro ('filter.apply' e 'filter.clear').
|
|
43657
|
+
*/
|
|
43658
|
+
onFilter(targetWidgetId) {
|
|
43659
|
+
return this.eventSubject$.asObservable().pipe(filter((evt) => {
|
|
43660
|
+
const isFilterEvent = evt.eventType === 'filter.apply' || evt.eventType === 'filter.clear';
|
|
43661
|
+
if (!isFilterEvent)
|
|
43662
|
+
return false;
|
|
43663
|
+
if (targetWidgetId) {
|
|
43664
|
+
return (!evt.targetWidgetId ||
|
|
43665
|
+
evt.targetWidgetId === '*' ||
|
|
43666
|
+
evt.targetWidgetId === targetWidgetId);
|
|
43667
|
+
}
|
|
43668
|
+
return true;
|
|
43669
|
+
}));
|
|
43670
|
+
}
|
|
43671
|
+
/**
|
|
43672
|
+
* Helper conveniente para escutar alterações de seleção de linha/entidade.
|
|
43673
|
+
*/
|
|
43674
|
+
onSelection(targetWidgetId) {
|
|
43675
|
+
return this.on('selection.change', targetWidgetId);
|
|
43676
|
+
}
|
|
43677
|
+
/**
|
|
43678
|
+
* Helper conveniente para despachar aplicação de filtros para um widget alvo.
|
|
43679
|
+
*/
|
|
43680
|
+
emitFilterApply(targetWidgetId, criteria, sourceWidgetId) {
|
|
43681
|
+
this.publish({
|
|
43682
|
+
eventType: 'filter.apply',
|
|
43683
|
+
targetWidgetId,
|
|
43684
|
+
sourceWidgetId,
|
|
43685
|
+
payload: criteria,
|
|
43686
|
+
});
|
|
43687
|
+
}
|
|
43688
|
+
/**
|
|
43689
|
+
* Helper conveniente para despachar limpeza de filtros para um widget alvo.
|
|
43690
|
+
*/
|
|
43691
|
+
emitFilterClear(targetWidgetId, sourceWidgetId) {
|
|
43692
|
+
this.publish({
|
|
43693
|
+
eventType: 'filter.clear',
|
|
43694
|
+
targetWidgetId,
|
|
43695
|
+
sourceWidgetId,
|
|
43696
|
+
payload: {},
|
|
43697
|
+
});
|
|
43698
|
+
}
|
|
43699
|
+
/**
|
|
43700
|
+
* Cria um escopo isolado filho (ex.: para modais, gavetas analíticas ou abas keep-alive).
|
|
43701
|
+
* Impede vazamento acidental de eventos para outras seções da aplicação.
|
|
43702
|
+
*/
|
|
43703
|
+
createChildScope(scopeName) {
|
|
43704
|
+
const child = new PraxisWidgetEventBus();
|
|
43705
|
+
child.parentBus = this;
|
|
43706
|
+
return child;
|
|
43707
|
+
}
|
|
43708
|
+
/**
|
|
43709
|
+
* Aplica um conjunto declarativo de regras de fiação (wiring) entre widgets.
|
|
43710
|
+
* Transforma automaticamente eventos da origem e publica ações ou filtros no destino.
|
|
43711
|
+
*/
|
|
43712
|
+
applyWiring(rules) {
|
|
43713
|
+
const wiringSub = new Subscription();
|
|
43714
|
+
if (!rules || rules.length === 0) {
|
|
43715
|
+
return wiringSub;
|
|
43716
|
+
}
|
|
43717
|
+
for (const rule of rules) {
|
|
43718
|
+
wiringSub.add(this.eventSubject$
|
|
43719
|
+
.pipe(filter((evt) => {
|
|
43720
|
+
// Previne loops de reentrância em eventos já despachados por fiação
|
|
43721
|
+
if (evt.metadata?.['viaWiring']) {
|
|
43722
|
+
return false;
|
|
43723
|
+
}
|
|
43724
|
+
// Verifica widget de origem
|
|
43725
|
+
if (evt.sourceWidgetId !== rule.from.widgetId) {
|
|
43726
|
+
return false;
|
|
43727
|
+
}
|
|
43728
|
+
// Verifica correspondência de evento ou actionId
|
|
43729
|
+
if (rule.from.event && evt.eventType !== rule.from.event) {
|
|
43730
|
+
return false;
|
|
43731
|
+
}
|
|
43732
|
+
if (rule.from.actionId) {
|
|
43733
|
+
const payloadAction = evt.payload?.actionId ||
|
|
43734
|
+
evt.payload?.action ||
|
|
43735
|
+
evt.payload?.id;
|
|
43736
|
+
if (payloadAction !== rule.from.actionId) {
|
|
43737
|
+
return false;
|
|
43738
|
+
}
|
|
43739
|
+
}
|
|
43740
|
+
return true;
|
|
43741
|
+
}))
|
|
43742
|
+
.subscribe((sourceEvt) => {
|
|
43743
|
+
let transformedPayload;
|
|
43744
|
+
if (typeof rule.transform === 'function') {
|
|
43745
|
+
transformedPayload = rule.transform(sourceEvt.payload);
|
|
43746
|
+
}
|
|
43747
|
+
else if (rule.transform && typeof rule.transform === 'object') {
|
|
43748
|
+
transformedPayload = { ...rule.transform };
|
|
43749
|
+
}
|
|
43750
|
+
else {
|
|
43751
|
+
transformedPayload = sourceEvt.payload;
|
|
43752
|
+
}
|
|
43753
|
+
const targetEventType = rule.to.target === 'filterCriteria'
|
|
43754
|
+
? 'filter.apply'
|
|
43755
|
+
: rule.to.target === 'selection'
|
|
43756
|
+
? 'selection.change'
|
|
43757
|
+
: rule.to.target === 'refresh'
|
|
43758
|
+
? 'refresh'
|
|
43759
|
+
: 'action.dispatch';
|
|
43760
|
+
this.publish({
|
|
43761
|
+
sourceWidgetId: rule.from.widgetId,
|
|
43762
|
+
targetWidgetId: rule.to.widgetId,
|
|
43763
|
+
eventType: targetEventType,
|
|
43764
|
+
payload: transformedPayload,
|
|
43765
|
+
metadata: {
|
|
43766
|
+
targetProperty: rule.to.target,
|
|
43767
|
+
viaWiring: true,
|
|
43768
|
+
},
|
|
43769
|
+
});
|
|
43770
|
+
}));
|
|
43771
|
+
}
|
|
43772
|
+
this.internalSubs.add(wiringSub);
|
|
43773
|
+
return wiringSub;
|
|
43774
|
+
}
|
|
43775
|
+
ngOnDestroy() {
|
|
43776
|
+
this.internalSubs.unsubscribe();
|
|
43777
|
+
this.eventSubject$.complete();
|
|
43778
|
+
}
|
|
43779
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisWidgetEventBus, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
43780
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisWidgetEventBus, providedIn: 'root' });
|
|
43781
|
+
}
|
|
43782
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisWidgetEventBus, decorators: [{
|
|
43783
|
+
type: Injectable,
|
|
43784
|
+
args: [{ providedIn: 'root' }]
|
|
43785
|
+
}], ctorParameters: () => [] });
|
|
43786
|
+
|
|
41825
43787
|
class DynamicWidgetContextToolbarComponent {
|
|
41826
43788
|
showSize = input(false, ...(ngDevMode ? [{ debugName: "showSize" }] : /* istanbul ignore next */ []));
|
|
41827
43789
|
sizeDisabled = input(false, ...(ngDevMode ? [{ debugName: "sizeDisabled" }] : /* istanbul ignore next */ []));
|
|
@@ -42617,6 +44579,8 @@ const CANVAS_RESIZE_HANDLES = [
|
|
|
42617
44579
|
class DynamicWidgetPageComponent {
|
|
42618
44580
|
widgetSizeTemplate;
|
|
42619
44581
|
pageCanvasHost;
|
|
44582
|
+
widgetEventBus = inject(PraxisWidgetEventBus, { optional: true });
|
|
44583
|
+
wiringSubscription;
|
|
42620
44584
|
page;
|
|
42621
44585
|
context = null;
|
|
42622
44586
|
strictValidation = true;
|
|
@@ -42688,6 +44652,8 @@ class DynamicWidgetPageComponent {
|
|
|
42688
44652
|
blockedCanvasWidgetKey = null;
|
|
42689
44653
|
canvasPreviewState = signal(null, ...(ngDevMode ? [{ debugName: "canvasPreviewState" }] : /* istanbul ignore next */ []));
|
|
42690
44654
|
canvasPreviewInvalidState = signal(false, ...(ngDevMode ? [{ debugName: "canvasPreviewInvalidState" }] : /* istanbul ignore next */ []));
|
|
44655
|
+
canvasPreviewInvalidMessageState = signal(null, ...(ngDevMode ? [{ debugName: "canvasPreviewInvalidMessageState" }] : /* istanbul ignore next */ []));
|
|
44656
|
+
canvasPreviewSwapTargetState = signal(null, ...(ngDevMode ? [{ debugName: "canvasPreviewSwapTargetState" }] : /* istanbul ignore next */ []));
|
|
42691
44657
|
resizeFeedbackState = signal({}, ...(ngDevMode ? [{ debugName: "resizeFeedbackState" }] : /* istanbul ignore next */ []));
|
|
42692
44658
|
resizeFeedbackOrigin = signal(null, ...(ngDevMode ? [{ debugName: "resizeFeedbackOrigin" }] : /* istanbul ignore next */ []));
|
|
42693
44659
|
resizeFeedbackPositions = [
|
|
@@ -42831,6 +44797,7 @@ class DynamicWidgetPageComponent {
|
|
|
42831
44797
|
this.runtimeObservationRegistration = null;
|
|
42832
44798
|
this.hostResizeObserver?.disconnect();
|
|
42833
44799
|
this.hostResizeObserver = undefined;
|
|
44800
|
+
this.wiringSubscription?.unsubscribe();
|
|
42834
44801
|
this.compositionRuntime.destroy();
|
|
42835
44802
|
}
|
|
42836
44803
|
ngOnChanges(changes) {
|
|
@@ -42948,6 +44915,9 @@ class DynamicWidgetPageComponent {
|
|
|
42948
44915
|
if (evt?.output && this.maybeExecuteMappedAction(fromKey, evt)) {
|
|
42949
44916
|
return;
|
|
42950
44917
|
}
|
|
44918
|
+
if (evt?.output === 'queryContextClear') {
|
|
44919
|
+
this.handleQueryContextClear(fromKey, evt);
|
|
44920
|
+
}
|
|
42951
44921
|
const page = this.ensurePageDefinition();
|
|
42952
44922
|
const widgetInputPatchResult = this.applyWidgetInputPatchToPage(page, fromKey, evt);
|
|
42953
44923
|
const pageWithPatchedInputs = widgetInputPatchResult.page;
|
|
@@ -45131,6 +47101,64 @@ class DynamicWidgetPageComponent {
|
|
|
45131
47101
|
findWidgetLoader(key) {
|
|
45132
47102
|
return this.widgetLoaders?.find((loader) => loader.ownerWidgetKey === key);
|
|
45133
47103
|
}
|
|
47104
|
+
handleQueryContextClear(fromKey, _evt) {
|
|
47105
|
+
const page = this.ensurePageDefinition();
|
|
47106
|
+
const links = page.composition?.links || [];
|
|
47107
|
+
if (!links.length) {
|
|
47108
|
+
return;
|
|
47109
|
+
}
|
|
47110
|
+
const statePathsToReset = new Set();
|
|
47111
|
+
const sourceWidgetKeys = new Set();
|
|
47112
|
+
for (const link of links) {
|
|
47113
|
+
if (link.to.kind === 'component-port' &&
|
|
47114
|
+
link.to.ref.widget === fromKey &&
|
|
47115
|
+
(link.to.ref.port === 'queryContext' || link.to.ref.port === 'filterCriteria')) {
|
|
47116
|
+
if (link.from.kind === 'component-port') {
|
|
47117
|
+
sourceWidgetKeys.add(link.from.ref.widget);
|
|
47118
|
+
}
|
|
47119
|
+
else if (link.from.kind === 'state') {
|
|
47120
|
+
statePathsToReset.add(link.from.ref.path);
|
|
47121
|
+
}
|
|
47122
|
+
}
|
|
47123
|
+
}
|
|
47124
|
+
if (statePathsToReset.size > 0) {
|
|
47125
|
+
for (const link of links) {
|
|
47126
|
+
if (link.to.kind === 'state' &&
|
|
47127
|
+
statePathsToReset.has(link.to.ref.path) &&
|
|
47128
|
+
link.from.kind === 'component-port') {
|
|
47129
|
+
sourceWidgetKeys.add(link.from.ref.widget);
|
|
47130
|
+
}
|
|
47131
|
+
}
|
|
47132
|
+
}
|
|
47133
|
+
for (const sourceKey of sourceWidgetKeys) {
|
|
47134
|
+
if (sourceKey === fromKey)
|
|
47135
|
+
continue;
|
|
47136
|
+
const loader = this.findWidgetLoader(sourceKey);
|
|
47137
|
+
if (loader && typeof loader.clearSelection === 'function') {
|
|
47138
|
+
loader.clearSelection();
|
|
47139
|
+
}
|
|
47140
|
+
}
|
|
47141
|
+
if (statePathsToReset.size > 0) {
|
|
47142
|
+
const currentState = this.stateRuntime.normalizeState(page.state);
|
|
47143
|
+
const nextValues = { ...(currentState.values || {}) };
|
|
47144
|
+
let stateChanged = false;
|
|
47145
|
+
for (const path of statePathsToReset) {
|
|
47146
|
+
if (Object.prototype.hasOwnProperty.call(nextValues, path) && nextValues[path] != null) {
|
|
47147
|
+
delete nextValues[path];
|
|
47148
|
+
stateChanged = true;
|
|
47149
|
+
}
|
|
47150
|
+
}
|
|
47151
|
+
if (stateChanged) {
|
|
47152
|
+
const nextState = {
|
|
47153
|
+
...currentState,
|
|
47154
|
+
values: nextValues,
|
|
47155
|
+
};
|
|
47156
|
+
const next = this.clonePageDefinition(page);
|
|
47157
|
+
next.state = nextState;
|
|
47158
|
+
this.applyPageUpdate(next, true, undefined, false, true);
|
|
47159
|
+
}
|
|
47160
|
+
}
|
|
47161
|
+
}
|
|
45134
47162
|
dispatchWidgetComponentSettingsToRuntime(key) {
|
|
45135
47163
|
const loader = this.findWidgetLoader(String(key || '').trim());
|
|
45136
47164
|
if (typeof loader?.dispatchAction !== 'function') {
|
|
@@ -45516,6 +47544,12 @@ class DynamicWidgetPageComponent {
|
|
|
45516
47544
|
this.pageState = runtime.state;
|
|
45517
47545
|
this.pageRuntime = runtime;
|
|
45518
47546
|
this.applyResponsivePresentation(hydrated, hydrated?.widgets || stateBoundWidgets, runtime);
|
|
47547
|
+
if (this.widgetEventBus) {
|
|
47548
|
+
this.wiringSubscription?.unsubscribe();
|
|
47549
|
+
if (hydrated?.wiring && hydrated.wiring.length > 0) {
|
|
47550
|
+
this.wiringSubscription = this.widgetEventBus.applyWiring(hydrated.wiring);
|
|
47551
|
+
}
|
|
47552
|
+
}
|
|
45519
47553
|
const previousAuthoredPage = this.authoredPageDefinition;
|
|
45520
47554
|
const canonicalPage = this.toPersistedCanonicalPage(hydrated);
|
|
45521
47555
|
const authoredPageChanged = !previousAuthoredPage ||
|
|
@@ -45684,8 +47718,7 @@ class DynamicWidgetPageComponent {
|
|
|
45684
47718
|
this.activeCanvasInteraction = null;
|
|
45685
47719
|
this.resizeFeedbackOrigin.set(null);
|
|
45686
47720
|
this.releaseCanvasPointerCapture(interaction);
|
|
45687
|
-
this.
|
|
45688
|
-
this.canvasPreviewInvalidState.set(false);
|
|
47721
|
+
this.resetCanvasPreviewState();
|
|
45689
47722
|
this.transientCanvasItemsState.set({});
|
|
45690
47723
|
if (interaction.kind === 'resize') {
|
|
45691
47724
|
const moved = interaction.moved || Math.hypot(event.clientX - interaction.startX, event.clientY - interaction.startY) >= 4;
|
|
@@ -45705,15 +47738,13 @@ class DynamicWidgetPageComponent {
|
|
|
45705
47738
|
if (interaction.kind === 'drag') {
|
|
45706
47739
|
const result = this.updateCanvasItem(interaction.widgetKey, (item) => this.applyCanvasDrag(item, interaction, colDelta, rowDelta), true, this.canvasAnnouncement('drag', interaction.widgetKey), this.blockedCanvasAnnouncement('drag'), 'drag');
|
|
45707
47740
|
if (result.blocked) {
|
|
45708
|
-
this.
|
|
45709
|
-
this.canvasPreviewInvalidState.set(false);
|
|
47741
|
+
this.resetCanvasPreviewState();
|
|
45710
47742
|
}
|
|
45711
47743
|
return;
|
|
45712
47744
|
}
|
|
45713
47745
|
const result = this.updateCanvasItem(interaction.widgetKey, (item) => this.applyCanvasResize(item, interaction, colDelta, rowDelta), true, this.canvasAnnouncement('resize', interaction.widgetKey), this.blockedCanvasAnnouncement('resize'), 'resize');
|
|
45714
47746
|
if (result.blocked) {
|
|
45715
|
-
this.
|
|
45716
|
-
this.canvasPreviewInvalidState.set(false);
|
|
47747
|
+
this.resetCanvasPreviewState();
|
|
45717
47748
|
}
|
|
45718
47749
|
}
|
|
45719
47750
|
onCanvasPointerCancel(event) {
|
|
@@ -46212,8 +48243,7 @@ class DynamicWidgetPageComponent {
|
|
|
46212
48243
|
this.sizeEditorNotice.set(null);
|
|
46213
48244
|
this.transientCanvasItemsState.set({});
|
|
46214
48245
|
this.resizeFeedbackState.set({});
|
|
46215
|
-
this.
|
|
46216
|
-
this.canvasPreviewInvalidState.set(false);
|
|
48246
|
+
this.resetCanvasPreviewState();
|
|
46217
48247
|
if (restoreChoices) {
|
|
46218
48248
|
const revision = this.sizePreviewRevision;
|
|
46219
48249
|
afterNextRender({ read: () => {
|
|
@@ -47126,6 +49156,34 @@ class DynamicWidgetPageComponent {
|
|
|
47126
49156
|
canvasPreviewInvalid() {
|
|
47127
49157
|
return this.canvasPreviewInvalidState();
|
|
47128
49158
|
}
|
|
49159
|
+
canvasPreviewInvalidMessage() {
|
|
49160
|
+
return this.canvasPreviewInvalidMessageState() || this.t('canvas.blocked', 'Posição ocupada');
|
|
49161
|
+
}
|
|
49162
|
+
canvasPreviewSwapTarget() {
|
|
49163
|
+
return this.canvasPreviewSwapTargetState();
|
|
49164
|
+
}
|
|
49165
|
+
canvasPreviewSwapKey() {
|
|
49166
|
+
return this.canvasPreviewSwapTarget()?.widgetKey || null;
|
|
49167
|
+
}
|
|
49168
|
+
canvasPreviewSwapMessage(target) {
|
|
49169
|
+
const targetKey = target.widgetKey || '';
|
|
49170
|
+
const targetLabel = this.resolveWidgetDisplayLabel(targetKey);
|
|
49171
|
+
return this.t('canvas.swapWith', 'Trocar com {{target}}', { target: targetLabel });
|
|
49172
|
+
}
|
|
49173
|
+
resolveWidgetDisplayLabel(widgetKey) {
|
|
49174
|
+
const widget = this.widgets().find((w) => w.key === widgetKey);
|
|
49175
|
+
if (widget) {
|
|
49176
|
+
return this.resolveWidgetDisplayName(widget);
|
|
49177
|
+
}
|
|
49178
|
+
return widgetKey;
|
|
49179
|
+
}
|
|
49180
|
+
resetCanvasPreviewState() {
|
|
49181
|
+
this.canvasPreviewState.set(null);
|
|
49182
|
+
this.canvasPreviewInvalidState.set(false);
|
|
49183
|
+
this.canvasPreviewInvalidMessageState.set(null);
|
|
49184
|
+
this.canvasPreviewSwapTargetState.set(null);
|
|
49185
|
+
this.blockedCanvasWidgetKey = null;
|
|
49186
|
+
}
|
|
47129
49187
|
startCanvasDrag(widgetKey, event) {
|
|
47130
49188
|
if (!this.canCustomizeCanvas())
|
|
47131
49189
|
return;
|
|
@@ -47283,9 +49341,7 @@ class DynamicWidgetPageComponent {
|
|
|
47283
49341
|
this.resizeClickTargets = [];
|
|
47284
49342
|
this.resizeFeedbackOrigin.set(null);
|
|
47285
49343
|
this.releaseCanvasPointerCapture(interaction);
|
|
47286
|
-
this.
|
|
47287
|
-
this.canvasPreviewState.set(null);
|
|
47288
|
-
this.canvasPreviewInvalidState.set(false);
|
|
49344
|
+
this.resetCanvasPreviewState();
|
|
47289
49345
|
this.transientCanvasItemsState.set({});
|
|
47290
49346
|
this.resizeFeedbackState.set({});
|
|
47291
49347
|
}
|
|
@@ -47402,6 +49458,13 @@ class DynamicWidgetPageComponent {
|
|
|
47402
49458
|
: undefined,
|
|
47403
49459
|
});
|
|
47404
49460
|
this.canvasPreviewInvalidState.set(true);
|
|
49461
|
+
const invalidMsg = placement?.blockedReason === 'lock-position'
|
|
49462
|
+
? this.t('canvas.blockedLocked', 'Posição bloqueada — widget fixado')
|
|
49463
|
+
: placement?.blockedReason === 'asymmetric-swap'
|
|
49464
|
+
? this.t('canvas.blockedAsymmetricSwap', 'Espaço incompatível para troca direta')
|
|
49465
|
+
: this.t('canvas.blocked', 'Posição ocupada');
|
|
49466
|
+
this.canvasPreviewInvalidMessageState.set(invalidMsg);
|
|
49467
|
+
this.canvasPreviewSwapTargetState.set(null);
|
|
47405
49468
|
if (blockedAnnouncement) {
|
|
47406
49469
|
this.layoutAnnouncement = blockedAnnouncement;
|
|
47407
49470
|
}
|
|
@@ -47409,11 +49472,17 @@ class DynamicWidgetPageComponent {
|
|
|
47409
49472
|
}
|
|
47410
49473
|
this.blockedCanvasWidgetKey = null;
|
|
47411
49474
|
this.canvasPreviewInvalidState.set(false);
|
|
49475
|
+
this.canvasPreviewInvalidMessageState.set(null);
|
|
49476
|
+
if (placement?.swappedWith && placement.targetItem) {
|
|
49477
|
+
this.canvasPreviewSwapTargetState.set(placement.targetItem);
|
|
49478
|
+
}
|
|
49479
|
+
else {
|
|
49480
|
+
this.canvasPreviewSwapTargetState.set(null);
|
|
49481
|
+
}
|
|
47412
49482
|
const changed = placement.changed;
|
|
47413
49483
|
if (!changed) {
|
|
47414
49484
|
this.transientCanvasItemsState.set({});
|
|
47415
|
-
this.
|
|
47416
|
-
this.canvasPreviewInvalidState.set(false);
|
|
49485
|
+
this.resetCanvasPreviewState();
|
|
47417
49486
|
return { changed: false, blocked: false };
|
|
47418
49487
|
}
|
|
47419
49488
|
if (announcement && changed) {
|
|
@@ -47431,8 +49500,7 @@ class DynamicWidgetPageComponent {
|
|
|
47431
49500
|
};
|
|
47432
49501
|
}
|
|
47433
49502
|
this.transientCanvasItemsState.set({});
|
|
47434
|
-
this.
|
|
47435
|
-
this.canvasPreviewInvalidState.set(false);
|
|
49503
|
+
this.resetCanvasPreviewState();
|
|
47436
49504
|
this.applyAuthoringPageUpdate(page, true);
|
|
47437
49505
|
}
|
|
47438
49506
|
else {
|
|
@@ -47456,6 +49524,7 @@ class DynamicWidgetPageComponent {
|
|
|
47456
49524
|
}
|
|
47457
49525
|
: null);
|
|
47458
49526
|
this.canvasPreviewInvalidState.set(false);
|
|
49527
|
+
this.canvasPreviewInvalidMessageState.set(null);
|
|
47459
49528
|
}
|
|
47460
49529
|
return { changed, blocked: false, swappedWith: placement.swappedWith };
|
|
47461
49530
|
}
|
|
@@ -47496,9 +49565,7 @@ class DynamicWidgetPageComponent {
|
|
|
47496
49565
|
if (persist) {
|
|
47497
49566
|
this.resizeFeedbackState.set({});
|
|
47498
49567
|
this.transientCanvasItemsState.set({});
|
|
47499
|
-
this.
|
|
47500
|
-
this.canvasPreviewInvalidState.set(false);
|
|
47501
|
-
this.blockedCanvasWidgetKey = null;
|
|
49568
|
+
this.resetCanvasPreviewState();
|
|
47502
49569
|
if (changed) {
|
|
47503
49570
|
const target = this.resolveCanvasTarget(page);
|
|
47504
49571
|
const affected = Object.keys(placement.items).filter(itemKey => !this.isSameCanvasItem(canvas.items[itemKey], placement.items[itemKey]));
|
|
@@ -47527,6 +49594,8 @@ class DynamicWidgetPageComponent {
|
|
|
47527
49594
|
// Render the real clamped distribution, never an impossible overlapping ghost.
|
|
47528
49595
|
this.canvasPreviewState.set(placement.primaryItem);
|
|
47529
49596
|
this.canvasPreviewInvalidState.set(false);
|
|
49597
|
+
this.canvasPreviewInvalidMessageState.set(null);
|
|
49598
|
+
this.canvasPreviewSwapTargetState.set(null);
|
|
47530
49599
|
this.blockedCanvasWidgetKey = null;
|
|
47531
49600
|
}
|
|
47532
49601
|
return { changed, blocked: limited };
|
|
@@ -47706,7 +49775,12 @@ class DynamicWidgetPageComponent {
|
|
|
47706
49775
|
};
|
|
47707
49776
|
}
|
|
47708
49777
|
resolveCanvasCollisionPolicy(canvas) {
|
|
47709
|
-
|
|
49778
|
+
const policy = canvas.collisionPolicy;
|
|
49779
|
+
if (policy === 'swap')
|
|
49780
|
+
return 'swap';
|
|
49781
|
+
if (policy === 'push-down' || policy === 'cascade')
|
|
49782
|
+
return 'push-down';
|
|
49783
|
+
return 'block';
|
|
47710
49784
|
}
|
|
47711
49785
|
resolveCanvasPlacement(widgetKey, current, candidate, canvas, collisionPolicy) {
|
|
47712
49786
|
const collisions = this.findCanvasCollisions(widgetKey, candidate, canvas);
|
|
@@ -47718,36 +49792,115 @@ class DynamicWidgetPageComponent {
|
|
|
47718
49792
|
items: { [widgetKey]: candidate },
|
|
47719
49793
|
};
|
|
47720
49794
|
}
|
|
49795
|
+
if (collisionPolicy === 'push-down') {
|
|
49796
|
+
const pushDownResult = this.buildCanvasPushDownItems(widgetKey, candidate, canvas);
|
|
49797
|
+
if (!pushDownResult || pushDownResult.blocked) {
|
|
49798
|
+
return {
|
|
49799
|
+
blocked: true,
|
|
49800
|
+
changed: false,
|
|
49801
|
+
primaryItem: candidate,
|
|
49802
|
+
items: { [widgetKey]: candidate },
|
|
49803
|
+
blockedReason: pushDownResult?.blockedReason || 'collision',
|
|
49804
|
+
};
|
|
49805
|
+
}
|
|
49806
|
+
const changed = Object.entries(pushDownResult.items).some(([k, item]) => {
|
|
49807
|
+
const orig = canvas.items[k];
|
|
49808
|
+
return !orig || !this.isSameCanvasItem(orig, item);
|
|
49809
|
+
});
|
|
49810
|
+
return {
|
|
49811
|
+
blocked: false,
|
|
49812
|
+
changed,
|
|
49813
|
+
primaryItem: candidate,
|
|
49814
|
+
items: pushDownResult.items,
|
|
49815
|
+
};
|
|
49816
|
+
}
|
|
47721
49817
|
if (collisionPolicy !== 'swap' || collisions.length !== 1) {
|
|
47722
49818
|
return {
|
|
47723
49819
|
blocked: true,
|
|
47724
49820
|
changed: false,
|
|
47725
49821
|
primaryItem: candidate,
|
|
47726
49822
|
items: { [widgetKey]: candidate },
|
|
49823
|
+
blockedReason: 'collision',
|
|
47727
49824
|
};
|
|
47728
49825
|
}
|
|
47729
49826
|
const [collision] = collisions;
|
|
47730
|
-
const
|
|
47731
|
-
|
|
49827
|
+
const targetWithKey = { ...collision.item, widgetKey: collision.key };
|
|
49828
|
+
const swapResult = this.buildCanvasSwapItem(widgetKey, current, collision.key, collision.item, candidate, canvas);
|
|
49829
|
+
if (!swapResult.item) {
|
|
47732
49830
|
return {
|
|
47733
49831
|
blocked: true,
|
|
47734
49832
|
changed: false,
|
|
47735
49833
|
primaryItem: candidate,
|
|
47736
49834
|
items: { [widgetKey]: candidate },
|
|
49835
|
+
blockedReason: swapResult.blockedReason || 'collision',
|
|
49836
|
+
targetItem: targetWithKey,
|
|
47737
49837
|
};
|
|
47738
49838
|
}
|
|
47739
49839
|
return {
|
|
47740
49840
|
blocked: false,
|
|
47741
49841
|
changed: !this.isSameCanvasItem(current, candidate) ||
|
|
47742
|
-
!this.isSameCanvasItem(collision.item,
|
|
49842
|
+
!this.isSameCanvasItem(collision.item, swapResult.item),
|
|
47743
49843
|
primaryItem: candidate,
|
|
47744
49844
|
items: {
|
|
47745
49845
|
[widgetKey]: candidate,
|
|
47746
|
-
[collision.key]:
|
|
49846
|
+
[collision.key]: swapResult.item,
|
|
47747
49847
|
},
|
|
47748
49848
|
swappedWith: collision.key,
|
|
49849
|
+
targetItem: targetWithKey,
|
|
47749
49850
|
};
|
|
47750
49851
|
}
|
|
49852
|
+
buildCanvasPushDownItems(movingWidgetKey, candidate, canvas) {
|
|
49853
|
+
const resultItems = {
|
|
49854
|
+
[movingWidgetKey]: candidate,
|
|
49855
|
+
};
|
|
49856
|
+
const otherItems = Object.entries(canvas.items || {})
|
|
49857
|
+
.filter(([key]) => key !== movingWidgetKey)
|
|
49858
|
+
.map(([key, item]) => ({ key, item: { ...item } }));
|
|
49859
|
+
otherItems.sort((a, b) => a.item.row - b.item.row);
|
|
49860
|
+
let hasDisplacements = true;
|
|
49861
|
+
let iterations = 0;
|
|
49862
|
+
const maxIterations = otherItems.length * 2 + 10;
|
|
49863
|
+
while (hasDisplacements && iterations < maxIterations) {
|
|
49864
|
+
hasDisplacements = false;
|
|
49865
|
+
iterations++;
|
|
49866
|
+
for (const other of otherItems) {
|
|
49867
|
+
for (const [placedKey, placedItem] of Object.entries(resultItems)) {
|
|
49868
|
+
if (other.key === placedKey)
|
|
49869
|
+
continue;
|
|
49870
|
+
if (this.canvasItemsOverlap(other.item, placedItem)) {
|
|
49871
|
+
if (other.item.constraints?.lockPosition) {
|
|
49872
|
+
return {
|
|
49873
|
+
blocked: true,
|
|
49874
|
+
items: { [movingWidgetKey]: candidate },
|
|
49875
|
+
blockedReason: 'lock-position',
|
|
49876
|
+
};
|
|
49877
|
+
}
|
|
49878
|
+
const nextRow = placedItem.row + placedItem.rowSpan;
|
|
49879
|
+
if (nextRow > other.item.row) {
|
|
49880
|
+
other.item.row = nextRow;
|
|
49881
|
+
hasDisplacements = true;
|
|
49882
|
+
}
|
|
49883
|
+
}
|
|
49884
|
+
}
|
|
49885
|
+
resultItems[other.key] = other.item;
|
|
49886
|
+
}
|
|
49887
|
+
}
|
|
49888
|
+
for (const [key, item] of Object.entries(resultItems)) {
|
|
49889
|
+
if (key !== movingWidgetKey) {
|
|
49890
|
+
const original = canvas.items[key];
|
|
49891
|
+
if (original &&
|
|
49892
|
+
original.constraints?.lockPosition &&
|
|
49893
|
+
!this.isSameCanvasItem(original, item)) {
|
|
49894
|
+
return {
|
|
49895
|
+
blocked: true,
|
|
49896
|
+
items: { [movingWidgetKey]: candidate },
|
|
49897
|
+
blockedReason: 'lock-position',
|
|
49898
|
+
};
|
|
49899
|
+
}
|
|
49900
|
+
}
|
|
49901
|
+
}
|
|
49902
|
+
return { blocked: false, items: resultItems };
|
|
49903
|
+
}
|
|
47751
49904
|
findCanvasCollisions(widgetKey, candidate, canvas) {
|
|
47752
49905
|
return Object.entries(canvas.items || {})
|
|
47753
49906
|
.filter(([otherKey, otherItem]) => otherKey !== widgetKey &&
|
|
@@ -47756,18 +49909,18 @@ class DynamicWidgetPageComponent {
|
|
|
47756
49909
|
}
|
|
47757
49910
|
buildCanvasSwapItem(movingWidgetKey, sourceItem, targetWidgetKey, targetItem, movedItem, canvas) {
|
|
47758
49911
|
if (targetItem.constraints?.lockPosition) {
|
|
47759
|
-
return null;
|
|
49912
|
+
return { item: null, blockedReason: 'lock-position' };
|
|
47760
49913
|
}
|
|
47761
49914
|
const intendedSwapItem = {
|
|
47762
49915
|
...targetItem,
|
|
47763
49916
|
col: sourceItem.col,
|
|
47764
49917
|
row: sourceItem.row,
|
|
47765
|
-
colSpan:
|
|
47766
|
-
rowSpan:
|
|
49918
|
+
colSpan: targetItem.colSpan,
|
|
49919
|
+
rowSpan: targetItem.rowSpan,
|
|
47767
49920
|
};
|
|
47768
49921
|
const normalizedSwapItem = this.normalizeCanvasItem(intendedSwapItem, canvas.columns);
|
|
47769
49922
|
if (!this.isSameCanvasItem(intendedSwapItem, normalizedSwapItem)) {
|
|
47770
|
-
return null;
|
|
49923
|
+
return { item: null, blockedReason: 'asymmetric-swap' };
|
|
47771
49924
|
}
|
|
47772
49925
|
const collides = Object.entries(canvas.items || {}).some(([otherKey, otherItem]) => {
|
|
47773
49926
|
if (otherKey === movingWidgetKey || otherKey === targetWidgetKey) {
|
|
@@ -47776,9 +49929,9 @@ class DynamicWidgetPageComponent {
|
|
|
47776
49929
|
return this.canvasItemsOverlap(normalizedSwapItem, otherItem);
|
|
47777
49930
|
});
|
|
47778
49931
|
if (collides || this.canvasItemsOverlap(normalizedSwapItem, movedItem)) {
|
|
47779
|
-
return null;
|
|
49932
|
+
return { item: null, blockedReason: 'asymmetric-swap' };
|
|
47780
49933
|
}
|
|
47781
|
-
return normalizedSwapItem;
|
|
49934
|
+
return { item: normalizedSwapItem };
|
|
47782
49935
|
}
|
|
47783
49936
|
canPlaceCanvasItem(widgetKey, candidate, canvas) {
|
|
47784
49937
|
return !Object.entries(canvas.items || {}).some(([otherKey, otherItem]) => otherKey !== widgetKey && this.canvasItemsOverlap(candidate, otherItem));
|
|
@@ -48609,9 +50762,22 @@ class DynamicWidgetPageComponent {
|
|
|
48609
50762
|
<div
|
|
48610
50763
|
class="pdx-canvas-snap-preview"
|
|
48611
50764
|
[class.pdx-canvas-snap-preview--invalid]="canvasPreviewInvalid()"
|
|
50765
|
+
[class.pdx-canvas-snap-preview--swap]="canvasPreviewSwapKey()"
|
|
48612
50766
|
[style.gridColumn]="canvasPreviewGridColumn()"
|
|
48613
50767
|
[style.gridRow]="canvasPreviewGridRow()"
|
|
48614
|
-
|
|
50768
|
+
>
|
|
50769
|
+
@if (canvasPreviewInvalid()) {
|
|
50770
|
+
<div class="pdx-canvas-snap-preview__badge pdx-canvas-snap-preview__badge--invalid">
|
|
50771
|
+
<mat-icon class="pdx-canvas-snap-preview__badge-icon">block</mat-icon>
|
|
50772
|
+
<span>{{ canvasPreviewInvalidMessage() }}</span>
|
|
50773
|
+
</div>
|
|
50774
|
+
} @else if (canvasPreviewSwapTarget(); as swapTarget) {
|
|
50775
|
+
<div class="pdx-canvas-snap-preview__badge pdx-canvas-snap-preview__badge--swap">
|
|
50776
|
+
<mat-icon class="pdx-canvas-snap-preview__badge-icon">swap_horiz</mat-icon>
|
|
50777
|
+
<span>{{ canvasPreviewSwapMessage(swapTarget) }}</span>
|
|
50778
|
+
</div>
|
|
50779
|
+
}
|
|
50780
|
+
</div>
|
|
48615
50781
|
}
|
|
48616
50782
|
} @else if (renderedGroups().length) {
|
|
48617
50783
|
@for (group of renderedGroups(); track group.id) {
|
|
@@ -48878,7 +51044,7 @@ class DynamicWidgetPageComponent {
|
|
|
48878
51044
|
</div>
|
|
48879
51045
|
}
|
|
48880
51046
|
</div>
|
|
48881
|
-
`, isInline: true, styles: [":host{display:block;min-width:0}.pdx-page-wrapper{box-sizing:border-box;padding-inline:var(--pdx-page-padding-inline, 0px);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, 60px);padding-block-end:22px;padding-inline:22px;box-sizing:border-box}.pdx-page-settings{position:sticky;top:8px;z-index:2;color:inherit;margin-bottom:6px}.pdx-widget{position:relative;background:var(--pfx-surface, transparent);border-radius:6px;min-width:0;min-height:0}.pdx-widget--interactive{cursor:pointer}.pdx-widget--selected:before{content:\"\";position:absolute;inset:0;border:1px dashed color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent);border-radius:14px;pointer-events:none;z-index:1;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent),0 8px 20px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent)}.pdx-widget--canvas{align-self:stretch;--pdx-resize-gradient-diagonal-se: linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-widget--canvas:after{content:\"\";position:absolute;inset:0;padding:2px;border-radius:14px;background:var(--pdx-active-resize-gradient);opacity:0;pointer-events:none;transition:opacity .14s ease,filter .14s ease;filter:saturate(1.02) drop-shadow(0 0 5px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude}.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{content:\"\";position:absolute;inset:0;border-radius:14px;pointer-events:none;z-index:1;transition:opacity .14s ease,box-shadow .14s ease,border-color .14s ease}.pdx-widget--canvas-blocked:before{border:1px solid color-mix(in srgb,var(--md-sys-color-error) 74%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 20%,transparent),0 10px 24px color-mix(in srgb,var(--md-sys-color-error) 12%,transparent)}.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:hover):after,.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:focus-visible):after{opacity:.82}[data-resize-feedback=valid]{--pdx-resize-feedback-color: #27864b}[data-resize-feedback=minimum]{--pdx-resize-feedback-color: #bc8a00}[data-resize-feedback=blocked]{--pdx-resize-feedback-color: var(--md-sys-color-error)}.pdx-widget--canvas[data-resize-feedback]:after{background:var(--pdx-resize-feedback-color);opacity:1;z-index:2}.pdx-resize-feedback{position:absolute;inset-inline:8px;bottom:8px;width:fit-content;max-width:calc(100% - 16px);box-sizing:border-box;display:flex;align-items:center;gap:6px;padding:4px 8px;border:2px solid var(--pdx-resize-feedback-color);border-radius:8px;color:var(--md-sys-color-on-surface);background:var(--md-sys-color-surface);font-size:12px;line-height:18px;pointer-events:none;z-index:3}.pdx-standalone-size-editor{box-sizing:border-box;width:min(720px,calc(100vw - 32px));max-height:calc(100vh - 32px);overflow:auto;padding:20px;border:1px solid var(--md-sys-color-outline-variant);border-radius:16px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);box-shadow:var(--mat-sys-level3, 0 8px 24px rgba(0, 0, 0, .24))}.pdx-standalone-size-editor__footer{display:flex;justify-content:flex-end;gap:8px;margin-top:20px;padding-top:16px;border-top:1px solid var(--md-sys-color-outline-variant)}.pdx-resize-feedback mat-icon{flex:0 0 18px;width:18px;height:18px;font-size:18px}.pdx-resize-feedback--floating{position:static;max-width:min(320px,calc(100vw - 24px));overflow-wrap:anywhere}.pdx-resize-feedback--floating strong{display:block}.pdx-canvas-edges{position:absolute;inset:0;pointer-events:none;z-index:5}.pdx-canvas-edge{position:absolute;display:grid;place-items:center;box-sizing:border-box;width:min(24px,50%);height:min(24px,50%);padding:0;border:0;background:transparent;color:var(--md-sys-color-primary);pointer-events:auto;touch-action:none;transform:translate(-50%,-50%)}.pdx-canvas-edge:after{content:\"\";box-sizing:border-box;width:min(12px,100%);height:min(12px,100%);pointer-events:none;border:2px solid currentColor;border-radius:2px;background:var(--md-sys-color-surface)}.pdx-canvas-edge:hover:after,.pdx-canvas-edge:focus-visible:after{background:var(--md-sys-color-primary-container)}.pdx-canvas-edge[data-canvas-edge=north-west]{left:0;top:0;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=north]{left:50%;top:0;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=north-east]{left:100%;top:0;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=east]{left:100%;top:50%;width:min(24px,100%);cursor:ew-resize}.pdx-canvas-edge[data-canvas-edge=south-east]{left:100%;top:100%;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=south]{left:50%;top:100%;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=south-west]{left:0;top:100%;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=west]{left:0;top:50%;width:min(24px,100%);cursor:ew-resize}.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.expanded)>.pdx-page>.pdx-widget>.pdx-canvas-edges,.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.fullscreen)>.pdx-page>.pdx-widget>.pdx-canvas-edges{display:none}.pdx-widget--canvas:focus-visible,.pdx-canvas-edge:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-snap-preview{position:relative;align-self:stretch;border-radius:12px;pointer-events:none;z-index:0;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent),color-mix(in srgb,var(--md-sys-color-tertiary) 12%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 42%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 55%,transparent);animation:pdx-snap-preview-pulse .48s ease-out infinite alternate}.pdx-canvas-snap-preview:before,.pdx-canvas-snap-preview:after{content:\"\";position:absolute;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary) 82%,var(--md-sys-color-tertiary) 18%);opacity:.72}.pdx-canvas-snap-preview:before{inset:0 auto 0 0;width:3px}.pdx-canvas-snap-preview:after{inset:0 0 auto;height:3px}.pdx-canvas-snap-preview--invalid{background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-error) 18%,transparent),color-mix(in srgb,var(--md-sys-color-error-container) 22%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 58%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 40%,transparent)}.pdx-canvas-snap-preview--invalid:before,.pdx-canvas-snap-preview--invalid:after{background:color-mix(in srgb,var(--md-sys-color-error) 86%,var(--md-sys-color-error-container) 14%)}@media(prefers-reduced-motion:reduce){.pdx-canvas-snap-preview{animation:none}.pdx-widget--canvas:after,.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{transition:none}}@media(forced-colors:active){.pdx-widget--canvas-selected:before{border:2px solid Highlight}.pdx-widget--canvas:focus-visible,.pdx-canvas-edge:focus-visible{outline-color:Highlight}}@keyframes pdx-snap-preview-pulse{0%{opacity:.72;transform:scale(.996)}to{opacity:1;transform:scale(1)}}.pdx-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pdx-group{display:grid;gap:12px;grid-column:1 / -1;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 76%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent)}.pdx-group--hero{padding:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 42%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-low) 86%,transparent))}.pdx-group--rail{align-self:start}.pdx-group-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.pdx-group-title{font-size:.95rem;font-weight:600;color:var(--md-sys-color-on-surface)}.pdx-group-content{display:grid;gap:12px}.pdx-group-content--stack{grid-template-columns:minmax(0,1fr)}.pdx-group-content--row{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.pdx-group-content--grid{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.pdx-group-tabs{display:grid;gap:12px}.pdx-tabs-header{display:flex;flex-wrap:wrap;gap:8px}.pdx-tab-chip{appearance:none;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-lowest);color:var(--md-sys-color-on-surface);border-radius:999px;padding:8px 12px;font:inherit;cursor:pointer}.pdx-tab-chip.active{border-color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 78%,transparent);color:var(--md-sys-color-on-primary-container)}.pdx-page-wrapper.editing .pdx-widget-settings{opacity:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i5$2.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i6$1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: CanvasSizeEditorComponent, selector: "praxis-canvas-size-editor", inputs: ["layoutItems", "resetRevision", "restoredValue", "columns", "freeSpaceWidths", "northFreeSpaceHeight", "northUnavailable", "southFreeSpaceHeight", "southUnavailable", "cornerFreeSpaceSizes", "cornerUnavailable", "expandWidths", "notice", "hasUndo", "canUndo", "width", "height", "contentRows", "rowSpan", "widgetLabel", "scopeLabel", "previewPending", "error"], outputs: ["state", "undo", "preview", "apply", "cancel"] }, { kind: "component", type: DynamicWidgetContextToolbarComponent, selector: "praxis-dynamic-widget-context-toolbar", inputs: ["showSize", "sizeDisabled", "sizeLabel", "toolbarLabel", "contextLabel", "contextTooltip", "showAssistant", "assistantLabel", "assistantTooltip", "showComponentSettings", "componentSettingsBusy", "componentSettingsLabel", "componentSettingsTooltip", "showShellSettings", "shellSettingsLabel", "shellSettingsTooltip", "showRemove", "moreActionsLabel", "removeLabel"], outputs: ["size", "assistant", "componentSettings", "shellSettings", "remove"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { kind: "component", type: WidgetShellComponent, selector: "praxis-widget-shell", inputs: ["shell", "context", "dragSurfaceEnabled", "dragSurfaceLabel"], outputs: ["action", "dragSurfacePointerDown", "dragSurfaceKeydown"] }] });
|
|
51047
|
+
`, isInline: true, styles: [":host{display:block;min-width:0}.pdx-page-wrapper{box-sizing:border-box;padding-inline:var(--pdx-page-padding-inline, 0px);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, 60px);padding-block-end:22px;padding-inline:22px;box-sizing:border-box}.pdx-page-settings{position:sticky;top:8px;z-index:2;color:inherit;margin-bottom:6px}.pdx-widget{position:relative;background:var(--pfx-surface, transparent);border-radius:6px;min-width:0;min-height:0}.pdx-widget--interactive{cursor:pointer}.pdx-widget--selected:before{content:\"\";position:absolute;inset:0;border:1px dashed color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent);border-radius:14px;pointer-events:none;z-index:1;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent),0 8px 20px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent)}.pdx-widget--canvas{align-self:stretch;--pdx-resize-gradient-diagonal-se: linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-widget--canvas:after{content:\"\";position:absolute;inset:0;padding:2px;border-radius:14px;background:var(--pdx-active-resize-gradient);opacity:0;pointer-events:none;transition:opacity .14s ease,filter .14s ease;filter:saturate(1.02) drop-shadow(0 0 5px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude}.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{content:\"\";position:absolute;inset:0;border-radius:14px;pointer-events:none;z-index:1;transition:opacity .14s ease,box-shadow .14s ease,border-color .14s ease}.pdx-widget--canvas-blocked:before{border:1px solid color-mix(in srgb,var(--md-sys-color-error) 74%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 20%,transparent),0 10px 24px color-mix(in srgb,var(--md-sys-color-error) 12%,transparent)}.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:hover):after,.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:focus-visible):after{opacity:.82}[data-resize-feedback=valid]{--pdx-resize-feedback-color: #27864b}[data-resize-feedback=minimum]{--pdx-resize-feedback-color: #bc8a00}[data-resize-feedback=blocked]{--pdx-resize-feedback-color: var(--md-sys-color-error)}.pdx-widget--canvas[data-resize-feedback]:after{background:var(--pdx-resize-feedback-color);opacity:1;z-index:2}.pdx-resize-feedback{position:absolute;inset-inline:8px;bottom:8px;width:fit-content;max-width:calc(100% - 16px);box-sizing:border-box;display:flex;align-items:center;gap:6px;padding:4px 8px;border:2px solid var(--pdx-resize-feedback-color);border-radius:8px;color:var(--md-sys-color-on-surface);background:var(--md-sys-color-surface);font-size:12px;line-height:18px;pointer-events:none;z-index:3}.pdx-standalone-size-editor{box-sizing:border-box;width:min(720px,calc(100vw - 32px));max-height:calc(100vh - 32px);overflow:auto;padding:20px;border:1px solid var(--md-sys-color-outline-variant);border-radius:16px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);box-shadow:var(--mat-sys-level3, 0 8px 24px rgba(0, 0, 0, .24))}.pdx-standalone-size-editor__footer{display:flex;justify-content:flex-end;gap:8px;margin-top:20px;padding-top:16px;border-top:1px solid var(--md-sys-color-outline-variant)}.pdx-resize-feedback mat-icon{flex:0 0 18px;width:18px;height:18px;font-size:18px}.pdx-resize-feedback--floating{position:static;max-width:min(320px,calc(100vw - 24px));overflow-wrap:anywhere}.pdx-resize-feedback--floating strong{display:block}.pdx-canvas-edges{position:absolute;inset:0;pointer-events:none;z-index:5}.pdx-canvas-edge{position:absolute;display:grid;place-items:center;box-sizing:border-box;width:min(24px,50%);height:min(24px,50%);padding:0;border:0;background:transparent;color:var(--md-sys-color-primary);pointer-events:auto;touch-action:none;transform:translate(-50%,-50%)}.pdx-canvas-edge:after{content:\"\";box-sizing:border-box;width:min(12px,100%);height:min(12px,100%);pointer-events:none;border:2px solid currentColor;border-radius:2px;background:var(--md-sys-color-surface)}.pdx-canvas-edge:hover:after,.pdx-canvas-edge:focus-visible:after{background:var(--md-sys-color-primary-container)}.pdx-canvas-edge[data-canvas-edge=north-west]{left:0;top:0;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=north]{left:50%;top:0;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=north-east]{left:100%;top:0;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=east]{left:100%;top:50%;width:min(24px,100%);cursor:ew-resize}.pdx-canvas-edge[data-canvas-edge=south-east]{left:100%;top:100%;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=south]{left:50%;top:100%;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=south-west]{left:0;top:100%;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=west]{left:0;top:50%;width:min(24px,100%);cursor:ew-resize}.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.expanded)>.pdx-page>.pdx-widget>.pdx-canvas-edges,.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.fullscreen)>.pdx-page>.pdx-widget>.pdx-canvas-edges{display:none}.pdx-widget--canvas:focus-visible,.pdx-canvas-edge:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-snap-preview{position:relative;display:flex;align-items:center;justify-content:center;align-self:stretch;border-radius:12px;pointer-events:none;z-index:2;background:color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent);box-shadow:inset 0 0 0 1.5px color-mix(in srgb,var(--md-sys-color-primary) 45%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 60%,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:color-mix(in srgb,var(--md-sys-color-error) 4%,transparent);box-shadow:inset 0 0 0 1.5px color-mix(in srgb,var(--md-sys-color-error) 65%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 60%,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-snap-preview--swap{background:color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent);box-shadow:inset 0 0 0 1.5px color-mix(in srgb,var(--md-sys-color-primary) 65%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 60%,transparent)}.pdx-canvas-snap-preview--swap:before,.pdx-canvas-snap-preview--swap:after{background:color-mix(in srgb,var(--md-sys-color-primary) 86%,var(--md-sys-color-tertiary) 14%)}.pdx-canvas-snap-preview__badge{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;border-radius:999px;font-size:12px;font-weight:600;line-height:1.2;letter-spacing:.02em;white-space:nowrap;background:var(--md-sys-color-surface-container-highest, #ffffff);color:var(--md-sys-color-on-surface, #1e293b);box-shadow:0 4px 16px color-mix(in srgb,var(--mat-sys-shadow, #000) 20%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 40%,transparent);pointer-events:none}.pdx-canvas-snap-preview__badge-icon{font-size:16px;width:16px;height:16px;line-height:16px}.pdx-canvas-snap-preview__badge--invalid{color:var(--md-sys-color-error, #ba1a1a);border-color:color-mix(in srgb,var(--md-sys-color-error) 30%,transparent)}.pdx-canvas-snap-preview__badge--swap{color:var(--md-sys-color-primary, #0061a4);border-color:color-mix(in srgb,var(--md-sys-color-primary) 30%,transparent)}@media(prefers-reduced-motion:reduce){.pdx-canvas-snap-preview{animation:none}.pdx-widget--canvas:after,.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{transition:none}}@media(forced-colors:active){.pdx-widget--canvas-selected:before{border:2px solid Highlight}.pdx-widget--canvas:focus-visible,.pdx-canvas-edge:focus-visible{outline-color:Highlight}}@keyframes pdx-snap-preview-pulse{0%{opacity:.72;transform:scale(.996)}to{opacity:1;transform:scale(1)}}.pdx-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pdx-group{display:grid;gap:12px;grid-column:1 / -1;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 76%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent)}.pdx-group--hero{padding:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 42%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-low) 86%,transparent))}.pdx-group--rail{align-self:start}.pdx-group-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.pdx-group-title{font-size:.95rem;font-weight:600;color:var(--md-sys-color-on-surface)}.pdx-group-content{display:grid;gap:12px}.pdx-group-content--stack{grid-template-columns:minmax(0,1fr)}.pdx-group-content--row{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.pdx-group-content--grid{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.pdx-group-tabs{display:grid;gap:12px}.pdx-tabs-header{display:flex;flex-wrap:wrap;gap:8px}.pdx-tab-chip{appearance:none;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-lowest);color:var(--md-sys-color-on-surface);border-radius:999px;padding:8px 12px;font:inherit;cursor:pointer}.pdx-tab-chip.active{border-color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 78%,transparent);color:var(--md-sys-color-on-primary-container)}.pdx-page-wrapper.editing .pdx-widget-settings{opacity:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i5$2.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i6$1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: CanvasSizeEditorComponent, selector: "praxis-canvas-size-editor", inputs: ["layoutItems", "resetRevision", "restoredValue", "columns", "freeSpaceWidths", "northFreeSpaceHeight", "northUnavailable", "southFreeSpaceHeight", "southUnavailable", "cornerFreeSpaceSizes", "cornerUnavailable", "expandWidths", "notice", "hasUndo", "canUndo", "width", "height", "contentRows", "rowSpan", "widgetLabel", "scopeLabel", "previewPending", "error"], outputs: ["state", "undo", "preview", "apply", "cancel"] }, { kind: "component", type: DynamicWidgetContextToolbarComponent, selector: "praxis-dynamic-widget-context-toolbar", inputs: ["showSize", "sizeDisabled", "sizeLabel", "toolbarLabel", "contextLabel", "contextTooltip", "showAssistant", "assistantLabel", "assistantTooltip", "showComponentSettings", "componentSettingsBusy", "componentSettingsLabel", "componentSettingsTooltip", "showShellSettings", "shellSettingsLabel", "shellSettingsTooltip", "showRemove", "moreActionsLabel", "removeLabel"], outputs: ["size", "assistant", "componentSettings", "shellSettings", "remove"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { kind: "component", type: WidgetShellComponent, selector: "praxis-widget-shell", inputs: ["shell", "context", "dragSurfaceEnabled", "dragSurfaceLabel"], outputs: ["action", "dragSurfacePointerDown", "dragSurfaceKeydown"] }] });
|
|
48882
51048
|
}
|
|
48883
51049
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicWidgetPageComponent, decorators: [{
|
|
48884
51050
|
type: Component,
|
|
@@ -49105,9 +51271,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
49105
51271
|
<div
|
|
49106
51272
|
class="pdx-canvas-snap-preview"
|
|
49107
51273
|
[class.pdx-canvas-snap-preview--invalid]="canvasPreviewInvalid()"
|
|
51274
|
+
[class.pdx-canvas-snap-preview--swap]="canvasPreviewSwapKey()"
|
|
49108
51275
|
[style.gridColumn]="canvasPreviewGridColumn()"
|
|
49109
51276
|
[style.gridRow]="canvasPreviewGridRow()"
|
|
49110
|
-
|
|
51277
|
+
>
|
|
51278
|
+
@if (canvasPreviewInvalid()) {
|
|
51279
|
+
<div class="pdx-canvas-snap-preview__badge pdx-canvas-snap-preview__badge--invalid">
|
|
51280
|
+
<mat-icon class="pdx-canvas-snap-preview__badge-icon">block</mat-icon>
|
|
51281
|
+
<span>{{ canvasPreviewInvalidMessage() }}</span>
|
|
51282
|
+
</div>
|
|
51283
|
+
} @else if (canvasPreviewSwapTarget(); as swapTarget) {
|
|
51284
|
+
<div class="pdx-canvas-snap-preview__badge pdx-canvas-snap-preview__badge--swap">
|
|
51285
|
+
<mat-icon class="pdx-canvas-snap-preview__badge-icon">swap_horiz</mat-icon>
|
|
51286
|
+
<span>{{ canvasPreviewSwapMessage(swapTarget) }}</span>
|
|
51287
|
+
</div>
|
|
51288
|
+
}
|
|
51289
|
+
</div>
|
|
49111
51290
|
}
|
|
49112
51291
|
} @else if (renderedGroups().length) {
|
|
49113
51292
|
@for (group of renderedGroups(); track group.id) {
|
|
@@ -49374,7 +51553,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
49374
51553
|
</div>
|
|
49375
51554
|
}
|
|
49376
51555
|
</div>
|
|
49377
|
-
`, styles: [":host{display:block;min-width:0}.pdx-page-wrapper{box-sizing:border-box;padding-inline:var(--pdx-page-padding-inline, 0px);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, 60px);padding-block-end:22px;padding-inline:22px;box-sizing:border-box}.pdx-page-settings{position:sticky;top:8px;z-index:2;color:inherit;margin-bottom:6px}.pdx-widget{position:relative;background:var(--pfx-surface, transparent);border-radius:6px;min-width:0;min-height:0}.pdx-widget--interactive{cursor:pointer}.pdx-widget--selected:before{content:\"\";position:absolute;inset:0;border:1px dashed color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent);border-radius:14px;pointer-events:none;z-index:1;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent),0 8px 20px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent)}.pdx-widget--canvas{align-self:stretch;--pdx-resize-gradient-diagonal-se: linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-widget--canvas:after{content:\"\";position:absolute;inset:0;padding:2px;border-radius:14px;background:var(--pdx-active-resize-gradient);opacity:0;pointer-events:none;transition:opacity .14s ease,filter .14s ease;filter:saturate(1.02) drop-shadow(0 0 5px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude}.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{content:\"\";position:absolute;inset:0;border-radius:14px;pointer-events:none;z-index:1;transition:opacity .14s ease,box-shadow .14s ease,border-color .14s ease}.pdx-widget--canvas-blocked:before{border:1px solid color-mix(in srgb,var(--md-sys-color-error) 74%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 20%,transparent),0 10px 24px color-mix(in srgb,var(--md-sys-color-error) 12%,transparent)}.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:hover):after,.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:focus-visible):after{opacity:.82}[data-resize-feedback=valid]{--pdx-resize-feedback-color: #27864b}[data-resize-feedback=minimum]{--pdx-resize-feedback-color: #bc8a00}[data-resize-feedback=blocked]{--pdx-resize-feedback-color: var(--md-sys-color-error)}.pdx-widget--canvas[data-resize-feedback]:after{background:var(--pdx-resize-feedback-color);opacity:1;z-index:2}.pdx-resize-feedback{position:absolute;inset-inline:8px;bottom:8px;width:fit-content;max-width:calc(100% - 16px);box-sizing:border-box;display:flex;align-items:center;gap:6px;padding:4px 8px;border:2px solid var(--pdx-resize-feedback-color);border-radius:8px;color:var(--md-sys-color-on-surface);background:var(--md-sys-color-surface);font-size:12px;line-height:18px;pointer-events:none;z-index:3}.pdx-standalone-size-editor{box-sizing:border-box;width:min(720px,calc(100vw - 32px));max-height:calc(100vh - 32px);overflow:auto;padding:20px;border:1px solid var(--md-sys-color-outline-variant);border-radius:16px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);box-shadow:var(--mat-sys-level3, 0 8px 24px rgba(0, 0, 0, .24))}.pdx-standalone-size-editor__footer{display:flex;justify-content:flex-end;gap:8px;margin-top:20px;padding-top:16px;border-top:1px solid var(--md-sys-color-outline-variant)}.pdx-resize-feedback mat-icon{flex:0 0 18px;width:18px;height:18px;font-size:18px}.pdx-resize-feedback--floating{position:static;max-width:min(320px,calc(100vw - 24px));overflow-wrap:anywhere}.pdx-resize-feedback--floating strong{display:block}.pdx-canvas-edges{position:absolute;inset:0;pointer-events:none;z-index:5}.pdx-canvas-edge{position:absolute;display:grid;place-items:center;box-sizing:border-box;width:min(24px,50%);height:min(24px,50%);padding:0;border:0;background:transparent;color:var(--md-sys-color-primary);pointer-events:auto;touch-action:none;transform:translate(-50%,-50%)}.pdx-canvas-edge:after{content:\"\";box-sizing:border-box;width:min(12px,100%);height:min(12px,100%);pointer-events:none;border:2px solid currentColor;border-radius:2px;background:var(--md-sys-color-surface)}.pdx-canvas-edge:hover:after,.pdx-canvas-edge:focus-visible:after{background:var(--md-sys-color-primary-container)}.pdx-canvas-edge[data-canvas-edge=north-west]{left:0;top:0;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=north]{left:50%;top:0;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=north-east]{left:100%;top:0;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=east]{left:100%;top:50%;width:min(24px,100%);cursor:ew-resize}.pdx-canvas-edge[data-canvas-edge=south-east]{left:100%;top:100%;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=south]{left:50%;top:100%;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=south-west]{left:0;top:100%;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=west]{left:0;top:50%;width:min(24px,100%);cursor:ew-resize}.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.expanded)>.pdx-page>.pdx-widget>.pdx-canvas-edges,.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.fullscreen)>.pdx-page>.pdx-widget>.pdx-canvas-edges{display:none}.pdx-widget--canvas:focus-visible,.pdx-canvas-edge:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-snap-preview{position:relative;align-self:stretch;border-radius:12px;pointer-events:none;z-index:0;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent),color-mix(in srgb,var(--md-sys-color-tertiary) 12%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 42%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 55%,transparent);animation:pdx-snap-preview-pulse .48s ease-out infinite alternate}.pdx-canvas-snap-preview:before,.pdx-canvas-snap-preview:after{content:\"\";position:absolute;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary) 82%,var(--md-sys-color-tertiary) 18%);opacity:.72}.pdx-canvas-snap-preview:before{inset:0 auto 0 0;width:3px}.pdx-canvas-snap-preview:after{inset:0 0 auto;height:3px}.pdx-canvas-snap-preview--invalid{background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-error) 18%,transparent),color-mix(in srgb,var(--md-sys-color-error-container) 22%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 58%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 40%,transparent)}.pdx-canvas-snap-preview--invalid:before,.pdx-canvas-snap-preview--invalid:after{background:color-mix(in srgb,var(--md-sys-color-error) 86%,var(--md-sys-color-error-container) 14%)}@media(prefers-reduced-motion:reduce){.pdx-canvas-snap-preview{animation:none}.pdx-widget--canvas:after,.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{transition:none}}@media(forced-colors:active){.pdx-widget--canvas-selected:before{border:2px solid Highlight}.pdx-widget--canvas:focus-visible,.pdx-canvas-edge:focus-visible{outline-color:Highlight}}@keyframes pdx-snap-preview-pulse{0%{opacity:.72;transform:scale(.996)}to{opacity:1;transform:scale(1)}}.pdx-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pdx-group{display:grid;gap:12px;grid-column:1 / -1;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 76%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent)}.pdx-group--hero{padding:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 42%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-low) 86%,transparent))}.pdx-group--rail{align-self:start}.pdx-group-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.pdx-group-title{font-size:.95rem;font-weight:600;color:var(--md-sys-color-on-surface)}.pdx-group-content{display:grid;gap:12px}.pdx-group-content--stack{grid-template-columns:minmax(0,1fr)}.pdx-group-content--row{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.pdx-group-content--grid{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.pdx-group-tabs{display:grid;gap:12px}.pdx-tabs-header{display:flex;flex-wrap:wrap;gap:8px}.pdx-tab-chip{appearance:none;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-lowest);color:var(--md-sys-color-on-surface);border-radius:999px;padding:8px 12px;font:inherit;cursor:pointer}.pdx-tab-chip.active{border-color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 78%,transparent);color:var(--md-sys-color-on-primary-container)}.pdx-page-wrapper.editing .pdx-widget-settings{opacity:1}\n"] }]
|
|
51556
|
+
`, styles: [":host{display:block;min-width:0}.pdx-page-wrapper{box-sizing:border-box;padding-inline:var(--pdx-page-padding-inline, 0px);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, 60px);padding-block-end:22px;padding-inline:22px;box-sizing:border-box}.pdx-page-settings{position:sticky;top:8px;z-index:2;color:inherit;margin-bottom:6px}.pdx-widget{position:relative;background:var(--pfx-surface, transparent);border-radius:6px;min-width:0;min-height:0}.pdx-widget--interactive{cursor:pointer}.pdx-widget--selected:before{content:\"\";position:absolute;inset:0;border:1px dashed color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent);border-radius:14px;pointer-events:none;z-index:1;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent),0 8px 20px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent)}.pdx-widget--canvas{align-self:stretch;--pdx-resize-gradient-diagonal-se: linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-widget--canvas:after{content:\"\";position:absolute;inset:0;padding:2px;border-radius:14px;background:var(--pdx-active-resize-gradient);opacity:0;pointer-events:none;transition:opacity .14s ease,filter .14s ease;filter:saturate(1.02) drop-shadow(0 0 5px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude}.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{content:\"\";position:absolute;inset:0;border-radius:14px;pointer-events:none;z-index:1;transition:opacity .14s ease,box-shadow .14s ease,border-color .14s ease}.pdx-widget--canvas-blocked:before{border:1px solid color-mix(in srgb,var(--md-sys-color-error) 74%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 20%,transparent),0 10px 24px color-mix(in srgb,var(--md-sys-color-error) 12%,transparent)}.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:hover):after,.pdx-widget--canvas-selected:has(>.pdx-canvas-edges .pdx-canvas-edge:focus-visible):after{opacity:.82}[data-resize-feedback=valid]{--pdx-resize-feedback-color: #27864b}[data-resize-feedback=minimum]{--pdx-resize-feedback-color: #bc8a00}[data-resize-feedback=blocked]{--pdx-resize-feedback-color: var(--md-sys-color-error)}.pdx-widget--canvas[data-resize-feedback]:after{background:var(--pdx-resize-feedback-color);opacity:1;z-index:2}.pdx-resize-feedback{position:absolute;inset-inline:8px;bottom:8px;width:fit-content;max-width:calc(100% - 16px);box-sizing:border-box;display:flex;align-items:center;gap:6px;padding:4px 8px;border:2px solid var(--pdx-resize-feedback-color);border-radius:8px;color:var(--md-sys-color-on-surface);background:var(--md-sys-color-surface);font-size:12px;line-height:18px;pointer-events:none;z-index:3}.pdx-standalone-size-editor{box-sizing:border-box;width:min(720px,calc(100vw - 32px));max-height:calc(100vh - 32px);overflow:auto;padding:20px;border:1px solid var(--md-sys-color-outline-variant);border-radius:16px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);box-shadow:var(--mat-sys-level3, 0 8px 24px rgba(0, 0, 0, .24))}.pdx-standalone-size-editor__footer{display:flex;justify-content:flex-end;gap:8px;margin-top:20px;padding-top:16px;border-top:1px solid var(--md-sys-color-outline-variant)}.pdx-resize-feedback mat-icon{flex:0 0 18px;width:18px;height:18px;font-size:18px}.pdx-resize-feedback--floating{position:static;max-width:min(320px,calc(100vw - 24px));overflow-wrap:anywhere}.pdx-resize-feedback--floating strong{display:block}.pdx-canvas-edges{position:absolute;inset:0;pointer-events:none;z-index:5}.pdx-canvas-edge{position:absolute;display:grid;place-items:center;box-sizing:border-box;width:min(24px,50%);height:min(24px,50%);padding:0;border:0;background:transparent;color:var(--md-sys-color-primary);pointer-events:auto;touch-action:none;transform:translate(-50%,-50%)}.pdx-canvas-edge:after{content:\"\";box-sizing:border-box;width:min(12px,100%);height:min(12px,100%);pointer-events:none;border:2px solid currentColor;border-radius:2px;background:var(--md-sys-color-surface)}.pdx-canvas-edge:hover:after,.pdx-canvas-edge:focus-visible:after{background:var(--md-sys-color-primary-container)}.pdx-canvas-edge[data-canvas-edge=north-west]{left:0;top:0;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=north]{left:50%;top:0;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=north-east]{left:100%;top:0;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=east]{left:100%;top:50%;width:min(24px,100%);cursor:ew-resize}.pdx-canvas-edge[data-canvas-edge=south-east]{left:100%;top:100%;cursor:nwse-resize}.pdx-canvas-edge[data-canvas-edge=south]{left:50%;top:100%;cursor:ns-resize}.pdx-canvas-edge[data-canvas-edge=south-west]{left:0;top:100%;cursor:nesw-resize}.pdx-canvas-edge[data-canvas-edge=west]{left:0;top:50%;width:min(24px,100%);cursor:ew-resize}.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.expanded)>.pdx-page>.pdx-widget>.pdx-canvas-edges,.pdx-page-wrapper:has(>.pdx-page>.pdx-widget>praxis-widget-shell>.pdx-shell.fullscreen)>.pdx-page>.pdx-widget>.pdx-canvas-edges{display:none}.pdx-widget--canvas:focus-visible,.pdx-canvas-edge:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-snap-preview{position:relative;display:flex;align-items:center;justify-content:center;align-self:stretch;border-radius:12px;pointer-events:none;z-index:2;background:color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent);box-shadow:inset 0 0 0 1.5px color-mix(in srgb,var(--md-sys-color-primary) 45%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 60%,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:color-mix(in srgb,var(--md-sys-color-error) 4%,transparent);box-shadow:inset 0 0 0 1.5px color-mix(in srgb,var(--md-sys-color-error) 65%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 60%,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-snap-preview--swap{background:color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent);box-shadow:inset 0 0 0 1.5px color-mix(in srgb,var(--md-sys-color-primary) 65%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 60%,transparent)}.pdx-canvas-snap-preview--swap:before,.pdx-canvas-snap-preview--swap:after{background:color-mix(in srgb,var(--md-sys-color-primary) 86%,var(--md-sys-color-tertiary) 14%)}.pdx-canvas-snap-preview__badge{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;border-radius:999px;font-size:12px;font-weight:600;line-height:1.2;letter-spacing:.02em;white-space:nowrap;background:var(--md-sys-color-surface-container-highest, #ffffff);color:var(--md-sys-color-on-surface, #1e293b);box-shadow:0 4px 16px color-mix(in srgb,var(--mat-sys-shadow, #000) 20%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 40%,transparent);pointer-events:none}.pdx-canvas-snap-preview__badge-icon{font-size:16px;width:16px;height:16px;line-height:16px}.pdx-canvas-snap-preview__badge--invalid{color:var(--md-sys-color-error, #ba1a1a);border-color:color-mix(in srgb,var(--md-sys-color-error) 30%,transparent)}.pdx-canvas-snap-preview__badge--swap{color:var(--md-sys-color-primary, #0061a4);border-color:color-mix(in srgb,var(--md-sys-color-primary) 30%,transparent)}@media(prefers-reduced-motion:reduce){.pdx-canvas-snap-preview{animation:none}.pdx-widget--canvas:after,.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{transition:none}}@media(forced-colors:active){.pdx-widget--canvas-selected:before{border:2px solid Highlight}.pdx-widget--canvas:focus-visible,.pdx-canvas-edge:focus-visible{outline-color:Highlight}}@keyframes pdx-snap-preview-pulse{0%{opacity:.72;transform:scale(.996)}to{opacity:1;transform:scale(1)}}.pdx-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pdx-group{display:grid;gap:12px;grid-column:1 / -1;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 76%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent)}.pdx-group--hero{padding:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 42%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-low) 86%,transparent))}.pdx-group--rail{align-self:start}.pdx-group-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.pdx-group-title{font-size:.95rem;font-weight:600;color:var(--md-sys-color-on-surface)}.pdx-group-content{display:grid;gap:12px}.pdx-group-content--stack{grid-template-columns:minmax(0,1fr)}.pdx-group-content--row{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.pdx-group-content--grid{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.pdx-group-tabs{display:grid;gap:12px}.pdx-tabs-header{display:flex;flex-wrap:wrap;gap:8px}.pdx-tab-chip{appearance:none;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-lowest);color:var(--md-sys-color-on-surface);border-radius:999px;padding:8px 12px;font:inherit;cursor:pointer}.pdx-tab-chip.active{border-color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 78%,transparent);color:var(--md-sys-color-on-primary-container)}.pdx-page-wrapper.editing .pdx-widget-settings{opacity:1}\n"] }]
|
|
49378
51557
|
}], ctorParameters: () => [], propDecorators: { widgetSizeTemplate: [{
|
|
49379
51558
|
type: ViewChild,
|
|
49380
51559
|
args: ['widgetSizeTemplate', { static: true }]
|
|
@@ -53331,6 +55510,909 @@ function provideHookWhitelist(allowed) {
|
|
|
53331
55510
|
return [{ provide: FORM_HOOKS_WHITELIST, useValue: allowed, multi: true }];
|
|
53332
55511
|
}
|
|
53333
55512
|
|
|
55513
|
+
/**
|
|
55514
|
+
* PraxisKeepAliveTabDirective
|
|
55515
|
+
* ----------------------------
|
|
55516
|
+
* Diretiva canônica de plataforma para preservação de estado e ciclo de vida
|
|
55517
|
+
* em layouts de abas, dossiês, painéis expansíveis e drawers (Issue #2).
|
|
55518
|
+
*
|
|
55519
|
+
* Evita a destruição da árvore do DOM que ocorre com `@if` tradicional,
|
|
55520
|
+
* preservando instâncias de componentes, formulários reativos (`FormGroup`),
|
|
55521
|
+
* seleções de dropdowns, campos digitados e uploads em andamento.
|
|
55522
|
+
*
|
|
55523
|
+
* Suporta dois padrões canônicos:
|
|
55524
|
+
*
|
|
55525
|
+
* 1. Padrão Estrutural (Lazy Mounting + Keep-Alive):
|
|
55526
|
+
* ```html
|
|
55527
|
+
* <div *praxisKeepAliveTab="activeTab() === 'identidade'">
|
|
55528
|
+
* <praxis-dynamic-form ... />
|
|
55529
|
+
* </div>
|
|
55530
|
+
* ```
|
|
55531
|
+
* - Monta o componente somente na primeira vez que a aba fica ativa.
|
|
55532
|
+
* - Nas trocas de aba subsequentes, oculta via `display: none !important;` e `hidden`,
|
|
55533
|
+
* sem desmontar nem recriar o componente.
|
|
55534
|
+
*
|
|
55535
|
+
* 2. Padrão Atributo:
|
|
55536
|
+
* ```html
|
|
55537
|
+
* <div [praxisKeepAliveTab]="activeTab() === 'competencias'">
|
|
55538
|
+
* <praxis-dynamic-form ... />
|
|
55539
|
+
* </div>
|
|
55540
|
+
* ```
|
|
55541
|
+
*/
|
|
55542
|
+
class PraxisKeepAliveTabDirective {
|
|
55543
|
+
templateRef = inject(TemplateRef, { optional: true });
|
|
55544
|
+
viewContainer = inject(ViewContainerRef, { optional: true });
|
|
55545
|
+
elementRef = inject(ElementRef, { optional: true });
|
|
55546
|
+
renderer = inject(Renderer2);
|
|
55547
|
+
viewRef = null;
|
|
55548
|
+
isActive = false;
|
|
55549
|
+
set active(condition) {
|
|
55550
|
+
this.isActive = !!condition;
|
|
55551
|
+
this.updateVisibility();
|
|
55552
|
+
}
|
|
55553
|
+
get active() {
|
|
55554
|
+
return this.isActive;
|
|
55555
|
+
}
|
|
55556
|
+
updateVisibility() {
|
|
55557
|
+
if (this.templateRef && this.viewContainer) {
|
|
55558
|
+
this.updateStructuralView();
|
|
55559
|
+
}
|
|
55560
|
+
else if (this.elementRef) {
|
|
55561
|
+
this.updateAttributeView();
|
|
55562
|
+
}
|
|
55563
|
+
}
|
|
55564
|
+
updateStructuralView() {
|
|
55565
|
+
if (this.isActive) {
|
|
55566
|
+
if (!this.viewRef) {
|
|
55567
|
+
// Primeira ativação: cria a view no container
|
|
55568
|
+
this.viewRef = this.viewContainer.createEmbeddedView(this.templateRef);
|
|
55569
|
+
}
|
|
55570
|
+
else {
|
|
55571
|
+
// Reativação: exibe os nós preservados
|
|
55572
|
+
this.setNodesVisibility(this.viewRef.rootNodes, true);
|
|
55573
|
+
}
|
|
55574
|
+
}
|
|
55575
|
+
else if (this.viewRef) {
|
|
55576
|
+
// Inativação: oculta nós sem destruir a view
|
|
55577
|
+
this.setNodesVisibility(this.viewRef.rootNodes, false);
|
|
55578
|
+
}
|
|
55579
|
+
}
|
|
55580
|
+
updateAttributeView() {
|
|
55581
|
+
const el = this.elementRef.nativeElement;
|
|
55582
|
+
if (this.isActive) {
|
|
55583
|
+
this.renderer.removeAttribute(el, 'hidden');
|
|
55584
|
+
if (el.__praxisOriginalDisplay !== undefined) {
|
|
55585
|
+
const original = el.__praxisOriginalDisplay;
|
|
55586
|
+
if (original) {
|
|
55587
|
+
this.renderer.setStyle(el, 'display', original);
|
|
55588
|
+
}
|
|
55589
|
+
else {
|
|
55590
|
+
this.renderer.removeStyle(el, 'display');
|
|
55591
|
+
}
|
|
55592
|
+
delete el.__praxisOriginalDisplay;
|
|
55593
|
+
}
|
|
55594
|
+
}
|
|
55595
|
+
else {
|
|
55596
|
+
if (el.__praxisOriginalDisplay === undefined) {
|
|
55597
|
+
el.__praxisOriginalDisplay = el.style?.display || '';
|
|
55598
|
+
}
|
|
55599
|
+
this.renderer.setAttribute(el, 'hidden', '');
|
|
55600
|
+
this.renderer.setStyle(el, 'display', 'none', 1 /* !important */);
|
|
55601
|
+
}
|
|
55602
|
+
}
|
|
55603
|
+
setNodesVisibility(nodes, visible) {
|
|
55604
|
+
for (const node of nodes) {
|
|
55605
|
+
if (node && node.nodeType === 1 /* Node.ELEMENT_NODE */) {
|
|
55606
|
+
if (visible) {
|
|
55607
|
+
this.renderer.removeAttribute(node, 'hidden');
|
|
55608
|
+
if (node.__praxisOriginalDisplay !== undefined) {
|
|
55609
|
+
const original = node.__praxisOriginalDisplay;
|
|
55610
|
+
if (original) {
|
|
55611
|
+
this.renderer.setStyle(node, 'display', original);
|
|
55612
|
+
}
|
|
55613
|
+
else {
|
|
55614
|
+
this.renderer.removeStyle(node, 'display');
|
|
55615
|
+
}
|
|
55616
|
+
delete node.__praxisOriginalDisplay;
|
|
55617
|
+
}
|
|
55618
|
+
}
|
|
55619
|
+
else {
|
|
55620
|
+
if (node.__praxisOriginalDisplay === undefined) {
|
|
55621
|
+
node.__praxisOriginalDisplay = node.style?.display || '';
|
|
55622
|
+
}
|
|
55623
|
+
this.renderer.setAttribute(node, 'hidden', '');
|
|
55624
|
+
this.renderer.setStyle(node, 'display', 'none', 1 /* !important */);
|
|
55625
|
+
}
|
|
55626
|
+
}
|
|
55627
|
+
}
|
|
55628
|
+
}
|
|
55629
|
+
ngOnDestroy() {
|
|
55630
|
+
if (this.viewRef) {
|
|
55631
|
+
this.viewRef.destroy();
|
|
55632
|
+
this.viewRef = null;
|
|
55633
|
+
}
|
|
55634
|
+
}
|
|
55635
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisKeepAliveTabDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
55636
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.14", type: PraxisKeepAliveTabDirective, isStandalone: true, selector: "[praxisKeepAliveTab]", inputs: { active: ["praxisKeepAliveTab", "active"] }, ngImport: i0 });
|
|
55637
|
+
}
|
|
55638
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisKeepAliveTabDirective, decorators: [{
|
|
55639
|
+
type: Directive,
|
|
55640
|
+
args: [{
|
|
55641
|
+
selector: '[praxisKeepAliveTab]',
|
|
55642
|
+
standalone: true,
|
|
55643
|
+
}]
|
|
55644
|
+
}], propDecorators: { active: [{
|
|
55645
|
+
type: Input,
|
|
55646
|
+
args: ['praxisKeepAliveTab']
|
|
55647
|
+
}] } });
|
|
55648
|
+
|
|
55649
|
+
/**
|
|
55650
|
+
* =============================================================================
|
|
55651
|
+
* DYNAMIC DATA RECORD & METADATA-DRIVEN TYPES (Issue #35)
|
|
55652
|
+
* =============================================================================
|
|
55653
|
+
* Fornece contratos genéricos dinâmicos e utilitários puros para manipulação
|
|
55654
|
+
* de registros guiados por schema (OpenAPI / /schemas/filtered), eliminando a
|
|
55655
|
+
* necessidade de declarar DTOs TypeScript estáticos redundantes nas aplicações.
|
|
55656
|
+
*/
|
|
55657
|
+
const BLOCKED_KEYS = new Set(['__proto__', 'prototype', 'constructor']);
|
|
55658
|
+
/**
|
|
55659
|
+
* Acessa com segurança uma propriedade (inclusive aninhada com pontos, ex: 'endereco.cidade'
|
|
55660
|
+
* ou 'cliente.limiteCredito') em um registro dinâmico.
|
|
55661
|
+
*
|
|
55662
|
+
* @param record O registro ou objeto alvo
|
|
55663
|
+
* @param path Caminho da propriedade (ex.: 'nome', 'perfil.cargo', 'financeiro.total')
|
|
55664
|
+
* @param fallback Valor padrão retornado caso a propriedade seja nula ou indefinida
|
|
55665
|
+
*/
|
|
55666
|
+
function resolveDataField(record, path, fallback) {
|
|
55667
|
+
if (!record || typeof record !== 'object' || !path || typeof path !== 'string') {
|
|
55668
|
+
return fallback;
|
|
55669
|
+
}
|
|
55670
|
+
const normalized = path.trim();
|
|
55671
|
+
if (!normalized) {
|
|
55672
|
+
return fallback;
|
|
55673
|
+
}
|
|
55674
|
+
// Acesso direto O(1) se a chave existir no primeiro nível
|
|
55675
|
+
if (Object.prototype.hasOwnProperty.call(record, normalized)) {
|
|
55676
|
+
const val = record[normalized];
|
|
55677
|
+
return (val !== undefined && val !== null ? val : fallback);
|
|
55678
|
+
}
|
|
55679
|
+
// Decomposição de caminho com notação de ponto e colchetes de array (ex: 'pedidos[0].itens[1].valor')
|
|
55680
|
+
const pathWithDots = normalized.replace(/\[(\w+)\]/g, '.$1').replace(/^\./, '');
|
|
55681
|
+
const segments = pathWithDots.split('.');
|
|
55682
|
+
let current = record;
|
|
55683
|
+
for (let i = 0; i < segments.length; i++) {
|
|
55684
|
+
const segment = segments[i].trim();
|
|
55685
|
+
if (!segment || BLOCKED_KEYS.has(segment)) {
|
|
55686
|
+
return fallback;
|
|
55687
|
+
}
|
|
55688
|
+
if (current == null || (typeof current !== 'object' && typeof current !== 'function')) {
|
|
55689
|
+
return fallback;
|
|
55690
|
+
}
|
|
55691
|
+
current = current[segment];
|
|
55692
|
+
}
|
|
55693
|
+
return (current !== undefined && current !== null ? current : fallback);
|
|
55694
|
+
}
|
|
55695
|
+
/**
|
|
55696
|
+
* Cria ou encapsula um registro dinâmico anexando metadados de forma imutável.
|
|
55697
|
+
*/
|
|
55698
|
+
function createDynamicRecord(data, meta) {
|
|
55699
|
+
const base = { ...(data || {}) };
|
|
55700
|
+
if (meta) {
|
|
55701
|
+
base._meta = { ...(base._meta || {}), ...meta };
|
|
55702
|
+
}
|
|
55703
|
+
return base;
|
|
55704
|
+
}
|
|
55705
|
+
/**
|
|
55706
|
+
* Type-guard para verificar se um valor desconhecido é um objeto de registro válido.
|
|
55707
|
+
*/
|
|
55708
|
+
function isDynamicDataRecord(value) {
|
|
55709
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
55710
|
+
}
|
|
55711
|
+
/**
|
|
55712
|
+
* Extrai o identificador canônico de um registro com suporte a chaves alternativas ('id', '_id', 'codigo').
|
|
55713
|
+
*/
|
|
55714
|
+
function extractRecordId(record, fallbackKey) {
|
|
55715
|
+
if (!record || typeof record !== 'object') {
|
|
55716
|
+
return null;
|
|
55717
|
+
}
|
|
55718
|
+
const r = record;
|
|
55719
|
+
if (r['id'] !== undefined && r['id'] !== null && r['id'] !== '') {
|
|
55720
|
+
return r['id'];
|
|
55721
|
+
}
|
|
55722
|
+
if (r['_id'] !== undefined && r['_id'] !== null && r['_id'] !== '') {
|
|
55723
|
+
return r['_id'];
|
|
55724
|
+
}
|
|
55725
|
+
if (fallbackKey && r[fallbackKey] !== undefined && r[fallbackKey] !== null && r[fallbackKey] !== '') {
|
|
55726
|
+
return r[fallbackKey];
|
|
55727
|
+
}
|
|
55728
|
+
if (r['codigo'] !== undefined && r['codigo'] !== null && r['codigo'] !== '') {
|
|
55729
|
+
return r['codigo'];
|
|
55730
|
+
}
|
|
55731
|
+
return null;
|
|
55732
|
+
}
|
|
55733
|
+
|
|
55734
|
+
/**
|
|
55735
|
+
* Praxis UI Platform — Enterprise App Shell Models
|
|
55736
|
+
*
|
|
55737
|
+
* Contratos declarativos e fortemente tipados para a casca de aplicação corporativa
|
|
55738
|
+
* governada (PraxisAppShell).
|
|
55739
|
+
*/
|
|
55740
|
+
|
|
55741
|
+
class PraxisAppShellComponent {
|
|
55742
|
+
brand;
|
|
55743
|
+
navigation = [];
|
|
55744
|
+
user;
|
|
55745
|
+
showThemeToggle = true;
|
|
55746
|
+
cdr = inject(ChangeDetectorRef);
|
|
55747
|
+
loadingOrchestrator = inject(LoadingOrchestrator, { optional: true });
|
|
55748
|
+
orchestratorLoading = this.loadingOrchestrator
|
|
55749
|
+
? toSignal(this.loadingOrchestrator.watch().pipe(map((list) => list.length > 0)), {
|
|
55750
|
+
initialValue: false,
|
|
55751
|
+
})
|
|
55752
|
+
: signal(false);
|
|
55753
|
+
_isDarkTheme = signal(true, ...(ngDevMode ? [{ debugName: "_isDarkTheme" }] : /* istanbul ignore next */ []));
|
|
55754
|
+
set isDarkTheme(val) {
|
|
55755
|
+
this._isDarkTheme.set(!!val);
|
|
55756
|
+
this.cdr.markForCheck();
|
|
55757
|
+
}
|
|
55758
|
+
get isDarkTheme() {
|
|
55759
|
+
return this._isDarkTheme();
|
|
55760
|
+
}
|
|
55761
|
+
showSearch = true;
|
|
55762
|
+
searchPlaceholder = 'Buscar no sistema ou executar comando...';
|
|
55763
|
+
_footerStatus = signal(undefined, ...(ngDevMode ? [{ debugName: "_footerStatus" }] : /* istanbul ignore next */ []));
|
|
55764
|
+
set footerStatus(val) {
|
|
55765
|
+
this._footerStatus.set(val);
|
|
55766
|
+
this.cdr.markForCheck();
|
|
55767
|
+
}
|
|
55768
|
+
get footerStatus() {
|
|
55769
|
+
return this._footerStatus();
|
|
55770
|
+
}
|
|
55771
|
+
_isAnyLoading = signal(false, ...(ngDevMode ? [{ debugName: "_isAnyLoading" }] : /* istanbul ignore next */ []));
|
|
55772
|
+
set isAnyLoading(val) {
|
|
55773
|
+
this._isAnyLoading.set(!!val);
|
|
55774
|
+
this.cdr.markForCheck();
|
|
55775
|
+
}
|
|
55776
|
+
get isAnyLoading() {
|
|
55777
|
+
return this._isAnyLoading();
|
|
55778
|
+
}
|
|
55779
|
+
_collapsed = signal(false, ...(ngDevMode ? [{ debugName: "_collapsed" }] : /* istanbul ignore next */ []));
|
|
55780
|
+
set collapsed(val) {
|
|
55781
|
+
this._collapsed.set(!!val);
|
|
55782
|
+
this.cdr.markForCheck();
|
|
55783
|
+
}
|
|
55784
|
+
get collapsed() {
|
|
55785
|
+
return this._collapsed();
|
|
55786
|
+
}
|
|
55787
|
+
themeToggle = new EventEmitter();
|
|
55788
|
+
searchSubmit = new EventEmitter();
|
|
55789
|
+
searchChange = new EventEmitter();
|
|
55790
|
+
userProfileClick = new EventEmitter();
|
|
55791
|
+
collapsedChange = new EventEmitter();
|
|
55792
|
+
navItemClick = new EventEmitter();
|
|
55793
|
+
mobileOpen = signal(false, ...(ngDevMode ? [{ debugName: "mobileOpen" }] : /* istanbul ignore next */ []));
|
|
55794
|
+
searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : /* istanbul ignore next */ []));
|
|
55795
|
+
effectiveLoading = computed(() => {
|
|
55796
|
+
return this._isAnyLoading() || this.orchestratorLoading();
|
|
55797
|
+
}, ...(ngDevMode ? [{ debugName: "effectiveLoading" }] : /* istanbul ignore next */ []));
|
|
55798
|
+
handleEscape() {
|
|
55799
|
+
if (this.mobileOpen()) {
|
|
55800
|
+
this.closeMobile();
|
|
55801
|
+
}
|
|
55802
|
+
}
|
|
55803
|
+
toggleCollapse() {
|
|
55804
|
+
this.collapsed = !this.collapsed;
|
|
55805
|
+
this.collapsedChange.emit(this.collapsed);
|
|
55806
|
+
}
|
|
55807
|
+
openMobile() {
|
|
55808
|
+
this.mobileOpen.set(true);
|
|
55809
|
+
}
|
|
55810
|
+
closeMobile() {
|
|
55811
|
+
this.mobileOpen.set(false);
|
|
55812
|
+
}
|
|
55813
|
+
onThemeToggleClick() {
|
|
55814
|
+
this.isDarkTheme = !this.isDarkTheme;
|
|
55815
|
+
this.themeToggle.emit(this.isDarkTheme);
|
|
55816
|
+
}
|
|
55817
|
+
onSearchInput(value) {
|
|
55818
|
+
this.searchQuery.set(value);
|
|
55819
|
+
this.searchChange.emit(value);
|
|
55820
|
+
}
|
|
55821
|
+
onSearchEnter() {
|
|
55822
|
+
const query = this.searchQuery().trim();
|
|
55823
|
+
if (query) {
|
|
55824
|
+
this.searchSubmit.emit(query);
|
|
55825
|
+
}
|
|
55826
|
+
}
|
|
55827
|
+
onUserClick() {
|
|
55828
|
+
if (this.user) {
|
|
55829
|
+
this.userProfileClick.emit(this.user);
|
|
55830
|
+
}
|
|
55831
|
+
}
|
|
55832
|
+
onItemClick(item) {
|
|
55833
|
+
if (item.disabled)
|
|
55834
|
+
return;
|
|
55835
|
+
this.closeMobile();
|
|
55836
|
+
this.navItemClick.emit(item);
|
|
55837
|
+
}
|
|
55838
|
+
getUserInitials(name) {
|
|
55839
|
+
if (!name)
|
|
55840
|
+
return 'U';
|
|
55841
|
+
const parts = name.trim().split(/\s+/);
|
|
55842
|
+
if (parts.length === 1)
|
|
55843
|
+
return parts[0].substring(0, 2).toUpperCase();
|
|
55844
|
+
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
55845
|
+
}
|
|
55846
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisAppShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
55847
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisAppShellComponent, isStandalone: true, selector: "praxis-app-shell", inputs: { brand: "brand", navigation: "navigation", user: "user", showThemeToggle: "showThemeToggle", isDarkTheme: "isDarkTheme", showSearch: "showSearch", searchPlaceholder: "searchPlaceholder", footerStatus: "footerStatus", isAnyLoading: "isAnyLoading", collapsed: "collapsed" }, outputs: { themeToggle: "themeToggle", searchSubmit: "searchSubmit", searchChange: "searchChange", userProfileClick: "userProfileClick", collapsedChange: "collapsedChange", navItemClick: "navItemClick" }, host: { listeners: { "keydown.escape": "handleEscape()" } }, ngImport: i0, template: `
|
|
55848
|
+
<div
|
|
55849
|
+
class="praxis-shell"
|
|
55850
|
+
[class.praxis-shell--dark]="isDarkTheme"
|
|
55851
|
+
[class.praxis-shell--collapsed]="collapsed"
|
|
55852
|
+
[class.praxis-shell--mobile-open]="mobileOpen()"
|
|
55853
|
+
>
|
|
55854
|
+
<!-- A11y Skip to Main Content Link -->
|
|
55855
|
+
<a href="#praxis-main-content" class="praxis-shell__skip-link">
|
|
55856
|
+
Pular para o conteúdo principal
|
|
55857
|
+
</a>
|
|
55858
|
+
|
|
55859
|
+
<!-- Tactical Top Shimmer Progress Bar -->
|
|
55860
|
+
@if (effectiveLoading()) {
|
|
55861
|
+
<div
|
|
55862
|
+
class="praxis-shell__progress-bar"
|
|
55863
|
+
role="progressbar"
|
|
55864
|
+
aria-valuemin="0"
|
|
55865
|
+
aria-valuemax="100"
|
|
55866
|
+
aria-label="Sincronização em andamento"
|
|
55867
|
+
>
|
|
55868
|
+
<div class="praxis-shell__progress-laser"></div>
|
|
55869
|
+
</div>
|
|
55870
|
+
}
|
|
55871
|
+
|
|
55872
|
+
<!-- Mobile Backdrop -->
|
|
55873
|
+
@if (mobileOpen()) {
|
|
55874
|
+
<div
|
|
55875
|
+
class="praxis-shell__backdrop"
|
|
55876
|
+
(click)="closeMobile()"
|
|
55877
|
+
aria-hidden="true"
|
|
55878
|
+
></div>
|
|
55879
|
+
}
|
|
55880
|
+
|
|
55881
|
+
<!-- Sidebar -->
|
|
55882
|
+
<aside class="praxis-shell__sidebar" id="praxis-sidebar-nav" aria-label="Navegação Principal">
|
|
55883
|
+
<!-- Brand Header -->
|
|
55884
|
+
<div class="praxis-shell__brand">
|
|
55885
|
+
<a
|
|
55886
|
+
class="praxis-shell__brand-link"
|
|
55887
|
+
[routerLink]="brand?.href || '/'"
|
|
55888
|
+
(click)="closeMobile()"
|
|
55889
|
+
>
|
|
55890
|
+
@if (brand?.logoUrl) {
|
|
55891
|
+
<img
|
|
55892
|
+
[src]="brand?.logoUrl"
|
|
55893
|
+
[alt]="brand?.title || 'Logo'"
|
|
55894
|
+
class="praxis-shell__brand-logo"
|
|
55895
|
+
/>
|
|
55896
|
+
} @else {
|
|
55897
|
+
<div class="praxis-shell__brand-icon">
|
|
55898
|
+
<span class="material-symbols-outlined">{{ brand?.icon || 'apps' }}</span>
|
|
55899
|
+
</div>
|
|
55900
|
+
}
|
|
55901
|
+
|
|
55902
|
+
@if (!collapsed) {
|
|
55903
|
+
<div class="praxis-shell__brand-info">
|
|
55904
|
+
<span class="praxis-shell__brand-title">{{ brand?.title || 'Praxis' }}</span>
|
|
55905
|
+
@if (brand?.version || brand?.subtitle) {
|
|
55906
|
+
<span class="praxis-shell__brand-meta">
|
|
55907
|
+
{{ brand?.version || brand?.subtitle }}
|
|
55908
|
+
</span>
|
|
55909
|
+
}
|
|
55910
|
+
</div>
|
|
55911
|
+
}
|
|
55912
|
+
</a>
|
|
55913
|
+
|
|
55914
|
+
<ng-content select="[shell-brand-extra]"></ng-content>
|
|
55915
|
+
|
|
55916
|
+
<!-- Mobile Close Button -->
|
|
55917
|
+
<button
|
|
55918
|
+
type="button"
|
|
55919
|
+
class="praxis-shell__mobile-close-btn"
|
|
55920
|
+
(click)="closeMobile()"
|
|
55921
|
+
aria-label="Fechar navegação"
|
|
55922
|
+
>
|
|
55923
|
+
<span class="material-symbols-outlined">close</span>
|
|
55924
|
+
</button>
|
|
55925
|
+
</div>
|
|
55926
|
+
|
|
55927
|
+
<!-- Navigation Groups -->
|
|
55928
|
+
<nav class="praxis-shell__nav">
|
|
55929
|
+
@for (group of navigation; track group.label || $index) {
|
|
55930
|
+
<div class="praxis-shell__nav-group">
|
|
55931
|
+
@if (group.label && !collapsed) {
|
|
55932
|
+
<div class="praxis-shell__nav-group-title">{{ group.label }}</div>
|
|
55933
|
+
}
|
|
55934
|
+
<ul class="praxis-shell__nav-list">
|
|
55935
|
+
@for (item of group.items; track item.path) {
|
|
55936
|
+
<li class="praxis-shell__nav-item">
|
|
55937
|
+
<a
|
|
55938
|
+
[routerLink]="item.path"
|
|
55939
|
+
routerLinkActive="active"
|
|
55940
|
+
[routerLinkActiveOptions]="{ exact: item.exact ?? (item.path === '/') }"
|
|
55941
|
+
(click)="onItemClick(item)"
|
|
55942
|
+
class="praxis-shell__nav-link"
|
|
55943
|
+
[class.disabled]="item.disabled"
|
|
55944
|
+
[attr.title]="collapsed ? item.label : (item.title || null)"
|
|
55945
|
+
[attr.aria-disabled]="item.disabled ? 'true' : null"
|
|
55946
|
+
>
|
|
55947
|
+
<span class="praxis-shell__nav-icon">
|
|
55948
|
+
<span class="material-symbols-outlined">{{ item.icon || 'circle' }}</span>
|
|
55949
|
+
</span>
|
|
55950
|
+
|
|
55951
|
+
@if (!collapsed) {
|
|
55952
|
+
<span class="praxis-shell__nav-label">{{ item.label }}</span>
|
|
55953
|
+
|
|
55954
|
+
@if (item.badge !== undefined && item.badge !== null) {
|
|
55955
|
+
<span
|
|
55956
|
+
class="praxis-shell__nav-badge"
|
|
55957
|
+
[ngClass]="'praxis-shell__nav-badge--' + (item.badgeTone || 'primary')"
|
|
55958
|
+
>
|
|
55959
|
+
{{ item.badge }}
|
|
55960
|
+
</span>
|
|
55961
|
+
}
|
|
55962
|
+
}
|
|
55963
|
+
</a>
|
|
55964
|
+
</li>
|
|
55965
|
+
}
|
|
55966
|
+
</ul>
|
|
55967
|
+
</div>
|
|
55968
|
+
}
|
|
55969
|
+
</nav>
|
|
55970
|
+
|
|
55971
|
+
<!-- Sidebar Footer Status -->
|
|
55972
|
+
@if (footerStatus) {
|
|
55973
|
+
<div class="praxis-shell__sidebar-footer-status">
|
|
55974
|
+
@if (!collapsed) {
|
|
55975
|
+
<div
|
|
55976
|
+
class="praxis-shell__status-card"
|
|
55977
|
+
[ngClass]="'praxis-shell__status-card--' + (footerStatus.statusTone || 'info')"
|
|
55978
|
+
>
|
|
55979
|
+
<div class="praxis-shell__status-card-header">
|
|
55980
|
+
@if (footerStatus.pulse !== false) {
|
|
55981
|
+
<span class="praxis-shell__pulse-indicator">
|
|
55982
|
+
<span class="praxis-shell__pulse-ring"></span>
|
|
55983
|
+
<span class="praxis-shell__pulse-dot"></span>
|
|
55984
|
+
</span>
|
|
55985
|
+
}
|
|
55986
|
+
<span class="praxis-shell__status-card-title">{{ footerStatus.title }}</span>
|
|
55987
|
+
</div>
|
|
55988
|
+
@if (footerStatus.metric) {
|
|
55989
|
+
<div class="praxis-shell__status-card-metric">{{ footerStatus.metric }}</div>
|
|
55990
|
+
}
|
|
55991
|
+
</div>
|
|
55992
|
+
}
|
|
55993
|
+
</div>
|
|
55994
|
+
}
|
|
55995
|
+
|
|
55996
|
+
<ng-content select="[shell-footer-extra]"></ng-content>
|
|
55997
|
+
|
|
55998
|
+
<!-- Sidebar Collapse Toggle Button -->
|
|
55999
|
+
<div class="praxis-shell__sidebar-toggle-bar">
|
|
56000
|
+
<button
|
|
56001
|
+
type="button"
|
|
56002
|
+
class="praxis-shell__collapse-btn"
|
|
56003
|
+
(click)="toggleCollapse()"
|
|
56004
|
+
[attr.aria-expanded]="!collapsed"
|
|
56005
|
+
[attr.aria-label]="collapsed ? 'Expandir barra lateral' : 'Recolher barra lateral'"
|
|
56006
|
+
>
|
|
56007
|
+
<span class="material-symbols-outlined">
|
|
56008
|
+
{{ collapsed ? 'chevron_right' : 'chevron_left' }}
|
|
56009
|
+
</span>
|
|
56010
|
+
@if (!collapsed) {
|
|
56011
|
+
<span class="praxis-shell__collapse-btn-text">Recolher menu</span>
|
|
56012
|
+
}
|
|
56013
|
+
</button>
|
|
56014
|
+
</div>
|
|
56015
|
+
</aside>
|
|
56016
|
+
|
|
56017
|
+
<!-- Main Stage Container -->
|
|
56018
|
+
<div class="praxis-shell__stage">
|
|
56019
|
+
<!-- Top Application Bar -->
|
|
56020
|
+
<header class="praxis-shell__topbar" role="banner">
|
|
56021
|
+
<!-- Mobile Menu Trigger -->
|
|
56022
|
+
<button
|
|
56023
|
+
type="button"
|
|
56024
|
+
class="praxis-shell__burger-btn"
|
|
56025
|
+
(click)="openMobile()"
|
|
56026
|
+
[attr.aria-expanded]="mobileOpen()"
|
|
56027
|
+
aria-controls="praxis-sidebar-nav"
|
|
56028
|
+
aria-label="Abrir navegação"
|
|
56029
|
+
>
|
|
56030
|
+
<span class="material-symbols-outlined">menu</span>
|
|
56031
|
+
</button>
|
|
56032
|
+
|
|
56033
|
+
<!-- Search / Quick Command Area -->
|
|
56034
|
+
@if (showSearch) {
|
|
56035
|
+
<div class="praxis-shell__search-box" role="search">
|
|
56036
|
+
<span class="material-symbols-outlined praxis-shell__search-icon" aria-hidden="true">search</span>
|
|
56037
|
+
<input
|
|
56038
|
+
type="text"
|
|
56039
|
+
class="praxis-shell__search-input"
|
|
56040
|
+
[placeholder]="searchPlaceholder"
|
|
56041
|
+
[value]="searchQuery()"
|
|
56042
|
+
(input)="onSearchInput($any($event.target).value)"
|
|
56043
|
+
(keydown.enter)="onSearchEnter()"
|
|
56044
|
+
aria-label="Buscar no sistema"
|
|
56045
|
+
/>
|
|
56046
|
+
</div>
|
|
56047
|
+
}
|
|
56048
|
+
|
|
56049
|
+
<!-- Spacer -->
|
|
56050
|
+
<div class="praxis-shell__topbar-spacer"></div>
|
|
56051
|
+
|
|
56052
|
+
<!-- Header Actions Content Slot -->
|
|
56053
|
+
<div class="praxis-shell__header-actions">
|
|
56054
|
+
<ng-content select="[shell-header-actions]"></ng-content>
|
|
56055
|
+
</div>
|
|
56056
|
+
|
|
56057
|
+
<!-- Theme Toggle -->
|
|
56058
|
+
@if (showThemeToggle) {
|
|
56059
|
+
<button
|
|
56060
|
+
type="button"
|
|
56061
|
+
class="praxis-shell__icon-btn"
|
|
56062
|
+
(click)="onThemeToggleClick()"
|
|
56063
|
+
[attr.aria-label]="isDarkTheme ? 'Ativar modo claro' : 'Ativar modo escuro'"
|
|
56064
|
+
[attr.title]="isDarkTheme ? 'Modo Claro' : 'Modo Escuro'"
|
|
56065
|
+
>
|
|
56066
|
+
<span class="material-symbols-outlined">
|
|
56067
|
+
{{ isDarkTheme ? 'light_mode' : 'dark_mode' }}
|
|
56068
|
+
</span>
|
|
56069
|
+
</button>
|
|
56070
|
+
}
|
|
56071
|
+
|
|
56072
|
+
<!-- User Profile Badge -->
|
|
56073
|
+
@if (user) {
|
|
56074
|
+
<div
|
|
56075
|
+
class="praxis-shell__user-profile"
|
|
56076
|
+
(click)="onUserClick()"
|
|
56077
|
+
role="button"
|
|
56078
|
+
tabindex="0"
|
|
56079
|
+
(keydown.enter)="onUserClick()"
|
|
56080
|
+
(keydown.space)="onUserClick()"
|
|
56081
|
+
[attr.aria-label]="'Perfil de ' + user.name"
|
|
56082
|
+
>
|
|
56083
|
+
@if (user.avatarUrl) {
|
|
56084
|
+
<img [src]="user.avatarUrl" [alt]="user.name" class="praxis-shell__user-avatar" />
|
|
56085
|
+
} @else {
|
|
56086
|
+
<div class="praxis-shell__user-initials">
|
|
56087
|
+
{{ user.initials || getUserInitials(user.name) }}
|
|
56088
|
+
</div>
|
|
56089
|
+
}
|
|
56090
|
+
|
|
56091
|
+
<div class="praxis-shell__user-info">
|
|
56092
|
+
<span class="praxis-shell__user-name">{{ user.name }}</span>
|
|
56093
|
+
@if (user.role) {
|
|
56094
|
+
<span class="praxis-shell__user-role">{{ user.role }}</span>
|
|
56095
|
+
}
|
|
56096
|
+
</div>
|
|
56097
|
+
</div>
|
|
56098
|
+
}
|
|
56099
|
+
</header>
|
|
56100
|
+
|
|
56101
|
+
<!-- Main Viewport Content Area -->
|
|
56102
|
+
<main class="praxis-shell__main" id="praxis-main-content">
|
|
56103
|
+
<ng-content></ng-content>
|
|
56104
|
+
</main>
|
|
56105
|
+
</div>
|
|
56106
|
+
</div>
|
|
56107
|
+
`, isInline: true, styles: [":host{display:block;width:100%;height:100vh;overflow:hidden;font-family:inherit}.praxis-shell{display:flex;width:100%;height:100%;background:var(--background, #090d16);color:var(--foreground, #f0f4f8);position:relative;overflow:hidden;box-sizing:border-box}.praxis-shell__skip-link{position:absolute;top:-100px;left:16px;background:var(--primary, #0ea5e9);color:#fff;padding:8px 16px;border-radius:6px;font-weight:600;font-size:.875rem;z-index:9999;text-decoration:none;transition:top .2s ease}.praxis-shell__skip-link:focus{top:16px;outline:2px solid #ffffff;outline-offset:2px}.praxis-shell__progress-bar{position:absolute;top:0;left:0;right:0;height:3px;background:#38bdf826;z-index:1000;overflow:hidden}.praxis-shell__progress-laser{width:40%;height:100%;background:linear-gradient(90deg,transparent,var(--primary, #0ea5e9),#38bdf8,transparent);box-shadow:0 0 10px #38bdf8;animation:praxis-laser-slide 1.4s infinite cubic-bezier(.4,0,.2,1)}@keyframes praxis-laser-slide{0%{transform:translate(-150%)}to{transform:translate(350%)}}.praxis-shell__backdrop{position:fixed;inset:0;background:#0000008c;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:200;animation:praxis-fade-in .2s ease}@keyframes praxis-fade-in{0%{opacity:0}to{opacity:1}}.praxis-shell__sidebar{width:260px;min-width:260px;height:100%;background:var(--card, #0f172a);border-right:1px solid var(--border, rgba(255, 255, 255, .08));display:flex;flex-direction:column;transition:width .25s cubic-bezier(.16,1,.3,1),transform .25s cubic-bezier(.16,1,.3,1);z-index:250;overflow:hidden}.praxis-shell--collapsed .praxis-shell__sidebar{width:72px;min-width:72px}.praxis-shell__brand{height:64px;padding:0 16px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--border, rgba(255, 255, 255, .06))}.praxis-shell__brand-link{display:flex;align-items:center;gap:12px;text-decoration:none;color:inherit;min-width:0}.praxis-shell__brand-icon{width:40px;height:40px;border-radius:10px;background:linear-gradient(135deg,var(--primary, #0ea5e9),#6366f1);color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 12px #0ea5e940}.praxis-shell__brand-logo{height:36px;max-width:140px;object-fit:contain}.praxis-shell__brand-info{display:flex;flex-direction:column;overflow:hidden}.praxis-shell__brand-title{font-weight:700;font-size:.95rem;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;letter-spacing:-.01em}.praxis-shell__brand-meta{font-size:.72rem;color:var(--muted-foreground, #94a3b8);white-space:nowrap}.praxis-shell__mobile-close-btn{display:none;background:transparent;border:none;color:var(--muted-foreground, #94a3b8);cursor:pointer;padding:6px;border-radius:6px}.praxis-shell__nav{flex:1;padding:16px 10px;overflow-y:auto;overflow-x:hidden}.praxis-shell__nav-group{margin-bottom:20px}.praxis-shell__nav-group-title{padding:0 10px 8px;font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--muted-foreground, #64748b)}.praxis-shell__nav-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:4px}.praxis-shell__nav-item{margin:0}.praxis-shell__nav-link{display:flex;align-items:center;gap:12px;padding:9px 12px;border-radius:9px;color:var(--muted-foreground, #94a3b8);text-decoration:none;font-size:.88rem;font-weight:500;transition:background .15s ease,color .15s ease;cursor:pointer;white-space:nowrap}.praxis-shell__nav-link:hover{background:#ffffff0d;color:var(--foreground, #f8fafc)}.praxis-shell__nav-link.active{background:color-mix(in oklab,var(--primary, #0ea5e9) 16%,transparent);color:var(--primary, #38bdf8);font-weight:600}.praxis-shell__nav-icon{display:flex;align-items:center;justify-content:center;width:24px;height:24px;flex-shrink:0}.praxis-shell__nav-icon .material-symbols-outlined{font-size:20px}.praxis-shell__nav-label{flex:1;overflow:hidden;text-overflow:ellipsis}.praxis-shell__nav-badge{font-size:.7rem;font-weight:700;padding:2px 7px;border-radius:9999px;line-height:1}.praxis-shell__nav-badge--primary{background:var(--primary, #0ea5e9);color:#fff}.praxis-shell__nav-badge--success{background:#10b981;color:#fff}.praxis-shell__nav-badge--warning{background:#f59e0b;color:#fff}.praxis-shell__nav-badge--error{background:#ef4444;color:#fff}.praxis-shell__nav-badge--info{background:#3b82f6;color:#fff}.praxis-shell__nav-badge--neutral{background:#64748b;color:#fff}.praxis-shell__sidebar-footer-status{padding:10px}.praxis-shell__status-card{padding:10px 12px;border-radius:10px;background:#ffffff08;border:1px solid var(--border, rgba(255, 255, 255, .07))}.praxis-shell__status-card--success{border-color:#10b9814d}.praxis-shell__status-card--warning{border-color:#f59e0b4d}.praxis-shell__status-card--error{border-color:#ef44444d}.praxis-shell__status-card-header{display:flex;align-items:center;gap:8px;font-size:.75rem;font-weight:600}.praxis-shell__pulse-indicator{position:relative;display:inline-flex;width:8px;height:8px}.praxis-shell__pulse-ring{position:absolute;inset:-2px;border-radius:9999px;background:#10b981;opacity:.6;animation:praxis-pulse 1.8s cubic-bezier(0,0,.2,1) infinite}.praxis-shell__pulse-dot{width:8px;height:8px;border-radius:9999px;background:#10b981}@keyframes praxis-pulse{0%{transform:scale(.9);opacity:.8}70%{transform:scale(2.2);opacity:0}to{transform:scale(2.2);opacity:0}}.praxis-shell__status-card-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-shell__status-card-metric{font-size:.7rem;color:var(--muted-foreground, #94a3b8);margin-top:4px}.praxis-shell__sidebar-toggle-bar{padding:10px;border-top:1px solid var(--border, rgba(255, 255, 255, .06))}.praxis-shell__collapse-btn{display:flex;align-items:center;gap:10px;width:100%;height:38px;padding:0 10px;border-radius:8px;background:transparent;border:none;color:var(--muted-foreground, #94a3b8);cursor:pointer;font-size:.85rem;font-weight:500;transition:background .15s ease,color .15s ease}.praxis-shell__collapse-btn:hover{background:#ffffff0d;color:var(--foreground, #f8fafc)}.praxis-shell__stage{flex:1;min-width:0;display:flex;flex-direction:column;height:100%;overflow:hidden}.praxis-shell__topbar{height:64px;padding:0 24px;background:var(--card, #0f172a);border-bottom:1px solid var(--border, rgba(255, 255, 255, .08));display:flex;align-items:center;gap:16px;flex-shrink:0;z-index:100}.praxis-shell__burger-btn{display:none;background:transparent;border:none;color:var(--foreground, #f8fafc);cursor:pointer;padding:8px;border-radius:8px}.praxis-shell__search-box{display:flex;align-items:center;gap:10px;width:320px;max-width:100%;height:38px;padding:0 12px;background:#ffffff0a;border:1px solid var(--border, rgba(255, 255, 255, .08));border-radius:9px;color:var(--muted-foreground, #94a3b8);transition:border-color .15s ease,box-shadow .15s ease}.praxis-shell__search-box:focus-within{border-color:var(--primary, #0ea5e9);box-shadow:0 0 0 2px #0ea5e933;color:var(--foreground, #f8fafc)}.praxis-shell__search-icon{font-size:18px}.praxis-shell__search-input{flex:1;background:transparent;border:none;outline:none;color:inherit;font-size:.85rem}.praxis-shell__topbar-spacer{flex:1}.praxis-shell__header-actions{display:flex;align-items:center;gap:8px}.praxis-shell__icon-btn{display:flex;align-items:center;justify-content:center;width:38px;height:38px;border-radius:9px;background:transparent;border:1px solid var(--border, rgba(255, 255, 255, .08));color:var(--muted-foreground, #94a3b8);cursor:pointer;transition:all .15s ease}.praxis-shell__icon-btn:hover{background:#ffffff0f;color:var(--foreground, #f8fafc);border-color:#ffffff26}.praxis-shell__user-profile{display:flex;align-items:center;gap:10px;padding:5px 10px 5px 6px;border-radius:9999px;background:#ffffff08;border:1px solid var(--border, rgba(255, 255, 255, .08));cursor:pointer;transition:all .15s ease;-webkit-user-select:none;user-select:none}.praxis-shell__user-profile:hover{background:#ffffff12;border-color:#ffffff29}.praxis-shell__user-avatar{width:28px;height:28px;border-radius:9999px;object-fit:cover}.praxis-shell__user-initials{width:28px;height:28px;border-radius:9999px;background:var(--primary, #0ea5e9);color:#fff;display:flex;align-items:center;justify-content:center;font-size:.75rem;font-weight:700}.praxis-shell__user-info{display:flex;flex-direction:column;line-height:1.2}.praxis-shell__user-name{font-size:.82rem;font-weight:600;color:var(--foreground, #f8fafc)}.praxis-shell__user-role{font-size:.68rem;color:var(--muted-foreground, #94a3b8)}.praxis-shell__main{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding:24px;box-sizing:border-box;background:var(--background, #090d16)}@media(max-width:900px){.praxis-shell__burger-btn,.praxis-shell__mobile-close-btn{display:flex}.praxis-shell__sidebar{position:fixed;top:0;bottom:0;left:0;transform:translate(-100%);width:280px!important;box-shadow:4px 0 24px #00000080}.praxis-shell--mobile-open .praxis-shell__sidebar{transform:translate(0)}.praxis-shell__search-box{width:200px}.praxis-shell__user-info{display:none}}@media(max-width:600px){.praxis-shell__topbar{padding:0 12px}.praxis-shell__search-box{display:none}.praxis-shell__main{padding:16px 12px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
56108
|
+
}
|
|
56109
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisAppShellComponent, decorators: [{
|
|
56110
|
+
type: Component,
|
|
56111
|
+
args: [{ selector: 'praxis-app-shell', standalone: true, imports: [CommonModule, RouterLink, RouterLinkActive], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
56112
|
+
<div
|
|
56113
|
+
class="praxis-shell"
|
|
56114
|
+
[class.praxis-shell--dark]="isDarkTheme"
|
|
56115
|
+
[class.praxis-shell--collapsed]="collapsed"
|
|
56116
|
+
[class.praxis-shell--mobile-open]="mobileOpen()"
|
|
56117
|
+
>
|
|
56118
|
+
<!-- A11y Skip to Main Content Link -->
|
|
56119
|
+
<a href="#praxis-main-content" class="praxis-shell__skip-link">
|
|
56120
|
+
Pular para o conteúdo principal
|
|
56121
|
+
</a>
|
|
56122
|
+
|
|
56123
|
+
<!-- Tactical Top Shimmer Progress Bar -->
|
|
56124
|
+
@if (effectiveLoading()) {
|
|
56125
|
+
<div
|
|
56126
|
+
class="praxis-shell__progress-bar"
|
|
56127
|
+
role="progressbar"
|
|
56128
|
+
aria-valuemin="0"
|
|
56129
|
+
aria-valuemax="100"
|
|
56130
|
+
aria-label="Sincronização em andamento"
|
|
56131
|
+
>
|
|
56132
|
+
<div class="praxis-shell__progress-laser"></div>
|
|
56133
|
+
</div>
|
|
56134
|
+
}
|
|
56135
|
+
|
|
56136
|
+
<!-- Mobile Backdrop -->
|
|
56137
|
+
@if (mobileOpen()) {
|
|
56138
|
+
<div
|
|
56139
|
+
class="praxis-shell__backdrop"
|
|
56140
|
+
(click)="closeMobile()"
|
|
56141
|
+
aria-hidden="true"
|
|
56142
|
+
></div>
|
|
56143
|
+
}
|
|
56144
|
+
|
|
56145
|
+
<!-- Sidebar -->
|
|
56146
|
+
<aside class="praxis-shell__sidebar" id="praxis-sidebar-nav" aria-label="Navegação Principal">
|
|
56147
|
+
<!-- Brand Header -->
|
|
56148
|
+
<div class="praxis-shell__brand">
|
|
56149
|
+
<a
|
|
56150
|
+
class="praxis-shell__brand-link"
|
|
56151
|
+
[routerLink]="brand?.href || '/'"
|
|
56152
|
+
(click)="closeMobile()"
|
|
56153
|
+
>
|
|
56154
|
+
@if (brand?.logoUrl) {
|
|
56155
|
+
<img
|
|
56156
|
+
[src]="brand?.logoUrl"
|
|
56157
|
+
[alt]="brand?.title || 'Logo'"
|
|
56158
|
+
class="praxis-shell__brand-logo"
|
|
56159
|
+
/>
|
|
56160
|
+
} @else {
|
|
56161
|
+
<div class="praxis-shell__brand-icon">
|
|
56162
|
+
<span class="material-symbols-outlined">{{ brand?.icon || 'apps' }}</span>
|
|
56163
|
+
</div>
|
|
56164
|
+
}
|
|
56165
|
+
|
|
56166
|
+
@if (!collapsed) {
|
|
56167
|
+
<div class="praxis-shell__brand-info">
|
|
56168
|
+
<span class="praxis-shell__brand-title">{{ brand?.title || 'Praxis' }}</span>
|
|
56169
|
+
@if (brand?.version || brand?.subtitle) {
|
|
56170
|
+
<span class="praxis-shell__brand-meta">
|
|
56171
|
+
{{ brand?.version || brand?.subtitle }}
|
|
56172
|
+
</span>
|
|
56173
|
+
}
|
|
56174
|
+
</div>
|
|
56175
|
+
}
|
|
56176
|
+
</a>
|
|
56177
|
+
|
|
56178
|
+
<ng-content select="[shell-brand-extra]"></ng-content>
|
|
56179
|
+
|
|
56180
|
+
<!-- Mobile Close Button -->
|
|
56181
|
+
<button
|
|
56182
|
+
type="button"
|
|
56183
|
+
class="praxis-shell__mobile-close-btn"
|
|
56184
|
+
(click)="closeMobile()"
|
|
56185
|
+
aria-label="Fechar navegação"
|
|
56186
|
+
>
|
|
56187
|
+
<span class="material-symbols-outlined">close</span>
|
|
56188
|
+
</button>
|
|
56189
|
+
</div>
|
|
56190
|
+
|
|
56191
|
+
<!-- Navigation Groups -->
|
|
56192
|
+
<nav class="praxis-shell__nav">
|
|
56193
|
+
@for (group of navigation; track group.label || $index) {
|
|
56194
|
+
<div class="praxis-shell__nav-group">
|
|
56195
|
+
@if (group.label && !collapsed) {
|
|
56196
|
+
<div class="praxis-shell__nav-group-title">{{ group.label }}</div>
|
|
56197
|
+
}
|
|
56198
|
+
<ul class="praxis-shell__nav-list">
|
|
56199
|
+
@for (item of group.items; track item.path) {
|
|
56200
|
+
<li class="praxis-shell__nav-item">
|
|
56201
|
+
<a
|
|
56202
|
+
[routerLink]="item.path"
|
|
56203
|
+
routerLinkActive="active"
|
|
56204
|
+
[routerLinkActiveOptions]="{ exact: item.exact ?? (item.path === '/') }"
|
|
56205
|
+
(click)="onItemClick(item)"
|
|
56206
|
+
class="praxis-shell__nav-link"
|
|
56207
|
+
[class.disabled]="item.disabled"
|
|
56208
|
+
[attr.title]="collapsed ? item.label : (item.title || null)"
|
|
56209
|
+
[attr.aria-disabled]="item.disabled ? 'true' : null"
|
|
56210
|
+
>
|
|
56211
|
+
<span class="praxis-shell__nav-icon">
|
|
56212
|
+
<span class="material-symbols-outlined">{{ item.icon || 'circle' }}</span>
|
|
56213
|
+
</span>
|
|
56214
|
+
|
|
56215
|
+
@if (!collapsed) {
|
|
56216
|
+
<span class="praxis-shell__nav-label">{{ item.label }}</span>
|
|
56217
|
+
|
|
56218
|
+
@if (item.badge !== undefined && item.badge !== null) {
|
|
56219
|
+
<span
|
|
56220
|
+
class="praxis-shell__nav-badge"
|
|
56221
|
+
[ngClass]="'praxis-shell__nav-badge--' + (item.badgeTone || 'primary')"
|
|
56222
|
+
>
|
|
56223
|
+
{{ item.badge }}
|
|
56224
|
+
</span>
|
|
56225
|
+
}
|
|
56226
|
+
}
|
|
56227
|
+
</a>
|
|
56228
|
+
</li>
|
|
56229
|
+
}
|
|
56230
|
+
</ul>
|
|
56231
|
+
</div>
|
|
56232
|
+
}
|
|
56233
|
+
</nav>
|
|
56234
|
+
|
|
56235
|
+
<!-- Sidebar Footer Status -->
|
|
56236
|
+
@if (footerStatus) {
|
|
56237
|
+
<div class="praxis-shell__sidebar-footer-status">
|
|
56238
|
+
@if (!collapsed) {
|
|
56239
|
+
<div
|
|
56240
|
+
class="praxis-shell__status-card"
|
|
56241
|
+
[ngClass]="'praxis-shell__status-card--' + (footerStatus.statusTone || 'info')"
|
|
56242
|
+
>
|
|
56243
|
+
<div class="praxis-shell__status-card-header">
|
|
56244
|
+
@if (footerStatus.pulse !== false) {
|
|
56245
|
+
<span class="praxis-shell__pulse-indicator">
|
|
56246
|
+
<span class="praxis-shell__pulse-ring"></span>
|
|
56247
|
+
<span class="praxis-shell__pulse-dot"></span>
|
|
56248
|
+
</span>
|
|
56249
|
+
}
|
|
56250
|
+
<span class="praxis-shell__status-card-title">{{ footerStatus.title }}</span>
|
|
56251
|
+
</div>
|
|
56252
|
+
@if (footerStatus.metric) {
|
|
56253
|
+
<div class="praxis-shell__status-card-metric">{{ footerStatus.metric }}</div>
|
|
56254
|
+
}
|
|
56255
|
+
</div>
|
|
56256
|
+
}
|
|
56257
|
+
</div>
|
|
56258
|
+
}
|
|
56259
|
+
|
|
56260
|
+
<ng-content select="[shell-footer-extra]"></ng-content>
|
|
56261
|
+
|
|
56262
|
+
<!-- Sidebar Collapse Toggle Button -->
|
|
56263
|
+
<div class="praxis-shell__sidebar-toggle-bar">
|
|
56264
|
+
<button
|
|
56265
|
+
type="button"
|
|
56266
|
+
class="praxis-shell__collapse-btn"
|
|
56267
|
+
(click)="toggleCollapse()"
|
|
56268
|
+
[attr.aria-expanded]="!collapsed"
|
|
56269
|
+
[attr.aria-label]="collapsed ? 'Expandir barra lateral' : 'Recolher barra lateral'"
|
|
56270
|
+
>
|
|
56271
|
+
<span class="material-symbols-outlined">
|
|
56272
|
+
{{ collapsed ? 'chevron_right' : 'chevron_left' }}
|
|
56273
|
+
</span>
|
|
56274
|
+
@if (!collapsed) {
|
|
56275
|
+
<span class="praxis-shell__collapse-btn-text">Recolher menu</span>
|
|
56276
|
+
}
|
|
56277
|
+
</button>
|
|
56278
|
+
</div>
|
|
56279
|
+
</aside>
|
|
56280
|
+
|
|
56281
|
+
<!-- Main Stage Container -->
|
|
56282
|
+
<div class="praxis-shell__stage">
|
|
56283
|
+
<!-- Top Application Bar -->
|
|
56284
|
+
<header class="praxis-shell__topbar" role="banner">
|
|
56285
|
+
<!-- Mobile Menu Trigger -->
|
|
56286
|
+
<button
|
|
56287
|
+
type="button"
|
|
56288
|
+
class="praxis-shell__burger-btn"
|
|
56289
|
+
(click)="openMobile()"
|
|
56290
|
+
[attr.aria-expanded]="mobileOpen()"
|
|
56291
|
+
aria-controls="praxis-sidebar-nav"
|
|
56292
|
+
aria-label="Abrir navegação"
|
|
56293
|
+
>
|
|
56294
|
+
<span class="material-symbols-outlined">menu</span>
|
|
56295
|
+
</button>
|
|
56296
|
+
|
|
56297
|
+
<!-- Search / Quick Command Area -->
|
|
56298
|
+
@if (showSearch) {
|
|
56299
|
+
<div class="praxis-shell__search-box" role="search">
|
|
56300
|
+
<span class="material-symbols-outlined praxis-shell__search-icon" aria-hidden="true">search</span>
|
|
56301
|
+
<input
|
|
56302
|
+
type="text"
|
|
56303
|
+
class="praxis-shell__search-input"
|
|
56304
|
+
[placeholder]="searchPlaceholder"
|
|
56305
|
+
[value]="searchQuery()"
|
|
56306
|
+
(input)="onSearchInput($any($event.target).value)"
|
|
56307
|
+
(keydown.enter)="onSearchEnter()"
|
|
56308
|
+
aria-label="Buscar no sistema"
|
|
56309
|
+
/>
|
|
56310
|
+
</div>
|
|
56311
|
+
}
|
|
56312
|
+
|
|
56313
|
+
<!-- Spacer -->
|
|
56314
|
+
<div class="praxis-shell__topbar-spacer"></div>
|
|
56315
|
+
|
|
56316
|
+
<!-- Header Actions Content Slot -->
|
|
56317
|
+
<div class="praxis-shell__header-actions">
|
|
56318
|
+
<ng-content select="[shell-header-actions]"></ng-content>
|
|
56319
|
+
</div>
|
|
56320
|
+
|
|
56321
|
+
<!-- Theme Toggle -->
|
|
56322
|
+
@if (showThemeToggle) {
|
|
56323
|
+
<button
|
|
56324
|
+
type="button"
|
|
56325
|
+
class="praxis-shell__icon-btn"
|
|
56326
|
+
(click)="onThemeToggleClick()"
|
|
56327
|
+
[attr.aria-label]="isDarkTheme ? 'Ativar modo claro' : 'Ativar modo escuro'"
|
|
56328
|
+
[attr.title]="isDarkTheme ? 'Modo Claro' : 'Modo Escuro'"
|
|
56329
|
+
>
|
|
56330
|
+
<span class="material-symbols-outlined">
|
|
56331
|
+
{{ isDarkTheme ? 'light_mode' : 'dark_mode' }}
|
|
56332
|
+
</span>
|
|
56333
|
+
</button>
|
|
56334
|
+
}
|
|
56335
|
+
|
|
56336
|
+
<!-- User Profile Badge -->
|
|
56337
|
+
@if (user) {
|
|
56338
|
+
<div
|
|
56339
|
+
class="praxis-shell__user-profile"
|
|
56340
|
+
(click)="onUserClick()"
|
|
56341
|
+
role="button"
|
|
56342
|
+
tabindex="0"
|
|
56343
|
+
(keydown.enter)="onUserClick()"
|
|
56344
|
+
(keydown.space)="onUserClick()"
|
|
56345
|
+
[attr.aria-label]="'Perfil de ' + user.name"
|
|
56346
|
+
>
|
|
56347
|
+
@if (user.avatarUrl) {
|
|
56348
|
+
<img [src]="user.avatarUrl" [alt]="user.name" class="praxis-shell__user-avatar" />
|
|
56349
|
+
} @else {
|
|
56350
|
+
<div class="praxis-shell__user-initials">
|
|
56351
|
+
{{ user.initials || getUserInitials(user.name) }}
|
|
56352
|
+
</div>
|
|
56353
|
+
}
|
|
56354
|
+
|
|
56355
|
+
<div class="praxis-shell__user-info">
|
|
56356
|
+
<span class="praxis-shell__user-name">{{ user.name }}</span>
|
|
56357
|
+
@if (user.role) {
|
|
56358
|
+
<span class="praxis-shell__user-role">{{ user.role }}</span>
|
|
56359
|
+
}
|
|
56360
|
+
</div>
|
|
56361
|
+
</div>
|
|
56362
|
+
}
|
|
56363
|
+
</header>
|
|
56364
|
+
|
|
56365
|
+
<!-- Main Viewport Content Area -->
|
|
56366
|
+
<main class="praxis-shell__main" id="praxis-main-content">
|
|
56367
|
+
<ng-content></ng-content>
|
|
56368
|
+
</main>
|
|
56369
|
+
</div>
|
|
56370
|
+
</div>
|
|
56371
|
+
`, styles: [":host{display:block;width:100%;height:100vh;overflow:hidden;font-family:inherit}.praxis-shell{display:flex;width:100%;height:100%;background:var(--background, #090d16);color:var(--foreground, #f0f4f8);position:relative;overflow:hidden;box-sizing:border-box}.praxis-shell__skip-link{position:absolute;top:-100px;left:16px;background:var(--primary, #0ea5e9);color:#fff;padding:8px 16px;border-radius:6px;font-weight:600;font-size:.875rem;z-index:9999;text-decoration:none;transition:top .2s ease}.praxis-shell__skip-link:focus{top:16px;outline:2px solid #ffffff;outline-offset:2px}.praxis-shell__progress-bar{position:absolute;top:0;left:0;right:0;height:3px;background:#38bdf826;z-index:1000;overflow:hidden}.praxis-shell__progress-laser{width:40%;height:100%;background:linear-gradient(90deg,transparent,var(--primary, #0ea5e9),#38bdf8,transparent);box-shadow:0 0 10px #38bdf8;animation:praxis-laser-slide 1.4s infinite cubic-bezier(.4,0,.2,1)}@keyframes praxis-laser-slide{0%{transform:translate(-150%)}to{transform:translate(350%)}}.praxis-shell__backdrop{position:fixed;inset:0;background:#0000008c;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:200;animation:praxis-fade-in .2s ease}@keyframes praxis-fade-in{0%{opacity:0}to{opacity:1}}.praxis-shell__sidebar{width:260px;min-width:260px;height:100%;background:var(--card, #0f172a);border-right:1px solid var(--border, rgba(255, 255, 255, .08));display:flex;flex-direction:column;transition:width .25s cubic-bezier(.16,1,.3,1),transform .25s cubic-bezier(.16,1,.3,1);z-index:250;overflow:hidden}.praxis-shell--collapsed .praxis-shell__sidebar{width:72px;min-width:72px}.praxis-shell__brand{height:64px;padding:0 16px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--border, rgba(255, 255, 255, .06))}.praxis-shell__brand-link{display:flex;align-items:center;gap:12px;text-decoration:none;color:inherit;min-width:0}.praxis-shell__brand-icon{width:40px;height:40px;border-radius:10px;background:linear-gradient(135deg,var(--primary, #0ea5e9),#6366f1);color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 12px #0ea5e940}.praxis-shell__brand-logo{height:36px;max-width:140px;object-fit:contain}.praxis-shell__brand-info{display:flex;flex-direction:column;overflow:hidden}.praxis-shell__brand-title{font-weight:700;font-size:.95rem;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;letter-spacing:-.01em}.praxis-shell__brand-meta{font-size:.72rem;color:var(--muted-foreground, #94a3b8);white-space:nowrap}.praxis-shell__mobile-close-btn{display:none;background:transparent;border:none;color:var(--muted-foreground, #94a3b8);cursor:pointer;padding:6px;border-radius:6px}.praxis-shell__nav{flex:1;padding:16px 10px;overflow-y:auto;overflow-x:hidden}.praxis-shell__nav-group{margin-bottom:20px}.praxis-shell__nav-group-title{padding:0 10px 8px;font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--muted-foreground, #64748b)}.praxis-shell__nav-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:4px}.praxis-shell__nav-item{margin:0}.praxis-shell__nav-link{display:flex;align-items:center;gap:12px;padding:9px 12px;border-radius:9px;color:var(--muted-foreground, #94a3b8);text-decoration:none;font-size:.88rem;font-weight:500;transition:background .15s ease,color .15s ease;cursor:pointer;white-space:nowrap}.praxis-shell__nav-link:hover{background:#ffffff0d;color:var(--foreground, #f8fafc)}.praxis-shell__nav-link.active{background:color-mix(in oklab,var(--primary, #0ea5e9) 16%,transparent);color:var(--primary, #38bdf8);font-weight:600}.praxis-shell__nav-icon{display:flex;align-items:center;justify-content:center;width:24px;height:24px;flex-shrink:0}.praxis-shell__nav-icon .material-symbols-outlined{font-size:20px}.praxis-shell__nav-label{flex:1;overflow:hidden;text-overflow:ellipsis}.praxis-shell__nav-badge{font-size:.7rem;font-weight:700;padding:2px 7px;border-radius:9999px;line-height:1}.praxis-shell__nav-badge--primary{background:var(--primary, #0ea5e9);color:#fff}.praxis-shell__nav-badge--success{background:#10b981;color:#fff}.praxis-shell__nav-badge--warning{background:#f59e0b;color:#fff}.praxis-shell__nav-badge--error{background:#ef4444;color:#fff}.praxis-shell__nav-badge--info{background:#3b82f6;color:#fff}.praxis-shell__nav-badge--neutral{background:#64748b;color:#fff}.praxis-shell__sidebar-footer-status{padding:10px}.praxis-shell__status-card{padding:10px 12px;border-radius:10px;background:#ffffff08;border:1px solid var(--border, rgba(255, 255, 255, .07))}.praxis-shell__status-card--success{border-color:#10b9814d}.praxis-shell__status-card--warning{border-color:#f59e0b4d}.praxis-shell__status-card--error{border-color:#ef44444d}.praxis-shell__status-card-header{display:flex;align-items:center;gap:8px;font-size:.75rem;font-weight:600}.praxis-shell__pulse-indicator{position:relative;display:inline-flex;width:8px;height:8px}.praxis-shell__pulse-ring{position:absolute;inset:-2px;border-radius:9999px;background:#10b981;opacity:.6;animation:praxis-pulse 1.8s cubic-bezier(0,0,.2,1) infinite}.praxis-shell__pulse-dot{width:8px;height:8px;border-radius:9999px;background:#10b981}@keyframes praxis-pulse{0%{transform:scale(.9);opacity:.8}70%{transform:scale(2.2);opacity:0}to{transform:scale(2.2);opacity:0}}.praxis-shell__status-card-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-shell__status-card-metric{font-size:.7rem;color:var(--muted-foreground, #94a3b8);margin-top:4px}.praxis-shell__sidebar-toggle-bar{padding:10px;border-top:1px solid var(--border, rgba(255, 255, 255, .06))}.praxis-shell__collapse-btn{display:flex;align-items:center;gap:10px;width:100%;height:38px;padding:0 10px;border-radius:8px;background:transparent;border:none;color:var(--muted-foreground, #94a3b8);cursor:pointer;font-size:.85rem;font-weight:500;transition:background .15s ease,color .15s ease}.praxis-shell__collapse-btn:hover{background:#ffffff0d;color:var(--foreground, #f8fafc)}.praxis-shell__stage{flex:1;min-width:0;display:flex;flex-direction:column;height:100%;overflow:hidden}.praxis-shell__topbar{height:64px;padding:0 24px;background:var(--card, #0f172a);border-bottom:1px solid var(--border, rgba(255, 255, 255, .08));display:flex;align-items:center;gap:16px;flex-shrink:0;z-index:100}.praxis-shell__burger-btn{display:none;background:transparent;border:none;color:var(--foreground, #f8fafc);cursor:pointer;padding:8px;border-radius:8px}.praxis-shell__search-box{display:flex;align-items:center;gap:10px;width:320px;max-width:100%;height:38px;padding:0 12px;background:#ffffff0a;border:1px solid var(--border, rgba(255, 255, 255, .08));border-radius:9px;color:var(--muted-foreground, #94a3b8);transition:border-color .15s ease,box-shadow .15s ease}.praxis-shell__search-box:focus-within{border-color:var(--primary, #0ea5e9);box-shadow:0 0 0 2px #0ea5e933;color:var(--foreground, #f8fafc)}.praxis-shell__search-icon{font-size:18px}.praxis-shell__search-input{flex:1;background:transparent;border:none;outline:none;color:inherit;font-size:.85rem}.praxis-shell__topbar-spacer{flex:1}.praxis-shell__header-actions{display:flex;align-items:center;gap:8px}.praxis-shell__icon-btn{display:flex;align-items:center;justify-content:center;width:38px;height:38px;border-radius:9px;background:transparent;border:1px solid var(--border, rgba(255, 255, 255, .08));color:var(--muted-foreground, #94a3b8);cursor:pointer;transition:all .15s ease}.praxis-shell__icon-btn:hover{background:#ffffff0f;color:var(--foreground, #f8fafc);border-color:#ffffff26}.praxis-shell__user-profile{display:flex;align-items:center;gap:10px;padding:5px 10px 5px 6px;border-radius:9999px;background:#ffffff08;border:1px solid var(--border, rgba(255, 255, 255, .08));cursor:pointer;transition:all .15s ease;-webkit-user-select:none;user-select:none}.praxis-shell__user-profile:hover{background:#ffffff12;border-color:#ffffff29}.praxis-shell__user-avatar{width:28px;height:28px;border-radius:9999px;object-fit:cover}.praxis-shell__user-initials{width:28px;height:28px;border-radius:9999px;background:var(--primary, #0ea5e9);color:#fff;display:flex;align-items:center;justify-content:center;font-size:.75rem;font-weight:700}.praxis-shell__user-info{display:flex;flex-direction:column;line-height:1.2}.praxis-shell__user-name{font-size:.82rem;font-weight:600;color:var(--foreground, #f8fafc)}.praxis-shell__user-role{font-size:.68rem;color:var(--muted-foreground, #94a3b8)}.praxis-shell__main{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding:24px;box-sizing:border-box;background:var(--background, #090d16)}@media(max-width:900px){.praxis-shell__burger-btn,.praxis-shell__mobile-close-btn{display:flex}.praxis-shell__sidebar{position:fixed;top:0;bottom:0;left:0;transform:translate(-100%);width:280px!important;box-shadow:4px 0 24px #00000080}.praxis-shell--mobile-open .praxis-shell__sidebar{transform:translate(0)}.praxis-shell__search-box{width:200px}.praxis-shell__user-info{display:none}}@media(max-width:600px){.praxis-shell__topbar{padding:0 12px}.praxis-shell__search-box{display:none}.praxis-shell__main{padding:16px 12px}}\n"] }]
|
|
56372
|
+
}], propDecorators: { brand: [{
|
|
56373
|
+
type: Input
|
|
56374
|
+
}], navigation: [{
|
|
56375
|
+
type: Input
|
|
56376
|
+
}], user: [{
|
|
56377
|
+
type: Input
|
|
56378
|
+
}], showThemeToggle: [{
|
|
56379
|
+
type: Input
|
|
56380
|
+
}], isDarkTheme: [{
|
|
56381
|
+
type: Input
|
|
56382
|
+
}], showSearch: [{
|
|
56383
|
+
type: Input
|
|
56384
|
+
}], searchPlaceholder: [{
|
|
56385
|
+
type: Input
|
|
56386
|
+
}], footerStatus: [{
|
|
56387
|
+
type: Input
|
|
56388
|
+
}], isAnyLoading: [{
|
|
56389
|
+
type: Input
|
|
56390
|
+
}], collapsed: [{
|
|
56391
|
+
type: Input
|
|
56392
|
+
}], themeToggle: [{
|
|
56393
|
+
type: Output
|
|
56394
|
+
}], searchSubmit: [{
|
|
56395
|
+
type: Output
|
|
56396
|
+
}], searchChange: [{
|
|
56397
|
+
type: Output
|
|
56398
|
+
}], userProfileClick: [{
|
|
56399
|
+
type: Output
|
|
56400
|
+
}], collapsedChange: [{
|
|
56401
|
+
type: Output
|
|
56402
|
+
}], navItemClick: [{
|
|
56403
|
+
type: Output
|
|
56404
|
+
}], handleEscape: [{
|
|
56405
|
+
type: HostListener,
|
|
56406
|
+
args: ['keydown.escape']
|
|
56407
|
+
}] } });
|
|
56408
|
+
|
|
56409
|
+
/**
|
|
56410
|
+
* Praxis UI Platform — Canonical Widget Event Bus Models (Issue #3)
|
|
56411
|
+
*
|
|
56412
|
+
* Contratos canônicos de eventos, escopos e fiação (wiring) declarativa
|
|
56413
|
+
* entre widgets heterogêneos (KPIs, Charts, Tabelas, Filtros, Formulários).
|
|
56414
|
+
*/
|
|
56415
|
+
|
|
53334
56416
|
/*
|
|
53335
56417
|
* Public API Surface of praxis-core
|
|
53336
56418
|
*/
|
|
@@ -53339,4 +56421,4 @@ function provideHookWhitelist(allowed) {
|
|
|
53339
56421
|
* Generated bundle index. Do not edit.
|
|
53340
56422
|
*/
|
|
53341
56423
|
|
|
53342
|
-
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, BUILTIN_WIDGET_SHELL_PRESETS, COMPONENT_METADATA_REGISTRY_I18N_CONFIG, COMPONENT_METADATA_REGISTRY_I18N_NAMESPACE, CONFIG_STORAGE, CONNECTION_STORAGE, ComponentAuthoringManifestProjectionError, ComponentKeyService, ComponentMetadataRegistry, ComponentRuntimeProfileService, CompositionRuntimeFacade, CompositionValidatorService, ConsoleLoggerSink, CrudOperationResolutionService, DEFAULT_FIELD_SELECTOR_CONTROL_TYPE_MAP, DEFAULT_JSON_LOGIC_OPERATORS, DEFAULT_SCHEMA_REQUEST_TIMEOUT_MS, DEFAULT_TABLE_CONFIG, DOMAIN_CATALOG_COMPONENT_CONTEXT_PACK, DOMAIN_CATALOG_CONTEXT_HINT_SCHEMA_VERSION, DYNAMIC_PAGE_AI_CAPABILITIES, DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK, DYNAMIC_PAGE_CONFIG_EDITOR, DYNAMIC_PAGE_SHELL_EDITOR, DefaultLoadingRenderer, DeferredAsyncConfigStorage, DomainCatalogService, DomainKnowledgeService, DomainRuleService, DynamicFormService, DynamicWidgetLoaderDirective, DynamicWidgetPageComponent, EDITORIAL_ALLOWED_CONTENT_FORMATS, EDITORIAL_COMPLIANCE_PRESETS, EDITORIAL_EXTERNAL_LINK_REL, EDITORIAL_FORM_TEMPLATE_CATALOG, EDITORIAL_HTML_ENABLED, EDITORIAL_MARKDOWN_IMAGES_ENABLED, EDITORIAL_SOLUTION_CATALOG, EDITORIAL_SOLUTION_PRESETS, EDITORIAL_THEME_PRESETS, EDITORIAL_WIDGET_CONVENTION_INPUTS, EDITORIAL_WIDGET_TAG, EMPLOYEE_ONBOARDING_EDITORIAL_SOLUTION, EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE, EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_SOLUTION, EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_TEMPLATE, EVENT_REGISTRATION_EDITORIAL_SOLUTION, EVENT_REGISTRATION_EDITORIAL_TEMPLATE, EmptyStateCardComponent, EnterpriseRuntimeContextService, ErrorMessageService, FIELD_METADATA_CAPABILITIES, FIELD_SELECTOR_REGISTRY_BASE, FIELD_SELECTOR_REGISTRY_DISABLE_DEFAULTS, FIELD_SELECTOR_REGISTRY_OVERRIDES, FORM_HOOKS, FORM_HOOKS_PRESETS, FORM_HOOKS_WHITELIST, FORM_HOOK_RESOLVERS, FieldControlType, FieldDataType, FieldSelectorRegistry, FormHooksRegistry, GLOBAL_ACTION_CATALOG, GLOBAL_ACTION_HANDLERS, GLOBAL_ACTION_UI_SCHEMAS, GLOBAL_ANALYTICS_SERVICE, GLOBAL_API_CLIENT, GLOBAL_CONFIG, GLOBAL_DIALOG_SERVICE, GLOBAL_ROUTE_GUARD_RESOLVER, GLOBAL_SURFACE_SERVICE, GLOBAL_TOAST_SERVICE, GOVERNED_COLOR_PALETTE_OPTIONS, GenericCrudService, GlobalActionService, GlobalConfigService, GovernedColorPaletteService, INLINE_FILTER_ALIAS_TOKENS, INLINE_FILTER_CONTROL_TYPES, INLINE_FILTER_CONTROL_TYPE_SET, INLINE_FILTER_CONTROL_TYPE_VALUES, INLINE_FILTER_TOKEN_TO_BASE_CONTROL_TYPE, INLINE_FILTER_TOKEN_TO_CONTROL_TYPE, IconPickerService, IconPosition, IconSize, LOGGER_LEVEL_BY_ENV, LOGGER_LEVEL_PRIORITY, LoadingOrchestrator, LocalConnectionStorage, LocalStorageAsyncAdapter, LocalStorageCacheAdapter, LocalStorageConfigService, LoggerService, LoggerThrottleTracker, LoggerWarnOnceTracker, MemoryCacheAdapter, NestedPortCatalogService, NestedWidgetConfigAccessor, NumericFormat, OVERLAY_DECIDER_DEBUG, OVERLAY_DECISION_MATRIX, ObservabilityDashboardService, OverlayDeciderService, PRAXIS_ACTION_CONTROL_DEFAULTS, PRAXIS_ACTION_CONTROL_VARS, PRAXIS_COLLECTION_EXPORT_HTTP_OPTIONS, PRAXIS_COLLECTION_EXPORT_PROVIDER, PRAXIS_COLLECTION_SEARCH_DEFAULTS, PRAXIS_COLLECTION_SEARCH_VARS, PRAXIS_CORPORATE_SENSITIVE_KEYS, PRAXIS_DEFAULT_EXPORT_SECURITY_POLICY, PRAXIS_DEFAULT_OBSERVABILITY_ALERT_RULES, PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY, PRAXIS_EXPORT_FORMULA_PREFIXES, PRAXIS_EXPORT_SECURITY_POLICY, PRAXIS_FOOTER_LINKS_METADATA, PRAXIS_GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_OPTIONS, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_READY, PRAXIS_GLOBAL_CONFIG_TENANT_RESOLVER, PRAXIS_HERO_BANNER_METADATA, PRAXIS_I18N_CONFIG, PRAXIS_I18N_TRANSLATOR, PRAXIS_JSON_LOGIC_OPERATORS, PRAXIS_LAYER_SCALE_DEFAULTS, PRAXIS_LAYER_SCALE_VARS, PRAXIS_LEGAL_NOTICE_METADATA, PRAXIS_LOADING_CTX, PRAXIS_LOADING_RENDERER, PRAXIS_LOGGER_CONFIG, PRAXIS_LOGGER_SINKS, PRAXIS_OBSERVABILITY_DASHBOARD_OPTIONS, PRAXIS_QUERY_FILTER_EXPRESSION_SCHEMA_VERSION, PRAXIS_RELATED_RESOURCE_OUTLET_AUTHORING_MANIFEST, PRAXIS_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA, PRAXIS_RELATED_RESOURCE_OUTLET_PORTS, PRAXIS_RICH_TEXT_BLOCK_METADATA, PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS, PRAXIS_TABLE_DETAIL_INLINE_RENDERERS, PRAXIS_TABLE_DETAIL_RESOURCE_RESOLVER, PRAXIS_TELEMETRY_TRANSPORT, PRAXIS_THEME_SURFACE_DEFAULTS, PRAXIS_THEME_SURFACE_VARS, PRAXIS_USER_CONTEXT_SUMMARY_METADATA, PRIVACY_CONSENT_EDITORIAL_SOLUTION, PRIVACY_CONSENT_EDITORIAL_TEMPLATE, PraxisCollectionExportService, PraxisCore, PraxisFooterLinksComponent, PraxisGlobalErrorHandler, PraxisHeroBannerComponent, PraxisHttpCollectionExportProvider, PraxisI18nService, PraxisIconButtonComponent, PraxisIconDirective, PraxisIconPickerComponent, PraxisJsonLogicError, PraxisJsonLogicService, PraxisLayerScaleStyleService, PraxisLegalNoticeComponent, PraxisLoadingInterceptor, PraxisRelatedResourceOutletComponent, PraxisRelatedResourceOutletConfigEditorComponent, PraxisResourceIdentityComponent, PraxisRichTextBlockComponent, PraxisRuntimeComponentObservationRegistryService, PraxisSurfaceHostComponent, PraxisUserContextSummaryComponent, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, RULE_PROPERTY_SCHEMA, RelatedResourceSurfaceResolverService, RemoteConfigStorage, ResourceActionOpenAdapterService, ResourceDiscoveryService, ResourceQuickConnectComponent, ResourceRecordOpenError, ResourceRecordOpenService, ResourceSurfaceOpenAdapterService, SCHEMA_METADATA_CLIENT_OPTIONS, SCHEMA_VIEWER_CONTEXT, SETTINGS_EDITOR_SECTIONS_HOSTED, SETTINGS_PANEL_BRIDGE, SETTINGS_PANEL_DATA, STEPPER_CONFIG_EDITOR, SURFACE_DRAWER_BRIDGE, SURFACE_DRAWER_CONTENT_DATA, SURFACE_DRAWER_REF, SURFACE_NAVIGATION_I18N_CONFIG, SURFACE_NAVIGATION_I18N_NAMESPACE, SURFACE_OPEN_I18N_CONFIG, SURFACE_OPEN_I18N_NAMESPACE, SURFACE_OPEN_PRESETS, SchemaMetadataClient, SchemaNormalizerService, SchemaViewerComponent, SettingsSectionTabsComponent, SurfaceBindingRuntimeService, SurfaceNavigationError, SurfaceOpenActionEditorComponent, SurfaceOpenMaterializerService, SurfaceOutletRegistryService, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageCompositionFactory, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, assertPraxisRuntimeComponentObservationSerializable, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisActionControlCss, buildPraxisCollectionSearchCss, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildPraxisThemeSurfaceCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, canonicalJsonSha256, canonicalJsonStringify, clampRange, classifyEntityLookupResult, clonePraxisRuntimeComponentObservation, cloneTableConfig, cnpjAlphaValidator, collapseWhitespace, composeHeadersWithVersion, conditionalAsyncValidator, convertFormLayoutToConfig, createCorporateLoggerConfig, createCorporateObservabilityOptions, createCpfCnpjValidator, createDefaultFormConfig, createDefaultTableConfig, createEmptyFormConfig, createEmptyRichContentDocument, createFieldLayoutItem, createPersistedPage, customAsyncValidatorFn, customValidatorFn, debounceAsyncValidator, deepMerge, domainKnowledgeTimelineToRichContentDocument, domainRuleTimelineToRichContentDocument, ensureIds, ensureNoConflictsHookFactory, ensurePageIds, escapePraxisExportCell, evaluateFieldAccess, extractNormalizedError, fetchWithETag, fileTypeValidator, fillUndefined, findBuiltinWidgetShellPreset, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionProviderEvidence, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getPraxisTableCellVisualizationConstraint, getPraxisTableCellVisualizationGuidance, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, getWidgetShellActionIdError, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isDomainRuleSnapshotProblemResponse, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionProviderOperational, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isPraxisI18nMessageDescriptor, isPraxisPresentationVisualizationTableSafe, isPraxisRuntimeGlobalActionEffect, isProgrammaticDateRangePreset, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isStaticDateRangePreset, isSurfaceNavigationError, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, markGlobalActionProviderOperational, matchFieldValidator, materializeFormLayoutFromMetadata, materializeGovernedPaletteColors, materializeGovernedPaletteEntries, materializeResourceIdentity, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, nestedPortPathIdentity, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldAccessMetadata, normalizeFieldConstraints, normalizeFieldPresentation, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef$1 as normalizeGlobalActionRef, normalizeLayoutPolicy, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizePraxisEffectPolicy, normalizePraxisPresentationVisualization, normalizePraxisQueryFilterExpression, normalizePraxisQueryFilterNode, normalizeReactiveDeterminations, normalizeResourceAvailabilityReasonCode, normalizeResourceIdentityContract, normalizeStart, normalizeSurfaceOperationContext, normalizeUnknownError, normalizeWidgetEventPath, notifySuccessHook, parseJsonResponseOrEmpty, praxisLoadingInterceptorFn, prefillFromContextHook, prepareCanvasArrangement, projectComponentAuthoringManifest, projectGroupedCommandPartialRows, provideDefaultFormHooks, provideFieldSelectorRegistryBase, provideFieldSelectorRegistryOverride, provideFieldSelectorRegistryRuntime, provideFormHookPresets, provideFormHooks, provideGlobalActionCatalog, provideGlobalActionHandler, provideGlobalConfig, provideGlobalConfigReady, provideGlobalConfigSeed, provideGlobalConfigTenant, provideHookResolvers, provideHookWhitelist, provideOverlayDecisionMatrix, providePraxisAnalyticsGlobalActions, providePraxisCollectionExportProvider, providePraxisDynamicPageMetadata, providePraxisEnterpriseRuntimeContext, providePraxisFooterLinksMetadata, providePraxisGlobalActionCatalog, providePraxisGlobalActions, providePraxisGlobalConfigBootstrap, providePraxisHeroBannerMetadata, providePraxisHttpCollectionExportProvider, providePraxisHttpLoading, providePraxisI18n, providePraxisI18nConfig, providePraxisI18nTranslator, providePraxisIconDefaults, providePraxisJsonLogicOperator, providePraxisJsonLogicOperatorOverride, providePraxisLegalNoticeMetadata, providePraxisLoadingDefaults, providePraxisLogging, providePraxisRelatedResourceOutletMetadata, providePraxisRichTextBlockMetadata, providePraxisTelemetry, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, registerPraxisRuntimeComponentObservation, removeDiacritics, renderPraxisPresentationVisualizationHtml, reportTelemetryHookFactory, requiredCheckedValidator, requiredPresenceValidator, resolveBuiltinPresets, resolveBuiltinWidgetShellAppearance, resolveColumnTypeFromFieldDefinition, resolveControlTypeAlias, resolveDateRangeShortcutPreset, resolveDateRangeShortcutPresets, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveFieldPresentation, resolveGroupedCommandPartialRowSpans, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolvePraxisI18nDocument, resolveResourceAvailabilityReasonKey, resolveResourceIdentityContract, resolveSpan, resolveTextMaskFormat, resolveTextMaskFormatFromFieldDefinition, resolveValuePresentation, resolveValuePresentationLocale, resolveWidgetPageLayoutPreset, serializeEntityLookupValueForPayload, serializeOptionSourceFilterRequest, serializePraxisCollectionToCsv, serializePraxisCollectionToExcel, serializePraxisCollectionToJson, slugify, staticDateRangePresetToPreset, stripMasksHook, supportsConfigDocuments, supportsImplicitValuePresentation, syncWithServerMetadata, textSha256, toCamel, toCapitalize, toKebab, toPascal, toSentenceCase, toSnake, toTitleCase, translateResourceAvailabilityReason, translateResourceDiscoveryText, translateSurfaceNavigationRejected, translateSurfaceOpenFailed, translateUnavailableWorkflowMessage, trim, uniqueAsyncValidator, urlValidator, validateCanvasArrangement, validateGlobalActionRef, validateGlobalActionRefs, withFormConfigSections, withMessage, withPraxisHttpLoading };
|
|
56424
|
+
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, BUILTIN_WIDGET_SHELL_PRESETS, COMPONENT_METADATA_REGISTRY_I18N_CONFIG, COMPONENT_METADATA_REGISTRY_I18N_NAMESPACE, CONFIG_STORAGE, CONNECTION_STORAGE, ComponentAuthoringManifestProjectionError, ComponentKeyService, ComponentMetadataRegistry, ComponentRuntimeProfileService, CompositionRuntimeFacade, CompositionValidatorService, ConsoleLoggerSink, CrudOperationResolutionService, DEFAULT_DYNAMIC_FORM_SCHEMA_CACHE_MAX_ENTRIES, DEFAULT_DYNAMIC_FORM_SCHEMA_CACHE_TTL_MS, DEFAULT_FIELD_SELECTOR_CONTROL_TYPE_MAP, DEFAULT_JSON_LOGIC_OPERATORS, DEFAULT_SCHEMA_REQUEST_TIMEOUT_MS, 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, EFFECTIVE_UI_LAYOUT_COMPOSITION_SCHEMA_VERSION, 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, EffectiveUiLayoutContractError, EffectiveUiLayoutHttpError, EffectiveUiLayoutService, EmptyStateCardComponent, EnterpriseRuntimeContextObsoleteError, EnterpriseRuntimeContextService, ErrorMessageService, FIELD_METADATA_CAPABILITIES, FIELD_SELECTOR_REGISTRY_BASE, FIELD_SELECTOR_REGISTRY_DISABLE_DEFAULTS, FIELD_SELECTOR_REGISTRY_OVERRIDES, FORM_HOOKS, FORM_HOOKS_PRESETS, FORM_HOOKS_WHITELIST, FORM_HOOK_RESOLVERS, FieldControlType, FieldDataType, FieldSelectorRegistry, FormHooksRegistry, GLOBAL_ACTION_CATALOG, GLOBAL_ACTION_HANDLERS, GLOBAL_ACTION_UI_SCHEMAS, GLOBAL_ANALYTICS_SERVICE, GLOBAL_API_CLIENT, GLOBAL_CONFIG, GLOBAL_DIALOG_SERVICE, GLOBAL_ROUTE_GUARD_RESOLVER, GLOBAL_SURFACE_SERVICE, GLOBAL_TOAST_SERVICE, GOVERNED_COLOR_PALETTE_OPTIONS, GenericCrudService, GlobalActionService, GlobalConfigService, GovernedColorPaletteService, INLINE_FILTER_ALIAS_TOKENS, INLINE_FILTER_CONTROL_TYPES, INLINE_FILTER_CONTROL_TYPE_SET, INLINE_FILTER_CONTROL_TYPE_VALUES, INLINE_FILTER_TOKEN_TO_BASE_CONTROL_TYPE, INLINE_FILTER_TOKEN_TO_CONTROL_TYPE, IconPickerService, IconPosition, IconSize, LOGGER_LEVEL_BY_ENV, LOGGER_LEVEL_PRIORITY, LoadingOrchestrator, LocalConnectionStorage, LocalStorageAsyncAdapter, LocalStorageCacheAdapter, LocalStorageConfigService, LoggerService, LoggerThrottleTracker, LoggerWarnOnceTracker, MemoryCacheAdapter, NestedPortCatalogService, NestedWidgetConfigAccessor, NumericFormat, OVERLAY_DECIDER_DEBUG, OVERLAY_DECISION_MATRIX, ObservabilityDashboardService, OverlayDeciderService, PRAXIS_ACTION_CONTROL_DEFAULTS, PRAXIS_ACTION_CONTROL_VARS, PRAXIS_COLLECTION_EXPORT_HTTP_OPTIONS, PRAXIS_COLLECTION_EXPORT_PROVIDER, PRAXIS_COLLECTION_SEARCH_DEFAULTS, PRAXIS_COLLECTION_SEARCH_VARS, PRAXIS_CORPORATE_SENSITIVE_KEYS, PRAXIS_DEFAULT_EXPORT_SECURITY_POLICY, PRAXIS_DEFAULT_OBSERVABILITY_ALERT_RULES, PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA, PRAXIS_EFFECTIVE_UI_LAYOUT_OPTIONS, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY, PRAXIS_EXPORT_FORMULA_PREFIXES, PRAXIS_EXPORT_SECURITY_POLICY, PRAXIS_FOOTER_LINKS_METADATA, PRAXIS_GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_OPTIONS, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_READY, PRAXIS_GLOBAL_CONFIG_TENANT_RESOLVER, PRAXIS_HERO_BANNER_METADATA, PRAXIS_I18N_CONFIG, PRAXIS_I18N_TRANSLATOR, PRAXIS_JSON_LOGIC_OPERATORS, PRAXIS_LAYER_SCALE_DEFAULTS, PRAXIS_LAYER_SCALE_VARS, PRAXIS_LEGAL_NOTICE_METADATA, PRAXIS_LOADING_CTX, PRAXIS_LOADING_RENDERER, PRAXIS_LOGGER_CONFIG, PRAXIS_LOGGER_SINKS, PRAXIS_OBSERVABILITY_DASHBOARD_OPTIONS, PRAXIS_QUERY_FILTER_EXPRESSION_SCHEMA_VERSION, PRAXIS_RELATED_RESOURCE_OUTLET_AUTHORING_MANIFEST, PRAXIS_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA, PRAXIS_RELATED_RESOURCE_OUTLET_PORTS, PRAXIS_RICH_TEXT_BLOCK_METADATA, PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS, PRAXIS_TABLE_DETAIL_INLINE_RENDERERS, PRAXIS_TABLE_DETAIL_RESOURCE_RESOLVER, PRAXIS_TELEMETRY_TRANSPORT, PRAXIS_THEME_SURFACE_DEFAULTS, PRAXIS_THEME_SURFACE_VARS, PRAXIS_USER_CONTEXT_SUMMARY_METADATA, PRIVACY_CONSENT_EDITORIAL_SOLUTION, PRIVACY_CONSENT_EDITORIAL_TEMPLATE, PraxisAppShellComponent, PraxisCollectionExportService, PraxisCore, PraxisFooterLinksComponent, PraxisGlobalErrorHandler, PraxisHeroBannerComponent, PraxisHttpCollectionExportProvider, PraxisI18nService, PraxisIconButtonComponent, PraxisIconDirective, PraxisIconPickerComponent, PraxisJsonLogicError, PraxisJsonLogicService, PraxisKeepAliveTabDirective, PraxisLayerScaleStyleService, PraxisLegalNoticeComponent, PraxisLoadingInterceptor, PraxisRelatedResourceOutletComponent, PraxisRelatedResourceOutletConfigEditorComponent, PraxisResourceIdentityComponent, PraxisRichTextBlockComponent, PraxisRuntimeComponentObservationRegistryService, PraxisSurfaceHostComponent, PraxisUserContextSummaryComponent, PraxisWidgetEventBus, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, RULE_PROPERTY_SCHEMA, RelatedResourceSurfaceResolverService, RemoteConfigStorage, ResourceActionOpenAdapterService, ResourceDiscoveryService, ResourceQuickConnectComponent, ResourceRecordOpenError, ResourceRecordOpenService, ResourceSurfaceOpenAdapterService, SCHEMA_METADATA_CLIENT_OPTIONS, SCHEMA_VIEWER_CONTEXT, SETTINGS_EDITOR_SECTIONS_HOSTED, SETTINGS_PANEL_BRIDGE, SETTINGS_PANEL_DATA, STEPPER_CONFIG_EDITOR, SURFACE_DRAWER_BRIDGE, SURFACE_DRAWER_CONTENT_DATA, SURFACE_DRAWER_REF, SURFACE_NAVIGATION_I18N_CONFIG, SURFACE_NAVIGATION_I18N_NAMESPACE, SURFACE_OPEN_I18N_CONFIG, SURFACE_OPEN_I18N_NAMESPACE, SURFACE_OPEN_PRESETS, SafeExpressionEvaluator, SchemaMetadataClient, SchemaNormalizerService, SchemaViewerComponent, SettingsSectionTabsComponent, SurfaceBindingRuntimeService, SurfaceNavigationError, SurfaceOpenActionEditorComponent, SurfaceOpenMaterializerService, SurfaceOutletRegistryService, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, UiLayoutLifecycleContractError, UiLayoutLifecycleHttpError, UiLayoutLifecycleService, ValidationPattern, WidgetPageCompositionFactory, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, assertPraxisRuntimeComponentObservationSerializable, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisActionControlCss, buildPraxisCollectionSearchCss, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildPraxisThemeSurfaceCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, canonicalJsonSha256, canonicalJsonStringify, clampRange, classifyEntityLookupResult, clonePraxisRuntimeComponentObservation, cloneTableConfig, cloneUiLayoutJsonDocument, cnpjAlphaValidator, collapseWhitespace, composeHeadersWithVersion, conditionalAsyncValidator, convertFormLayoutToConfig, createCorporateLoggerConfig, createCorporateObservabilityOptions, createCpfCnpjValidator, createDefaultFormConfig, createDefaultTableConfig, createDynamicRecord, createEmptyFormConfig, createEmptyRichContentDocument, createFieldLayoutItem, createPersistedPage, customAsyncValidatorFn, customValidatorFn, debounceAsyncValidator, deepMerge, domainKnowledgeTimelineToRichContentDocument, domainRuleTimelineToRichContentDocument, ensureIds, ensureNoConflictsHookFactory, ensurePageIds, escapePraxisExportCell, evaluateFieldAccess, extractNormalizedError, extractRecordId, fetchWithETag, fileTypeValidator, fillUndefined, findBuiltinWidgetShellPreset, formIdentityIssues, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionProviderEvidence, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getPraxisTableCellVisualizationConstraint, getPraxisTableCellVisualizationGuidance, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, getWidgetShellActionIdError, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isDomainRuleSnapshotProblemResponse, isDynamicDataRecord, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionProviderOperational, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isPraxisI18nMessageDescriptor, isPraxisPresentationVisualizationTableSafe, isPraxisRuntimeGlobalActionEffect, isProgrammaticDateRangePreset, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isStaticDateRangePreset, isSurfaceNavigationError, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, markGlobalActionProviderOperational, matchFieldValidator, materializeFormLayoutFromMetadata, materializeGovernedPaletteColors, materializeGovernedPaletteEntries, materializeResourceIdentity, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, nestedPortPathIdentity, normalizeCardMediaAspectRatio, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldAccessMetadata, normalizeFieldConstraints, normalizeFieldPresentation, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef$1 as normalizeGlobalActionRef, normalizeLayoutPolicy, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizePraxisEffectPolicy, normalizePraxisPresentationVisualization, normalizePraxisQueryFilterExpression, normalizePraxisQueryFilterNode, normalizeReactiveDeterminations, normalizeResourceAvailabilityReasonCode, normalizeResourceIdentityContract, normalizeStart, normalizeSurfaceOperationContext, normalizeUnknownError, normalizeWidgetEventPath, notifySuccessHook, parseJsonResponseOrEmpty, praxisLoadingInterceptorFn, prefillFromContextHook, prepareCanvasArrangement, projectComponentAuthoringManifest, projectGroupedCommandPartialRows, provideDefaultFormHooks, provideFieldSelectorRegistryBase, provideFieldSelectorRegistryOverride, provideFieldSelectorRegistryRuntime, provideFormHookPresets, provideFormHooks, provideGlobalActionCatalog, provideGlobalActionHandler, provideGlobalConfig, provideGlobalConfigReady, provideGlobalConfigSeed, provideGlobalConfigTenant, provideHookResolvers, provideHookWhitelist, provideOverlayDecisionMatrix, providePraxisAnalyticsGlobalActions, providePraxisCollectionExportProvider, providePraxisDynamicPageMetadata, providePraxisEnterpriseRuntimeContext, providePraxisFooterLinksMetadata, providePraxisGlobalActionCatalog, providePraxisGlobalActions, providePraxisGlobalConfigBootstrap, providePraxisHeroBannerMetadata, providePraxisHttpCollectionExportProvider, providePraxisHttpLoading, providePraxisI18n, providePraxisI18nConfig, providePraxisI18nTranslator, providePraxisIconDefaults, providePraxisJsonLogicOperator, providePraxisJsonLogicOperatorOverride, providePraxisLegalNoticeMetadata, providePraxisLoadingDefaults, providePraxisLogging, providePraxisRelatedResourceOutletMetadata, providePraxisRichTextBlockMetadata, providePraxisTelemetry, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, registerPraxisRuntimeComponentObservation, removeDiacritics, renderPraxisPresentationVisualizationHtml, reportTelemetryHookFactory, requiredCheckedValidator, requiredPresenceValidator, resolveBuiltinPresets, resolveBuiltinWidgetShellAppearance, resolveColumnTypeFromFieldDefinition, resolveControlTypeAlias, resolveDataField, resolveDateRangeShortcutPreset, resolveDateRangeShortcutPresets, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveFieldPresentation, resolveGroupedCommandPartialRowSpans, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolvePraxisI18nDocument, resolvePraxisMicroVisualizationTone, resolveResourceAvailabilityReasonKey, resolveResourceIdentityContract, resolveSpan, resolveTextMaskFormat, resolveTextMaskFormatFromFieldDefinition, resolveValuePresentation, resolveValuePresentationLocale, resolveWidgetPageLayoutPreset, serializeEntityLookupValueForPayload, serializeOptionSourceFilterRequest, serializePraxisCollectionToCsv, serializePraxisCollectionToExcel, serializePraxisCollectionToJson, slugify, staticDateRangePresetToPreset, stripMasksHook, supportsConfigDocuments, supportsImplicitValuePresentation, syncWithServerMetadata, textSha256, toCamel, toCapitalize, toKebab, toPascal, toSentenceCase, toSnake, toTitleCase, translateResourceAvailabilityReason, translateResourceDiscoveryText, translateSurfaceNavigationRejected, translateSurfaceOpenFailed, translateUnavailableWorkflowMessage, trim, uiLayoutJsonIdentity, uniqueAsyncValidator, urlValidator, validateCanvasArrangement, validateGlobalActionRef, validateGlobalActionRefs, withFormConfigSections, withMessage, withPraxisHttpLoading };
|