@contentful/experiences-svelte 0.9.1 → 0.11.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 +150 -0
- package/README.md +7 -10
- package/dist/ClientExperienceRenderer.svelte +4 -36
- package/dist/ClientExperienceRenderer.svelte.d.ts.map +1 -1
- package/dist/DebugExperience.svelte +3 -3
- package/dist/DebugExperience.test.js +0 -14
- package/dist/NodeRenderer.svelte +2 -17
- package/dist/NodeRenderer.svelte.d.ts.map +1 -1
- package/dist/NodeRenderer.test.js +2 -6
- package/dist/NodesRenderer.svelte +1 -2
- package/dist/ServerExperienceRenderer.svelte +2 -25
- package/dist/ServerExperienceRenderer.svelte.d.ts.map +1 -1
- package/dist/component-props.d.ts +0 -1
- package/dist/component-props.d.ts.map +1 -1
- package/dist/context.d.ts +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +2 -3
- package/dist/debug-panel-coverage.ssr.test.js +0 -2
- package/dist/debug-panel-coverage.test.js +1 -9
- package/dist/get-design-values.d.ts +3 -3
- package/dist/get-design-values.js +3 -3
- package/dist/index.d.ts +2 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/nodes-renderer.ssr.test.js +0 -6
- package/dist/server-renderer.test.js +18 -145
- package/dist/types.d.ts +2 -2
- package/dist/use-experience-plan.test.js +0 -10
- package/dist/use-live-preview-experience.test.js +0 -8
- package/dist/use-live-preview.test.js +0 -7
- package/package.json +5 -5
- package/dist/use-active-viewport.svelte.d.ts +0 -23
- package/dist/use-active-viewport.svelte.d.ts.map +0 -1
- package/dist/use-active-viewport.svelte.js +0 -66
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,153 @@
|
|
|
1
|
+
## 0.11.0 (2026-10-08)
|
|
2
|
+
|
|
3
|
+
### 🚀 Features
|
|
4
|
+
|
|
5
|
+
- ⚠️ remove sdk viewport surface [SPA-5275] ([#220](https://github.com/contentful/experiences/pull/220))
|
|
6
|
+
|
|
7
|
+
### ⚠️ Breaking Changes
|
|
8
|
+
|
|
9
|
+
- remove sdk viewport surface [SPA-5275] ([#220](https://github.com/contentful/experiences/pull/220))
|
|
10
|
+
The SDK no longer exposes viewport definitions, viewport-aware design-value resolution, or active-viewport hooks. Use CSS media queries or application-owned matchMedia integration for responsive behavior. Delivered design property values are now flat and require no migration."
|
|
11
|
+
M AGENTS.md
|
|
12
|
+
M ARCHITECTURE.md
|
|
13
|
+
M CONTRIBUTING.md
|
|
14
|
+
M README.md
|
|
15
|
+
M catalog-info.yaml
|
|
16
|
+
M examples/angular/README.md
|
|
17
|
+
M examples/angular/src/app/components/heading.component.ts
|
|
18
|
+
D examples/angular/src/app/lib/detect-viewport.ts
|
|
19
|
+
M examples/angular/src/app/lib/experience-config.ts
|
|
20
|
+
M examples/angular/src/app/lib/experience-route-data.ts
|
|
21
|
+
M examples/angular/src/app/pages/experience-page.component.ts
|
|
22
|
+
M examples/angular/src/server.ts
|
|
23
|
+
M examples/nextjs/README.md
|
|
24
|
+
M examples/nextjs/app/[slug]/page.tsx
|
|
25
|
+
M examples/nextjs/components/Heading.tsx
|
|
26
|
+
M examples/nextjs/components/LivePreviewExperience.tsx
|
|
27
|
+
M examples/nextjs/components/Section.tsx
|
|
28
|
+
D examples/nextjs/lib/detect-viewport.ts
|
|
29
|
+
M examples/nextjs/lib/experience-config.tsx
|
|
30
|
+
M examples/scripts/bootstrap-example.ts
|
|
31
|
+
M examples/scripts/fixture/experience.ts
|
|
32
|
+
M examples/scripts/fixture/types.ts
|
|
33
|
+
M examples/sveltekit/README.md
|
|
34
|
+
M examples/sveltekit/src/lib/components/Heading.svelte
|
|
35
|
+
D examples/sveltekit/src/lib/detect-viewport.ts
|
|
36
|
+
M examples/sveltekit/src/lib/experience-config.ts
|
|
37
|
+
M examples/sveltekit/src/routes/[slug]/+page.server.ts
|
|
38
|
+
M examples/sveltekit/src/routes/[slug]/+page.svelte
|
|
39
|
+
M examples/sveltekit/vite.config.ts
|
|
40
|
+
M package-lock.json
|
|
41
|
+
M packages/adapter-angular/README.md
|
|
42
|
+
M packages/adapter-angular/src/client-experience-renderer.component.ts
|
|
43
|
+
M packages/adapter-angular/src/context.ts
|
|
44
|
+
M packages/adapter-angular/src/debug-experience.test.ts
|
|
45
|
+
M packages/adapter-angular/src/debug-panel-coverage.ssr.test.ts
|
|
46
|
+
M packages/adapter-angular/src/debug-panel-coverage.test.ts
|
|
47
|
+
M packages/adapter-angular/src/dom-parity.test.ts
|
|
48
|
+
M packages/adapter-angular/src/experience-defaults.ts
|
|
49
|
+
M packages/adapter-angular/src/experience-scope.ts
|
|
50
|
+
M packages/adapter-angular/src/index.ts
|
|
51
|
+
D packages/adapter-angular/src/inject-active-viewport.ts
|
|
52
|
+
M packages/adapter-angular/src/inject-design-values.ts
|
|
53
|
+
M packages/adapter-angular/src/inject-experience-plan.ts
|
|
54
|
+
M packages/adapter-angular/src/live-preview-experience.ssr.test.ts
|
|
55
|
+
M packages/adapter-angular/src/live-preview-experience.test.ts
|
|
56
|
+
M packages/adapter-angular/src/node-render-engine.test.ts
|
|
57
|
+
M packages/adapter-angular/src/node-render-engine.ts
|
|
58
|
+
M packages/adapter-angular/src/node-scopes.ts
|
|
59
|
+
M packages/adapter-angular/src/nodes-renderer.ssr.test.ts
|
|
60
|
+
M packages/adapter-angular/src/server-experience-renderer.component.ts
|
|
61
|
+
M packages/adapter-angular/src/server-renderer.test.ts
|
|
62
|
+
M packages/adapter-angular/src/test-fixtures/render-harness.ts
|
|
63
|
+
M packages/adapter-angular/src/types.ts
|
|
64
|
+
M packages/adapter-react/README.md
|
|
65
|
+
M packages/adapter-react/src/client-renderer.tsx
|
|
66
|
+
M packages/adapter-react/src/context.tsx
|
|
67
|
+
M packages/adapter-react/src/debug-experience.test.tsx
|
|
68
|
+
M packages/adapter-react/src/debug-experience.tsx
|
|
69
|
+
M packages/adapter-react/src/debug-panel-coverage.test.tsx
|
|
70
|
+
M packages/adapter-react/src/index.ts
|
|
71
|
+
M packages/adapter-react/src/nodes-renderer.ssr.test.tsx
|
|
72
|
+
M packages/adapter-react/src/nodes-renderer.test.tsx
|
|
73
|
+
M packages/adapter-react/src/nodes-renderer.tsx
|
|
74
|
+
M packages/adapter-react/src/server-renderer.test.tsx
|
|
75
|
+
M packages/adapter-react/src/server-renderer.tsx
|
|
76
|
+
M packages/adapter-react/src/types.ts
|
|
77
|
+
D packages/adapter-react/src/use-active-viewport.ts
|
|
78
|
+
M packages/adapter-react/src/use-design-values.tsx
|
|
79
|
+
M packages/adapter-react/src/use-experience-plan.test.tsx
|
|
80
|
+
M packages/adapter-react/src/use-experience-plan.ts
|
|
81
|
+
M packages/adapter-react/src/use-live-preview-experience.test.tsx
|
|
82
|
+
M packages/adapter-react/src/use-live-preview.test.tsx
|
|
83
|
+
M packages/adapter-svelte/README.md
|
|
84
|
+
M packages/adapter-svelte/src/ClientExperienceRenderer.svelte
|
|
85
|
+
M packages/adapter-svelte/src/DebugExperience.svelte
|
|
86
|
+
M packages/adapter-svelte/src/DebugExperience.test.ts
|
|
87
|
+
M packages/adapter-svelte/src/NodeRenderer.svelte
|
|
88
|
+
M packages/adapter-svelte/src/NodeRenderer.test.ts
|
|
89
|
+
M packages/adapter-svelte/src/NodesRenderer.svelte
|
|
90
|
+
M packages/adapter-svelte/src/ServerExperienceRenderer.svelte
|
|
91
|
+
M packages/adapter-svelte/src/component-props.ts
|
|
92
|
+
M packages/adapter-svelte/src/context.ts
|
|
93
|
+
M packages/adapter-svelte/src/debug-panel-coverage.ssr.test.ts
|
|
94
|
+
M packages/adapter-svelte/src/debug-panel-coverage.test.ts
|
|
95
|
+
M packages/adapter-svelte/src/get-design-values.ts
|
|
96
|
+
M packages/adapter-svelte/src/index.ts
|
|
97
|
+
M packages/adapter-svelte/src/nodes-renderer.ssr.test.ts
|
|
98
|
+
M packages/adapter-svelte/src/server-renderer.test.ts
|
|
99
|
+
M packages/adapter-svelte/src/types.ts
|
|
100
|
+
D packages/adapter-svelte/src/use-active-viewport.svelte.ts
|
|
101
|
+
M packages/adapter-svelte/src/use-experience-plan.test.ts
|
|
102
|
+
M packages/adapter-svelte/src/use-live-preview-experience.test.ts
|
|
103
|
+
M packages/adapter-svelte/src/use-live-preview.test.ts
|
|
104
|
+
M packages/client/src/contentful-experiences.test.ts
|
|
105
|
+
M packages/client/src/contentful-experiences.ts
|
|
106
|
+
M packages/client/src/fetch-experience.test.ts
|
|
107
|
+
M packages/client/src/fetch-experience.ts
|
|
108
|
+
M packages/core/README.md
|
|
109
|
+
A packages/core/src/design-properties.test.ts
|
|
110
|
+
A packages/core/src/design-properties.ts
|
|
111
|
+
M packages/core/src/index.ts
|
|
112
|
+
M packages/core/src/resolve-experience.test.ts
|
|
113
|
+
M packages/core/src/resolve-experience.ts
|
|
114
|
+
M packages/core/src/types.ts
|
|
115
|
+
D packages/core/src/viewport.test.ts
|
|
116
|
+
D packages/core/src/viewport.ts
|
|
117
|
+
M packages/design/README.md
|
|
118
|
+
M packages/design/package.json
|
|
119
|
+
M packages/design/src/index.ts
|
|
120
|
+
D packages/design/src/media-query-matchers.ts
|
|
121
|
+
D packages/design/src/select-resolved-design.ts
|
|
122
|
+
D packages/design/src/viewport.test.ts
|
|
123
|
+
D packages/design/src/viewport.ts
|
|
124
|
+
M packages/live-preview/README.md
|
|
125
|
+
M packages/live-preview/src/experience-payload.ts
|
|
126
|
+
M packages/live-preview/src/fetch-preview-session.test.ts
|
|
127
|
+
M packages/live-preview/src/fetch-preview-session.ts
|
|
128
|
+
M packages/live-preview/src/live-preview-client.test.ts
|
|
129
|
+
M packages/node/README.md
|
|
130
|
+
M packages/node/src/contentful-experiences.test.ts
|
|
131
|
+
M packages/node/src/contentful-experiences.ts
|
|
132
|
+
M packages/web/README.md
|
|
133
|
+
M packages/web/src/contentful-experiences.test.ts
|
|
134
|
+
|
|
135
|
+
### 🧱 Updated Dependencies
|
|
136
|
+
|
|
137
|
+
- Updated live-preview to 0.6.0
|
|
138
|
+
- Updated client to 0.9.0
|
|
139
|
+
- Updated design to 0.12.0
|
|
140
|
+
- Updated core to 0.12.0
|
|
141
|
+
|
|
142
|
+
## 0.10.0 (2026-10-06)
|
|
143
|
+
|
|
144
|
+
### 🧱 Updated Dependencies
|
|
145
|
+
|
|
146
|
+
- Updated live-preview to 0.5.0
|
|
147
|
+
- Updated client to 0.8.0
|
|
148
|
+
- Updated design to 0.11.0
|
|
149
|
+
- Updated core to 0.11.0
|
|
150
|
+
|
|
1
151
|
## 0.9.1 (2026-10-01)
|
|
2
152
|
|
|
3
153
|
### 🚀 Features
|
package/README.md
CHANGED
|
@@ -107,11 +107,10 @@ fails. The last valid `data` remains available.
|
|
|
107
107
|
### Renderers
|
|
108
108
|
|
|
109
109
|
```ts
|
|
110
|
-
ServerExperienceRenderer; // SSR-safe
|
|
111
|
-
ClientExperienceRenderer; //
|
|
110
|
+
ServerExperienceRenderer; // SSR-safe renderer
|
|
111
|
+
ClientExperienceRenderer; // Client renderer
|
|
112
112
|
MissingComponent; // Default fallback for unregistered component types
|
|
113
113
|
NodesRenderer; // Exposed so you can re-render a slot's raw nodes yourself (see Slot children)
|
|
114
|
-
useActiveViewport; // Rune-backed reactive object; you'll rarely need it directly
|
|
115
114
|
```
|
|
116
115
|
|
|
117
116
|
### Styling + runtime context (helpers)
|
|
@@ -119,13 +118,13 @@ useActiveViewport; // Rune-backed reactive object; you'll rarely need it directl
|
|
|
119
118
|
```ts
|
|
120
119
|
getDesignValues<T>(); // Escape hatch: the same resolved design record that auto-fills props; read in a $derived to stay reactive
|
|
121
120
|
toCss(design, options?); // Turns a design record into a plain style object, keeping only real CSS keys
|
|
122
|
-
getExperience(); // RenderContext: debug, metadata
|
|
121
|
+
getExperience(); // RenderContext: debug, metadata
|
|
123
122
|
getContentfulComponent(); // Raw payload for the enclosing node (or undefined)
|
|
124
123
|
getContentfulExperienceTemplate(); // Same, for an enclosing coded Experience Template node
|
|
125
124
|
type ToCssOptions;
|
|
126
125
|
```
|
|
127
126
|
|
|
128
|
-
Resolved design values
|
|
127
|
+
Resolved design values are **auto-filled onto your component's props** by key, alongside content. Styling from `$props()` is the one recommended path. `getDesignValues()` exposes the same record as an escape hatch. Reach for it only for a nested child that isn't itself a registered component, or for design needed outside the render path (an effect, an imperative measurement) — see [Styling components](../../README.md#styling-components). Token resolution is configured with `resolveToken` on your `Config` (`type ResolveToken`).
|
|
129
128
|
|
|
130
129
|
### Re-exported types and utilities
|
|
131
130
|
|
|
@@ -137,12 +136,10 @@ type ContentfulComponent, ContentfulExperienceTemplate,
|
|
|
137
136
|
type RenderContext, ResolveToken,
|
|
138
137
|
type ExperiencePayload, ExperienceNode, ComponentNode, ExperienceTemplateNode,
|
|
139
138
|
type PortableRenderPlan, PortableRenderNode, PortableRegistration,
|
|
140
|
-
type DesignPropValue, ManualDesignValue, DesignToken,
|
|
141
|
-
type ViewportDef, ExperienceContext, ResolveContext,
|
|
139
|
+
type DesignPropValue, ManualDesignValue, DesignToken, ExperienceContext, ResolveContext,
|
|
142
140
|
type ResolverConfig, ResolveExperienceOptions
|
|
143
141
|
|
|
144
|
-
// From design
|
|
145
|
-
getValueForViewport, getViewportIndex, resolveDesignProperties, toCssMediaQuery,
|
|
142
|
+
// From design
|
|
146
143
|
isCssProperty, toCssKey, CSS_PROPERTIES
|
|
147
144
|
|
|
148
145
|
// From client
|
|
@@ -244,7 +241,7 @@ Every slot arrives as a prop named after the slot, holding an **array of Snippet
|
|
|
244
241
|
|
|
245
242
|
If you'd rather render a slot's raw nodes yourself, they are still on the payload at `getContentfulComponent().slots` (a `Record<string, PortableRenderNode[]>`) — hand them to `NodesRenderer`.
|
|
246
243
|
|
|
247
|
-
For the full getting-started walkthrough,
|
|
244
|
+
For the full getting-started walkthrough, merge-precedence rules, and design rationale, see the [root README](../../README.md) and [`AGENTS.md`](../../AGENTS.md).
|
|
248
245
|
|
|
249
246
|
---
|
|
250
247
|
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
* Client Experience renderer.
|
|
3
|
-
*
|
|
4
|
-
* `useActiveViewport` takes over via `window.matchMedia` and re-renders
|
|
5
|
-
* when the viewport changes.
|
|
6
|
-
*
|
|
7
|
-
* Safe to render on the server: `useActiveViewport` no-ops outside the
|
|
8
|
-
* browser, so SSR output matches `<ServerExperienceRenderer>` given the
|
|
9
|
-
* same seed.
|
|
2
|
+
* Client Experience renderer. It renders the resolved plan directly, with no
|
|
3
|
+
* browser-only design-property work.
|
|
10
4
|
-->
|
|
11
5
|
<script lang="ts">
|
|
12
|
-
import type { ExperienceContext
|
|
6
|
+
import type { ExperienceContext } from '@contentful/experiences-sdk-core';
|
|
13
7
|
|
|
14
8
|
import ComponentError from './ComponentError.svelte';
|
|
15
9
|
import DebugExperience from './DebugExperience.svelte';
|
|
@@ -18,25 +12,15 @@
|
|
|
18
12
|
import type { ClientExperienceRendererProps } from './component-props.js';
|
|
19
13
|
import { setExperience } from './context.js';
|
|
20
14
|
import type { RenderContext } from './types.js';
|
|
21
|
-
import { useActiveViewport } from './use-active-viewport.svelte.js';
|
|
22
15
|
|
|
23
16
|
const DEFAULT_CONTEXT: ExperienceContext = {
|
|
24
17
|
debug: false,
|
|
25
18
|
metadata: {},
|
|
26
|
-
viewports: [],
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const FALLBACK_VIEWPORT: ViewportDef = {
|
|
30
|
-
id: '_',
|
|
31
|
-
query: '*',
|
|
32
|
-
displayName: 'Default',
|
|
33
|
-
previewSize: '100%',
|
|
34
19
|
};
|
|
35
20
|
|
|
36
21
|
let {
|
|
37
22
|
experience,
|
|
38
23
|
config,
|
|
39
|
-
initialViewportId,
|
|
40
24
|
metadata,
|
|
41
25
|
debug,
|
|
42
26
|
renderUnknown = MissingComponent,
|
|
@@ -70,15 +54,8 @@
|
|
|
70
54
|
});
|
|
71
55
|
}
|
|
72
56
|
|
|
73
|
-
const viewports = $derived(experience?.viewports ?? []);
|
|
74
|
-
// Seed from the plan so first paint matches the server renderer.
|
|
75
|
-
const seedViewportId = $derived(
|
|
76
|
-
initialViewportId ?? experience?.viewports[experience.fallbackViewportIndex]?.id
|
|
77
|
-
);
|
|
78
|
-
const tracker = useActiveViewport(viewports, seedViewportId);
|
|
79
|
-
|
|
80
57
|
// A $state-backed mirror so descendants reading getExperience() stay
|
|
81
|
-
// reactive
|
|
58
|
+
// reactive when the plan or rendering options change.
|
|
82
59
|
const liveContext = $state<RenderContext>({
|
|
83
60
|
...DEFAULT_CONTEXT,
|
|
84
61
|
debug: debug ?? experience?.debug ?? false,
|
|
@@ -87,21 +64,12 @@
|
|
|
87
64
|
...(experience?.metadata ?? {}),
|
|
88
65
|
...(metadata ?? {}),
|
|
89
66
|
},
|
|
90
|
-
viewports: experience?.viewports ?? [],
|
|
91
|
-
activeViewport: experience?.viewports[0] ?? FALLBACK_VIEWPORT,
|
|
92
|
-
activeViewportIndex: 0,
|
|
93
|
-
fallbackViewportIndex: experience?.fallbackViewportIndex ?? 0,
|
|
94
67
|
});
|
|
95
68
|
|
|
96
69
|
setExperience(liveContext);
|
|
97
70
|
|
|
98
71
|
$effect(() => {
|
|
99
72
|
if (!experience) return;
|
|
100
|
-
const idx = tracker.activeViewportIndex;
|
|
101
|
-
liveContext.viewports = experience.viewports;
|
|
102
|
-
liveContext.activeViewport = experience.viewports[idx] ?? FALLBACK_VIEWPORT;
|
|
103
|
-
liveContext.activeViewportIndex = idx;
|
|
104
|
-
liveContext.fallbackViewportIndex = experience.fallbackViewportIndex;
|
|
105
73
|
liveContext.debug = resolvedDebug;
|
|
106
74
|
liveContext.metadata = {
|
|
107
75
|
...DEFAULT_CONTEXT.metadata,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClientExperienceRenderer.svelte.d.ts","sourceRoot":"","sources":["../src/ClientExperienceRenderer.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ClientExperienceRenderer.svelte.d.ts","sourceRoot":"","sources":["../src/ClientExperienceRenderer.svelte.ts"],"names":[],"mappings":"AAoGA,QAAA,MAAM,wBAAwB,kGAAwC,CAAC;AACvE,KAAK,wBAAwB,GAAG,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC5E,eAAe,wBAAwB,CAAC"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
* First-party debug panel. Renders the resolved Experience plan as pretty
|
|
3
3
|
* JSON so a customer can see exactly what the SDK interpreted from the payload
|
|
4
|
-
* — node tree, registrations, resolved props
|
|
4
|
+
* — node tree, registrations, and resolved props.
|
|
5
5
|
*
|
|
6
6
|
* Two ways to use it:
|
|
7
7
|
* - Auto-mounted by the renderers when `debug` is on (above the tree).
|
|
8
8
|
* - Mounted manually anywhere: `<DebugExperience experience={plan} />`.
|
|
9
9
|
*
|
|
10
10
|
* v1 is just the JSON dump wrapped in a native <details> so it collapses
|
|
11
|
-
* without any extra JS. Room to grow into a node-tree explorer
|
|
12
|
-
*
|
|
11
|
+
* without any extra JS. Room to grow into a node-tree explorer and resolveData
|
|
12
|
+
* timing panel — kept deliberately small for now.
|
|
13
13
|
-->
|
|
14
14
|
<script lang="ts">
|
|
15
15
|
import type { DebugExperienceProps } from './component-props.js';
|
|
@@ -3,8 +3,6 @@ import { describe, expect, it } from 'vitest';
|
|
|
3
3
|
import DebugExperience from './DebugExperience.svelte';
|
|
4
4
|
const emptyPlan = {
|
|
5
5
|
nodes: [],
|
|
6
|
-
viewports: [],
|
|
7
|
-
fallbackViewportIndex: 0,
|
|
8
6
|
metadata: {},
|
|
9
7
|
debug: false,
|
|
10
8
|
diagnostics: [],
|
|
@@ -40,9 +38,7 @@ describe('DebugExperience.svelte', () => {
|
|
|
40
38
|
const { container: zero } = render(DebugExperience, { props: { experience: emptyPlan } });
|
|
41
39
|
expect(zero.innerHTML).toContain('Experience debug — 0 top-level nodes');
|
|
42
40
|
const one = {
|
|
43
|
-
viewports: [],
|
|
44
41
|
nodes: [node('button')],
|
|
45
|
-
fallbackViewportIndex: 0,
|
|
46
42
|
metadata: {},
|
|
47
43
|
debug: false,
|
|
48
44
|
diagnostics: [],
|
|
@@ -52,9 +48,7 @@ describe('DebugExperience.svelte', () => {
|
|
|
52
48
|
});
|
|
53
49
|
it('names experienceTemplate nodes in the summary', () => {
|
|
54
50
|
const plan = {
|
|
55
|
-
viewports: [],
|
|
56
51
|
nodes: [templateNode('page')],
|
|
57
|
-
fallbackViewportIndex: 0,
|
|
58
52
|
metadata: {},
|
|
59
53
|
debug: false,
|
|
60
54
|
diagnostics: [],
|
|
@@ -64,9 +58,7 @@ describe('DebugExperience.svelte', () => {
|
|
|
64
58
|
});
|
|
65
59
|
it('omits the experience-template summary for a composite experience', () => {
|
|
66
60
|
const plan = {
|
|
67
|
-
viewports: [],
|
|
68
61
|
nodes: [node('button'), node('text')],
|
|
69
|
-
fallbackViewportIndex: 0,
|
|
70
62
|
metadata: {},
|
|
71
63
|
debug: false,
|
|
72
64
|
diagnostics: [],
|
|
@@ -77,9 +69,7 @@ describe('DebugExperience.svelte', () => {
|
|
|
77
69
|
});
|
|
78
70
|
it('dumps the plan as pretty JSON', () => {
|
|
79
71
|
const plan = {
|
|
80
|
-
viewports: [],
|
|
81
72
|
nodes: [node('button', { label: 'Go' })],
|
|
82
|
-
fallbackViewportIndex: 0,
|
|
83
73
|
metadata: {},
|
|
84
74
|
debug: false,
|
|
85
75
|
diagnostics: [],
|
|
@@ -93,9 +83,7 @@ describe('DebugExperience.svelte', () => {
|
|
|
93
83
|
const n = node('button');
|
|
94
84
|
n.props.resolved = { self: n.props };
|
|
95
85
|
const plan = {
|
|
96
|
-
viewports: [],
|
|
97
86
|
nodes: [n],
|
|
98
|
-
fallbackViewportIndex: 0,
|
|
99
87
|
metadata: {},
|
|
100
88
|
debug: false,
|
|
101
89
|
diagnostics: [],
|
|
@@ -117,9 +105,7 @@ describe('DebugExperience.svelte', () => {
|
|
|
117
105
|
},
|
|
118
106
|
});
|
|
119
107
|
const plan = {
|
|
120
|
-
viewports: [],
|
|
121
108
|
nodes: [n],
|
|
122
|
-
fallbackViewportIndex: 0,
|
|
123
109
|
metadata: {},
|
|
124
110
|
debug: false,
|
|
125
111
|
diagnostics: [],
|
package/dist/NodeRenderer.svelte
CHANGED
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
import type { Snippet } from 'svelte';
|
|
13
13
|
|
|
14
14
|
import type { PortableRenderNode } from '@contentful/experiences-sdk-core';
|
|
15
|
-
import { selectResolvedDesign } from '@contentful/experiences-design';
|
|
16
15
|
|
|
17
16
|
import {
|
|
18
17
|
setContentfulComponent,
|
|
@@ -58,7 +57,7 @@
|
|
|
58
57
|
const isExperienceTemplate = kind === 'experienceTemplate';
|
|
59
58
|
|
|
60
59
|
// Any reactive re-run of this component's `$derived`/`{@const}` blocks
|
|
61
|
-
//
|
|
60
|
+
// would otherwise re-report the same
|
|
62
61
|
// diagnostic every time — matches Angular's `lastDiagnostics` guard in
|
|
63
62
|
// NodeRenderEngine and React's equivalent in NodeRenderer. `reported` is a
|
|
64
63
|
// plain (non-reactive) binding, stable for this component instance's
|
|
@@ -102,21 +101,7 @@
|
|
|
102
101
|
setContentfulComponent(contentful);
|
|
103
102
|
}
|
|
104
103
|
|
|
105
|
-
const tokenResolvedDesign = $derived.
|
|
106
|
-
const { props, unresolved } = selectResolvedDesign(
|
|
107
|
-
node.props,
|
|
108
|
-
experience.viewports,
|
|
109
|
-
experience.activeViewportIndex,
|
|
110
|
-
experience.fallbackViewportIndex,
|
|
111
|
-
config.resolveToken
|
|
112
|
-
);
|
|
113
|
-
if (unresolved.length && typeof console !== 'undefined') {
|
|
114
|
-
console.warn(
|
|
115
|
-
`[@contentful/experiences-svelte] resolveToken returned undefined for token id(s) on ${kind} "${id}": ${unresolved.join(', ')}. getDesignValues() will omit those keys.`
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
return props;
|
|
119
|
-
});
|
|
104
|
+
const tokenResolvedDesign = $derived(node.props.design);
|
|
120
105
|
|
|
121
106
|
setResolvedDesign(() => tokenResolvedDesign);
|
|
122
107
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeRenderer.svelte.d.ts","sourceRoot":"","sources":["../src/NodeRenderer.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"NodeRenderer.svelte.d.ts","sourceRoot":"","sources":["../src/NodeRenderer.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAO3E,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAKH,KAAK,MAAM,EACX,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAGpB,UAAU,iBAAiB;IACzB,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,aAAa,CAAC;IAC1B,aAAa,EAAE,aAAa,CAAC;IAC7B,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,EAAE,kBAAkB,CAAC;IACjC;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;CACzC;AAiJH,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* for that documented, proven gap. Both `ServerExperienceRenderer` and
|
|
6
6
|
* `ClientExperienceRenderer` share the same `NodesRenderer`/`NodeRenderer`
|
|
7
7
|
* boundary code, so both are exercised — the distinction between the two
|
|
8
|
-
* components is about
|
|
8
|
+
* components is about client-side reactivity, not error handling.
|
|
9
9
|
*/
|
|
10
10
|
import { render } from '@testing-library/svelte';
|
|
11
11
|
import { describe, expect, it, vi } from 'vitest';
|
|
@@ -20,7 +20,6 @@ import ClientExperienceRenderer from './ClientExperienceRenderer.svelte';
|
|
|
20
20
|
import ServerExperienceRenderer from './ServerExperienceRenderer.svelte';
|
|
21
21
|
import BrokenFixture from './test-fixtures/BrokenFixture.svelte';
|
|
22
22
|
import ButtonFixture from './test-fixtures/ButtonFixture.svelte';
|
|
23
|
-
const VIEWPORTS = [{ id: 'desktop', query: '*', displayName: 'Desktop', previewSize: '100%' }];
|
|
24
23
|
function componentNode(typeId, rest = {}) {
|
|
25
24
|
return {
|
|
26
25
|
component: {
|
|
@@ -41,7 +40,6 @@ describe.each([
|
|
|
41
40
|
const warn = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
42
41
|
try {
|
|
43
42
|
const payload = {
|
|
44
|
-
viewports: VIEWPORTS,
|
|
45
43
|
nodes: [
|
|
46
44
|
componentNode('broken', { id: 'b' }),
|
|
47
45
|
componentNode('contentful-button', { id: 'f', contentProperties: { label: 'sibling' } }),
|
|
@@ -81,7 +79,6 @@ describe.each([
|
|
|
81
79
|
const warn = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
82
80
|
try {
|
|
83
81
|
const payload = {
|
|
84
|
-
viewports: VIEWPORTS,
|
|
85
82
|
nodes: [componentNode('broken', { id: 'b' })],
|
|
86
83
|
};
|
|
87
84
|
const config = { components: { broken: BrokenFixture } };
|
|
@@ -102,7 +99,6 @@ describe('ClientExperienceRenderer — render-time diagnostics dedupe across re-
|
|
|
102
99
|
const warn = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
103
100
|
try {
|
|
104
101
|
const payload = {
|
|
105
|
-
viewports: VIEWPORTS,
|
|
106
102
|
nodes: [componentNode('missing', { id: 'm' })],
|
|
107
103
|
};
|
|
108
104
|
const config = { components: {} };
|
|
@@ -111,7 +107,7 @@ describe('ClientExperienceRenderer — render-time diagnostics dedupe across re-
|
|
|
111
107
|
props: { experience: plan, config, debug: true },
|
|
112
108
|
});
|
|
113
109
|
// Force NodeRenderer's reactive blocks to re-run without any real new
|
|
114
|
-
// occurrence — an ancestor re-render (
|
|
110
|
+
// occurrence — an ancestor re-render (an unrelated
|
|
115
111
|
// parent update) does the same thing in production.
|
|
116
112
|
await rerender({ experience: plan, config, debug: true });
|
|
117
113
|
expect(container.querySelectorAll('[data-experiences-debug-errors] li')).toHaveLength(1);
|
|
@@ -17,8 +17,7 @@
|
|
|
17
17
|
* The Experience runtime context and the raw Contentful payload are read
|
|
18
18
|
* via `getExperience` / `getContentfulComponent`.
|
|
19
19
|
*
|
|
20
|
-
* Server
|
|
21
|
-
* the active viewport is sourced (initial seed vs reactive matchMedia).
|
|
20
|
+
* Server and client renderers share this component.
|
|
22
21
|
-->
|
|
23
22
|
<script lang="ts">
|
|
24
23
|
import type { Snippet } from 'svelte';
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
* Server-safe Experience renderer.
|
|
3
|
-
* `initialViewportId` (typically derived from User-Agent on the request)
|
|
4
|
-
* and renders without any reactive subscription. SSR-friendly.
|
|
2
|
+
* Server-safe Experience renderer. It renders the resolved plan directly.
|
|
5
3
|
*
|
|
6
4
|
* SSR + interactive editor mode are mutually exclusive — the message-event
|
|
7
5
|
* preview client requires window listeners and lives only in the client
|
|
8
6
|
* renderer. For editor mode, render the client variant on a hydrated route.
|
|
9
7
|
-->
|
|
10
8
|
<script lang="ts">
|
|
11
|
-
import type { ExperienceContext
|
|
12
|
-
import { getViewportIndex } from '@contentful/experiences-design';
|
|
9
|
+
import type { ExperienceContext } from '@contentful/experiences-sdk-core';
|
|
13
10
|
|
|
14
11
|
import ComponentError from './ComponentError.svelte';
|
|
15
12
|
import DebugExperience from './DebugExperience.svelte';
|
|
@@ -22,20 +19,11 @@
|
|
|
22
19
|
const DEFAULT_CONTEXT: ExperienceContext = {
|
|
23
20
|
debug: false,
|
|
24
21
|
metadata: {},
|
|
25
|
-
viewports: [],
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const FALLBACK_VIEWPORT: ViewportDef = {
|
|
29
|
-
id: '_',
|
|
30
|
-
query: '*',
|
|
31
|
-
displayName: 'Default',
|
|
32
|
-
previewSize: '100%',
|
|
33
22
|
};
|
|
34
23
|
|
|
35
24
|
let {
|
|
36
25
|
experience,
|
|
37
26
|
config,
|
|
38
|
-
initialViewportId,
|
|
39
27
|
metadata,
|
|
40
28
|
debug,
|
|
41
29
|
renderUnknown = MissingComponent,
|
|
@@ -46,13 +34,6 @@
|
|
|
46
34
|
const resolvedDebug = $derived(debug ?? experience?.debug ?? false);
|
|
47
35
|
|
|
48
36
|
function buildContext(): RenderContext {
|
|
49
|
-
const viewports = experience?.viewports ?? [];
|
|
50
|
-
// Default to the pre-resolved viewport so first paint needs no recompute.
|
|
51
|
-
const idx = !experience
|
|
52
|
-
? 0
|
|
53
|
-
: initialViewportId === undefined
|
|
54
|
-
? experience.fallbackViewportIndex
|
|
55
|
-
: getViewportIndex(experience.viewports, initialViewportId);
|
|
56
37
|
return {
|
|
57
38
|
...DEFAULT_CONTEXT,
|
|
58
39
|
debug: resolvedDebug,
|
|
@@ -61,10 +42,6 @@
|
|
|
61
42
|
...(experience?.metadata ?? {}),
|
|
62
43
|
...(metadata ?? {}),
|
|
63
44
|
},
|
|
64
|
-
viewports,
|
|
65
|
-
activeViewport: experience?.viewports[idx] ?? FALLBACK_VIEWPORT,
|
|
66
|
-
activeViewportIndex: idx,
|
|
67
|
-
fallbackViewportIndex: experience?.fallbackViewportIndex ?? 0,
|
|
68
45
|
};
|
|
69
46
|
}
|
|
70
47
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServerExperienceRenderer.svelte.d.ts","sourceRoot":"","sources":["../src/ServerExperienceRenderer.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ServerExperienceRenderer.svelte.d.ts","sourceRoot":"","sources":["../src/ServerExperienceRenderer.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAqE1E,QAAA,MAAM,wBAAwB,mEAAwC,CAAC;AACvE,KAAK,wBAAwB,GAAG,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC5E,eAAe,wBAAwB,CAAC"}
|
|
@@ -4,7 +4,6 @@ import type { Config } from './types.js';
|
|
|
4
4
|
export interface ServerExperienceRendererProps {
|
|
5
5
|
experience: PortableRenderPlan | null | undefined;
|
|
6
6
|
config: Config;
|
|
7
|
-
initialViewportId?: string;
|
|
8
7
|
/** Shallow-merges over the plan's `metadata`. Only needed to override it. */
|
|
9
8
|
metadata?: Record<string, unknown>;
|
|
10
9
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-props.d.ts","sourceRoot":"","sources":["../src/component-props.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAE3E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,WAAW,6BAA6B;IAC5C,UAAU,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,
|
|
1
|
+
{"version":3,"file":"component-props.d.ts","sourceRoot":"","sources":["../src/component-props.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAE3E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,WAAW,6BAA6B;IAC5C,UAAU,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,yEAAyE;IACzE,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,MAAM,MAAM,6BAA6B,GAAG,6BAA6B,CAAC;AAE1E,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC,qBAAqB,CAAC,CAAC;AAE7D,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,WAAW,GAAG,SAAS,CAAC,mBAAmB,CAAC,CAAC;AAEzD;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;AAExD,MAAM,WAAW,oBAAoB;IACnC,+EAA+E;IAC/E,UAAU,EAAE,kBAAkB,CAAC;IAC/B,oEAAoE;IACpE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CAClB"}
|
package/dist/context.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare function setContentfulExperienceTemplate(tpl: ContentfulExperienc
|
|
|
5
5
|
/**
|
|
6
6
|
* Publish the resolved design values for the enclosing node or experience template. Takes a
|
|
7
7
|
* getter (not a snapshot) so callers reading it inside a `$derived` stay
|
|
8
|
-
* reactive across
|
|
8
|
+
* reactive across plan changes.
|
|
9
9
|
*/
|
|
10
10
|
export declare function setResolvedDesign(getDesign: () => Record<string, unknown>): void;
|
|
11
11
|
export declare function getExperience(): RenderContext;
|
package/dist/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,4BAA4B,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AASnG,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAEtD;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAEtE;AAED,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,4BAA4B,GAAG,IAAI,CAEvF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAEhF;AAED,wBAAgB,aAAa,IAAI,aAAa,CAQ7C;AAED,wBAAgB,sBAAsB,IAAI,mBAAmB,GAAG,SAAS,CAExE;AAED,wBAAgB,+BAA+B,IAAI,4BAA4B,GAAG,SAAS,CAE1F;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAGvE"}
|
package/dist/context.js
CHANGED
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
* the helper from the top of its `<script>` block.
|
|
7
7
|
*
|
|
8
8
|
* Reactivity: the client renderer stores a `$state` proxy in context, so
|
|
9
|
-
* reads through the returned object
|
|
10
|
-
* template or a `$derived`) stay reactive across viewport changes.
|
|
9
|
+
* reads through the returned object stay reactive across plan changes.
|
|
11
10
|
* Destructuring the return of `getExperience()` loses that reactivity —
|
|
12
11
|
* same rule as Svelte 5 `$props()`.
|
|
13
12
|
*
|
|
@@ -32,7 +31,7 @@ export function setContentfulExperienceTemplate(tpl) {
|
|
|
32
31
|
/**
|
|
33
32
|
* Publish the resolved design values for the enclosing node or experience template. Takes a
|
|
34
33
|
* getter (not a snapshot) so callers reading it inside a `$derived` stay
|
|
35
|
-
* reactive across
|
|
34
|
+
* reactive across plan changes.
|
|
36
35
|
*/
|
|
37
36
|
export function setResolvedDesign(getDesign) {
|
|
38
37
|
setContext(RESOLVED_DESIGN_KEY, getDesign);
|
|
@@ -16,7 +16,6 @@ import { render } from 'svelte/server';
|
|
|
16
16
|
import { resolveExperience } from '@contentful/experiences-sdk-core';
|
|
17
17
|
import ServerExperienceRenderer from './ServerExperienceRenderer.svelte';
|
|
18
18
|
import ButtonFixture from './test-fixtures/ButtonFixture.svelte';
|
|
19
|
-
const VIEWPORTS = [{ id: 'desktop', query: '*', displayName: 'Desktop', previewSize: '100%' }];
|
|
20
19
|
function componentNode(typeId, rest = {}) {
|
|
21
20
|
return {
|
|
22
21
|
component: {
|
|
@@ -34,7 +33,6 @@ describe('debug panel — true SSR coverage of a resolve-time diagnostic', () =>
|
|
|
34
33
|
const warn = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
35
34
|
try {
|
|
36
35
|
const payload = {
|
|
37
|
-
viewports: VIEWPORTS,
|
|
38
36
|
nodes: [
|
|
39
37
|
componentNode('button', {
|
|
40
38
|
id: 'b',
|