ngx-blocks-studio 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/ngx-blocks-studio.mjs +354 -229
- package/fesm2022/ngx-blocks-studio.mjs.map +1 -1
- package/package.json +14 -5
- package/types/ngx-blocks-studio.d.ts +13 -23
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, signal, computed, Injectable, isSignal, isWritableSignal, linkedSignal, inputBinding, twoWayBinding, outputBinding, Injector, ViewContainerRef, DestroyRef, input, effect, Directive } from '@angular/core';
|
|
2
|
+
import { inject, signal, computed, Injectable, isSignal, reflectComponentType, isWritableSignal, linkedSignal, inputBinding, twoWayBinding, outputBinding, Injector, ViewContainerRef, DestroyRef, input, effect, Directive } from '@angular/core';
|
|
3
3
|
import { Router } from '@angular/router';
|
|
4
4
|
import { HttpClient } from '@angular/common/http';
|
|
5
5
|
import { firstValueFrom } from 'rxjs';
|
|
@@ -720,14 +720,17 @@ class RouteLoader {
|
|
|
720
720
|
http = inject(HttpClient);
|
|
721
721
|
componentRegistry = ComponentRegistry.getInstance();
|
|
722
722
|
guardRegistry = GuardRegistry.getInstance();
|
|
723
|
-
_routeConfigFile = signal(null,
|
|
724
|
-
|
|
723
|
+
_routeConfigFile = signal(null, /* @ts-ignore */
|
|
724
|
+
...(ngDevMode ? [{ debugName: "_routeConfigFile" }] : /* istanbul ignore next */ []));
|
|
725
|
+
_configPath = signal('', /* @ts-ignore */
|
|
726
|
+
...(ngDevMode ? [{ debugName: "_configPath" }] : /* istanbul ignore next */ []));
|
|
725
727
|
/** Currently loaded route config file, or null if not yet loaded. */
|
|
726
728
|
routeConfigFile = this._routeConfigFile.asReadonly();
|
|
727
729
|
/** Path from which the config was loaded. */
|
|
728
730
|
configPath = this._configPath.asReadonly();
|
|
729
731
|
/** Route config array from the loaded file. */
|
|
730
|
-
routeConfig = computed(() => this._routeConfigFile()?.routes ?? [],
|
|
732
|
+
routeConfig = computed(() => this._routeConfigFile()?.routes ?? [], /* @ts-ignore */
|
|
733
|
+
...(ngDevMode ? [{ debugName: "routeConfig" }] : /* istanbul ignore next */ []));
|
|
731
734
|
/**
|
|
732
735
|
* Load routes from a config object. Updates signals and resets the router.
|
|
733
736
|
*/
|
|
@@ -848,10 +851,10 @@ class RouteLoader {
|
|
|
848
851
|
}
|
|
849
852
|
return guard;
|
|
850
853
|
}
|
|
851
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
852
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
854
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: RouteLoader, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
855
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: RouteLoader, providedIn: 'root' });
|
|
853
856
|
}
|
|
854
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
857
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: RouteLoader, decorators: [{
|
|
855
858
|
type: Injectable,
|
|
856
859
|
args: [{
|
|
857
860
|
providedIn: 'root',
|
|
@@ -935,10 +938,10 @@ class BlockRegistryService {
|
|
|
935
938
|
getParentScopeKey(scopeKey) {
|
|
936
939
|
return this.registry.get(scopeKey)?.parentScopeKey ?? null;
|
|
937
940
|
}
|
|
938
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
939
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
941
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: BlockRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
942
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: BlockRegistryService, providedIn: 'root' });
|
|
940
943
|
}
|
|
941
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
944
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: BlockRegistryService, decorators: [{
|
|
942
945
|
type: Injectable,
|
|
943
946
|
args: [{ providedIn: 'root' }]
|
|
944
947
|
}] });
|
|
@@ -1270,15 +1273,15 @@ function isTwoWayRefString(value) {
|
|
|
1270
1273
|
return TWOWAY_REF_RE.test(value.trim());
|
|
1271
1274
|
}
|
|
1272
1275
|
/**
|
|
1273
|
-
* True when a string contains two-way ref
|
|
1274
|
-
*
|
|
1276
|
+
* True when a string contains the two-way ref opener `[(` but is not a valid standalone
|
|
1277
|
+
* two-way ref (exact form `[(refPath)]`). Mixing two-way with literals or {{ }} is invalid.
|
|
1278
|
+
* Plain `)]` substrings (e.g. Tailwind `minmax(0,1fr)]`) are not treated as two-way syntax.
|
|
1275
1279
|
*/
|
|
1276
1280
|
function isInvalidTwoWayMix(value) {
|
|
1277
1281
|
if (typeof value !== 'string')
|
|
1278
1282
|
return false;
|
|
1279
1283
|
const s = value.trim();
|
|
1280
|
-
|
|
1281
|
-
return hasDelimiters && !TWOWAY_REF_RE.test(s);
|
|
1284
|
+
return s.includes('[(') && !TWOWAY_REF_RE.test(s);
|
|
1282
1285
|
}
|
|
1283
1286
|
/**
|
|
1284
1287
|
* One trim + one pass: classify string for two-way ref handling. Use instead of calling
|
|
@@ -1290,15 +1293,8 @@ function classifyTwoWayString(value) {
|
|
|
1290
1293
|
const s = value.trim();
|
|
1291
1294
|
if (TWOWAY_REF_RE.test(s))
|
|
1292
1295
|
return 'two-way';
|
|
1293
|
-
|
|
1294
|
-
const hasClose = s.includes(')]');
|
|
1295
|
-
if (!hasOpen && !hasClose)
|
|
1296
|
-
return 'none';
|
|
1297
|
-
// Only treat as invalid mix when the string looks like an attempted two-way ref
|
|
1298
|
-
// wrapper, not when it contains ")]" from normal indexing/calls inside templates.
|
|
1299
|
-
if ((hasOpen && hasClose) || s.startsWith('[(') || s.endsWith(')]')) {
|
|
1296
|
+
if (s.includes('[('))
|
|
1300
1297
|
return 'invalid-mix';
|
|
1301
|
-
}
|
|
1302
1298
|
return 'none';
|
|
1303
1299
|
}
|
|
1304
1300
|
function parseTwoWayRef(value) {
|
|
@@ -1354,7 +1350,9 @@ function resolveRefPath(refPath, ctx) {
|
|
|
1354
1350
|
instance = ctx.currentInstance;
|
|
1355
1351
|
}
|
|
1356
1352
|
else {
|
|
1357
|
-
|
|
1353
|
+
/* v8 ignore next -- registry is always set when blockId resolves (see scope guard above) */
|
|
1354
|
+
const blockRegistry = registry ?? ctx.registry;
|
|
1355
|
+
const handle = blockRegistry.get(blockId);
|
|
1358
1356
|
if (!handle) {
|
|
1359
1357
|
warnOnce(`Ref "${refPath}" could not resolve block id "${blockId}".`);
|
|
1360
1358
|
return null;
|
|
@@ -1437,11 +1435,16 @@ function getValueByPath(obj, path) {
|
|
|
1437
1435
|
*/
|
|
1438
1436
|
function refPathResolvesToSignal(refPath, ctx) {
|
|
1439
1437
|
const resolved = resolveRefPath(refPath, ctx);
|
|
1440
|
-
if (resolved == null)
|
|
1438
|
+
if (resolved == null) {
|
|
1441
1439
|
return false;
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1440
|
+
}
|
|
1441
|
+
let val;
|
|
1442
|
+
if (resolved.path.length === 0) {
|
|
1443
|
+
val = resolved.target;
|
|
1444
|
+
}
|
|
1445
|
+
else {
|
|
1446
|
+
val = resolved.target?.[resolved.path[0]];
|
|
1447
|
+
}
|
|
1445
1448
|
return val != null && isSignal(val);
|
|
1446
1449
|
}
|
|
1447
1450
|
/**
|
|
@@ -1507,8 +1510,12 @@ function setRefValue(refPath, ctx, value) {
|
|
|
1507
1510
|
if (writable) {
|
|
1508
1511
|
writable.set(value);
|
|
1509
1512
|
}
|
|
1510
|
-
else
|
|
1511
|
-
|
|
1513
|
+
else {
|
|
1514
|
+
/* v8 ignore start */
|
|
1515
|
+
if (obj != null && typeof obj === 'object') {
|
|
1516
|
+
obj[key] = value;
|
|
1517
|
+
}
|
|
1518
|
+
/* v8 ignore end */
|
|
1512
1519
|
}
|
|
1513
1520
|
}
|
|
1514
1521
|
/**
|
|
@@ -1594,12 +1601,12 @@ function parseFlowTemplate(template) {
|
|
|
1594
1601
|
let next = bodyEnd + 1;
|
|
1595
1602
|
let elseBody;
|
|
1596
1603
|
let cursor = next;
|
|
1597
|
-
while (cursor < template.length && /\s/.test(template[cursor]
|
|
1604
|
+
while (cursor < template.length && /\s/.test(template[cursor])) {
|
|
1598
1605
|
cursor++;
|
|
1599
1606
|
}
|
|
1600
1607
|
if (template.startsWith('@else', cursor)) {
|
|
1601
1608
|
let elseCursor = cursor + '@else'.length;
|
|
1602
|
-
while (elseCursor < template.length && /\s/.test(template[elseCursor]
|
|
1609
|
+
while (elseCursor < template.length && /\s/.test(template[elseCursor])) {
|
|
1603
1610
|
elseCursor++;
|
|
1604
1611
|
}
|
|
1605
1612
|
if (template[elseCursor] === '{') {
|
|
@@ -1669,7 +1676,7 @@ function parseFlowTemplate(template) {
|
|
|
1669
1676
|
i = end;
|
|
1670
1677
|
}
|
|
1671
1678
|
else {
|
|
1672
|
-
nodes.push({ type: 'text', value: rest
|
|
1679
|
+
nodes.push({ type: 'text', value: rest.charAt(0) });
|
|
1673
1680
|
i++;
|
|
1674
1681
|
}
|
|
1675
1682
|
}
|
|
@@ -1785,6 +1792,7 @@ function interpretFlow(nodes, ctx, scope = {}, options) {
|
|
|
1785
1792
|
}
|
|
1786
1793
|
continue;
|
|
1787
1794
|
}
|
|
1795
|
+
/* v8 ignore start -- exhaustive node.type chain; non-for nodes handled above */
|
|
1788
1796
|
if (node.type === 'for') {
|
|
1789
1797
|
const arr = resolveRefOrModel(node.refPath, ctx);
|
|
1790
1798
|
const list = Array.isArray(arr) ? arr : [];
|
|
@@ -1797,6 +1805,7 @@ function interpretFlow(nodes, ctx, scope = {}, options) {
|
|
|
1797
1805
|
}
|
|
1798
1806
|
continue;
|
|
1799
1807
|
}
|
|
1808
|
+
/* v8 ignore end */
|
|
1800
1809
|
}
|
|
1801
1810
|
return out;
|
|
1802
1811
|
}
|
|
@@ -2101,6 +2110,7 @@ function evalExpr(expr, ctx) {
|
|
|
2101
2110
|
if (obj == null || (typeof obj !== 'object' && typeof obj !== 'function'))
|
|
2102
2111
|
return undefined;
|
|
2103
2112
|
const key = evalExpr(expr.index, ctx);
|
|
2113
|
+
/* v8 ignore next */
|
|
2104
2114
|
if (typeof key !== 'string' && typeof key !== 'number')
|
|
2105
2115
|
return undefined;
|
|
2106
2116
|
return obj[key];
|
|
@@ -2126,13 +2136,18 @@ function evalExpr(expr, ctx) {
|
|
|
2126
2136
|
}
|
|
2127
2137
|
case 'unary': {
|
|
2128
2138
|
const v = evalExpr(expr.argument, ctx);
|
|
2129
|
-
if (expr.op === '!')
|
|
2139
|
+
if (expr.op === '!') {
|
|
2130
2140
|
return !v;
|
|
2131
|
-
|
|
2141
|
+
}
|
|
2142
|
+
if (expr.op === '+') {
|
|
2132
2143
|
return Number(v);
|
|
2133
|
-
|
|
2144
|
+
}
|
|
2145
|
+
/* v8 ignore start */
|
|
2146
|
+
if (expr.op === '-') {
|
|
2134
2147
|
return -Number(v);
|
|
2148
|
+
}
|
|
2135
2149
|
return undefined;
|
|
2150
|
+
/* v8 ignore end */
|
|
2136
2151
|
}
|
|
2137
2152
|
case 'binary': {
|
|
2138
2153
|
const left = evalExpr(expr.left, ctx);
|
|
@@ -2155,6 +2170,7 @@ function evalExpr(expr, ctx) {
|
|
|
2155
2170
|
case '!=': return left != right;
|
|
2156
2171
|
case '===': return left === right;
|
|
2157
2172
|
case '!==': return left !== right;
|
|
2173
|
+
/* v8 ignore next */
|
|
2158
2174
|
default: return undefined;
|
|
2159
2175
|
}
|
|
2160
2176
|
}
|
|
@@ -2175,9 +2191,11 @@ function evaluateSafeExpression(expression, resolverContext, payload, resolveRef
|
|
|
2175
2191
|
const MUSTACHE_MAX_SEGMENTS = 200;
|
|
2176
2192
|
function resolveReferenceValue(ref, ctx) {
|
|
2177
2193
|
const resolved = resolveRefPath(ref, ctx);
|
|
2178
|
-
if (resolved != null)
|
|
2194
|
+
if (resolved != null) {
|
|
2179
2195
|
return getRefValue(ref, ctx);
|
|
2180
|
-
|
|
2196
|
+
}
|
|
2197
|
+
const model = ctx.currentInstance?.model?.() ?? {};
|
|
2198
|
+
return getValueByPath(model, ref);
|
|
2181
2199
|
}
|
|
2182
2200
|
/**
|
|
2183
2201
|
* Safe expression evaluation (same as output `{{ }}` / `@if (...)` when used with this module).
|
|
@@ -2217,7 +2235,7 @@ function resolveMustacheInterpolatedString(value, ctx, payload) {
|
|
|
2217
2235
|
let out = '';
|
|
2218
2236
|
let lastIndex = 0;
|
|
2219
2237
|
for (const match of limited) {
|
|
2220
|
-
const start = match.index
|
|
2238
|
+
const start = match.index;
|
|
2221
2239
|
out += value.slice(lastIndex, start);
|
|
2222
2240
|
const evaluated = evaluateExpression(match[1], ctx, payload);
|
|
2223
2241
|
out += evaluated != null ? String(evaluated) : '';
|
|
@@ -2425,9 +2443,14 @@ function runThenChain(steps, index, ctx, parentDef, payload, onComplete) {
|
|
|
2425
2443
|
}
|
|
2426
2444
|
}
|
|
2427
2445
|
function runOnError(def, ctx, payload) {
|
|
2428
|
-
|
|
2429
|
-
|
|
2446
|
+
const onError = def.onError;
|
|
2447
|
+
if (onError == null) {
|
|
2448
|
+
return;
|
|
2430
2449
|
}
|
|
2450
|
+
if (!shouldRunWhen(onError.when, ctx, payload)) {
|
|
2451
|
+
return;
|
|
2452
|
+
}
|
|
2453
|
+
invokeRefMethod(ctx, onError.ref, payload, resolveStepParams(onError.params, ctx, payload));
|
|
2431
2454
|
}
|
|
2432
2455
|
function invokeRefMethod(ctx, refTemplate, payload, params) {
|
|
2433
2456
|
const resolvedCallable = resolveReferencePath(refTemplate, ctx, payload);
|
|
@@ -2455,6 +2478,107 @@ function createOutputHandler(outputValue, _outputKey, ctx) {
|
|
|
2455
2478
|
return () => { };
|
|
2456
2479
|
}
|
|
2457
2480
|
|
|
2481
|
+
/** JSON-like objects only — skip class instances, Date, Map, etc. */
|
|
2482
|
+
function isPlainObject(value) {
|
|
2483
|
+
if (value === null || typeof value !== 'object')
|
|
2484
|
+
return false;
|
|
2485
|
+
if (Array.isArray(value))
|
|
2486
|
+
return false;
|
|
2487
|
+
const proto = Object.getPrototypeOf(value);
|
|
2488
|
+
return proto === null || proto === Object.prototype;
|
|
2489
|
+
}
|
|
2490
|
+
function stringNeedsInputResolve(s) {
|
|
2491
|
+
if (classifyTwoWayString(s) !== 'none')
|
|
2492
|
+
return true;
|
|
2493
|
+
if (s.includes('{{') && s.includes('}}'))
|
|
2494
|
+
return true;
|
|
2495
|
+
if (looksLikeFlowTemplate(s))
|
|
2496
|
+
return true;
|
|
2497
|
+
return false;
|
|
2498
|
+
}
|
|
2499
|
+
/** True when any string leaf in the tree needs input-style resolution (mustache, flow, or `[( )]`). */
|
|
2500
|
+
function valueNeedsInputResolve(value, visited = new WeakSet()) {
|
|
2501
|
+
if (typeof value === 'string') {
|
|
2502
|
+
return stringNeedsInputResolve(value);
|
|
2503
|
+
}
|
|
2504
|
+
if (Array.isArray(value)) {
|
|
2505
|
+
return value.some((item) => valueNeedsInputResolve(item, visited));
|
|
2506
|
+
}
|
|
2507
|
+
if (value != null && typeof value === 'object') {
|
|
2508
|
+
if (!isPlainObject(value))
|
|
2509
|
+
return false;
|
|
2510
|
+
if (visited.has(value))
|
|
2511
|
+
return false;
|
|
2512
|
+
visited.add(value);
|
|
2513
|
+
return Object.values(value).some((item) => valueNeedsInputResolve(item, visited));
|
|
2514
|
+
}
|
|
2515
|
+
return false;
|
|
2516
|
+
}
|
|
2517
|
+
/** True when any string leaf contains `{{ }}` (block model seeding). */
|
|
2518
|
+
function valueContainsMustacheInTree(value, visited = new WeakSet()) {
|
|
2519
|
+
if (typeof value === 'string') {
|
|
2520
|
+
return value.includes('{{') && value.includes('}}');
|
|
2521
|
+
}
|
|
2522
|
+
if (Array.isArray(value)) {
|
|
2523
|
+
return value.some((item) => valueContainsMustacheInTree(item, visited));
|
|
2524
|
+
}
|
|
2525
|
+
if (value != null && typeof value === 'object') {
|
|
2526
|
+
if (!isPlainObject(value))
|
|
2527
|
+
return false;
|
|
2528
|
+
if (visited.has(value))
|
|
2529
|
+
return false;
|
|
2530
|
+
visited.add(value);
|
|
2531
|
+
return Object.values(value).some((item) => valueContainsMustacheInTree(item, visited));
|
|
2532
|
+
}
|
|
2533
|
+
return false;
|
|
2534
|
+
}
|
|
2535
|
+
function resolveStringLeaf(str, ctx, path, options) {
|
|
2536
|
+
const twoWayKind = classifyTwoWayString(str);
|
|
2537
|
+
if (twoWayKind === 'invalid-mix') {
|
|
2538
|
+
throw new Error(`Invalid value at "${path}": two-way ref "[( )]" cannot be mixed with literals or "{{ }}". ` +
|
|
2539
|
+
`Use exactly "[(refPath)]" for read-resolve or "{{ refPath }}" for read-only.`);
|
|
2540
|
+
}
|
|
2541
|
+
if (twoWayKind === 'two-way' && options.resolveTwoWayStringsAsReadonly) {
|
|
2542
|
+
const refPath = parseTwoWayRef(str);
|
|
2543
|
+
if (refPath) {
|
|
2544
|
+
return getRefValue(refPath, ctx);
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
return resolveTemplateString(str, ctx, undefined, {
|
|
2548
|
+
escapeFlowRefs: options.escapeFlowRefs !== false,
|
|
2549
|
+
});
|
|
2550
|
+
}
|
|
2551
|
+
/**
|
|
2552
|
+
* Deep-resolve template strings in plain objects and arrays (new object graph each call).
|
|
2553
|
+
*/
|
|
2554
|
+
function resolveNestedTemplateValues(value, ctx, path = '', visited = new WeakSet(), options = {}) {
|
|
2555
|
+
if (typeof value === 'string') {
|
|
2556
|
+
return resolveStringLeaf(value, ctx, path || 'input', options);
|
|
2557
|
+
}
|
|
2558
|
+
if (Array.isArray(value)) {
|
|
2559
|
+
return value.map((item, index) => {
|
|
2560
|
+
const childPath = path ? `${path}[${index}]` : `[${index}]`;
|
|
2561
|
+
return resolveNestedTemplateValues(item, ctx, childPath, visited, options);
|
|
2562
|
+
});
|
|
2563
|
+
}
|
|
2564
|
+
if (value != null && typeof value === 'object') {
|
|
2565
|
+
if (!isPlainObject(value))
|
|
2566
|
+
return value;
|
|
2567
|
+
if (visited.has(value))
|
|
2568
|
+
return value;
|
|
2569
|
+
visited.add(value);
|
|
2570
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => {
|
|
2571
|
+
const childPath = path ? `${path}.${key}` : key;
|
|
2572
|
+
return [key, resolveNestedTemplateValues(item, ctx, childPath, visited, options)];
|
|
2573
|
+
}));
|
|
2574
|
+
}
|
|
2575
|
+
return value;
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2578
|
+
const NESTED_INPUT_RESOLVE_OPTIONS = {
|
|
2579
|
+
resolveTwoWayStringsAsReadonly: true,
|
|
2580
|
+
escapeFlowRefs: true,
|
|
2581
|
+
};
|
|
2458
2582
|
function getBlockInputsAndOutputs(componentOrDirectives) {
|
|
2459
2583
|
const inputs = new Set();
|
|
2460
2584
|
const outputs = new Set();
|
|
@@ -2469,22 +2593,50 @@ function getBlockInputsAndOutputs(componentOrDirectives) {
|
|
|
2469
2593
|
}
|
|
2470
2594
|
return { inputs, outputs, twoWay };
|
|
2471
2595
|
}
|
|
2596
|
+
function isTwoWayInput(publicName, publicOutputKeys, _inputDef, outputsRecord) {
|
|
2597
|
+
const changeOutputName = `${publicName}Change`;
|
|
2598
|
+
// model(): def.outputs is { value: 'valueChange' } (key = input name, not *Change)
|
|
2599
|
+
if (outputsRecord?.[publicName] === changeOutputName) {
|
|
2600
|
+
return true;
|
|
2601
|
+
}
|
|
2602
|
+
// @Input + @Output *Change, or signal/model inputs with a public *Change output
|
|
2603
|
+
return publicOutputKeys.has(changeOutputName);
|
|
2604
|
+
}
|
|
2472
2605
|
function getDirectiveMetadata(type) {
|
|
2473
|
-
|
|
2474
|
-
|
|
2606
|
+
const angularType = type;
|
|
2607
|
+
if (angularType.ɵcmp) {
|
|
2608
|
+
const mirror = reflectComponentType(type);
|
|
2609
|
+
if (mirror != null && mirror.inputs.length > 0) {
|
|
2610
|
+
const outputNames = new Set(mirror.outputs.map((o) => o.templateName));
|
|
2611
|
+
const twoWay = [];
|
|
2612
|
+
const inputs = [];
|
|
2613
|
+
for (const inp of mirror.inputs) {
|
|
2614
|
+
const name = inp.templateName;
|
|
2615
|
+
if (isTwoWayInput(name, outputNames, null, undefined)) {
|
|
2616
|
+
twoWay.push(name);
|
|
2617
|
+
}
|
|
2618
|
+
else {
|
|
2619
|
+
inputs.push(name);
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
const outputs = mirror.outputs.map((o) => o.templateName);
|
|
2623
|
+
return { inputs, outputs, twoWay, isComponent: true };
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
// Directives have ɵdir, Components have ɵcmp (fallback when mirror is empty)
|
|
2627
|
+
const def = angularType.ɵdir || angularType.ɵcmp;
|
|
2475
2628
|
if (!def)
|
|
2476
2629
|
return null;
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
const
|
|
2481
|
-
const
|
|
2482
|
-
const twoWay = publicInputs.filter((key) => publicOutputs.includes(`${key}Change`) && def.inputs[key][1]);
|
|
2630
|
+
const inputsRecord = def.inputs || {};
|
|
2631
|
+
const outputsRecord = def.outputs || {};
|
|
2632
|
+
const publicInputs = Object.keys(inputsRecord);
|
|
2633
|
+
const publicOutputs = new Set(Object.keys(outputsRecord));
|
|
2634
|
+
const twoWay = publicInputs.filter((key) => isTwoWayInput(key, publicOutputs, inputsRecord[key], outputsRecord));
|
|
2483
2635
|
return {
|
|
2484
2636
|
inputs: publicInputs.filter((key) => !twoWay.includes(key)),
|
|
2485
|
-
outputs: publicOutputs.filter((key) => !twoWay.includes(key)),
|
|
2637
|
+
outputs: [...publicOutputs].filter((key) => !twoWay.includes(key)),
|
|
2486
2638
|
twoWay,
|
|
2487
|
-
isComponent: !!
|
|
2639
|
+
isComponent: !!angularType.ɵcmp,
|
|
2488
2640
|
};
|
|
2489
2641
|
}
|
|
2490
2642
|
function resolveBlockInputsAndOutputs(description, inputKeys, outputKeys, twoWayKeys, ctx) {
|
|
@@ -2536,13 +2688,15 @@ function resolveBlockInputsAndOutputs(description, inputKeys, outputKeys, twoWay
|
|
|
2536
2688
|
continue;
|
|
2537
2689
|
}
|
|
2538
2690
|
}
|
|
2539
|
-
if (Array.isArray(value)) {
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
}
|
|
2691
|
+
if (Array.isArray(value) || isPlainObject(value)) {
|
|
2692
|
+
if (valueNeedsInputResolve(value)) {
|
|
2693
|
+
resolvedInputs[key] = computed(() => resolveNestedTemplateValues(value, ctx, key, new WeakSet(), NESTED_INPUT_RESOLVE_OPTIONS));
|
|
2694
|
+
}
|
|
2695
|
+
else if (inputKeys.has(key)) {
|
|
2696
|
+
resolvedInputs[key] = () => value;
|
|
2697
|
+
}
|
|
2698
|
+
if (twoWayKeys.has(key))
|
|
2699
|
+
resolvedTwoWay[key] = signal(value);
|
|
2546
2700
|
continue;
|
|
2547
2701
|
}
|
|
2548
2702
|
if (inputKeys.has(key))
|
|
@@ -2561,6 +2715,10 @@ function resolveBlockInputsAndOutputs(description, inputKeys, outputKeys, twoWay
|
|
|
2561
2715
|
}
|
|
2562
2716
|
|
|
2563
2717
|
const INTERPOLATE_MAX_PLACEHOLDERS = 200;
|
|
2718
|
+
/** Builds a two-way binding when only a read getter exists for the key (used by {@link createInputBindingsWithWarnings}). */
|
|
2719
|
+
function linkedTwoWayFromInputGetter(resolvedInputs, key) {
|
|
2720
|
+
return linkedSignal(() => resolvedInputs[key]?.());
|
|
2721
|
+
}
|
|
2564
2722
|
function createInputBindingsWithWarnings(ownerName, inputKeys, twoWayKeys, outputKeys, resolvedInputs, resolvedTwoWay, resolvedOutputs) {
|
|
2565
2723
|
const inputBindingsArray = Array.from(inputKeys)
|
|
2566
2724
|
.filter((key) => {
|
|
@@ -2579,7 +2737,7 @@ function createInputBindingsWithWarnings(ownerName, inputKeys, twoWayKeys, outpu
|
|
|
2579
2737
|
})
|
|
2580
2738
|
// resolvedTwoWay is guaranteed non-null after the filter.
|
|
2581
2739
|
.map((key) => twoWayBinding(key, (resolvedTwoWay[key] ??
|
|
2582
|
-
|
|
2740
|
+
linkedTwoWayFromInputGetter(resolvedInputs, key))));
|
|
2583
2741
|
const outputBindingsArray = Array.from(outputKeys)
|
|
2584
2742
|
.filter((key) => {
|
|
2585
2743
|
if (resolvedOutputs[key] == null) {
|
|
@@ -2590,15 +2748,6 @@ function createInputBindingsWithWarnings(ownerName, inputKeys, twoWayKeys, outpu
|
|
|
2590
2748
|
.map((key) => outputBinding(key, resolvedOutputs[key]));
|
|
2591
2749
|
return [...inputBindingsArray, ...twoWayBindingsArray, ...outputBindingsArray];
|
|
2592
2750
|
}
|
|
2593
|
-
/** JSON-like objects only — skip class instances, Date, Map, etc. */
|
|
2594
|
-
function isPlainObject(value) {
|
|
2595
|
-
if (value === null || typeof value !== 'object')
|
|
2596
|
-
return false;
|
|
2597
|
-
if (Array.isArray(value))
|
|
2598
|
-
return false;
|
|
2599
|
-
const proto = Object.getPrototypeOf(value);
|
|
2600
|
-
return proto === null || proto === Object.prototype;
|
|
2601
|
-
}
|
|
2602
2751
|
class BlockLoaderService {
|
|
2603
2752
|
componentRegistry = ComponentRegistry.getInstance();
|
|
2604
2753
|
directiveRegistry = DirectiveRegistry.getInstance();
|
|
@@ -2777,9 +2926,9 @@ class BlockLoaderService {
|
|
|
2777
2926
|
}
|
|
2778
2927
|
}
|
|
2779
2928
|
else {
|
|
2780
|
-
const hasTemplates =
|
|
2929
|
+
const hasTemplates = valueContainsMustacheInTree(directiveModel);
|
|
2781
2930
|
blockInstanceModel = hasTemplates
|
|
2782
|
-
? linkedSignal(() =>
|
|
2931
|
+
? linkedSignal(() => resolveNestedTemplateValues(blockModel(), this.withModelOverrideContext(ctx, blockModel), 'model', new WeakSet(), { resolveTwoWayStringsAsReadonly: false }))
|
|
2783
2932
|
: blockModel;
|
|
2784
2933
|
}
|
|
2785
2934
|
if (blockInstanceModel != null) {
|
|
@@ -2789,43 +2938,6 @@ class BlockLoaderService {
|
|
|
2789
2938
|
blockInstance.model = blockInstanceModel;
|
|
2790
2939
|
}
|
|
2791
2940
|
}
|
|
2792
|
-
valueContainsTemplate(value, visited = new WeakSet()) {
|
|
2793
|
-
if (typeof value === 'string') {
|
|
2794
|
-
return value.includes('{{') && value.includes('}}');
|
|
2795
|
-
}
|
|
2796
|
-
if (Array.isArray(value)) {
|
|
2797
|
-
return value.some((item) => this.valueContainsTemplate(item, visited));
|
|
2798
|
-
}
|
|
2799
|
-
if (value != null && typeof value === 'object') {
|
|
2800
|
-
if (!isPlainObject(value))
|
|
2801
|
-
return false;
|
|
2802
|
-
if (visited.has(value))
|
|
2803
|
-
return false;
|
|
2804
|
-
visited.add(value);
|
|
2805
|
-
return Object.values(value).some((item) => this.valueContainsTemplate(item, visited));
|
|
2806
|
-
}
|
|
2807
|
-
return false;
|
|
2808
|
-
}
|
|
2809
|
-
resolveNestedModelTemplates(value, ctx, visited = new WeakSet()) {
|
|
2810
|
-
if (typeof value === 'string') {
|
|
2811
|
-
return resolveTemplateString(value, ctx);
|
|
2812
|
-
}
|
|
2813
|
-
if (Array.isArray(value)) {
|
|
2814
|
-
return value.map((item) => this.resolveNestedModelTemplates(item, ctx, visited));
|
|
2815
|
-
}
|
|
2816
|
-
if (value != null && typeof value === 'object') {
|
|
2817
|
-
if (!isPlainObject(value))
|
|
2818
|
-
return value;
|
|
2819
|
-
if (visited.has(value))
|
|
2820
|
-
return value;
|
|
2821
|
-
visited.add(value);
|
|
2822
|
-
return Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
2823
|
-
key,
|
|
2824
|
-
this.resolveNestedModelTemplates(item, ctx, visited),
|
|
2825
|
-
]));
|
|
2826
|
-
}
|
|
2827
|
-
return value;
|
|
2828
|
-
}
|
|
2829
2941
|
withModelOverrideContext(ctx, model) {
|
|
2830
2942
|
if (ctx.currentInstance == null)
|
|
2831
2943
|
return ctx;
|
|
@@ -2837,10 +2949,10 @@ class BlockLoaderService {
|
|
|
2837
2949
|
},
|
|
2838
2950
|
};
|
|
2839
2951
|
}
|
|
2840
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2841
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
2952
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: BlockLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2953
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: BlockLoaderService, providedIn: 'root' });
|
|
2842
2954
|
}
|
|
2843
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2955
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: BlockLoaderService, decorators: [{
|
|
2844
2956
|
type: Injectable,
|
|
2845
2957
|
args: [{ providedIn: 'root' }]
|
|
2846
2958
|
}] });
|
|
@@ -2864,141 +2976,154 @@ function safeJsonKey(value) {
|
|
|
2864
2976
|
return String(value);
|
|
2865
2977
|
}
|
|
2866
2978
|
}
|
|
2979
|
+
|
|
2980
|
+
function createInitialBlockDirectiveLoadState() {
|
|
2981
|
+
return {
|
|
2982
|
+
loadResult: null,
|
|
2983
|
+
lastRegistry: null,
|
|
2984
|
+
lastId: null,
|
|
2985
|
+
loadedComponent: null,
|
|
2986
|
+
loadedServicesKey: null,
|
|
2987
|
+
loadedReloadKey: null,
|
|
2988
|
+
loadedDescKey: null,
|
|
2989
|
+
loadGeneration: 0,
|
|
2990
|
+
effectRunId: 0,
|
|
2991
|
+
lastDescRef: null,
|
|
2992
|
+
lastParsedData: null,
|
|
2993
|
+
};
|
|
2994
|
+
}
|
|
2995
|
+
function clearBlockDirective(state, viewContainerRef) {
|
|
2996
|
+
state.loadGeneration++;
|
|
2997
|
+
state.lastDescRef = null;
|
|
2998
|
+
state.lastParsedData = null;
|
|
2999
|
+
if (state.lastId != null) {
|
|
3000
|
+
state.lastRegistry?.unregister(state.lastId);
|
|
3001
|
+
state.lastId = null;
|
|
3002
|
+
}
|
|
3003
|
+
if (state.loadResult) {
|
|
3004
|
+
viewContainerRef.clear();
|
|
3005
|
+
state.loadResult = null;
|
|
3006
|
+
state.loadedComponent = null;
|
|
3007
|
+
state.loadedServicesKey = null;
|
|
3008
|
+
state.loadedReloadKey = null;
|
|
3009
|
+
state.loadedDescKey = null;
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
function runBlockDirectiveEffect(state, ctx, desc, inputDefs, blockRegistry, reloadKey) {
|
|
3013
|
+
const runId = ++state.effectRunId;
|
|
3014
|
+
if (desc == null) {
|
|
3015
|
+
state.lastDescRef = null;
|
|
3016
|
+
state.lastParsedData = null;
|
|
3017
|
+
clearBlockDirective(state, ctx.viewContainerRef);
|
|
3018
|
+
return;
|
|
3019
|
+
}
|
|
3020
|
+
const runAfterResolved = (resolved) => {
|
|
3021
|
+
if (runId !== state.effectRunId) {
|
|
3022
|
+
return;
|
|
3023
|
+
}
|
|
3024
|
+
let data;
|
|
3025
|
+
if (resolved === state.lastDescRef && state.lastParsedData != null) {
|
|
3026
|
+
data = state.lastParsedData;
|
|
3027
|
+
}
|
|
3028
|
+
else {
|
|
3029
|
+
const parsed = safeParseBlockDescription(resolved);
|
|
3030
|
+
if (!parsed.success) {
|
|
3031
|
+
return;
|
|
3032
|
+
}
|
|
3033
|
+
state.lastDescRef = resolved;
|
|
3034
|
+
state.lastParsedData = parsed.data;
|
|
3035
|
+
data = parsed.data;
|
|
3036
|
+
}
|
|
3037
|
+
const servicesKey = getServicesKey(data.services);
|
|
3038
|
+
const descKey = safeJsonKey(resolved);
|
|
3039
|
+
const effectiveReloadKey = reloadKey ?? descKey;
|
|
3040
|
+
const mustReload = state.loadResult == null ||
|
|
3041
|
+
state.loadedComponent !== data.component ||
|
|
3042
|
+
state.loadedServicesKey !== servicesKey ||
|
|
3043
|
+
state.loadedReloadKey !== effectiveReloadKey ||
|
|
3044
|
+
state.loadedDescKey !== descKey;
|
|
3045
|
+
if (!mustReload) {
|
|
3046
|
+
return;
|
|
3047
|
+
}
|
|
3048
|
+
clearBlockDirective(state, ctx.viewContainerRef);
|
|
3049
|
+
const registry = blockRegistry ?? undefined;
|
|
3050
|
+
state.lastRegistry = registry ?? null;
|
|
3051
|
+
state.lastId = data.id ?? null;
|
|
3052
|
+
const generation = ++state.loadGeneration;
|
|
3053
|
+
ctx
|
|
3054
|
+
.loadBlock(resolved, registry, inputDefs ?? undefined)
|
|
3055
|
+
.then((result) => {
|
|
3056
|
+
if (generation !== state.loadGeneration)
|
|
3057
|
+
return;
|
|
3058
|
+
state.loadResult = result;
|
|
3059
|
+
state.loadedComponent = data.component;
|
|
3060
|
+
state.loadedServicesKey = servicesKey;
|
|
3061
|
+
state.loadedReloadKey = effectiveReloadKey;
|
|
3062
|
+
state.loadedDescKey = descKey;
|
|
3063
|
+
})
|
|
3064
|
+
.catch((err) => {
|
|
3065
|
+
if (generation !== state.loadGeneration)
|
|
3066
|
+
return;
|
|
3067
|
+
console.error('Block load failed:', err);
|
|
3068
|
+
});
|
|
3069
|
+
};
|
|
3070
|
+
if (isBlockReference(desc)) {
|
|
3071
|
+
void resolveBlockReference(desc, inputDefs ?? undefined)
|
|
3072
|
+
.then((resolved) => {
|
|
3073
|
+
runAfterResolved(resolved);
|
|
3074
|
+
})
|
|
3075
|
+
.catch((err) => {
|
|
3076
|
+
if (runId !== state.effectRunId)
|
|
3077
|
+
return;
|
|
3078
|
+
console.error('Block reference resolution failed:', err);
|
|
3079
|
+
});
|
|
3080
|
+
return;
|
|
3081
|
+
}
|
|
3082
|
+
runAfterResolved(desc);
|
|
3083
|
+
}
|
|
3084
|
+
|
|
2867
3085
|
class BlockDirective {
|
|
2868
3086
|
viewContainerRef = inject(ViewContainerRef);
|
|
2869
3087
|
loader = inject(BlockLoaderService);
|
|
2870
3088
|
destroyRef = inject(DestroyRef);
|
|
3089
|
+
loadState = createInitialBlockDirectiveLoadState();
|
|
2871
3090
|
/** Full description, or { id } / { blockId, blockDefinition? } to reuse/override from blockDefinitions. */
|
|
2872
|
-
description = input(null,
|
|
3091
|
+
description = input(null, /* @ts-ignore */
|
|
3092
|
+
...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
|
|
2873
3093
|
/** Registry for block instances by id; pass from root so nested blocks share it. */
|
|
2874
|
-
blockRegistry = input(null,
|
|
3094
|
+
blockRegistry = input(null, /* @ts-ignore */
|
|
3095
|
+
...(ngDevMode ? [{ debugName: "blockRegistry" }] : /* istanbul ignore next */ []));
|
|
2875
3096
|
/** Map id → full description or loader; used when description is a block reference (id/blockId). */
|
|
2876
|
-
blockDefinitions = input(null,
|
|
3097
|
+
blockDefinitions = input(null, /* @ts-ignore */
|
|
3098
|
+
...(ngDevMode ? [{ debugName: "blockDefinitions" }] : /* istanbul ignore next */ []));
|
|
2877
3099
|
/** Model for the block. */
|
|
2878
|
-
model = input(undefined,
|
|
3100
|
+
model = input(undefined, /* @ts-ignore */
|
|
3101
|
+
...(ngDevMode ? [{ debugName: "model" }] : /* istanbul ignore next */ []));
|
|
2879
3102
|
/**
|
|
2880
3103
|
* Forces a reload when this value changes, even if component/services are the same.
|
|
2881
3104
|
* Useful for "same component, different inputs" scenarios like tabs/switch blocks.
|
|
2882
3105
|
*/
|
|
2883
|
-
reloadKey = input(null,
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
loadGeneration = 0;
|
|
2892
|
-
/** Invalidates in-flight block-reference resolution when the effect re-runs. */
|
|
2893
|
-
effectRunId = 0;
|
|
2894
|
-
/** Avoid re-parsing when the same description reference is passed (e.g. stable signal). */
|
|
2895
|
-
lastDescRef = null;
|
|
2896
|
-
lastParsedData = null;
|
|
3106
|
+
reloadKey = input(null, /* @ts-ignore */
|
|
3107
|
+
...(ngDevMode ? [{ debugName: "reloadKey" }] : /* istanbul ignore next */ []));
|
|
3108
|
+
loadBlock(resolved, registry, blockDefinitions) {
|
|
3109
|
+
return this.loader.load(resolved, this.viewContainerRef, this.model, {
|
|
3110
|
+
registry,
|
|
3111
|
+
blockDefinitions,
|
|
3112
|
+
});
|
|
3113
|
+
}
|
|
2897
3114
|
constructor() {
|
|
2898
3115
|
effect(() => {
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
if (desc == null) {
|
|
2904
|
-
this.lastDescRef = null;
|
|
2905
|
-
this.lastParsedData = null;
|
|
2906
|
-
this.clear();
|
|
2907
|
-
return;
|
|
2908
|
-
}
|
|
2909
|
-
const runAfterResolved = (resolved) => {
|
|
2910
|
-
if (runId !== this.effectRunId) {
|
|
2911
|
-
return;
|
|
2912
|
-
}
|
|
2913
|
-
let data;
|
|
2914
|
-
if (resolved === this.lastDescRef && this.lastParsedData != null) {
|
|
2915
|
-
data = this.lastParsedData;
|
|
2916
|
-
}
|
|
2917
|
-
else {
|
|
2918
|
-
const parsed = safeParseBlockDescription(resolved);
|
|
2919
|
-
if (!parsed.success) {
|
|
2920
|
-
return;
|
|
2921
|
-
}
|
|
2922
|
-
this.lastDescRef = resolved;
|
|
2923
|
-
this.lastParsedData = parsed.data;
|
|
2924
|
-
data = parsed.data;
|
|
2925
|
-
}
|
|
2926
|
-
const servicesKey = getServicesKey(data.services);
|
|
2927
|
-
const descKey = safeJsonKey(resolved);
|
|
2928
|
-
const effectiveReloadKey = reloadKey ?? descKey;
|
|
2929
|
-
// Only clear when the logical description changed (component or services). Avoids
|
|
2930
|
-
// clear+reload when the parent passes a new reference with the same content (e.g. BlockFor).
|
|
2931
|
-
const mustReload = this.loadResult == null ||
|
|
2932
|
-
this.loadedComponent !== data.component ||
|
|
2933
|
-
this.loadedServicesKey !== servicesKey ||
|
|
2934
|
-
this.loadedReloadKey !== effectiveReloadKey ||
|
|
2935
|
-
this.loadedDescKey !== descKey;
|
|
2936
|
-
if (!mustReload) {
|
|
2937
|
-
// Description is logically unchanged (same component + services); no work needed.
|
|
2938
|
-
return;
|
|
2939
|
-
}
|
|
2940
|
-
this.clear();
|
|
2941
|
-
const registry = this.blockRegistry() ?? undefined;
|
|
2942
|
-
this.lastRegistry = registry ?? null;
|
|
2943
|
-
this.lastId = data.id ?? null;
|
|
2944
|
-
const generation = ++this.loadGeneration;
|
|
2945
|
-
this.loader
|
|
2946
|
-
.load(resolved, this.viewContainerRef, this.model, {
|
|
2947
|
-
registry,
|
|
2948
|
-
blockDefinitions: inputDefs ?? undefined,
|
|
2949
|
-
})
|
|
2950
|
-
.then((result) => {
|
|
2951
|
-
if (generation !== this.loadGeneration)
|
|
2952
|
-
return;
|
|
2953
|
-
this.loadResult = result;
|
|
2954
|
-
this.loadedComponent = data.component;
|
|
2955
|
-
this.loadedServicesKey = servicesKey;
|
|
2956
|
-
this.loadedReloadKey = effectiveReloadKey;
|
|
2957
|
-
this.loadedDescKey = descKey;
|
|
2958
|
-
})
|
|
2959
|
-
.catch((err) => {
|
|
2960
|
-
if (generation !== this.loadGeneration)
|
|
2961
|
-
return;
|
|
2962
|
-
console.error('Block load failed:', err);
|
|
2963
|
-
});
|
|
2964
|
-
};
|
|
2965
|
-
if (isBlockReference(desc)) {
|
|
2966
|
-
void resolveBlockReference(desc, inputDefs ?? undefined)
|
|
2967
|
-
.then((resolved) => {
|
|
2968
|
-
runAfterResolved(resolved);
|
|
2969
|
-
})
|
|
2970
|
-
.catch((err) => {
|
|
2971
|
-
if (runId !== this.effectRunId)
|
|
2972
|
-
return;
|
|
2973
|
-
console.error('Block reference resolution failed:', err);
|
|
2974
|
-
});
|
|
2975
|
-
return;
|
|
2976
|
-
}
|
|
2977
|
-
runAfterResolved(desc);
|
|
3116
|
+
runBlockDirectiveEffect(this.loadState, {
|
|
3117
|
+
viewContainerRef: this.viewContainerRef,
|
|
3118
|
+
loadBlock: this.loadBlock.bind(this),
|
|
3119
|
+
}, this.description(), this.blockDefinitions(), this.blockRegistry(), this.reloadKey());
|
|
2978
3120
|
});
|
|
2979
|
-
this.destroyRef.onDestroy(() => this.
|
|
3121
|
+
this.destroyRef.onDestroy(() => clearBlockDirective(this.loadState, this.viewContainerRef));
|
|
2980
3122
|
}
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
if (this.lastId != null) {
|
|
2986
|
-
this.lastRegistry?.unregister(this.lastId);
|
|
2987
|
-
this.lastId = null;
|
|
2988
|
-
}
|
|
2989
|
-
if (this.loadResult) {
|
|
2990
|
-
this.viewContainerRef.clear();
|
|
2991
|
-
this.loadResult = null;
|
|
2992
|
-
this.loadedComponent = null;
|
|
2993
|
-
this.loadedServicesKey = null;
|
|
2994
|
-
this.loadedReloadKey = null;
|
|
2995
|
-
this.loadedDescKey = null;
|
|
2996
|
-
}
|
|
2997
|
-
}
|
|
2998
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: BlockDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2999
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.0", type: BlockDirective, isStandalone: true, selector: "[block]", inputs: { description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, blockRegistry: { classPropertyName: "blockRegistry", publicName: "blockRegistry", isSignal: true, isRequired: false, transformFunction: null }, blockDefinitions: { classPropertyName: "blockDefinitions", publicName: "blockDefinitions", isSignal: true, isRequired: false, transformFunction: null }, model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, reloadKey: { classPropertyName: "reloadKey", publicName: "reloadKey", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
3000
|
-
}
|
|
3001
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: BlockDirective, decorators: [{
|
|
3123
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: BlockDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3124
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.2.3", type: BlockDirective, isStandalone: true, selector: "[block]", inputs: { description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, blockRegistry: { classPropertyName: "blockRegistry", publicName: "blockRegistry", isSignal: true, isRequired: false, transformFunction: null }, blockDefinitions: { classPropertyName: "blockDefinitions", publicName: "blockDefinitions", isSignal: true, isRequired: false, transformFunction: null }, model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, reloadKey: { classPropertyName: "reloadKey", publicName: "reloadKey", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
3125
|
+
}
|
|
3126
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: BlockDirective, decorators: [{
|
|
3002
3127
|
type: Directive,
|
|
3003
3128
|
args: [{
|
|
3004
3129
|
selector: '[block]',
|
|
@@ -3014,5 +3139,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
3014
3139
|
* Generated bundle index. Do not edit.
|
|
3015
3140
|
*/
|
|
3016
3141
|
|
|
3017
|
-
export { BlockDefinitionsRegistry, BlockDirective, BlockLoaderService, BlockRegistryImpl, BlockRegistryService, ChainedBlockRegistry, ComponentRegistry, DirectiveRegistry, GuardRegistry, INTERPOLATE_MAX_PLACEHOLDERS, RegistryMetadataStore, RouteLoader, ServiceRegistry, buildComputedForTemplate, classifyTwoWayString, collectRefPaths, createOutputHandler, deepMergeBlockDefinition, evaluateExpression, extractReadonlyRefs, getRefPathFromReadonly, getRefSignal, getRefValue, getValueByPath, interpretFlow, isBlockDefinitionLoader, isBlockReference, isInvalidTwoWayMix, isOutputCallObject, isOutputReference, isTwoWayRefString, looksLikeFlowTemplate, mustacheSegmentToString, normalizeDirectives, normalizeServices, parseFlowTemplate, parseRefPath, parseTwoWayRef, refPathResolvesToSignal, resolveBlockReference, resolveMustacheInterpolatedString, resolveRefOrModel, resolveRefPath, resolveReferenceValue, resolveTemplateString, safeParseBlockDescription, setRefValue, splitCallableRef };
|
|
3142
|
+
export { BlockDefinitionsRegistry, BlockDirective, BlockLoaderService, BlockRegistryImpl, BlockRegistryService, ChainedBlockRegistry, ComponentRegistry, DirectiveRegistry, GuardRegistry, INTERPOLATE_MAX_PLACEHOLDERS, RegistryMetadataStore, RouteLoader, ServiceRegistry, buildComputedForTemplate, classifyTwoWayString, collectRefPaths, createInputBindingsWithWarnings, createOutputHandler, deepMergeBlockDefinition, evaluateExpression, extractReadonlyRefs, getRefPathFromReadonly, getRefSignal, getRefValue, getValueByPath, interpretFlow, isBlockDefinitionLoader, isBlockReference, isInvalidTwoWayMix, isOutputCallObject, isOutputReference, isTwoWayRefString, linkedTwoWayFromInputGetter, looksLikeFlowTemplate, mustacheSegmentToString, normalizeDirectives, normalizeServices, parseFlowTemplate, parseRefPath, parseTwoWayRef, refPathResolvesToSignal, resolveBlockReference, resolveMustacheInterpolatedString, resolveRefOrModel, resolveRefPath, resolveReferenceValue, resolveTemplateString, safeParseBlockDescription, setRefValue, splitCallableRef };
|
|
3018
3143
|
//# sourceMappingURL=ngx-blocks-studio.mjs.map
|