@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.
- package/CHANGELOG.md +189 -0
- package/README.md +368 -0
- package/dist/client-experience-renderer.component.d.ts +42 -0
- package/dist/client-experience-renderer.component.d.ts.map +1 -0
- package/dist/client-experience-renderer.component.js +155 -0
- package/dist/client-experience-renderer.component.js.map +1 -0
- package/dist/component-error.component.d.ts +14 -0
- package/dist/component-error.component.d.ts.map +1 -0
- package/dist/component-error.component.js +81 -0
- package/dist/component-error.component.js.map +1 -0
- package/dist/context.d.ts +21 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +54 -0
- package/dist/context.js.map +1 -0
- package/dist/debug-experience.component.d.ts +17 -0
- package/dist/debug-experience.component.d.ts.map +1 -0
- package/dist/debug-experience.component.js +143 -0
- package/dist/debug-experience.component.js.map +1 -0
- package/dist/design-utils.d.ts +22 -0
- package/dist/design-utils.d.ts.map +1 -0
- package/dist/design-utils.js +40 -0
- package/dist/design-utils.js.map +1 -0
- package/dist/experience-defaults.d.ts +16 -0
- package/dist/experience-defaults.d.ts.map +1 -0
- package/dist/experience-defaults.js +27 -0
- package/dist/experience-defaults.js.map +1 -0
- package/dist/experience-scope.d.ts +33 -0
- package/dist/experience-scope.d.ts.map +1 -0
- package/dist/experience-scope.js +90 -0
- package/dist/experience-scope.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/inject-active-viewport.d.ts +32 -0
- package/dist/inject-active-viewport.d.ts.map +1 -0
- package/dist/inject-active-viewport.js +78 -0
- package/dist/inject-active-viewport.js.map +1 -0
- package/dist/inject-design-values.d.ts +14 -0
- package/dist/inject-design-values.d.ts.map +1 -0
- package/dist/inject-design-values.js +24 -0
- package/dist/inject-design-values.js.map +1 -0
- package/dist/inject-experience-plan.d.ts +15 -0
- package/dist/inject-experience-plan.d.ts.map +1 -0
- package/dist/inject-experience-plan.js +39 -0
- package/dist/inject-experience-plan.js.map +1 -0
- package/dist/inject-live-preview-experience.d.ts +13 -0
- package/dist/inject-live-preview-experience.d.ts.map +1 -0
- package/dist/inject-live-preview-experience.js +47 -0
- package/dist/inject-live-preview-experience.js.map +1 -0
- package/dist/inject-live-preview.d.ts +16 -0
- package/dist/inject-live-preview.d.ts.map +1 -0
- package/dist/inject-live-preview.js +14 -0
- package/dist/inject-live-preview.js.map +1 -0
- package/dist/missing-component.component.d.ts +14 -0
- package/dist/missing-component.component.d.ts.map +1 -0
- package/dist/missing-component.component.js +83 -0
- package/dist/missing-component.component.js.map +1 -0
- package/dist/node-render-engine.d.ts +109 -0
- package/dist/node-render-engine.d.ts.map +1 -0
- package/dist/node-render-engine.js +528 -0
- package/dist/node-render-engine.js.map +1 -0
- package/dist/node-renderer.directive.d.ts +46 -0
- package/dist/node-renderer.directive.d.ts.map +1 -0
- package/dist/node-renderer.directive.js +96 -0
- package/dist/node-renderer.directive.js.map +1 -0
- package/dist/node-scopes.d.ts +39 -0
- package/dist/node-scopes.d.ts.map +1 -0
- package/dist/node-scopes.js +75 -0
- package/dist/node-scopes.js.map +1 -0
- package/dist/server-experience-renderer.component.d.ts +46 -0
- package/dist/server-experience-renderer.component.d.ts.map +1 -0
- package/dist/server-experience-renderer.component.js +159 -0
- package/dist/server-experience-renderer.component.js.map +1 -0
- package/dist/types.d.ts +137 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +44 -0
- package/dist/types.js.map +1 -0
- 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":"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"}
|
|
@@ -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"}
|