@contentful/experiences-angular 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.
Files changed (79) hide show
  1. package/CHANGELOG.md +189 -0
  2. package/README.md +368 -0
  3. package/dist/client-experience-renderer.component.d.ts +42 -0
  4. package/dist/client-experience-renderer.component.d.ts.map +1 -0
  5. package/dist/client-experience-renderer.component.js +155 -0
  6. package/dist/client-experience-renderer.component.js.map +1 -0
  7. package/dist/component-error.component.d.ts +14 -0
  8. package/dist/component-error.component.d.ts.map +1 -0
  9. package/dist/component-error.component.js +81 -0
  10. package/dist/component-error.component.js.map +1 -0
  11. package/dist/context.d.ts +21 -0
  12. package/dist/context.d.ts.map +1 -0
  13. package/dist/context.js +54 -0
  14. package/dist/context.js.map +1 -0
  15. package/dist/debug-experience.component.d.ts +17 -0
  16. package/dist/debug-experience.component.d.ts.map +1 -0
  17. package/dist/debug-experience.component.js +143 -0
  18. package/dist/debug-experience.component.js.map +1 -0
  19. package/dist/design-utils.d.ts +22 -0
  20. package/dist/design-utils.d.ts.map +1 -0
  21. package/dist/design-utils.js +40 -0
  22. package/dist/design-utils.js.map +1 -0
  23. package/dist/experience-defaults.d.ts +16 -0
  24. package/dist/experience-defaults.d.ts.map +1 -0
  25. package/dist/experience-defaults.js +27 -0
  26. package/dist/experience-defaults.js.map +1 -0
  27. package/dist/experience-scope.d.ts +33 -0
  28. package/dist/experience-scope.d.ts.map +1 -0
  29. package/dist/experience-scope.js +90 -0
  30. package/dist/experience-scope.js.map +1 -0
  31. package/dist/index.d.ts +40 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +62 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/inject-active-viewport.d.ts +32 -0
  36. package/dist/inject-active-viewport.d.ts.map +1 -0
  37. package/dist/inject-active-viewport.js +78 -0
  38. package/dist/inject-active-viewport.js.map +1 -0
  39. package/dist/inject-design-values.d.ts +14 -0
  40. package/dist/inject-design-values.d.ts.map +1 -0
  41. package/dist/inject-design-values.js +24 -0
  42. package/dist/inject-design-values.js.map +1 -0
  43. package/dist/inject-experience-plan.d.ts +15 -0
  44. package/dist/inject-experience-plan.d.ts.map +1 -0
  45. package/dist/inject-experience-plan.js +39 -0
  46. package/dist/inject-experience-plan.js.map +1 -0
  47. package/dist/inject-live-preview-experience.d.ts +13 -0
  48. package/dist/inject-live-preview-experience.d.ts.map +1 -0
  49. package/dist/inject-live-preview-experience.js +47 -0
  50. package/dist/inject-live-preview-experience.js.map +1 -0
  51. package/dist/inject-live-preview.d.ts +16 -0
  52. package/dist/inject-live-preview.d.ts.map +1 -0
  53. package/dist/inject-live-preview.js +14 -0
  54. package/dist/inject-live-preview.js.map +1 -0
  55. package/dist/missing-component.component.d.ts +14 -0
  56. package/dist/missing-component.component.d.ts.map +1 -0
  57. package/dist/missing-component.component.js +83 -0
  58. package/dist/missing-component.component.js.map +1 -0
  59. package/dist/node-render-engine.d.ts +109 -0
  60. package/dist/node-render-engine.d.ts.map +1 -0
  61. package/dist/node-render-engine.js +528 -0
  62. package/dist/node-render-engine.js.map +1 -0
  63. package/dist/node-renderer.directive.d.ts +46 -0
  64. package/dist/node-renderer.directive.d.ts.map +1 -0
  65. package/dist/node-renderer.directive.js +96 -0
  66. package/dist/node-renderer.directive.js.map +1 -0
  67. package/dist/node-scopes.d.ts +39 -0
  68. package/dist/node-scopes.d.ts.map +1 -0
  69. package/dist/node-scopes.js +75 -0
  70. package/dist/node-scopes.js.map +1 -0
  71. package/dist/server-experience-renderer.component.d.ts +46 -0
  72. package/dist/server-experience-renderer.component.d.ts.map +1 -0
  73. package/dist/server-experience-renderer.component.js +159 -0
  74. package/dist/server-experience-renderer.component.js.map +1 -0
  75. package/dist/types.d.ts +137 -0
  76. package/dist/types.d.ts.map +1 -0
  77. package/dist/types.js +44 -0
  78. package/dist/types.js.map +1 -0
  79. package/package.json +57 -0
