@contentful/experiences-svelte 0.5.5 → 0.5.7
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 +24 -0
- package/README.md +8 -6
- package/dist/ClientExperienceRenderer.svelte +6 -11
- package/dist/ClientExperienceRenderer.svelte.d.ts.map +1 -1
- package/dist/DebugExperience.svelte +9 -2
- package/dist/DebugExperience.svelte.d.ts.map +1 -1
- package/dist/DebugExperience.test.js +22 -9
- package/dist/NodeRenderer.svelte +73 -19
- package/dist/NodeRenderer.svelte.d.ts +6 -1
- package/dist/NodeRenderer.svelte.d.ts.map +1 -1
- package/dist/NodesRenderer.svelte +40 -17
- package/dist/NodesRenderer.svelte.d.ts.map +1 -1
- package/dist/ServerExperienceRenderer.svelte +6 -11
- package/dist/ServerExperienceRenderer.svelte.d.ts.map +1 -1
- package/dist/design-utils.d.ts +0 -8
- package/dist/design-utils.d.ts.map +1 -1
- package/dist/design-utils.js +1 -10
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/nodes-renderer.ssr.test.d.ts +2 -0
- package/dist/nodes-renderer.ssr.test.d.ts.map +1 -0
- package/dist/nodes-renderer.ssr.test.js +126 -0
- package/dist/server-renderer.test.js +100 -44
- package/dist/test-fixtures/ExperienceTemplateFixture.svelte +8 -3
- package/dist/test-fixtures/ExperienceTemplateFixture.svelte.d.ts +1 -1
- package/dist/test-fixtures/ExperienceTemplateFixture.svelte.d.ts.map +1 -1
- package/dist/types.d.ts +28 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/use-active-viewport.svelte.d.ts.map +1 -1
- package/dist/use-active-viewport.svelte.js +1 -22
- package/package.json +5 -5
- package/dist/WrapWithExperienceTemplate.svelte +0 -90
- package/dist/WrapWithExperienceTemplate.svelte.d.ts +0 -13
- package/dist/WrapWithExperienceTemplate.svelte.d.ts.map +0 -1
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* True SSR coverage: renders through `svelte/server` so Svelte's *server*
|
|
3
|
+
* compiler output is exercised. Every other test in this package renders via
|
|
4
|
+
* `@testing-library/svelte`, i.e. the client build.
|
|
5
|
+
*
|
|
6
|
+
* The two builds differ in how a compiled snippet receives its arguments — by
|
|
7
|
+
* getter on the client, by value on the server — and `NodesRenderer` builds one
|
|
8
|
+
* snippet call by hand (`toChildSnippet`). These tests pin that nested nodes
|
|
9
|
+
* render under SSR for both node kinds; without the normalization in
|
|
10
|
+
* `NodesRenderer`, every child node throws.
|
|
11
|
+
*
|
|
12
|
+
* Runs under vitest.ssr.config.ts (environment: node).
|
|
13
|
+
*/
|
|
14
|
+
import { describe, expect, it } from 'vitest';
|
|
15
|
+
import { render } from 'svelte/server';
|
|
16
|
+
import { resolveExperience } from '@contentful/experiences-sdk-core';
|
|
17
|
+
import ServerExperienceRenderer from './ServerExperienceRenderer.svelte';
|
|
18
|
+
import ButtonFixture from './test-fixtures/ButtonFixture.svelte';
|
|
19
|
+
import ContainerFixture from './test-fixtures/ContainerFixture.svelte';
|
|
20
|
+
import ExperienceTemplateFixture from './test-fixtures/ExperienceTemplateFixture.svelte';
|
|
21
|
+
const VIEWPORTS = [{ id: 'desktop', query: '*', displayName: 'Desktop', previewSize: '100%' }];
|
|
22
|
+
const componentNode = (typeId, rest = {}) => ({
|
|
23
|
+
component: {
|
|
24
|
+
sys: {
|
|
25
|
+
type: 'ResourceLink',
|
|
26
|
+
linkType: 'Contentful:Component',
|
|
27
|
+
urn: `crn:contentful:::experience:spaces/$self/environments/$self/components/${typeId}`,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
...rest,
|
|
31
|
+
});
|
|
32
|
+
const experienceTemplateNode = (typeId, rest = {}) => ({
|
|
33
|
+
experienceTemplate: {
|
|
34
|
+
sys: {
|
|
35
|
+
type: 'ResourceLink',
|
|
36
|
+
linkType: 'Contentful:ExperienceTemplate',
|
|
37
|
+
urn: `crn:contentful:::experience:spaces/$self/environments/$self/experienceTemplates/${typeId}`,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
...rest,
|
|
41
|
+
});
|
|
42
|
+
const button = (label) => componentNode('contentful-button', {
|
|
43
|
+
id: `btn-${label}`,
|
|
44
|
+
contentProperties: { label },
|
|
45
|
+
designProperties: {},
|
|
46
|
+
slots: {},
|
|
47
|
+
});
|
|
48
|
+
const config = {
|
|
49
|
+
components: {
|
|
50
|
+
'contentful-container': ContainerFixture,
|
|
51
|
+
'contentful-button': ButtonFixture,
|
|
52
|
+
},
|
|
53
|
+
experienceTemplates: { page: ExperienceTemplateFixture },
|
|
54
|
+
};
|
|
55
|
+
const renderPlan = async (payload) => {
|
|
56
|
+
const plan = await resolveExperience(payload, config);
|
|
57
|
+
return render(ServerExperienceRenderer, {
|
|
58
|
+
props: { experience: plan, config },
|
|
59
|
+
}).body;
|
|
60
|
+
};
|
|
61
|
+
describe('NodesRenderer — SSR (server-compiled output)', () => {
|
|
62
|
+
it('renders a component node’s slot children', async () => {
|
|
63
|
+
const html = await renderPlan({
|
|
64
|
+
viewports: VIEWPORTS,
|
|
65
|
+
nodes: [
|
|
66
|
+
componentNode('contentful-container', {
|
|
67
|
+
id: 'container',
|
|
68
|
+
contentProperties: {},
|
|
69
|
+
designProperties: {},
|
|
70
|
+
slots: { children: [button('Get started')] },
|
|
71
|
+
}),
|
|
72
|
+
],
|
|
73
|
+
});
|
|
74
|
+
expect(html).toContain('Get started');
|
|
75
|
+
expect(html.indexOf('<div')).toBeLessThan(html.indexOf('Get started'));
|
|
76
|
+
});
|
|
77
|
+
it('renders a coded Experience Template node’s named `content` slot', async () => {
|
|
78
|
+
const html = await renderPlan({
|
|
79
|
+
viewports: VIEWPORTS,
|
|
80
|
+
nodes: [
|
|
81
|
+
experienceTemplateNode('page', {
|
|
82
|
+
id: 'tpl',
|
|
83
|
+
contentProperties: { title: 'Coded page' },
|
|
84
|
+
designProperties: {},
|
|
85
|
+
slots: { content: [button('Read the blog')] },
|
|
86
|
+
}),
|
|
87
|
+
],
|
|
88
|
+
});
|
|
89
|
+
expect(html).toContain('data-experience-template="page"');
|
|
90
|
+
expect(html).toContain('data-title="Coded page"');
|
|
91
|
+
expect(html).toContain('Read the blog');
|
|
92
|
+
// The button is inside the template chrome, not a sibling of it.
|
|
93
|
+
expect(html.split('<main')[1]).toContain('Read the blog');
|
|
94
|
+
});
|
|
95
|
+
it('renders deeply nested slot children', async () => {
|
|
96
|
+
const html = await renderPlan({
|
|
97
|
+
viewports: VIEWPORTS,
|
|
98
|
+
nodes: [
|
|
99
|
+
experienceTemplateNode('page', {
|
|
100
|
+
id: 'tpl',
|
|
101
|
+
contentProperties: {},
|
|
102
|
+
designProperties: {},
|
|
103
|
+
slots: {
|
|
104
|
+
content: [
|
|
105
|
+
componentNode('contentful-container', {
|
|
106
|
+
id: 'container',
|
|
107
|
+
contentProperties: {},
|
|
108
|
+
designProperties: {},
|
|
109
|
+
slots: { children: [button('Deep')] },
|
|
110
|
+
}),
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
}),
|
|
114
|
+
],
|
|
115
|
+
});
|
|
116
|
+
expect(html).toContain('Deep');
|
|
117
|
+
});
|
|
118
|
+
it('renders a composite experience unwrapped', async () => {
|
|
119
|
+
const html = await renderPlan({
|
|
120
|
+
viewports: VIEWPORTS,
|
|
121
|
+
nodes: [button('Alone')],
|
|
122
|
+
});
|
|
123
|
+
expect(html).toContain('Alone');
|
|
124
|
+
expect(html).not.toContain('<main');
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -35,6 +35,38 @@ function componentNode(typeId, rest = {}) {
|
|
|
35
35
|
...rest,
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* A coded Experience Template is an ordinary top-level node — the only
|
|
40
|
+
* difference from `componentNode` is which registry its id resolves against.
|
|
41
|
+
*/
|
|
42
|
+
function experienceTemplateNode(typeId, rest = {}) {
|
|
43
|
+
return {
|
|
44
|
+
experienceTemplate: {
|
|
45
|
+
sys: {
|
|
46
|
+
type: 'ResourceLink',
|
|
47
|
+
linkType: 'Contentful:ExperienceTemplate',
|
|
48
|
+
urn: `crn:contentful:::experience:spaces/$self/environments/$self/experienceTemplates/${typeId}`,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
...rest,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* `sys.experienceTemplate` rides along on every Experience — coded and
|
|
56
|
+
* composite alike — so it must never influence rendering. Tests attach it to
|
|
57
|
+
* prove it is ignored.
|
|
58
|
+
*/
|
|
59
|
+
function sysWithExperienceTemplate(typeId) {
|
|
60
|
+
return {
|
|
61
|
+
experienceTemplate: {
|
|
62
|
+
sys: {
|
|
63
|
+
type: 'ResourceLink',
|
|
64
|
+
linkType: 'Contentful:ExperienceTemplate',
|
|
65
|
+
urn: `crn:contentful:::experience:spaces/$self/environments/$self/experienceTemplates/${typeId}`,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
38
70
|
beforeEach(() => {
|
|
39
71
|
captureSink.splice(0);
|
|
40
72
|
});
|
|
@@ -158,13 +190,13 @@ describe('ServerExperienceRenderer', () => {
|
|
|
158
190
|
nodes: [
|
|
159
191
|
{
|
|
160
192
|
nodeId: 'root',
|
|
161
|
-
registration: {
|
|
193
|
+
registration: { kind: 'component', id: 'contentful-container' },
|
|
162
194
|
props: { content: {}, design: {}, designRaw: {} },
|
|
163
195
|
slots: {
|
|
164
196
|
children: [
|
|
165
197
|
{
|
|
166
198
|
nodeId: 'ghost',
|
|
167
|
-
registration: {
|
|
199
|
+
registration: { kind: 'component', id: 'NotRegistered' },
|
|
168
200
|
props: { content: {}, design: {}, designRaw: {} },
|
|
169
201
|
slots: {},
|
|
170
202
|
},
|
|
@@ -247,7 +279,7 @@ describe('ServerExperienceRenderer', () => {
|
|
|
247
279
|
nodes: [
|
|
248
280
|
{
|
|
249
281
|
nodeId: 'r',
|
|
250
|
-
registration: {
|
|
282
|
+
registration: { kind: 'component', id: 'item' },
|
|
251
283
|
props: {
|
|
252
284
|
content: { value: 'fromContent' },
|
|
253
285
|
design: {},
|
|
@@ -263,25 +295,26 @@ describe('ServerExperienceRenderer', () => {
|
|
|
263
295
|
});
|
|
264
296
|
expect(container.innerHTML).toContain('data-value="fromResolveData"');
|
|
265
297
|
});
|
|
266
|
-
it('
|
|
298
|
+
it('renders an experienceTemplate node from the experienceTemplates registry', async () => {
|
|
267
299
|
const tplConfig = {
|
|
268
300
|
components: { item: PrecedenceFixture },
|
|
269
301
|
experienceTemplates: {
|
|
270
302
|
page: { component: ExperienceTemplateFixture, defaults: { title: 'Default Title' } },
|
|
271
303
|
},
|
|
272
304
|
};
|
|
305
|
+
// The payload's `content` slot must arrive as a named `content` Snippet[]
|
|
306
|
+
// prop — the fixture renders it, so the child only appears if that holds.
|
|
273
307
|
const tplPayload = {
|
|
274
|
-
sys:
|
|
275
|
-
experienceTemplate: {
|
|
276
|
-
sys: {
|
|
277
|
-
type: 'ResourceLink',
|
|
278
|
-
linkType: 'Contentful:ExperienceTemplate',
|
|
279
|
-
urn: 'crn:contentful:::experience:spaces/$self/environments/$self/experienceTemplates/page',
|
|
280
|
-
},
|
|
281
|
-
},
|
|
282
|
-
},
|
|
308
|
+
sys: sysWithExperienceTemplate('page'),
|
|
283
309
|
viewports: VIEWPORTS,
|
|
284
|
-
nodes: [
|
|
310
|
+
nodes: [
|
|
311
|
+
experienceTemplateNode('page', {
|
|
312
|
+
id: 'tpl',
|
|
313
|
+
slots: {
|
|
314
|
+
content: [componentNode('item', { id: 'i', contentProperties: { value: 'inside' } })],
|
|
315
|
+
},
|
|
316
|
+
}),
|
|
317
|
+
],
|
|
285
318
|
};
|
|
286
319
|
const plan = await resolveExperience(tplPayload, tplConfig);
|
|
287
320
|
const { container } = render(ServerExperienceRenderer, {
|
|
@@ -291,26 +324,52 @@ describe('ServerExperienceRenderer', () => {
|
|
|
291
324
|
expect(container.innerHTML).toContain('data-title="Default Title"');
|
|
292
325
|
expect(container.innerHTML).toContain('inside');
|
|
293
326
|
});
|
|
294
|
-
it('renders
|
|
327
|
+
it('renders a composite experience unwrapped — sys.experienceTemplate is ignored', async () => {
|
|
328
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
329
|
+
// `hero` is registered as a template, but the nodes are plain components,
|
|
330
|
+
// so nothing may wrap them.
|
|
331
|
+
const cfg = {
|
|
332
|
+
components: { item: PrecedenceFixture },
|
|
333
|
+
experienceTemplates: { hero: ExperienceTemplateFixture },
|
|
334
|
+
};
|
|
335
|
+
const plan = await resolveExperience({
|
|
336
|
+
sys: sysWithExperienceTemplate('hero'),
|
|
337
|
+
viewports: VIEWPORTS,
|
|
338
|
+
nodes: [
|
|
339
|
+
componentNode('item', { id: 'a', contentProperties: { value: 'one' } }),
|
|
340
|
+
componentNode('item', { id: 'b', contentProperties: { value: 'two' } }),
|
|
341
|
+
],
|
|
342
|
+
}, cfg);
|
|
343
|
+
const { container } = render(ServerExperienceRenderer, {
|
|
344
|
+
props: { experience: plan, config: cfg },
|
|
345
|
+
});
|
|
346
|
+
expect(container.innerHTML).toContain('data-value="one"');
|
|
347
|
+
expect(container.innerHTML).toContain('data-value="two"');
|
|
348
|
+
expect(container.innerHTML).not.toContain('data-experience-template');
|
|
349
|
+
expect(warn).not.toHaveBeenCalled();
|
|
350
|
+
warn.mockRestore();
|
|
351
|
+
});
|
|
352
|
+
it('renders slot children unwrapped + warns when the experienceTemplate is not registered', async () => {
|
|
295
353
|
const warn = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
296
354
|
const cfg = { components: { item: PrecedenceFixture } };
|
|
297
355
|
const tplPayload = {
|
|
298
|
-
sys: {
|
|
299
|
-
experienceTemplate: {
|
|
300
|
-
sys: {
|
|
301
|
-
type: 'ResourceLink',
|
|
302
|
-
linkType: 'Contentful:ExperienceTemplate',
|
|
303
|
-
urn: 'crn:contentful:::experience:spaces/$self/environments/$self/experienceTemplates/missing-experienceTemplate',
|
|
304
|
-
},
|
|
305
|
-
},
|
|
306
|
-
},
|
|
307
356
|
viewports: VIEWPORTS,
|
|
308
|
-
nodes: [
|
|
357
|
+
nodes: [
|
|
358
|
+
experienceTemplateNode('missing-experienceTemplate', {
|
|
359
|
+
id: 'tpl',
|
|
360
|
+
slots: {
|
|
361
|
+
content: [
|
|
362
|
+
componentNode('item', { id: 'i', contentProperties: { value: 'unwrapped' } }),
|
|
363
|
+
],
|
|
364
|
+
},
|
|
365
|
+
}),
|
|
366
|
+
],
|
|
309
367
|
};
|
|
310
368
|
const plan = await resolveExperience(tplPayload, cfg);
|
|
311
369
|
const { container } = render(ServerExperienceRenderer, {
|
|
312
370
|
props: { experience: plan, config: cfg },
|
|
313
371
|
});
|
|
372
|
+
// The subtree survives — an unregistered template must not blank the page.
|
|
314
373
|
expect(container.innerHTML).toContain('data-value="unwrapped"');
|
|
315
374
|
expect(container.innerHTML).not.toContain('data-experience-template');
|
|
316
375
|
expect(warn).toHaveBeenCalledWith(expect.stringContaining('missing-experienceTemplate'));
|
|
@@ -407,8 +466,9 @@ describe('ServerExperienceRenderer — bare-component registrations', () => {
|
|
|
407
466
|
expect(keys).toContain('text');
|
|
408
467
|
expect(keys).not.toContain('experience');
|
|
409
468
|
expect(keys).not.toContain('contentful');
|
|
410
|
-
//
|
|
411
|
-
|
|
469
|
+
// Slot props exist only for slots the payload actually carries — `children`
|
|
470
|
+
// is just a slot name, so a node without slots gets no `children` prop.
|
|
471
|
+
expect(keys).not.toContain('children');
|
|
412
472
|
});
|
|
413
473
|
});
|
|
414
474
|
describe('ServerExperienceRenderer — getContentfulComponent()', () => {
|
|
@@ -518,32 +578,28 @@ describe('ServerExperienceRenderer — resolveToken', () => {
|
|
|
518
578
|
// unchanged, so the customer can inspect it or resolve it themselves.
|
|
519
579
|
expect(container.innerHTML).toContain('data-bg="[object Object]"');
|
|
520
580
|
});
|
|
521
|
-
it('runs on
|
|
581
|
+
it('runs on an experienceTemplate node design props too', async () => {
|
|
522
582
|
const tplConfig = {
|
|
523
583
|
components: { item: PrecedenceFixture },
|
|
524
584
|
experienceTemplates: { page: ExperienceTemplateFixture },
|
|
525
585
|
resolveToken: (ref) => (ref.value === 'brand/canvas' ? '#111827' : undefined),
|
|
526
586
|
};
|
|
527
587
|
const tplPayload = {
|
|
528
|
-
sys:
|
|
529
|
-
experienceTemplate: {
|
|
530
|
-
sys: {
|
|
531
|
-
type: 'ResourceLink',
|
|
532
|
-
linkType: 'Contentful:ExperienceTemplate',
|
|
533
|
-
urn: 'crn:contentful:::experience:spaces/$self/environments/$self/experienceTemplates/page',
|
|
534
|
-
},
|
|
535
|
-
},
|
|
536
|
-
},
|
|
588
|
+
sys: sysWithExperienceTemplate('page'),
|
|
537
589
|
viewports: VIEWPORTS,
|
|
538
|
-
nodes: [
|
|
590
|
+
nodes: [
|
|
591
|
+
experienceTemplateNode('page', {
|
|
592
|
+
id: 'tpl',
|
|
593
|
+
designProperties: { cfBackground: dt('brand/canvas') },
|
|
594
|
+
slots: {
|
|
595
|
+
content: [componentNode('item', { id: 'i', contentProperties: { value: 'ok' } })],
|
|
596
|
+
},
|
|
597
|
+
}),
|
|
598
|
+
],
|
|
539
599
|
};
|
|
540
600
|
const plan = await resolveExperience(tplPayload, tplConfig);
|
|
541
|
-
//
|
|
542
|
-
//
|
|
543
|
-
// experienceTemplate path. Render at a non-fallback viewport (mobile ≠
|
|
544
|
-
// fallback index 0) so the adapter recomputes from the seeded raw design
|
|
545
|
-
// and runs resolveToken.
|
|
546
|
-
plan.experienceTemplate.props.designRaw = { cfBackground: dt('brand/canvas') };
|
|
601
|
+
// Render at a non-fallback viewport (mobile ≠ fallback index 0) so the
|
|
602
|
+
// adapter recomputes from the raw design and runs resolveToken itself.
|
|
547
603
|
const { container } = render(ServerExperienceRenderer, {
|
|
548
604
|
props: { experience: plan, config: tplConfig, initialViewportId: 'mobile' },
|
|
549
605
|
});
|
|
@@ -3,16 +3,21 @@
|
|
|
3
3
|
|
|
4
4
|
import { getDesignValues } from '../get-design-values.js';
|
|
5
5
|
|
|
6
|
+
// A coded Experience Template's slots arrive as named `Snippet[]` props, so
|
|
7
|
+
// the payload's `content` slot lands on a `content` prop — no `children`
|
|
8
|
+
// special case.
|
|
6
9
|
let {
|
|
7
10
|
title,
|
|
8
|
-
|
|
11
|
+
content,
|
|
9
12
|
}: {
|
|
10
13
|
title?: string;
|
|
11
|
-
|
|
14
|
+
content?: Snippet[];
|
|
12
15
|
} = $props();
|
|
13
16
|
const design = $derived(getDesignValues());
|
|
14
17
|
</script>
|
|
15
18
|
|
|
16
19
|
<main data-experience-template="page" data-title={title} data-bg={design.cfBackground as string}>
|
|
17
|
-
{
|
|
20
|
+
{#each content ?? [] as childSnippet, index (index)}
|
|
21
|
+
{@render childSnippet()}
|
|
22
|
+
{/each}
|
|
18
23
|
</main>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
type $$ComponentProps = {
|
|
3
3
|
title?: string;
|
|
4
|
-
|
|
4
|
+
content?: Snippet[];
|
|
5
5
|
};
|
|
6
6
|
declare const ExperienceTemplateFixture: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
7
|
type ExperienceTemplateFixture = ReturnType<typeof ExperienceTemplateFixture>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExperienceTemplateFixture.svelte.d.ts","sourceRoot":"","sources":["../../src/test-fixtures/ExperienceTemplateFixture.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAIrC,KAAK,gBAAgB,GAAI;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,
|
|
1
|
+
{"version":3,"file":"ExperienceTemplateFixture.svelte.d.ts","sourceRoot":"","sources":["../../src/test-fixtures/ExperienceTemplateFixture.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAIrC,KAAK,gBAAgB,GAAI;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;CACrB,CAAC;AAwBJ,QAAA,MAAM,yBAAyB,sDAAwC,CAAC;AACxE,KAAK,yBAAyB,GAAG,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC9E,eAAe,yBAAyB,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export type { ResolveContext, ResolveToken };
|
|
|
7
7
|
* node. Useful for custom design-property resolution outside the SDK's
|
|
8
8
|
* cascade, branching by `componentId` in a generic wrapper, keying
|
|
9
9
|
* analytics on `nodeId`, rendering a raw-payload panel in preview, or
|
|
10
|
-
* rendering
|
|
10
|
+
* re-rendering a slot's nodes yourself through the exported `<NodesRenderer />`.
|
|
11
11
|
*
|
|
12
12
|
* Design properties stay in their **raw discriminated form** here (the same
|
|
13
13
|
* shape `ctx.design` carries inside `resolveData`). The viewport-cascaded,
|
|
@@ -20,20 +20,21 @@ export interface ContentfulComponent {
|
|
|
20
20
|
design: Record<string, DesignPropValue>;
|
|
21
21
|
resolved?: Record<string, unknown>;
|
|
22
22
|
/**
|
|
23
|
-
* Raw per-slot node arrays from the payload.
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* `<NodesRenderer nodes={...} />`.
|
|
23
|
+
* Raw per-slot node arrays from the payload. Every slot is also rendered
|
|
24
|
+
* automatically and passed as a same-named `Snippet[]` prop (`children` is
|
|
25
|
+
* not special); these raw nodes are here for callers that want to render a
|
|
26
|
+
* slot themselves with `<NodesRenderer nodes={...} />`.
|
|
27
27
|
*/
|
|
28
28
|
slots: Record<string, unknown>;
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
-
* Same shape as `ContentfulComponent`, but for
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* Same shape as `ContentfulComponent`, but for an Experience Template node.
|
|
32
|
+
* Exposed via `getContentfulExperienceTemplate()` inside an Experience
|
|
33
|
+
* Template's component tree.
|
|
34
34
|
*/
|
|
35
35
|
export interface ContentfulExperienceTemplate {
|
|
36
36
|
experienceTemplateId: string;
|
|
37
|
+
nodeId?: string;
|
|
37
38
|
content: Record<string, unknown>;
|
|
38
39
|
design: Record<string, DesignPropValue>;
|
|
39
40
|
resolved?: Record<string, unknown>;
|
|
@@ -56,8 +57,8 @@ export interface RenderContext extends ExperienceContext {
|
|
|
56
57
|
}
|
|
57
58
|
/**
|
|
58
59
|
* Customer-supplied configuration for a single component type. The `component`
|
|
59
|
-
* receives the merged props (design + content + resolveData + `
|
|
60
|
-
*
|
|
60
|
+
* receives the merged props (design + content + resolveData + one `Snippet[]`
|
|
61
|
+
* prop per slot); resolved design values auto-fill matching props and are also
|
|
61
62
|
* readable via `getDesignValues()`. Runtime context and raw payload come from
|
|
62
63
|
* `getExperience()` / `getContentfulComponent()`.
|
|
63
64
|
*/
|
|
@@ -76,6 +77,13 @@ export interface ComponentConfig<Props extends object = Record<string, unknown>>
|
|
|
76
77
|
* card: defineComponent<CardProps>({ component: Card, resolveData: ... }),
|
|
77
78
|
*/
|
|
78
79
|
export type Registration<Props extends object = Record<string, unknown>> = Component<any> | ComponentConfig<Props>;
|
|
80
|
+
/**
|
|
81
|
+
* Customer-supplied configuration for a coded Experience Template. Identical in
|
|
82
|
+
* shape and behavior to `ComponentConfig` — an Experience Template is just a
|
|
83
|
+
* node whose implementation lives in the `experienceTemplates` registry. Its
|
|
84
|
+
* slots arrive as named `Snippet[]` props (a `content` slot becomes a `content`
|
|
85
|
+
* prop), so there is no `children` special case.
|
|
86
|
+
*/
|
|
79
87
|
export interface ExperienceTemplateConfig<Props extends object = Record<string, unknown>> {
|
|
80
88
|
defaults?: Partial<Props>;
|
|
81
89
|
resolveData?: (ctx: ResolveContext) => Partial<Props> | Promise<Partial<Props>>;
|
|
@@ -84,7 +92,17 @@ export interface ExperienceTemplateConfig<Props extends object = Record<string,
|
|
|
84
92
|
export type ExperienceTemplateRegistration<Props extends object = Record<string, unknown>> = Component<any> | ExperienceTemplateConfig<Props>;
|
|
85
93
|
export declare function defineExperienceTemplate<Props extends object = Record<string, unknown>>(config: ExperienceTemplateConfig<Props>): ExperienceTemplateConfig<Props>;
|
|
86
94
|
export declare function defineComponent<Props extends object = Record<string, unknown>>(config: ComponentConfig<Props>): ComponentConfig<Props>;
|
|
95
|
+
/**
|
|
96
|
+
* Component registry — keyed by `componentId` (last slash-segment of
|
|
97
|
+
* `component.sys.urn`).
|
|
98
|
+
*/
|
|
87
99
|
export type Components = Record<string, Registration<any>>;
|
|
100
|
+
/**
|
|
101
|
+
* Experience Template registry — keyed by `experienceTemplateId` (last
|
|
102
|
+
* slash-segment of an Experience Template node's own
|
|
103
|
+
* `experienceTemplate.sys.urn`). Not read from `payload.sys`; templates are
|
|
104
|
+
* ordinary nodes.
|
|
105
|
+
*/
|
|
88
106
|
export type ExperienceTemplates = Record<string, ExperienceTemplateRegistration<any>>;
|
|
89
107
|
export interface Config {
|
|
90
108
|
components: Components;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-active-viewport.svelte.d.ts","sourceRoot":"","sources":["../src/use-active-viewport.svelte.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAGpE,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACtC;
|
|
1
|
+
{"version":3,"file":"use-active-viewport.svelte.d.ts","sourceRoot":"","sources":["../src/use-active-viewport.svelte.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAGpE,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACtC;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,WAAW,EAAE,EACxB,iBAAiB,CAAC,EAAE,MAAM,GACzB,uBAAuB,CAiDzB"}
|
|
@@ -10,28 +10,7 @@
|
|
|
10
10
|
* to seed the first render so SSR + client agree on viewport before
|
|
11
11
|
* window.matchMedia takes over.
|
|
12
12
|
*/
|
|
13
|
-
import {
|
|
14
|
-
function createMediaQueryMatchers(viewports) {
|
|
15
|
-
const mediaQueryMatches = new Array(viewports.length).fill(false);
|
|
16
|
-
// The first viewport is the wildcard "*" and always matches.
|
|
17
|
-
mediaQueryMatches[0] = true;
|
|
18
|
-
const mediaQueryMatchers = [];
|
|
19
|
-
if (typeof window === 'undefined') {
|
|
20
|
-
return [mediaQueryMatchers, mediaQueryMatches];
|
|
21
|
-
}
|
|
22
|
-
for (let index = 0; index < viewports.length; index++) {
|
|
23
|
-
const viewport = viewports[index];
|
|
24
|
-
if (!viewport)
|
|
25
|
-
continue;
|
|
26
|
-
const cssQuery = toCssMediaQuery(viewport);
|
|
27
|
-
if (!cssQuery)
|
|
28
|
-
continue;
|
|
29
|
-
const matcher = window.matchMedia(cssQuery);
|
|
30
|
-
mediaQueryMatches[index] = matcher.matches;
|
|
31
|
-
mediaQueryMatchers.push({ index, signal: matcher });
|
|
32
|
-
}
|
|
33
|
-
return [mediaQueryMatchers, mediaQueryMatches];
|
|
34
|
-
}
|
|
13
|
+
import { createMediaQueryMatchers, getViewportIndex } from '@contentful/experiences-design';
|
|
35
14
|
/**
|
|
36
15
|
* Returns a reactive object whose `activeViewportIndex` updates as the
|
|
37
16
|
* window's matched media queries change. Mounts listeners via `$effect`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/experiences-svelte",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.7",
|
|
4
4
|
"description": "Svelte adapter for Contentful Experiences — Server and Client renderers over a PortableRenderPlan",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
33
|
"build": "svelte-package -i src -o dist && publint",
|
|
34
|
-
"test": "vitest run",
|
|
34
|
+
"test": "vitest run && vitest run -c vitest.ssr.config.ts",
|
|
35
35
|
"check": "svelte-check --tsconfig ./tsconfig.json"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@contentful/experiences-client": "0.3.
|
|
39
|
-
"@contentful/experiences-sdk-core": "0.7.
|
|
40
|
-
"@contentful/experiences-design": "0.7.
|
|
38
|
+
"@contentful/experiences-client": "0.3.6",
|
|
39
|
+
"@contentful/experiences-sdk-core": "0.7.6",
|
|
40
|
+
"@contentful/experiences-design": "0.7.6"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"svelte": "^5.55.7"
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
* Wraps the rendered Experience nodes with the page-level Experience Template when the
|
|
3
|
-
* plan carries one and the customer registered an Experience Template config under that
|
|
4
|
-
* id. When the Experience Template is referenced but unregistered, warns once and
|
|
5
|
-
* renders children unwrapped — graceful degradation matches the
|
|
6
|
-
* unknown-component fallback story.
|
|
7
|
-
-->
|
|
8
|
-
<script lang="ts">
|
|
9
|
-
import type { Snippet } from 'svelte';
|
|
10
|
-
|
|
11
|
-
import type { PortableExperienceTemplate } from '@contentful/experiences-sdk-core';
|
|
12
|
-
|
|
13
|
-
import { setContentfulExperienceTemplate, setResolvedDesign } from './context.js';
|
|
14
|
-
import { selectResolvedDesign } from './design-utils.js';
|
|
15
|
-
import {
|
|
16
|
-
normalizeExperienceTemplateRegistration,
|
|
17
|
-
type ContentfulExperienceTemplate,
|
|
18
|
-
type Config,
|
|
19
|
-
type RenderContext,
|
|
20
|
-
} from './types.js';
|
|
21
|
-
|
|
22
|
-
interface WrapWithExperienceTemplateProps {
|
|
23
|
-
experienceTemplate: PortableExperienceTemplate | undefined;
|
|
24
|
-
config: Config;
|
|
25
|
-
experience: RenderContext;
|
|
26
|
-
children: Snippet;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
let { experienceTemplate, config, experience, children }: WrapWithExperienceTemplateProps = $props();
|
|
30
|
-
|
|
31
|
-
// setContext must run during synchronous component init — call once with
|
|
32
|
-
// the initial value (Experience Templates do not toggle on/off mid-mount).
|
|
33
|
-
if (experienceTemplate) {
|
|
34
|
-
setContentfulExperienceTemplate({
|
|
35
|
-
experienceTemplateId: experienceTemplate.experienceTemplateId,
|
|
36
|
-
content: experienceTemplate.props.content,
|
|
37
|
-
design: experienceTemplate.props.designRaw,
|
|
38
|
-
resolved: experienceTemplate.props.resolved,
|
|
39
|
-
} satisfies ContentfulExperienceTemplate);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const entry = $derived(experienceTemplate ? config.experienceTemplates?.[experienceTemplate.experienceTemplateId] : undefined);
|
|
43
|
-
const experienceTemplateConfig = $derived(entry ? normalizeExperienceTemplateRegistration(entry) : null);
|
|
44
|
-
|
|
45
|
-
const tokenResolvedDesign = $derived.by(() => {
|
|
46
|
-
if (!experienceTemplate) return {};
|
|
47
|
-
const { props, unresolved } = selectResolvedDesign(
|
|
48
|
-
experienceTemplate.props,
|
|
49
|
-
experience.viewports,
|
|
50
|
-
experience.activeViewportIndex,
|
|
51
|
-
experience.fallbackViewportIndex,
|
|
52
|
-
config.resolveToken
|
|
53
|
-
);
|
|
54
|
-
if (unresolved.length && typeof console !== 'undefined') {
|
|
55
|
-
console.warn(
|
|
56
|
-
`[@contentful/experiences-svelte] resolveToken returned undefined for token id(s) on experience template "${experienceTemplate.experienceTemplateId}": ${unresolved.join(', ')}. getDesignValues() will omit those keys.`
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
return props;
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// A getter (not a snapshot) so getDesignValues() stays reactive.
|
|
63
|
-
setResolvedDesign(() => tokenResolvedDesign);
|
|
64
|
-
|
|
65
|
-
// Same precedence as component nodes.
|
|
66
|
-
const composed = $derived.by(() => {
|
|
67
|
-
if (!experienceTemplate || !experienceTemplateConfig) return null;
|
|
68
|
-
return {
|
|
69
|
-
...experienceTemplateConfig.defaults,
|
|
70
|
-
...tokenResolvedDesign,
|
|
71
|
-
...experienceTemplate.props.content,
|
|
72
|
-
...experienceTemplate.props.resolved,
|
|
73
|
-
};
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
$effect(() => {
|
|
77
|
-
if (experienceTemplate && !experienceTemplateConfig && typeof console !== 'undefined') {
|
|
78
|
-
console.warn(
|
|
79
|
-
`[@contentful/experiences-svelte] No experience template registered for id "${experienceTemplate.experienceTemplateId}". Rendering nodes without the experience template wrapper.`
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
</script>
|
|
84
|
-
|
|
85
|
-
{#if experienceTemplate && experienceTemplateConfig && composed}
|
|
86
|
-
{@const Tpl = experienceTemplateConfig.component}
|
|
87
|
-
<Tpl {...composed} {children} />
|
|
88
|
-
{:else}
|
|
89
|
-
{@render children()}
|
|
90
|
-
{/if}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { Snippet } from 'svelte';
|
|
2
|
-
import type { PortableExperienceTemplate } from '@contentful/experiences-sdk-core';
|
|
3
|
-
import { type Config, type RenderContext } from './types.js';
|
|
4
|
-
interface WrapWithExperienceTemplateProps {
|
|
5
|
-
experienceTemplate: PortableExperienceTemplate | undefined;
|
|
6
|
-
config: Config;
|
|
7
|
-
experience: RenderContext;
|
|
8
|
-
children: Snippet;
|
|
9
|
-
}
|
|
10
|
-
declare const WrapWithExperienceTemplate: import("svelte").Component<WrapWithExperienceTemplateProps, {}, "">;
|
|
11
|
-
type WrapWithExperienceTemplate = ReturnType<typeof WrapWithExperienceTemplate>;
|
|
12
|
-
export default WrapWithExperienceTemplate;
|
|
13
|
-
//# sourceMappingURL=WrapWithExperienceTemplate.svelte.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WrapWithExperienceTemplate.svelte.d.ts","sourceRoot":"","sources":["../src/WrapWithExperienceTemplate.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAInF,OAAO,EAGH,KAAK,MAAM,EACX,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAGpB,UAAU,+BAA+B;IACvC,kBAAkB,EAAE,0BAA0B,GAAG,SAAS,CAAC;IAC3D,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,aAAa,CAAC;IAC1B,QAAQ,EAAE,OAAO,CAAC;CACnB;AA6EH,QAAA,MAAM,0BAA0B,qEAAwC,CAAC;AACzE,KAAK,0BAA0B,GAAG,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAChF,eAAe,0BAA0B,CAAC"}
|