ngx-blocks-studio 0.2.1 → 0.2.2

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/README.md CHANGED
@@ -113,7 +113,7 @@ JSON route files can include `children`, `data`, `title`, and guard arrays (`can
113
113
 
114
114
  ## Example: render a block with `[block]`
115
115
 
116
- Register the component key, then pass a **block description** and a shared **`BlockRegistry`** so nested blocks and cross-block refs resolve.
116
+ Register the component key, then pass a **block description** and a shared **`BlockRegistry`** (`BlockRegistryImpl` or `ChainedBlockRegistry`) so nested blocks and cross-block refs resolve. See `docs/core/block-registry.md`.
117
117
 
118
118
  ```typescript
119
119
  ComponentRegistry.getInstance().register('MyPanel', MyPanelComponent);
@@ -153,4 +153,4 @@ ComponentRegistry.getInstance().register('MyPanel', MyPanelComponent);
153
153
 
154
154
  ## API surface (where to look in docs)
155
155
 
156
- When you have the repo: **Registry** (registries and metadata), **Block loader** (`BlockDirective`, `BlockLoaderService`, refs, outputs), **Route loader** (`RouteLoader`, `RouteConfig`, JSON loading). The source tree under `projects/blocks-studio/src/lib` matches the public exports.
156
+ When you have the repo, see `docs/` in the repository root: **Registry** (type registries), **Block instance registry** (`BlockRegistryImpl`, `ChainedBlockRegistry`, `BlockRegistryService`), **Block loader** (`BlockDirective`, refs, outputs), **Route loader**. The source tree under `projects/blocks-studio/src/lib` matches the public exports.
@@ -1414,6 +1414,87 @@ function resolveRefPath(refPath, ctx) {
1414
1414
  // can consistently handle signals and functions at the leaf.
1415
1415
  return { target: current, path: effectiveParts.slice(-1) };
1416
1416
  }
1417
+ /** Root value and property keys for a resolved ref (for path reactivity checks). */
1418
+ function getRefPathWalk(refPath, ctx) {
1419
+ const parsed = parseRefPath(refPath);
1420
+ const { scopeKey, blockId, serviceOrModel, pathParts } = parsed;
1421
+ if (!serviceOrModel) {
1422
+ return null;
1423
+ }
1424
+ const registry = scopeKey != null ? (ctx.getRegistryForScope?.(scopeKey) ?? null) : ctx.registry;
1425
+ if (scopeKey != null && registry == null) {
1426
+ return null;
1427
+ }
1428
+ let instance;
1429
+ if (blockId != null) {
1430
+ if (scopeKey == null &&
1431
+ ctx.currentBlockId != null &&
1432
+ blockId === ctx.currentBlockId &&
1433
+ ctx.currentInstance != null) {
1434
+ instance = ctx.currentInstance;
1435
+ }
1436
+ else {
1437
+ if (registry == null) {
1438
+ return null;
1439
+ }
1440
+ const handle = registry.get(blockId);
1441
+ if (!handle) {
1442
+ return null;
1443
+ }
1444
+ instance = handle.instance;
1445
+ }
1446
+ }
1447
+ else {
1448
+ instance = ctx.currentInstance ?? undefined;
1449
+ }
1450
+ if (instance == null)
1451
+ return null;
1452
+ if (serviceOrModel === 'model') {
1453
+ const base = instance.model;
1454
+ if (!base) {
1455
+ return null;
1456
+ }
1457
+ return { start: base, parts: pathParts };
1458
+ }
1459
+ const service = instance.services?.[serviceOrModel];
1460
+ const shouldModelFallback = blockId != null && service == null && instance.model != null;
1461
+ const base = shouldModelFallback ? instance.model : service;
1462
+ const effectiveParts = shouldModelFallback ? [serviceOrModel, ...pathParts] : pathParts;
1463
+ if (!base) {
1464
+ return null;
1465
+ }
1466
+ return { start: base, parts: effectiveParts };
1467
+ }
1468
+ /**
1469
+ * True when any segment on the ref path is (or ends at) a signal or callable leaf.
1470
+ */
1471
+ function refPathHasSignalAlongPath(refPath, ctx) {
1472
+ const walk = getRefPathWalk(refPath, ctx);
1473
+ if (walk == null) {
1474
+ return false;
1475
+ }
1476
+ let current = walk.start;
1477
+ if (current != null && isSignal(current)) {
1478
+ return true;
1479
+ }
1480
+ const parts = walk.parts;
1481
+ for (let i = 0; i < parts.length; i++) {
1482
+ if (current == null || typeof current !== 'object') {
1483
+ return false;
1484
+ }
1485
+ const key = parts[i];
1486
+ const next = current[key];
1487
+ const isLast = i === parts.length - 1;
1488
+ if (isLast) {
1489
+ return next != null && (isSignal(next) || typeof next === 'function');
1490
+ }
1491
+ if (next != null && isSignal(next)) {
1492
+ return true;
1493
+ }
1494
+ current = next;
1495
+ }
1496
+ return false;
1497
+ }
1417
1498
  /**
1418
1499
  * Get a value from an object by dot-notation path (e.g. "name.firstName" -> obj.name?.firstName).
1419
1500
  * Returns undefined if any segment is null/undefined or not an object.
@@ -1794,7 +1875,10 @@ function interpretFlow(nodes, ctx, scope = {}, options) {
1794
1875
  }
1795
1876
  /* v8 ignore start -- exhaustive node.type chain; non-for nodes handled above */
1796
1877
  if (node.type === 'for') {
1797
- const arr = resolveRefOrModel(node.refPath, ctx);
1878
+ const rawExpr = node.refPath.trim();
1879
+ const arr = options?.resolveCondition
1880
+ ? options.resolveCondition(rawExpr, scope)
1881
+ : resolveRefOrModel(rawExpr, ctx);
1798
1882
  const list = Array.isArray(arr) ? arr : [];
1799
1883
  for (let idx = 0; idx < list.length; idx++) {
1800
1884
  out += interpretFlow(node.body, ctx, {
@@ -2081,6 +2165,8 @@ function evalExpr(expr, ctx) {
2081
2165
  if (expr.name === '$event' || expr.name === 'event' || expr.name === 'payload' || expr.name === 'value') {
2082
2166
  return ctx.payload;
2083
2167
  }
2168
+ if (ctx.scope != null && expr.name in ctx.scope)
2169
+ return ctx.scope[expr.name];
2084
2170
  if (expr.name in ctx.model)
2085
2171
  return ctx.model[expr.name];
2086
2172
  if (ctx.services != null && expr.name in ctx.services)
@@ -2178,12 +2264,13 @@ function evalExpr(expr, ctx) {
2178
2264
  return evalExpr(expr.test, ctx) ? evalExpr(expr.consequent, ctx) : evalExpr(expr.alternate, ctx);
2179
2265
  }
2180
2266
  }
2181
- function evaluateSafeExpression(expression, resolverContext, payload, resolveRefValue) {
2267
+ function evaluateSafeExpression(expression, resolverContext, payload, resolveRefValue, scope) {
2182
2268
  const ast = new Parser(tokenize(expression)).parse();
2183
2269
  return evalExpr(ast, {
2184
2270
  payload,
2185
2271
  model: (resolverContext.currentInstance?.model?.() ?? {}),
2186
2272
  services: resolverContext.currentInstance?.services,
2273
+ scope,
2187
2274
  resolveRefValue: (ref) => resolveRefValue(ref, resolverContext),
2188
2275
  });
2189
2276
  }
@@ -2201,12 +2288,12 @@ function resolveReferenceValue(ref, ctx) {
2201
2288
  * Safe expression evaluation (same as output `{{ }}` / `@if (...)` when used with this module).
2202
2289
  * Falls back to `resolveReferenceValue` if parsing fails (treat whole string as a ref path).
2203
2290
  */
2204
- function evaluateExpression(expression, ctx, payload) {
2291
+ function evaluateExpression(expression, ctx, payload, scope) {
2205
2292
  const trimmed = expression.trim();
2206
2293
  if (!trimmed)
2207
2294
  return undefined;
2208
2295
  try {
2209
- return evaluateSafeExpression(trimmed, ctx, payload, resolveReferenceValue);
2296
+ return evaluateSafeExpression(trimmed, ctx, payload, resolveReferenceValue, scope);
2210
2297
  }
2211
2298
  catch {
2212
2299
  return resolveReferenceValue(trimmed, ctx);
@@ -2254,14 +2341,14 @@ function mustacheSegmentToString(segment, ctx, payload) {
2254
2341
  }
2255
2342
  /**
2256
2343
  * Unified template resolution: flow (`@if`, `@for`, `${}`) plus `{{ }}` in flow text segments.
2257
- * `@if` conditions use `evaluateExpression` (safe expressions + ref fallback).
2344
+ * `@if` / `@for (… of …)` use `evaluateExpression` (safe expressions + ref fallback).
2258
2345
  */
2259
2346
  function resolveTemplateString(value, ctx, payload = undefined, options) {
2260
2347
  const escapeFlowRefs = options?.escapeFlowRefs !== false;
2261
2348
  if (looksLikeFlowTemplate(value)) {
2262
2349
  return interpretFlow(parseFlowTemplate(value), ctx, {}, {
2263
2350
  escapeRefValues: escapeFlowRefs,
2264
- resolveCondition: (expr) => evaluateExpression(expr, ctx, payload),
2351
+ resolveCondition: (expr, scope) => evaluateExpression(expr, ctx, payload, scope),
2265
2352
  interpolateText: (segment) => mustacheSegmentToString(segment, ctx, payload),
2266
2353
  });
2267
2354
  }
@@ -2614,6 +2701,147 @@ function resolveNestedTemplateValues(value, ctx, path = '', visited = new WeakSe
2614
2701
  }
2615
2702
  return value;
2616
2703
  }
2704
+ function parseSingleMustacheExpression(value) {
2705
+ const trimmed = value.trim();
2706
+ if (!trimmed.includes('{{') || !trimmed.includes('}}')) {
2707
+ return undefined;
2708
+ }
2709
+ const re = /\{\{([\s\S]*?)\}\}/g;
2710
+ const matches = [...trimmed.matchAll(re)];
2711
+ if (matches.length !== 1 || matches[0][0] !== trimmed) {
2712
+ return undefined;
2713
+ }
2714
+ return matches[0][1].trim();
2715
+ }
2716
+ /** Single full-string mustache / two-way ref for nested input materialization. */
2717
+ function parseTemplateInputRefLeaf(str, ctx) {
2718
+ const twoWayKind = classifyTwoWayString(str);
2719
+ if (twoWayKind === 'two-way') {
2720
+ const refPath = parseTwoWayRef(str);
2721
+ return refPath ? { refPath, embedLeafSignal: false } : undefined;
2722
+ }
2723
+ const expr = parseSingleMustacheExpression(str);
2724
+ if (expr == null) {
2725
+ return undefined;
2726
+ }
2727
+ const refCall = /^ref\s*\(\s*['"]([^'"]+)['"]\s*(?:,\s*(true|false))?\s*\)$/.exec(expr);
2728
+ if (refCall) {
2729
+ return {
2730
+ refPath: refCall[1],
2731
+ embedLeafSignal: refCall[2] === 'true',
2732
+ };
2733
+ }
2734
+ // Only dotted / BlockId:path shapes — not ternaries (`:`) or other safe expressions.
2735
+ if (!isSimpleDottedRefPathExpression(expr)) {
2736
+ return undefined;
2737
+ }
2738
+ return resolveRefPath(expr, ctx) != null ? { refPath: expr, embedLeafSignal: false } : undefined;
2739
+ }
2740
+ /** `BlockId:service.path` or `service.path` only (no `ref()`, ternaries, or operators). */
2741
+ function isSimpleDottedRefPathExpression(expr) {
2742
+ const t = expr.trim();
2743
+ if (!t || /[?+]|===|!==|&&|\|\||\bref\s*\(/.test(t)) {
2744
+ return false;
2745
+ }
2746
+ return /^[\w./-]+:[\w.]+$|^[\w.-]+(?:\.[\w.-]+)+$|^[\w.-]+$/.test(t);
2747
+ }
2748
+ function materializeEmbedRefLeaf(ctx, refPath) {
2749
+ const refSignal = getRefSignal(refPath, ctx);
2750
+ if (refSignal != null) {
2751
+ return refSignal;
2752
+ }
2753
+ if (!refPathHasSignalAlongPath(refPath, ctx)) {
2754
+ return getRefValue(refPath, ctx);
2755
+ }
2756
+ return computed(() => getRefValue(refPath, ctx));
2757
+ }
2758
+ /**
2759
+ * Stable nested graph at bind time: literals and unresolved template strings stay as-is;
2760
+ * only `{{ ref('path', true) }}` embeds the leaf {@link Signal} (or reactive fallback).
2761
+ */
2762
+ function materializeNestedReactiveInput(value, ctx, path = '', visited = new WeakSet(), options = {}) {
2763
+ if (typeof value === 'string') {
2764
+ if (!stringNeedsInputResolve(value)) {
2765
+ return value;
2766
+ }
2767
+ const refLeaf = parseTemplateInputRefLeaf(value, ctx);
2768
+ if (refLeaf?.embedLeafSignal) {
2769
+ return materializeEmbedRefLeaf(ctx, refLeaf.refPath);
2770
+ }
2771
+ return value;
2772
+ }
2773
+ if (Array.isArray(value)) {
2774
+ return value.map((item, index) => {
2775
+ const childPath = path ? `${path}[${index}]` : `[${index}]`;
2776
+ return materializeNestedReactiveInput(item, ctx, childPath, visited, options);
2777
+ });
2778
+ }
2779
+ if (value != null && typeof value === 'object') {
2780
+ if (!isPlainObject(value))
2781
+ return value;
2782
+ if (looksLikeBlockDescriptor(value))
2783
+ return value;
2784
+ if (visited.has(value))
2785
+ return value;
2786
+ visited.add(value);
2787
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => {
2788
+ const childPath = path ? `${path}.${key}` : key;
2789
+ return [key, materializeNestedReactiveInput(item, ctx, childPath, visited, options)];
2790
+ }));
2791
+ }
2792
+ return value;
2793
+ }
2794
+ /**
2795
+ * Resolve a {@link materializeNestedReactiveInput} graph for block input binding:
2796
+ * template strings become plain values; embedded {@link Signal}s are kept as references.
2797
+ */
2798
+ function resolveMaterializedNestedInput(value, ctx, path = '', visited = new WeakSet(), options = {}) {
2799
+ if (isSignal(value)) {
2800
+ return value;
2801
+ }
2802
+ if (typeof value === 'string') {
2803
+ if (!stringNeedsInputResolve(value)) {
2804
+ return value;
2805
+ }
2806
+ return resolveStringLeaf(value, ctx, path || 'input', options);
2807
+ }
2808
+ if (Array.isArray(value)) {
2809
+ return value.map((item, index) => {
2810
+ const childPath = path ? `${path}[${index}]` : `[${index}]`;
2811
+ return resolveMaterializedNestedInput(item, ctx, childPath, visited, options);
2812
+ });
2813
+ }
2814
+ if (value != null && typeof value === 'object') {
2815
+ if (!isPlainObject(value))
2816
+ return value;
2817
+ if (looksLikeBlockDescriptor(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
+ const childPath = path ? `${path}.${key}` : key;
2824
+ return [key, resolveMaterializedNestedInput(item, ctx, childPath, visited, options)];
2825
+ }));
2826
+ }
2827
+ return value;
2828
+ }
2829
+ /**
2830
+ * Deep-read values from {@link materializeNestedReactiveInput}: unwraps embedded
2831
+ * `Signal`s / `computed`s and recurses through plain objects and arrays.
2832
+ */
2833
+ function readNestedInputValue(value) {
2834
+ if (isSignal(value)) {
2835
+ return readNestedInputValue(value());
2836
+ }
2837
+ if (Array.isArray(value)) {
2838
+ return value.map((item) => readNestedInputValue(item));
2839
+ }
2840
+ if (isPlainObject(value)) {
2841
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, readNestedInputValue(item)]));
2842
+ }
2843
+ return value;
2844
+ }
2617
2845
 
2618
2846
  const NESTED_INPUT_RESOLVE_OPTIONS = {
2619
2847
  resolveTwoWayStringsAsReadonly: true,
@@ -2730,7 +2958,8 @@ function resolveBlockInputsAndOutputs(description, inputKeys, outputKeys, twoWay
2730
2958
  }
2731
2959
  if (Array.isArray(value) || isPlainObject(value)) {
2732
2960
  if (valueNeedsInputResolve(value)) {
2733
- resolvedInputs[key] = computed(() => resolveNestedTemplateValues(value, ctx, key, new WeakSet(), NESTED_INPUT_RESOLVE_OPTIONS));
2961
+ const materialized = materializeNestedReactiveInput(value, ctx, key, new WeakSet(), NESTED_INPUT_RESOLVE_OPTIONS);
2962
+ resolvedInputs[key] = computed(() => resolveMaterializedNestedInput(materialized, ctx, key, new WeakSet(), NESTED_INPUT_RESOLVE_OPTIONS));
2734
2963
  }
2735
2964
  else if (inputKeys.has(key)) {
2736
2965
  resolvedInputs[key] = () => value;
@@ -2754,6 +2983,12 @@ function resolveBlockInputsAndOutputs(description, inputKeys, outputKeys, twoWay
2754
2983
  return { resolvedInputs, resolvedOutputs, resolvedTwoWay };
2755
2984
  }
2756
2985
 
2986
+ function isBlockLoadStale(options) {
2987
+ if (options?.loadGeneration == null || options.getCurrentLoadGeneration == null) {
2988
+ return false;
2989
+ }
2990
+ return options.loadGeneration !== options.getCurrentLoadGeneration();
2991
+ }
2757
2992
  const INTERPOLATE_MAX_PLACEHOLDERS = 200;
2758
2993
  /** Builds a two-way binding when only a read getter exists for the key (used by {@link createInputBindingsWithWarnings}). */
2759
2994
  function linkedTwoWayFromInputGetter(resolvedInputs, key) {
@@ -2794,9 +3029,13 @@ class BlockLoaderService {
2794
3029
  serviceRegistry = ServiceRegistry.getInstance();
2795
3030
  blockRegistryService = inject(BlockRegistryService);
2796
3031
  async load(description, viewContainerRef, model, options) {
3032
+ const blockId = (id) => id != null && id !== '' ? id : null;
2797
3033
  let resolved = description;
2798
3034
  if (isBlockReference(description)) {
2799
3035
  resolved = await resolveBlockReference(description, options?.blockDefinitions);
3036
+ if (isBlockLoadStale(options)) {
3037
+ return null;
3038
+ }
2800
3039
  }
2801
3040
  const parsed = safeParseBlockDescription(resolved);
2802
3041
  if (!parsed.success) {
@@ -2804,10 +3043,10 @@ class BlockLoaderService {
2804
3043
  }
2805
3044
  const desc = parsed.data;
2806
3045
  const registry = options?.registry ?? new BlockRegistryImpl();
2807
- if (desc.id != null && desc.id !== '' && registry.hasLocal(desc.id)) {
2808
- throw new Error(`Block id "${desc.id}" is already registered.`);
2809
- }
2810
3046
  const componentType = await this.componentRegistry.get(desc.component);
3047
+ if (isBlockLoadStale(options)) {
3048
+ return null;
3049
+ }
2811
3050
  if (!componentType) {
2812
3051
  throw new Error(`Component "${desc.component}" is not registered.`);
2813
3052
  }
@@ -2823,13 +3062,16 @@ class BlockLoaderService {
2823
3062
  this.resolveContextModel(ctx, model);
2824
3063
  const resolvedModel = blockInstance.model;
2825
3064
  const handle = { instance: blockInstance };
2826
- //... Register the block instance with the registry if it has an id
2827
- if (desc.id != null && desc.id !== '')
2828
- registry.register(desc.id, handle);
2829
3065
  //... Resolve services for the block
2830
3066
  await this.resolveServices(viewContainerRef, blockInstance, desc, resolvedModel, model);
3067
+ if (isBlockLoadStale(options)) {
3068
+ return null;
3069
+ }
2831
3070
  const directiveIds = normalizeDirectives(desc.directives);
2832
3071
  const directiveTypes = await this.getDirectiveTypes(directiveIds);
3072
+ if (isBlockLoadStale(options)) {
3073
+ return null;
3074
+ }
2833
3075
  const nonNullDirectiveTypes = directiveTypes.filter((d) => d != null);
2834
3076
  // get inputs and outputs from the component and host directives
2835
3077
  const componentMetadata = getBlockInputsAndOutputs([componentType]);
@@ -2861,11 +3103,36 @@ class BlockLoaderService {
2861
3103
  ...createInputBindingsWithWarnings(`directive "${d.type.name}"`, d.metadata.inputs, d.metadata.twoWay, d.metadata.outputs, initialResolved.resolvedInputs, initialResolved.resolvedTwoWay, initialResolved.resolvedOutputs),
2862
3104
  ],
2863
3105
  }));
2864
- const componentRef = viewContainerRef.createComponent(componentType, {
2865
- directives: directiveAndBindings,
2866
- bindings: componentBindings,
2867
- });
2868
- return componentRef;
3106
+ const id = blockId(desc.id);
3107
+ try {
3108
+ if (id != null) {
3109
+ if (registry.hasLocal(id)) {
3110
+ registry.unregister(id);
3111
+ }
3112
+ if (isBlockLoadStale(options)) {
3113
+ return null;
3114
+ }
3115
+ registry.register(id, handle);
3116
+ }
3117
+ const componentRef = viewContainerRef.createComponent(componentType, {
3118
+ directives: directiveAndBindings,
3119
+ bindings: componentBindings,
3120
+ });
3121
+ if (isBlockLoadStale(options)) {
3122
+ componentRef.destroy();
3123
+ if (id != null) {
3124
+ registry.unregister(id);
3125
+ }
3126
+ return null;
3127
+ }
3128
+ return componentRef;
3129
+ }
3130
+ catch (err) {
3131
+ if (id != null) {
3132
+ registry.unregister(id);
3133
+ }
3134
+ throw err;
3135
+ }
2869
3136
  }
2870
3137
  async resolveServices(viewContainerRef, blockInstance, desc, resolvedModel, model) {
2871
3138
  // services are stored under `blockInstance.services`, so `model` no longer collides structurally,
@@ -3040,14 +3307,12 @@ function clearBlockDirective(state, viewContainerRef) {
3040
3307
  state.lastRegistry?.unregister(state.lastId);
3041
3308
  state.lastId = null;
3042
3309
  }
3043
- if (state.loadResult) {
3044
- viewContainerRef.clear();
3045
- state.loadResult = null;
3046
- state.loadedComponent = null;
3047
- state.loadedServicesKey = null;
3048
- state.loadedReloadKey = null;
3049
- state.loadedDescKey = null;
3050
- }
3310
+ viewContainerRef.clear();
3311
+ state.loadResult = null;
3312
+ state.loadedComponent = null;
3313
+ state.loadedServicesKey = null;
3314
+ state.loadedReloadKey = null;
3315
+ state.loadedDescKey = null;
3051
3316
  }
3052
3317
  function runBlockDirectiveEffect(state, ctx, desc, inputDefs, blockRegistry, reloadKey) {
3053
3318
  const runId = ++state.effectRunId;
@@ -3091,10 +3356,15 @@ function runBlockDirectiveEffect(state, ctx, desc, inputDefs, blockRegistry, rel
3091
3356
  state.lastId = data.id ?? null;
3092
3357
  const generation = ++state.loadGeneration;
3093
3358
  ctx
3094
- .loadBlock(resolved, registry, inputDefs ?? undefined)
3359
+ .loadBlock(resolved, registry, inputDefs ?? undefined, generation, () => state.loadGeneration)
3095
3360
  .then((result) => {
3096
- if (generation !== state.loadGeneration)
3361
+ if (generation !== state.loadGeneration) {
3362
+ result?.destroy();
3097
3363
  return;
3364
+ }
3365
+ if (result == null) {
3366
+ return;
3367
+ }
3098
3368
  state.loadResult = result;
3099
3369
  state.loadedComponent = data.component;
3100
3370
  state.loadedServicesKey = servicesKey;
@@ -3145,10 +3415,12 @@ class BlockDirective {
3145
3415
  */
3146
3416
  reloadKey = input(null, /* @ts-ignore */
3147
3417
  ...(ngDevMode ? [{ debugName: "reloadKey" }] : /* istanbul ignore next */ []));
3148
- loadBlock(resolved, registry, blockDefinitions) {
3418
+ loadBlock(resolved, registry, blockDefinitions, loadGeneration, getCurrentLoadGeneration) {
3149
3419
  return this.loader.load(resolved, this.viewContainerRef, this.model, {
3150
3420
  registry,
3151
3421
  blockDefinitions,
3422
+ loadGeneration,
3423
+ getCurrentLoadGeneration,
3152
3424
  });
3153
3425
  }
3154
3426
  constructor() {
@@ -3179,5 +3451,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImpor
3179
3451
  * Generated bundle index. Do not edit.
3180
3452
  */
3181
3453
 
3182
- 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, isPlainObject, isTwoWayRefString, linkedTwoWayFromInputGetter, looksLikeBlockDescriptor, looksLikeFlowTemplate, mustacheSegmentToString, normalizeDirectives, normalizeServices, parseFlowTemplate, parseRefPath, parseTwoWayRef, refPathResolvesToSignal, resolveBlockReference, resolveMustacheInterpolatedString, resolveNestedTemplateValues, resolveRefOrModel, resolveRefPath, resolveReferenceValue, resolveTemplateString, safeParseBlockDescription, setRefValue, shouldDeferInputTemplateResolution, splitCallableRef, valueContainsMustacheInTree, valueNeedsInputResolve };
3454
+ 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, isPlainObject, isTwoWayRefString, linkedTwoWayFromInputGetter, looksLikeBlockDescriptor, looksLikeFlowTemplate, materializeNestedReactiveInput, mustacheSegmentToString, normalizeDirectives, normalizeServices, parseFlowTemplate, parseRefPath, parseTemplateInputRefLeaf, parseTwoWayRef, readNestedInputValue, refPathHasSignalAlongPath, refPathResolvesToSignal, resolveBlockReference, resolveMaterializedNestedInput, resolveMustacheInterpolatedString, resolveNestedTemplateValues, resolveRefOrModel, resolveRefPath, resolveReferenceValue, resolveTemplateString, safeParseBlockDescription, setRefValue, shouldDeferInputTemplateResolution, splitCallableRef, valueContainsMustacheInTree, valueNeedsInputResolve };
3183
3455
  //# sourceMappingURL=ngx-blocks-studio.mjs.map