@@ -0,0 +1,528 @@
1
+ /*
2
+ * Per-node render logic, plus the imperative engine that puts customer
3
+ * components into the DOM. Port of adapter-svelte/src/NodeRenderer.svelte.
4
+ *
5
+ * Why an engine class instead of components: an Angular component selector is
6
+ * always a real DOM element, so a dispatch chain built out of components
7
+ * physically nests wrappers between a customer component and its slot children —
8
+ * where React renders a fragment and Svelte renders nothing. `display: contents`
9
+ * hides those wrappers from layout but not from CSS: `.grid > .card`,
10
+ * `:nth-child(n)`, `+` and `~` still see the plumbing. A structural directive
11
+ * has no host element, so `<ng-container *cfNodes="nodes">` leaves nothing but a
12
+ * comment anchor, and children are created as *siblings of that anchor* —
13
+ * direct children of the customer's own element. `Element.children` excludes
14
+ * comments, so `:nth-child`, `:first-child` and sibling combinators all behave
15
+ * as they do in React and Svelte. Svelte leaves comment anchors too.
16
+ *
17
+ * That is also why the per-node DI scopes are built with `Injector.create`
18
+ * rather than a component `providers` array. `providers` is static per class,
19
+ * which is what previously forced "component node" and "experience template
20
+ * node" to be two different component classes; an injector built per node can
21
+ * decide per node. The `parent` is the anchor's own injector, which is exactly
22
+ * what `NgComponentOutlet` passes by default, so the element-injector walk-up
23
+ * that `injectExperience()` / `injectContentfulExperienceTemplate()` rely on is
24
+ * unchanged.
25
+ *
26
+ * The Svelte adapter's ordering guarantee — an unregistered node still exposes
27
+ * its payload to whatever renders in its place — used to be structural here
28
+ * (the scope-providing wrapper was constructed before the host that performed
29
+ * the registry lookup). It is now statement order in `createUnit`: the scopes
30
+ * are constructed and connected before `createComponent` is ever called. Keep
31
+ * it that way.
32
+ */
33
+ import { Injector, computed, inputBinding, reflectComponentType, signal, } from '@angular/core';
34
+ import { selectResolvedDesign } from '@contentful/experiences-design';
35
+ import { ComponentScope, DesignScope, ExperienceTemplateScope } from './node-scopes.js';
36
+ import { normalizeComponentRegistration, normalizeExperienceTemplateRegistration, } from './types.js';
37
+ /**
38
+ * One `PortableRenderNode[]` input per slot, keyed by slot name. Angular has no
39
+ * lazy renderable-child primitive that supports arbitrary named slots, so slots
40
+ * arrive as raw node arrays and customers render them with `*cfNodes`. That
41
+ * keeps slot children lazy: an unrendered slot never instantiates.
42
+ *
43
+ * Defensive: `node.slots[x]` is typed as an array, but a hand-built
44
+ * PortableRenderPlan (a supported path — customers can construct one
45
+ * directly instead of going through `resolveExperience`) is not
46
+ * type-checked at runtime. Warn + drop rather than throwing, matching
47
+ * React/Svelte — this used to be this adapter's one remaining throw.
48
+ */
49
+ function toSlotInputs(node) {
50
+ const slots = {};
51
+ const diagnostics = [];
52
+ for (const [slotName, children] of Object.entries(node.slots)) {
53
+ if (!Array.isArray(children)) {
54
+ const { kind, id } = node.registration;
55
+ const message = `Slot "${slotName}" on ${kind} "${id}"${node.nodeId ? ` (node "${node.nodeId}")` : ''} ` +
56
+ `is not an array of nodes; rendering it as empty instead of throwing.`;
57
+ // console.warn is fine inside the `resolution` computed this feeds —
58
+ // Angular's signal-purity rule only forbids *signal writes* there.
59
+ // Reporting into `ExperienceScope.diagnostics` (a signal write) happens
60
+ // imperatively in `collect()` instead, once per fresh computation —
61
+ // see the `lastDiagnostics` reference check there.
62
+ if (typeof console !== 'undefined') {
63
+ console.warn(`[@contentful/experiences-angular] ${message}`);
64
+ }
65
+ diagnostics.push(new Error(message));
66
+ slots[slotName] = [];
67
+ continue;
68
+ }
69
+ slots[slotName] = children;
70
+ }
71
+ return { slots, diagnostics };
72
+ }
73
+ /**
74
+ * Note `design` reads from `props.designRaw`, not `props.design`: the raw record
75
+ * keeps every viewport's value, so a customer component doing its own cascade
76
+ * math has the full picture. `injectDesignValues()` is the resolved view.
77
+ */
78
+ function toContentfulComponent(node) {
79
+ return {
80
+ componentId: node.registration.id,
81
+ nodeId: node.nodeId,
82
+ content: node.props.content,
83
+ design: node.props.designRaw,
84
+ resolved: node.props.resolved,
85
+ slots: node.slots,
86
+ };
87
+ }
88
+ function toContentfulExperienceTemplate(node) {
89
+ return {
90
+ experienceTemplateId: node.registration.id,
91
+ nodeId: node.nodeId,
92
+ content: node.props.content,
93
+ design: node.props.designRaw,
94
+ resolved: node.props.resolved,
95
+ };
96
+ }
97
+ /** Viewport-cascaded, token-resolved design values for one node. */
98
+ function resolveDesign(node, experienceScope) {
99
+ const experience = experienceScope.experience();
100
+ const { props, unresolved } = selectResolvedDesign(node.props, experience.viewports, experience.activeViewportIndex, experience.fallbackViewportIndex, experienceScope.config().resolveToken);
101
+ if (unresolved.length && typeof console !== 'undefined') {
102
+ const { kind, id } = node.registration;
103
+ console.warn(`[@contentful/experiences-angular] resolveToken returned undefined for token id(s) on ${kind} "${id}": ${unresolved.join(', ')}. injectDesignValues() will omit those keys.`);
104
+ }
105
+ return props;
106
+ }
107
+ /**
108
+ * Every key the merge could produce, from sources that do not depend on the
109
+ * active viewport. Both `design` (resolved for the fallback viewport) and
110
+ * `designRaw` (every viewport) contribute, because token resolution may omit
111
+ * keys from the former.
112
+ *
113
+ * A key in this set that the merge does not currently produce is bound as
114
+ * `undefined` — a small, deliberate divergence from React and Svelte, where
115
+ * nothing would be passed at all. Setters written as `value ?? fallback` (the
116
+ * shape the README recommends) are unaffected.
117
+ */
118
+ function bindableKeys(node, defaults) {
119
+ const keys = new Set();
120
+ const sources = [
121
+ defaults,
122
+ node.props.design,
123
+ node.props.designRaw,
124
+ node.props.content,
125
+ node.props.resolved,
126
+ node.slots,
127
+ ];
128
+ for (const source of sources) {
129
+ if (source)
130
+ for (const key of Object.keys(source))
131
+ keys.add(key);
132
+ }
133
+ return [...keys];
134
+ }
135
+ /**
136
+ * Narrow a key list to the inputs the target component actually declares.
137
+ * Angular-only, and not optional: binding an undeclared input is an error, so
138
+ * passing the full merged record would fail on every design key the component
139
+ * never asked for.
140
+ *
141
+ * The visible consequence — dropped keys are not passed as inputs — is the
142
+ * documented Angular divergence in the README's parity table. They stay
143
+ * reachable through `injectDesignValues()` and `injectContentfulComponent()`.
144
+ * A pleasant side effect: the adapter cannot leak framework props onto a
145
+ * customer component, because it never declared them.
146
+ */
147
+ function declaredOnly(component, keys) {
148
+ const mirror = reflectComponentType(component);
149
+ if (!mirror)
150
+ return [];
151
+ const declared = new Set(mirror.inputs.map(({ templateName }) => templateName));
152
+ return keys.filter((key) => declared.has(key));
153
+ }
154
+ function resolveNode(node, experienceScope, design) {
155
+ // Read ahead of the registry lookup: the unregistered-template path renders
156
+ // slot children unwrapped, so a malformed slot has to fail identically for
157
+ // registered and unregistered nodes.
158
+ const { slots, diagnostics } = toSlotInputs(node);
159
+ const { kind, id } = node.registration;
160
+ const isExperienceTemplate = kind === 'experienceTemplate';
161
+ const config = experienceScope.config();
162
+ const entry = isExperienceTemplate ? config.experienceTemplates?.[id] : config.components[id];
163
+ if (entry) {
164
+ const normalized = isExperienceTemplate
165
+ ? normalizeExperienceTemplateRegistration(entry)
166
+ : normalizeComponentRegistration(entry);
167
+ // Merge precedence (last wins): defaults < design < content < resolveData < slots.
168
+ const props = {
169
+ ...normalized.defaults,
170
+ ...design,
171
+ ...node.props.content,
172
+ ...node.props.resolved,
173
+ ...slots,
174
+ };
175
+ return {
176
+ mode: 'render',
177
+ component: normalized.component,
178
+ props,
179
+ bindable: declaredOnly(normalized.component, bindableKeys(node, normalized.defaults)),
180
+ diagnostics,
181
+ };
182
+ }
183
+ // An unregistered Experience Template would blank the page if we swapped it
184
+ // for the missing-component box, so warn and render its slot children
185
+ // unwrapped — the content survives, the diagnostic names what's missing.
186
+ if (isExperienceTemplate) {
187
+ const message = `No experience template registered for id "${id}". Rendering its slot children without the experience template wrapper.`;
188
+ if (typeof console !== 'undefined') {
189
+ console.warn(`[@contentful/experiences-angular] ${message}`);
190
+ }
191
+ return {
192
+ mode: 'orphaned',
193
+ nodes: Object.values(slots).flat(),
194
+ diagnostics: [...diagnostics, new Error(message)],
195
+ };
196
+ }
197
+ const renderUnknown = experienceScope.renderUnknown();
198
+ // `MissingComponentComponent` (the default `renderUnknown`) does its own
199
+ // console.warn from `ngOnInit`; a custom override may not, so the
200
+ // diagnostic is recorded here regardless of which fallback ends up
201
+ // rendering.
202
+ return {
203
+ mode: 'render',
204
+ component: renderUnknown,
205
+ props: { componentId: id, nodeId: node.nodeId },
206
+ bindable: declaredOnly(renderUnknown, ['componentId', 'nodeId']),
207
+ diagnostics: [
208
+ ...diagnostics,
209
+ new Error(`No component registered for id "${id}"${node.nodeId ? ` (nodeId: ${node.nodeId})` : ''}.`),
210
+ ],
211
+ };
212
+ }
213
+ /**
214
+ * Creates, reuses, reorders and destroys the views for a list of nodes in one
215
+ * `ViewContainerRef`. Driven by the two structural directives in
216
+ * node-renderer.directive.ts; not exported from the package.
217
+ */
218
+ export class NodeRenderEngine {
219
+ constructor(viewContainerRef, hostInjector, experienceScope) {
220
+ this.viewContainerRef = viewContainerRef;
221
+ this.hostInjector = hostInjector;
222
+ this.experienceScope = experienceScope;
223
+ this.units = new Map();
224
+ this.nodes = [];
225
+ this.lastConfig = null;
226
+ }
227
+ /**
228
+ * Called synchronously from the directive's input setter — the same point
229
+ * `NgComponentOutlet` creates from in `ngOnChanges`. It has to be synchronous
230
+ * rather than deferred to an effect: a single `detectChanges()` (which is all
231
+ * the test harness and `renderApplication` give us) must produce the full
232
+ * tree.
233
+ */
234
+ setNodes(nodes) {
235
+ this.nodes = nodes;
236
+ this.sync();
237
+ }
238
+ /**
239
+ * Re-syncs if the registry changed under us. Which component a node resolves
240
+ * to depends on `config`, and nothing else the engine reads is structural —
241
+ * design values and content flow through the input bindings, which change
242
+ * detection already tracks.
243
+ */
244
+ checkConfig() {
245
+ if (this.experienceScope.config() === this.lastConfig)
246
+ return;
247
+ this.sync();
248
+ }
249
+ destroy() {
250
+ for (const unit of this.units.values())
251
+ this.detach(unit);
252
+ this.units.clear();
253
+ }
254
+ sync() {
255
+ this.lastConfig = this.experienceScope.config();
256
+ const live = [];
257
+ const seen = new Set();
258
+ this.collect(this.nodes, this.hostInjector, '', live, seen);
259
+ for (const [key, unit] of this.units) {
260
+ if (seen.has(key))
261
+ continue;
262
+ this.detach(unit);
263
+ this.units.delete(key);
264
+ }
265
+ // Views are appended as they are created, so a reordered plan needs a
266
+ // normalizing pass. `move` relocates a live view without re-creating it.
267
+ live.forEach((unit, index) => {
268
+ const view = unit.ref.hostView;
269
+ if (this.viewContainerRef.indexOf(view) !== index) {
270
+ this.viewContainerRef.move(view, index);
271
+ }
272
+ });
273
+ }
274
+ /**
275
+ * Walks `nodes` in DOM order, appending every unit that owns a view to
276
+ * `live`. Recurses only through orphaned experience templates: ordinary
277
+ * recursion happens through the customer component, which renders its own
278
+ * slots with its own `*cfNodes`.
279
+ */
280
+ collect(nodes, parentInjector, path, live, seen) {
281
+ nodes.forEach((node, index) => {
282
+ // `nodeId` is the stable identity that lets a reordered plan reuse views.
283
+ // Fall back to position when it is absent or duplicated in one plan.
284
+ const key = node.nodeId && !seen.has(node.nodeId) ? node.nodeId : `${path}#${index}`;
285
+ seen.add(key);
286
+ let unit = this.units.get(key);
287
+ // A node whose kind changed needs the other scope class, and one that
288
+ // moved under a different parent needs a re-parented injector. Neither is
289
+ // patchable — rebuild.
290
+ if (unit &&
291
+ (unit.parentInjector !== parentInjector ||
292
+ unit.node().registration.kind !== node.registration.kind)) {
293
+ this.detach(unit);
294
+ this.units.delete(key);
295
+ unit = undefined;
296
+ }
297
+ if (unit) {
298
+ unit.node.set(node);
299
+ }
300
+ else {
301
+ unit = this.createUnit(node, parentInjector);
302
+ this.units.set(key, unit);
303
+ }
304
+ // `resolveNode`/`resolveDesign` are expected to degrade rather than
305
+ // throw (malformed slots, unresolved tokens — see resolve-experience.ts
306
+ // for the equivalent core-level guarding), but nothing stops a future
307
+ // change there, or a customer-supplied `resolveToken` throwing, from
308
+ // taking that guarantee away. This is a *recomputation* on an existing
309
+ // unit — the same failure mode `createView`'s catch handles for brand
310
+ // new ones, just triggered by a later sync instead of first creation.
311
+ const wasResolutionFailing = unit.resolutionFailed;
312
+ let resolution;
313
+ try {
314
+ resolution = unit.resolution();
315
+ unit.resolutionFailed = false;
316
+ }
317
+ catch (error) {
318
+ if (wasResolutionFailing) {
319
+ // Still the same ongoing failure as last sync (Angular's
320
+ // `computed()` caches and rethrows until a dependency changes
321
+ // again) — the fallback is already mounted; don't tear it down
322
+ // and recreate it every sync.
323
+ live.push(unit);
324
+ return;
325
+ }
326
+ unit.resolutionFailed = true;
327
+ const index = unit.ref ? this.viewContainerRef.indexOf(unit.ref.hostView) : -1;
328
+ if (unit.ref)
329
+ this.detach(unit);
330
+ this.mountErrorFallback(unit, node, error, index >= 0 ? index : this.viewContainerRef.length);
331
+ live.push(unit);
332
+ return;
333
+ }
334
+ if (wasResolutionFailing) {
335
+ // Recovered. `mountErrorFallback` only updates `componentType`, not
336
+ // `attemptedComponentType` — so the gating below, comparing against
337
+ // the customer's (pre-failure) class, would see "same resolution,
338
+ // already attempted" and leave the stale fallback mounted forever.
339
+ // Force it down so the normal creation path below runs clean.
340
+ this.detach(unit);
341
+ unit.attemptedComponentType = null;
342
+ }
343
+ this.reportDiagnostics(unit, resolution);
344
+ if (resolution.mode === 'orphaned') {
345
+ this.detach(unit);
346
+ this.collect(resolution.nodes, unit.injector, `${key}/`, live, seen);
347
+ return;
348
+ }
349
+ // Gate on `attemptedComponentType`, not `componentType`: a customer
350
+ // component that threw is deliberately re-rendered as the error
351
+ // fallback (a different class than `resolution.component`), and that
352
+ // swap must not itself look like "the resolution changed" on the next
353
+ // sync — that would tear the fallback down and retry the same failing
354
+ // `createComponent` call forever. Only a genuine change in what
355
+ // `resolveNode` resolved to (a registry swap, a node whose id changed)
356
+ // should detach and retry.
357
+ if (unit.attemptedComponentType !== resolution.component) {
358
+ this.detach(unit);
359
+ unit.attemptedComponentType = null;
360
+ }
361
+ if (!unit.ref) {
362
+ unit.attemptedComponentType = resolution.component;
363
+ this.createView(unit, node, resolution);
364
+ }
365
+ live.push(unit);
366
+ });
367
+ }
368
+ /**
369
+ * Reports every diagnostic in a fresh `resolution` computation exactly
370
+ * once. `resolution.diagnostics` is a new array only when `resolveNode`
371
+ * actually re-ran (a reference check, not a deep-equality one) —
372
+ * `collect()` reads `unit.resolution()` on every sync, including syncs
373
+ * where nothing about this node changed, and re-reporting on every read
374
+ * would spam `ExperienceScope.diagnostics` with duplicates of the same
375
+ * event.
376
+ */
377
+ reportDiagnostics(unit, resolution) {
378
+ if (resolution.diagnostics === unit.lastDiagnostics)
379
+ return;
380
+ unit.lastDiagnostics = resolution.diagnostics;
381
+ for (const diagnostic of resolution.diagnostics) {
382
+ this.experienceScope.reportDiagnostic(diagnostic);
383
+ }
384
+ }
385
+ /**
386
+ * Creates the view for a `render`-mode resolution. Wrapped in try/catch: a
387
+ * customer component that throws while Angular constructs and first-checks
388
+ * it (constructor, template evaluation, `ngOnInit`) must not take down its
389
+ * siblings.
390
+ *
391
+ * This covers the SSR path with no separate SSR-specific code needed,
392
+ * unlike the React and Svelte adapters: `@angular/platform-server` runs
393
+ * this exact `createComponent` call, not a parallel server renderer, so a
394
+ * synchronous creation-time throw is caught here identically in SSR and
395
+ * CSR.
396
+ *
397
+ * A *later* throw — one that happens after creation succeeded, on a
398
+ * subsequent sync rather than this one — is a different case, covered by
399
+ * `collect()`'s own try/catch around `unit.resolution()`, not here. That
400
+ * split matters: `resolution.bindable`'s `inputBinding` getters (built by
401
+ * `bindings()` below) also call `unit.resolution()`, and it's tempting to
402
+ * wrap *those* instead — but `resolution`'s only tracked dependencies
403
+ * (`unit.node`, `experienceScope.config()`) are exclusively mutated from
404
+ * inside `collect()` (`unit.node.set(...)`, and `checkConfig()`'s call into
405
+ * `sync()`/`collect()`), so any throw from a genuine dependency change
406
+ * always reaches `collect()`'s own read first — by the time Angular's CD
407
+ * independently re-invokes a binding getter for that unit, the computed's
408
+ * error is already cached and `collect()` has already handled it. A
409
+ * `bindings()`-level catch would be unreachable dead code.
410
+ *
411
+ * What no fix here reaches: a throw inside the *customer* component's own
412
+ * internals on a later change-detection pass (its own template expression,
413
+ * computed, or lifecycle hook unrelated to our bindings) — that never
414
+ * touches adapter code at all. A per-node `ErrorHandler` provider in
415
+ * `unit.injector` doesn't help here either: `ApplicationRef.tick()`
416
+ * resolves `ErrorHandler` once, from the *root* injector, at construction,
417
+ * and never re-resolves it from whichever component's injector actually
418
+ * threw — a per-node override in a child injector is structurally
419
+ * unreachable from that catch. Documented gap; see the README's
420
+ * error-handling section.
421
+ */
422
+ createView(unit, node, resolution) {
423
+ try {
424
+ unit.componentType = resolution.component;
425
+ unit.ref = this.viewContainerRef.createComponent(resolution.component, {
426
+ index: this.viewContainerRef.length,
427
+ injector: unit.injector,
428
+ bindings: this.bindings(unit, resolution.bindable),
429
+ });
430
+ }
431
+ catch (error) {
432
+ this.mountErrorFallback(unit, node, error, this.viewContainerRef.length);
433
+ }
434
+ }
435
+ /**
436
+ * Shared by `createView`'s creation-time catch and
437
+ * `reportPostCreationFailure`'s later-pass catch: reports the diagnostic
438
+ * and mounts the customer's `renderError` override (or the built-in
439
+ * default) at `index`. The caller picks `index` — appending at the current
440
+ * end for a brand-new unit, or the unit's own prior position when
441
+ * replacing an already-mounted view — since this method has no way to
442
+ * know which situation it's in.
443
+ */
444
+ mountErrorFallback(unit, node, error, index) {
445
+ const { kind, id } = node.registration;
446
+ const reason = error instanceof Error ? error.message : String(error);
447
+ const message = `Component "${id}" (${kind}${node.nodeId ? `, node "${node.nodeId}"` : ''}) threw ` +
448
+ `while rendering: ${reason}. Rendering the error fallback instead of crashing the ` +
449
+ `surrounding tree.`;
450
+ if (typeof console !== 'undefined') {
451
+ console.warn(`[@contentful/experiences-angular] ${message}`);
452
+ }
453
+ this.experienceScope.reportDiagnostic(new Error(message, { cause: error instanceof Error ? error : undefined }));
454
+ const renderError = this.experienceScope.renderError();
455
+ const errorProps = {
456
+ componentId: id,
457
+ nodeId: node.nodeId,
458
+ message: reason,
459
+ };
460
+ unit.componentType = renderError;
461
+ unit.ref = this.viewContainerRef.createComponent(renderError, {
462
+ index,
463
+ injector: unit.injector,
464
+ bindings: declaredOnly(renderError, ['componentId', 'nodeId', 'message']).map((key) => inputBinding(key, () => errorProps[key])),
465
+ });
466
+ }
467
+ createUnit(node, parentInjector) {
468
+ const nodeSignal = signal(node, ...(ngDevMode ? [{ debugName: "nodeSignal" }] : []));
469
+ const design = computed(() => resolveDesign(nodeSignal(), this.experienceScope), ...(ngDevMode ? [{ debugName: "design" }] : []));
470
+ const resolution = computed(() => resolveNode(nodeSignal(), this.experienceScope, design()), ...(ngDevMode ? [{ debugName: "resolution" }] : []));
471
+ // Constructed and connected before `createComponent` runs, so an
472
+ // unregistered node already exposes its payload to whatever renders in its
473
+ // place. The scopes hold *getters*, so later `nodeSignal.set` calls flow
474
+ // through without reconnecting.
475
+ const designScope = new DesignScope();
476
+ designScope.connect(() => design());
477
+ const providers = [{ provide: DesignScope, useValue: designScope }];
478
+ // Never both: a component nested inside an experience template shadows
479
+ // `ComponentScope` and `DesignScope` while leaving `ExperienceTemplateScope`
480
+ // unshadowed, so the element-injector walk-up still reaches the enclosing
481
+ // template's payload.
482
+ if (node.registration.kind === 'experienceTemplate') {
483
+ const templateScope = new ExperienceTemplateScope();
484
+ templateScope.connect(() => toContentfulExperienceTemplate(nodeSignal()));
485
+ providers.push({ provide: ExperienceTemplateScope, useValue: templateScope });
486
+ }
487
+ else {
488
+ const componentScope = new ComponentScope();
489
+ componentScope.connect(() => toContentfulComponent(nodeSignal()));
490
+ providers.push({ provide: ComponentScope, useValue: componentScope });
491
+ }
492
+ return {
493
+ node: nodeSignal,
494
+ resolution,
495
+ injector: Injector.create({ providers, parent: parentInjector }),
496
+ parentInjector,
497
+ ref: null,
498
+ componentType: null,
499
+ attemptedComponentType: null,
500
+ lastDiagnostics: null,
501
+ resolutionFailed: false,
502
+ };
503
+ }
504
+ /**
505
+ * Change-detection-integrated, unlike a one-shot `setInput` record: each
506
+ * binding re-reads the merged props when the node, the active viewport or a
507
+ * design token changes, and marks the (likely `OnPush`) customer component
508
+ * dirty only when its own value did.
509
+ */
510
+ bindings(unit, keys) {
511
+ return keys.map((key) => inputBinding(key, () => {
512
+ const resolution = unit.resolution();
513
+ return resolution.mode === 'render' ? resolution.props[key] : undefined;
514
+ }));
515
+ }
516
+ detach(unit) {
517
+ if (!unit.ref)
518
+ return;
519
+ const index = this.viewContainerRef.indexOf(unit.ref.hostView);
520
+ if (index >= 0)
521
+ this.viewContainerRef.remove(index);
522
+ else
523
+ unit.ref.destroy();
524
+ unit.ref = null;
525
+ unit.componentType = null;
526
+ }
527
+ }
528
+ //# sourceMappingURL=node-render-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-render-engine.js","sourceRoot":"","sources":["../src/node-render-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAGL,QAAQ,EAMR,QAAQ,EACR,YAAY,EACZ,oBAAoB,EACpB,MAAM,GACP,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAItE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AACxF,OAAO,EAIL,8BAA8B,EAC9B,uCAAuC,GACxC,MAAM,YAAY,CAAC;AA4BpB;;;;;;;;;;;GAWG;AACH,SAAS,YAAY,CAAC,IAAwB;IAI5C,MAAM,KAAK,GAAyC,EAAE,CAAC;IACvD,MAAM,WAAW,GAAY,EAAE,CAAC;IAChC,KAAK,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;YACvC,MAAM,OAAO,GACX,SAAS,QAAQ,QAAQ,IAAI,KAAK,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG;gBACxF,sEAAsE,CAAC;YACzE,qEAAqE;YACrE,mEAAmE;YACnE,wEAAwE;YACxE,oEAAoE;YACpE,mDAAmD;YACnD,IAAI,OAAO,OAAO,KAAK,WAAW,EAAE,CAAC;gBACnC,OAAO,CAAC,IAAI,CAAC,qCAAqC,OAAO,EAAE,CAAC,CAAC;YAC/D,CAAC;YACD,WAAW,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YACrC,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC;YACrB,SAAS;QACX,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;IAC7B,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,SAAS,qBAAqB,CAAC,IAAwB;IACrD,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,EAAE;QACjC,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;QAC3B,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS;QAC5B,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ;QAC7B,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAC;AACJ,CAAC;AAED,SAAS,8BAA8B,CAAC,IAAwB;IAC9D,OAAO;QACL,oBAAoB,EAAE,IAAI,CAAC,YAAY,CAAC,EAAE;QAC1C,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;QAC3B,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS;QAC5B,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ;KAC9B,CAAC;AACJ,CAAC;AAED,oEAAoE;AACpE,SAAS,aAAa,CACpB,IAAwB,EACxB,eAAgC;IAEhC,MAAM,UAAU,GAAG,eAAe,CAAC,UAAU,EAAE,CAAC;IAChD,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,oBAAoB,CAChD,IAAI,CAAC,KAAK,EACV,UAAU,CAAC,SAAS,EACpB,UAAU,CAAC,mBAAmB,EAC9B,UAAU,CAAC,qBAAqB,EAChC,eAAe,CAAC,MAAM,EAAE,CAAC,YAAY,CACtC,CAAC;IACF,IAAI,UAAU,CAAC,MAAM,IAAI,OAAO,OAAO,KAAK,WAAW,EAAE,CAAC;QACxD,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;QACvC,OAAO,CAAC,IAAI,CACV,wFAAwF,IAAI,KAAK,EAAE,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,8CAA8C,CAC7K,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,YAAY,CAAC,IAAwB,EAAE,QAA4B;IAC1E,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAA8B;QACzC,QAAQ;QACR,IAAI,CAAC,KAAK,CAAC,MAAM;QACjB,IAAI,CAAC,KAAK,CAAC,SAAS;QACpB,IAAI,CAAC,KAAK,CAAC,OAAO;QAClB,IAAI,CAAC,KAAK,CAAC,QAAQ;QACnB,IAAI,CAAC,KAAK;KACX,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM;YAAE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;gBAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,YAAY,CAAC,SAAwB,EAAE,IAAuB;IACrE,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAC/C,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IACvB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;IAChF,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,WAAW,CAClB,IAAwB,EACxB,eAAgC,EAChC,MAA+B;IAE/B,4EAA4E;IAC5E,2EAA2E;IAC3E,qCAAqC;IACrC,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAElD,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;IACvC,MAAM,oBAAoB,GAAG,IAAI,KAAK,oBAAoB,CAAC;IAC3D,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,oBAAoB,CAAC,CAAC,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAE9F,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,UAAU,GAAG,oBAAoB;YACrC,CAAC,CAAC,uCAAuC,CAAC,KAAK,CAAC;YAChD,CAAC,CAAC,8BAA8B,CAAC,KAAK,CAAC,CAAC;QAC1C,mFAAmF;QACnF,MAAM,KAAK,GAAG;YACZ,GAAG,UAAU,CAAC,QAAQ;YACtB,GAAG,MAAM;YACT,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO;YACrB,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ;YACtB,GAAG,KAAK;SACT,CAAC;QACF,OAAO;YACL,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,UAAU,CAAC,SAAS;YAC/B,KAAK;YACL,QAAQ,EAAE,YAAY,CAAC,UAAU,CAAC,SAAS,EAAE,YAAY,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;YACrF,WAAW;SACZ,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,sEAAsE;IACtE,yEAAyE;IACzE,IAAI,oBAAoB,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,6CAA6C,EAAE,yEAAyE,CAAC;QACzI,IAAI,OAAO,OAAO,KAAK,WAAW,EAAE,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,qCAAqC,OAAO,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO;YACL,IAAI,EAAE,UAAU;YAChB,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE;YAClC,WAAW,EAAE,CAAC,GAAG,WAAW,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;SAClD,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG,eAAe,CAAC,aAAa,EAAE,CAAC;IACtD,yEAAyE;IACzE,kEAAkE;IAClE,mEAAmE;IACnE,aAAa;IACb,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,SAAS,EAAE,aAAa;QACxB,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;QAC/C,QAAQ,EAAE,YAAY,CAAC,aAAa,EAAE,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QAChE,WAAW,EAAE;YACX,GAAG,WAAW;YACd,IAAI,KAAK,CACP,mCAAmC,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAC3F;SACF;KACF,CAAC;AACJ,CAAC;AA0CD;;;;GAIG;AACH,MAAM,OAAO,gBAAgB;IAK3B,YACmB,gBAAkC,EAClC,YAAsB,EACtB,eAAgC;QAFhC,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,iBAAY,GAAZ,YAAY,CAAU;QACtB,oBAAe,GAAf,eAAe,CAAiB;QAPlC,UAAK,GAAG,IAAI,GAAG,EAAgB,CAAC;QACzC,UAAK,GAAkC,EAAE,CAAC;QAC1C,eAAU,GAAkB,IAAI,CAAC;IAMtC,CAAC;IAEJ;;;;;;OAMG;IACH,QAAQ,CAAC,KAAoC;QAC3C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,WAAW;QACT,IAAI,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,UAAU;YAAE,OAAO;QAC9D,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAED,OAAO;QACL,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1D,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAEO,IAAI;QACV,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC;QAEhD,MAAM,IAAI,GAAW,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAE5D,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACrC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,SAAS;YAC5B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAClB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QAED,sEAAsE;QACtE,yEAAyE;QACzE,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAI,CAAC,QAAQ,CAAC;YAChC,IAAI,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC;gBAClD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACK,OAAO,CACb,KAAoC,EACpC,cAAwB,EACxB,IAAY,EACZ,IAAY,EACZ,IAAiB;QAEjB,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YAC5B,0EAA0E;YAC1E,qEAAqE;YACrE,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC;YACrF,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAEd,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC/B,sEAAsE;YACtE,0EAA0E;YAC1E,uBAAuB;YACvB,IACE,IAAI;gBACJ,CAAC,IAAI,CAAC,cAAc,KAAK,cAAc;oBACrC,IAAI,CAAC,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,KAAK,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAC3D,CAAC;gBACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAClB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACvB,IAAI,GAAG,SAAS,CAAC;YACnB,CAAC;YAED,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC;iBAAM,CAAC;gBACN,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;gBAC7C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC5B,CAAC;YAED,oEAAoE;YACpE,wEAAwE;YACxE,sEAAsE;YACtE,qEAAqE;YACrE,uEAAuE;YACvE,sEAAsE;YACtE,sEAAsE;YACtE,MAAM,oBAAoB,GAAG,IAAI,CAAC,gBAAgB,CAAC;YACnD,IAAI,UAAsB,CAAC;YAC3B,IAAI,CAAC;gBACH,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;gBAC/B,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;YAChC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,oBAAoB,EAAE,CAAC;oBACzB,yDAAyD;oBACzD,8DAA8D;oBAC9D,+DAA+D;oBAC/D,8BAA8B;oBAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAChB,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;gBAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC/E,IAAI,IAAI,CAAC,GAAG;oBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAChC,IAAI,CAAC,kBAAkB,CACrB,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAClD,CAAC;gBACF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAChB,OAAO;YACT,CAAC;YAED,IAAI,oBAAoB,EAAE,CAAC;gBACzB,oEAAoE;gBACpE,oEAAoE;gBACpE,kEAAkE;gBAClE,mEAAmE;gBACnE,8DAA8D;gBAC9D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAClB,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC;YACrC,CAAC;YAED,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YAEzC,IAAI,UAAU,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBACnC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAClB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;gBACrE,OAAO;YACT,CAAC;YAED,oEAAoE;YACpE,gEAAgE;YAChE,qEAAqE;YACrE,sEAAsE;YACtE,sEAAsE;YACtE,gEAAgE;YAChE,uEAAuE;YACvE,2BAA2B;YAC3B,IAAI,IAAI,CAAC,sBAAsB,KAAK,UAAU,CAAC,SAAS,EAAE,CAAC;gBACzD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAClB,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC;YACrC,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACd,IAAI,CAAC,sBAAsB,GAAG,UAAU,CAAC,SAAS,CAAC;gBACnD,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;YAC1C,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;OAQG;IACK,iBAAiB,CAAC,IAAU,EAAE,UAAsB;QAC1D,IAAI,UAAU,CAAC,WAAW,KAAK,IAAI,CAAC,eAAe;YAAE,OAAO;QAC5D,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC,WAAW,CAAC;QAC9C,KAAK,MAAM,UAAU,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;YAChD,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoCG;IACK,UAAU,CAChB,IAAU,EACV,IAAwB,EACxB,UAAmD;QAEnD,IAAI,CAAC;YACH,IAAI,CAAC,aAAa,GAAG,UAAU,CAAC,SAAS,CAAC;YAC1C,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,gBAAgB,CAAC,eAAe,CAAC,UAAU,CAAC,SAAS,EAAE;gBACrE,KAAK,EAAE,IAAI,CAAC,gBAAgB,CAAC,MAAM;gBACnC,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC;aACnD,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACK,kBAAkB,CACxB,IAAU,EACV,IAAwB,EACxB,KAAc,EACd,KAAa;QAEb,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;QACvC,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtE,MAAM,OAAO,GACX,cAAc,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,UAAU;YACnF,oBAAoB,MAAM,yDAAyD;YACnF,mBAAmB,CAAC;QACtB,IAAI,OAAO,OAAO,KAAK,WAAW,EAAE,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,qCAAqC,OAAO,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,CAAC,eAAe,CAAC,gBAAgB,CACnC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAC1E,CAAC;QAEF,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,CAAC;QACvD,MAAM,UAAU,GAA4B;YAC1C,WAAW,EAAE,EAAE;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,MAAM;SAChB,CAAC;QACF,IAAI,CAAC,aAAa,GAAG,WAAW,CAAC;QACjC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,gBAAgB,CAAC,eAAe,CAAC,WAAW,EAAE;YAC5D,KAAK;YACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,YAAY,CAAC,WAAW,EAAE,CAAC,aAAa,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CACpF,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CACzC;SACF,CAAC,CAAC;IACL,CAAC;IAEO,UAAU,CAAC,IAAwB,EAAE,cAAwB;QACnE,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,sDAAC,CAAC;QAChC,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,eAAe,CAAC,kDAAC,CAAC;QACjF,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC,sDAAC,CAAC;QAE7F,iEAAiE;QACjE,2EAA2E;QAC3E,yEAAyE;QACzE,gCAAgC;QAChC,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;QACtC,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;QACpC,MAAM,SAAS,GAAqB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;QAEtF,uEAAuE;QACvE,6EAA6E;QAC7E,0EAA0E;QAC1E,sBAAsB;QACtB,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,KAAK,oBAAoB,EAAE,CAAC;YACpD,MAAM,aAAa,GAAG,IAAI,uBAAuB,EAAE,CAAC;YACpD,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,8BAA8B,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAC1E,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,uBAAuB,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC,CAAC;QAChF,CAAC;aAAM,CAAC;YACN,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC;YAC5C,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAClE,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC;QACxE,CAAC;QAED,OAAO;YACL,IAAI,EAAE,UAAU;YAChB,UAAU;YACV,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;YAChE,cAAc;YACd,GAAG,EAAE,IAAI;YACT,aAAa,EAAE,IAAI;YACnB,sBAAsB,EAAE,IAAI;YAC5B,eAAe,EAAE,IAAI;YACrB,gBAAgB,EAAE,KAAK;SACxB,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACK,QAAQ,CAAC,IAAU,EAAE,IAAuB;QAClD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CACtB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE;YACrB,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YACrC,OAAO,UAAU,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1E,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,IAAU;QACvB,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE,OAAO;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC/D,IAAI,KAAK,IAAI,CAAC;YAAE,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;;YAC/C,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;QAChB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;IAC5B,CAAC;CACF"}
@@ -0,0 +1,46 @@
1
+ import { type DoCheck, type OnDestroy } from '@angular/core';
2
+ import type { PortableRenderNode } from '@contentful/experiences-sdk-core';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Renders a slot's nodes as direct children of the surrounding element.
6
+ *
7
+ * ```html
8
+ * <div class="grid"><ng-container *cfNodes="children()"></ng-container></div>
9
+ * ```
10
+ *
11
+ * Load-bearing in this adapter rather than an escape hatch: Angular has no lazy
12
+ * renderable-child primitive for arbitrary named slots, so each slot arrives as
13
+ * a same-named `PortableRenderNode[]` input and this is how it gets rendered.
14
+ */
15
+ export declare class NodesRendererDirective implements DoCheck, OnDestroy {
16
+ private readonly engine;
17
+ /**
18
+ * Not `required`, so a component can forward an optional slot input straight
19
+ * through — `*cfNodes="children()"` where `children` may be undefined —
20
+ * without a non-null assertion at every call site.
21
+ */
22
+ set cfNodes(value: PortableRenderNode[] | null | undefined);
23
+ ngDoCheck(): void;
24
+ ngOnDestroy(): void;
25
+ static ɵfac: i0.ɵɵFactoryDeclaration<NodesRendererDirective, never>;
26
+ static ɵdir: i0.ɵɵDirectiveDeclaration<NodesRendererDirective, "[cfNodes]", never, { "cfNodes": { "alias": "cfNodes"; "required": false; }; }, {}, never, never, true, never>;
27
+ }
28
+ /**
29
+ * Renders a single node. Use it to wrap, reorder or drop slot children
30
+ * individually:
31
+ *
32
+ * ```html
33
+ * @for (child of children() ?? []; track $index) {
34
+ * <div class="cell"><ng-container *cfNode="child"></ng-container></div>
35
+ * }
36
+ * ```
37
+ */
38
+ export declare class NodeRendererDirective implements DoCheck, OnDestroy {
39
+ private readonly engine;
40
+ set cfNode(value: PortableRenderNode);
41
+ ngDoCheck(): void;
42
+ ngOnDestroy(): void;
43
+ static ɵfac: i0.ɵɵFactoryDeclaration<NodeRendererDirective, never>;
44
+ static ɵdir: i0.ɵɵDirectiveDeclaration<NodeRendererDirective, "[cfNode]", never, { "cfNode": { "alias": "cfNode"; "required": true; }; }, {}, never, never, true, never>;
45
+ }
46
+ //# sourceMappingURL=node-renderer.directive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-renderer.directive.d.ts","sourceRoot":"","sources":["../src/node-renderer.directive.ts"],"names":[],"mappings":"AAkBA,OAAO,EAEL,KAAK,OAAO,EAGZ,KAAK,SAAS,EAGf,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;;AAK3E;;;;;;;;;;GAUG;AACH,qBACa,sBAAuB,YAAW,OAAO,EAAE,SAAS;IAI/D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAIrB;IAEF;;;;OAIG;IACH,IAAa,OAAO,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,IAAI,GAAG,SAAS,EAElE;IAED,SAAS,IAAI,IAAI;IAIjB,WAAW,IAAI,IAAI;yCAvBR,sBAAsB;2CAAtB,sBAAsB;CA0BlC;AAED;;;;;;;;;GASG;AACH,qBACa,qBAAsB,YAAW,OAAO,EAAE,SAAS;IAC9D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAIrB;IAEF,IAA+B,MAAM,CAAC,KAAK,EAAE,kBAAkB,EAE9D;IAED,SAAS,IAAI,IAAI;IAIjB,WAAW,IAAI,IAAI;yCAfR,qBAAqB;2CAArB,qBAAqB;CAkBjC"}