@contentful/experiences-react 0.7.4 → 0.7.6
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 +5 -5
- package/dist/client-renderer.js +4 -14
- package/dist/client-renderer.js.map +1 -1
- package/dist/context.d.ts +6 -5
- package/dist/context.js.map +1 -1
- package/dist/debug-experience.js +2 -1
- package/dist/debug-experience.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +0 -6
- package/dist/index.js.map +1 -1
- package/dist/nodes-renderer.d.ts +2 -17
- package/dist/nodes-renderer.js +34 -61
- package/dist/nodes-renderer.js.map +1 -1
- package/dist/server-renderer.js +4 -14
- package/dist/server-renderer.js.map +1 -1
- package/dist/types.d.ts +15 -13
- package/dist/types.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
## 0.7.6 (2026-08-12)
|
|
2
|
+
|
|
3
|
+
### 🩹 Fixes
|
|
4
|
+
|
|
5
|
+
- **core,adapters:** render Experience Templates as ordinary nodes [AIS-413] ([#133](https://github.com/contentful/experiences/pull/133))
|
|
6
|
+
|
|
7
|
+
### 🧱 Updated Dependencies
|
|
8
|
+
|
|
9
|
+
- Updated client to 0.3.5
|
|
10
|
+
- Updated design to 0.7.5
|
|
11
|
+
- Updated core to 0.7.5
|
|
12
|
+
|
|
13
|
+
## 0.7.5 (2026-08-11)
|
|
14
|
+
|
|
15
|
+
### 🚀 Features
|
|
16
|
+
|
|
17
|
+
- stop sending the alpha-feature header manually ([#131](https://github.com/contentful/experiences/pull/131))
|
|
18
|
+
|
|
19
|
+
### 🧱 Updated Dependencies
|
|
20
|
+
|
|
21
|
+
- Updated client to 0.3.4
|
|
22
|
+
- Updated design to 0.7.4
|
|
23
|
+
- Updated core to 0.7.4
|
|
24
|
+
|
|
1
25
|
## 0.7.4 (2026-08-11)
|
|
2
26
|
|
|
3
27
|
### 🧱 Updated Dependencies
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ This is the **only SDK package you install**. It re-exports everything you need
|
|
|
18
18
|
|
|
19
19
|
```ts
|
|
20
20
|
defineComponent<Props>(config); // Type-narrowing identity for component-type configs
|
|
21
|
-
defineExperienceTemplate<Props>(config); // Same shape, for
|
|
21
|
+
defineExperienceTemplate<Props>(config); // Same shape, for coded Experience Template configs
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
### Fetching
|
|
@@ -54,7 +54,7 @@ useDesignValues<T>(); // Optional hook: the same resolved design record that aut
|
|
|
54
54
|
toCss(design, options?); // Turns a design record into CSSProperties, keeping only real CSS keys
|
|
55
55
|
useExperience(); // RenderContext: debug, metadata, viewports, activeViewport
|
|
56
56
|
useContentfulComponent(); // Raw payload for the enclosing node (or null)
|
|
57
|
-
useContentfulExperienceTemplate(); // Same, for
|
|
57
|
+
useContentfulExperienceTemplate(); // Same, for an enclosing coded Experience Template node
|
|
58
58
|
type ToCssOptions;
|
|
59
59
|
```
|
|
60
60
|
|
|
@@ -69,7 +69,7 @@ type ComponentConfig, ExperienceTemplateConfig,
|
|
|
69
69
|
type ContentfulComponent, ContentfulExperienceTemplate,
|
|
70
70
|
type RenderContext, ResolveToken,
|
|
71
71
|
type ExperiencePayload, ExperienceNode, ComponentNode, ExperienceTemplateNode,
|
|
72
|
-
type PortableRenderPlan, PortableRenderNode,
|
|
72
|
+
type PortableRenderPlan, PortableRenderNode, PortableRegistration,
|
|
73
73
|
type DesignPropValue, ManualDesignValue, DesignToken, ValuesByViewport,
|
|
74
74
|
type ViewportDef, ExperienceContext, ResolveContext,
|
|
75
75
|
type ResolverConfig, ResolveExperienceOptions
|
|
@@ -141,7 +141,7 @@ return <ServerExperienceRenderer experience={experience} config={experienceConfi
|
|
|
141
141
|
|
|
142
142
|
### Slot children
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
Every slot arrives as a prop named after the slot, holding an **array of pre-rendered nodes** (`ReactNode[]`) keyed by the renderer — not a single wrapping node. Drop the array straight into JSX for the common "just render them" case (React renders keyed arrays), or `map` / `filter` over it to wrap, reorder, or drop children individually.
|
|
145
145
|
|
|
146
146
|
```tsx
|
|
147
147
|
// components/Section.tsx
|
|
@@ -162,7 +162,7 @@ export function Section({ children }: { children?: ReactNode[] }) {
|
|
|
162
162
|
}
|
|
163
163
|
```
|
|
164
164
|
|
|
165
|
-
|
|
165
|
+
`children` is not special — it is simply the conventional name for the default slot. **Every** slot is merged into props under its own name, each as its own `ReactNode[]`, so a component with a `header` slot just declares `header?: ReactNode[]` and renders it the same way. This applies identically to coded Experience Templates: a template with a `content` slot receives a `content` prop.
|
|
166
166
|
|
|
167
167
|
For the full getting-started walkthrough, the merge-precedence rules, viewport handling, and design rationale, see the [root README](../../README.md) and [`AGENTS.md`](../../AGENTS.md).
|
|
168
168
|
|
package/dist/client-renderer.js
CHANGED
|
@@ -3,7 +3,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { DebugExperience } from "./debug-experience";
|
|
4
4
|
import { ExperienceProvider } from "./context";
|
|
5
5
|
import { MissingComponent } from "./missing-component";
|
|
6
|
-
import { NodesRenderer
|
|
6
|
+
import { NodesRenderer } from "./nodes-renderer";
|
|
7
7
|
import { useActiveViewport } from "./use-active-viewport";
|
|
8
8
|
const DEFAULT_CONTEXT = {
|
|
9
9
|
debug: false,
|
|
@@ -39,24 +39,14 @@ function ClientExperienceRenderer({
|
|
|
39
39
|
return /* @__PURE__ */ jsxs(ExperienceProvider, { value: renderContext, children: [
|
|
40
40
|
debug ? /* @__PURE__ */ jsx(DebugExperience, { experience }) : null,
|
|
41
41
|
/* @__PURE__ */ jsx(
|
|
42
|
-
|
|
42
|
+
NodesRenderer,
|
|
43
43
|
{
|
|
44
|
-
|
|
44
|
+
nodes: experience.nodes,
|
|
45
45
|
config,
|
|
46
46
|
viewports: experience.viewports,
|
|
47
47
|
activeViewportIndex,
|
|
48
48
|
fallbackViewportIndex: experience.fallbackViewportIndex,
|
|
49
|
-
|
|
50
|
-
NodesRenderer,
|
|
51
|
-
{
|
|
52
|
-
nodes: experience.nodes,
|
|
53
|
-
config,
|
|
54
|
-
viewports: experience.viewports,
|
|
55
|
-
activeViewportIndex,
|
|
56
|
-
fallbackViewportIndex: experience.fallbackViewportIndex,
|
|
57
|
-
renderUnknown
|
|
58
|
-
}
|
|
59
|
-
)
|
|
49
|
+
renderUnknown
|
|
60
50
|
}
|
|
61
51
|
)
|
|
62
52
|
] });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client-renderer.tsx"],"sourcesContent":["/*\n * Client Experience renderer. First paint matches the server renderer; after\n * hydration `useActiveViewport` takes over via `matchMedia`. Server-safe: the\n * hook returns the seeded index and registers no listeners when there's no\n * window, so SSR output matches `<ServerExperienceRenderer>`.\n */\n\n'use client';\n\nimport type { ReactNode } from 'react';\n\nimport type {\n ExperienceContext,\n PortableRenderPlan,\n ViewportDef,\n} from '@contentful/experiences-sdk-core';\n\nimport { DebugExperience } from './debug-experience';\nimport { ExperienceProvider } from './context';\nimport { MissingComponent } from './missing-component';\nimport { NodesRenderer,
|
|
1
|
+
{"version":3,"sources":["../src/client-renderer.tsx"],"sourcesContent":["/*\n * Client Experience renderer. First paint matches the server renderer; after\n * hydration `useActiveViewport` takes over via `matchMedia`. Server-safe: the\n * hook returns the seeded index and registers no listeners when there's no\n * window, so SSR output matches `<ServerExperienceRenderer>`.\n */\n\n'use client';\n\nimport type { ReactNode } from 'react';\n\nimport type {\n ExperienceContext,\n PortableRenderPlan,\n ViewportDef,\n} from '@contentful/experiences-sdk-core';\n\nimport { DebugExperience } from './debug-experience';\nimport { ExperienceProvider } from './context';\nimport { MissingComponent } from './missing-component';\nimport { NodesRenderer, type RenderUnknown } from './nodes-renderer';\nimport type { Config, RenderContext } from './types';\nimport { useActiveViewport } from './use-active-viewport';\n\nconst DEFAULT_CONTEXT: ExperienceContext = {\n debug: false,\n metadata: {},\n viewports: [],\n};\n\nconst FALLBACK_VIEWPORT: ViewportDef = {\n id: '_',\n query: '*',\n displayName: 'Default',\n previewSize: '100%',\n};\n\nexport interface ClientExperienceRendererProps {\n experience: PortableRenderPlan | null | undefined;\n config: Config;\n /** Initial viewport seed; should match what the server-rendered output used. */\n initialViewportId?: string;\n /**\n * Arbitrary per-render metadata, readable by descendants via\n * `useExperience()` and by resolvers via `ctx.experience.metadata`.\n */\n metadata?: Record<string, unknown>;\n /**\n * Observability switch. When on: renders the visible missing-component box,\n * turns the default `renderUnknown` fallback into the debug component, and\n * auto-mounts `<DebugExperience>` after the tree.\n */\n debug?: boolean;\n renderUnknown?: RenderUnknown;\n}\n\nexport function ClientExperienceRenderer({\n experience,\n config,\n initialViewportId,\n metadata,\n debug = false,\n renderUnknown = MissingComponent,\n}: ClientExperienceRendererProps): ReactNode {\n if (!experience) return null;\n const { activeViewportIndex } = useActiveViewport(experience.viewports, initialViewportId);\n // Copy so the context shares no object identity with the plan arrays — see\n // the note in `server-renderer.tsx`.\n const contextViewports = experience.viewports.map((v) => ({ ...v }));\n const activeViewport = { ...(experience.viewports[activeViewportIndex] ?? FALLBACK_VIEWPORT) };\n\n const renderContext: RenderContext = {\n ...DEFAULT_CONTEXT,\n debug,\n metadata: { ...DEFAULT_CONTEXT.metadata, ...(metadata ?? {}) },\n viewports: contextViewports,\n activeViewport,\n activeViewportIndex,\n };\n\n return (\n <ExperienceProvider value={renderContext}>\n {debug ? <DebugExperience experience={experience} /> : null}\n <NodesRenderer\n nodes={experience.nodes}\n config={config}\n viewports={experience.viewports}\n activeViewportIndex={activeViewportIndex}\n fallbackViewportIndex={experience.fallbackViewportIndex}\n renderUnknown={renderUnknown}\n />\n </ExperienceProvider>\n );\n}\n"],"mappings":";AAiFI,SACW,KADX;AAhEJ,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AACjC,SAAS,qBAAyC;AAElD,SAAS,yBAAyB;AAElC,MAAM,kBAAqC;AAAA,EACzC,OAAO;AAAA,EACP,UAAU,CAAC;AAAA,EACX,WAAW,CAAC;AACd;AAEA,MAAM,oBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,aAAa;AAAA,EACb,aAAa;AACf;AAqBO,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,gBAAgB;AAClB,GAA6C;AAC3C,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,EAAE,oBAAoB,IAAI,kBAAkB,WAAW,WAAW,iBAAiB;AAGzF,QAAM,mBAAmB,WAAW,UAAU,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE;AACnE,QAAM,iBAAiB,EAAE,GAAI,WAAW,UAAU,mBAAmB,KAAK,kBAAmB;AAE7F,QAAM,gBAA+B;AAAA,IACnC,GAAG;AAAA,IACH;AAAA,IACA,UAAU,EAAE,GAAG,gBAAgB,UAAU,GAAI,YAAY,CAAC,EAAG;AAAA,IAC7D,WAAW;AAAA,IACX;AAAA,IACA;AAAA,EACF;AAEA,SACE,qBAAC,sBAAmB,OAAO,eACxB;AAAA,YAAQ,oBAAC,mBAAgB,YAAwB,IAAK;AAAA,IACvD;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,WAAW;AAAA,QAClB;AAAA,QACA,WAAW,WAAW;AAAA,QACtB;AAAA,QACA,uBAAuB,WAAW;AAAA,QAClC;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":[]}
|
package/dist/context.d.ts
CHANGED
|
@@ -25,14 +25,15 @@ declare function ResolvedDesignProvider({ value, children, }: {
|
|
|
25
25
|
*/
|
|
26
26
|
declare function useExperience(): RenderContext;
|
|
27
27
|
/**
|
|
28
|
-
* Read the raw Contentful payload for the nearest enclosing
|
|
29
|
-
* Returns `null` outside any rendered node
|
|
30
|
-
*
|
|
28
|
+
* Read the raw Contentful payload for the nearest enclosing *component* node.
|
|
29
|
+
* Returns `null` outside any rendered component node — including inside a coded
|
|
30
|
+
* Experience Template, which publishes `useContentfulExperienceTemplate()`
|
|
31
|
+
* instead.
|
|
31
32
|
*/
|
|
32
33
|
declare function useContentfulComponent(): ContentfulComponent | null;
|
|
33
34
|
/**
|
|
34
|
-
* Read the raw Contentful payload for the
|
|
35
|
-
*
|
|
35
|
+
* Read the raw Contentful payload for the nearest enclosing Experience Template
|
|
36
|
+
* node. Returns `null` outside an Experience Template's render tree.
|
|
36
37
|
*/
|
|
37
38
|
declare function useContentfulExperienceTemplate(): ContentfulExperienceTemplate | null;
|
|
38
39
|
/**
|
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.tsx"],"sourcesContent":["/*\n * React context providers + hooks that expose runtime context and the raw\n * Contentful payload to descendants of a rendered Experience. Customer\n * components receive only their declared props via the renderer; anything\n * that needs the Experience runtime context or the underlying payload calls\n * the hook explicitly at the top of its component body.\n */\n\n'use client';\n\nimport { createContext, useContext, type ReactNode } from 'react';\n\nimport type { ContentfulComponent, ContentfulExperienceTemplate, RenderContext } from './types';\n\nconst ExperienceContext = createContext<RenderContext | null>(null);\nconst ContentfulComponentContext = createContext<ContentfulComponent | null>(null);\nconst ContentfulExperienceTemplateContext = createContext<ContentfulExperienceTemplate | null>(\n null\n);\n// Plain data only (never the Config or its functions) so it crosses RSC cleanly.\nconst ResolvedDesignContext = createContext<Record<string, unknown> | null>(null);\n\n// Wrapped as real client-component functions, not re-exported `Context.Provider`\n// objects — the server renderer imports these across the RSC boundary and\n// Next.js requires a function reference there (\"Element type is invalid\" otherwise).\n\nexport function ExperienceProvider({\n value,\n children,\n}: {\n value: RenderContext;\n children: ReactNode;\n}): ReactNode {\n return <ExperienceContext.Provider value={value}>{children}</ExperienceContext.Provider>;\n}\n\nexport function ContentfulComponentProvider({\n value,\n children,\n}: {\n value: ContentfulComponent;\n children: ReactNode;\n}): ReactNode {\n return (\n <ContentfulComponentContext.Provider value={value}>\n {children}\n </ContentfulComponentContext.Provider>\n );\n}\n\nexport function ContentfulExperienceTemplateProvider({\n value,\n children,\n}: {\n value: ContentfulExperienceTemplate;\n children: ReactNode;\n}): ReactNode {\n return (\n <ContentfulExperienceTemplateContext.Provider value={value}>\n {children}\n </ContentfulExperienceTemplateContext.Provider>\n );\n}\n\nexport function ResolvedDesignProvider({\n value,\n children,\n}: {\n value: Record<string, unknown>;\n children: ReactNode;\n}): ReactNode {\n return <ResolvedDesignContext.Provider value={value}>{children}</ResolvedDesignContext.Provider>;\n}\n\n/**\n * Read the current Experience runtime context — viewports, the active\n * viewport, the `debug` flag, and free-form metadata. Throws when called\n * outside any Experience renderer subtree.\n */\nexport function useExperience(): RenderContext {\n const ctx = useContext(ExperienceContext);\n if (ctx === null) {\n throw new Error(\n 'useExperience() must be called inside a <ServerExperienceRenderer> or <ClientExperienceRenderer> subtree.'\n );\n }\n return ctx;\n}\n\n/**\n * Read the raw Contentful payload for the nearest enclosing
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx"],"sourcesContent":["/*\n * React context providers + hooks that expose runtime context and the raw\n * Contentful payload to descendants of a rendered Experience. Customer\n * components receive only their declared props via the renderer; anything\n * that needs the Experience runtime context or the underlying payload calls\n * the hook explicitly at the top of its component body.\n */\n\n'use client';\n\nimport { createContext, useContext, type ReactNode } from 'react';\n\nimport type { ContentfulComponent, ContentfulExperienceTemplate, RenderContext } from './types';\n\nconst ExperienceContext = createContext<RenderContext | null>(null);\nconst ContentfulComponentContext = createContext<ContentfulComponent | null>(null);\nconst ContentfulExperienceTemplateContext = createContext<ContentfulExperienceTemplate | null>(\n null\n);\n// Plain data only (never the Config or its functions) so it crosses RSC cleanly.\nconst ResolvedDesignContext = createContext<Record<string, unknown> | null>(null);\n\n// Wrapped as real client-component functions, not re-exported `Context.Provider`\n// objects — the server renderer imports these across the RSC boundary and\n// Next.js requires a function reference there (\"Element type is invalid\" otherwise).\n\nexport function ExperienceProvider({\n value,\n children,\n}: {\n value: RenderContext;\n children: ReactNode;\n}): ReactNode {\n return <ExperienceContext.Provider value={value}>{children}</ExperienceContext.Provider>;\n}\n\nexport function ContentfulComponentProvider({\n value,\n children,\n}: {\n value: ContentfulComponent;\n children: ReactNode;\n}): ReactNode {\n return (\n <ContentfulComponentContext.Provider value={value}>\n {children}\n </ContentfulComponentContext.Provider>\n );\n}\n\nexport function ContentfulExperienceTemplateProvider({\n value,\n children,\n}: {\n value: ContentfulExperienceTemplate;\n children: ReactNode;\n}): ReactNode {\n return (\n <ContentfulExperienceTemplateContext.Provider value={value}>\n {children}\n </ContentfulExperienceTemplateContext.Provider>\n );\n}\n\nexport function ResolvedDesignProvider({\n value,\n children,\n}: {\n value: Record<string, unknown>;\n children: ReactNode;\n}): ReactNode {\n return <ResolvedDesignContext.Provider value={value}>{children}</ResolvedDesignContext.Provider>;\n}\n\n/**\n * Read the current Experience runtime context — viewports, the active\n * viewport, the `debug` flag, and free-form metadata. Throws when called\n * outside any Experience renderer subtree.\n */\nexport function useExperience(): RenderContext {\n const ctx = useContext(ExperienceContext);\n if (ctx === null) {\n throw new Error(\n 'useExperience() must be called inside a <ServerExperienceRenderer> or <ClientExperienceRenderer> subtree.'\n );\n }\n return ctx;\n}\n\n/**\n * Read the raw Contentful payload for the nearest enclosing *component* node.\n * Returns `null` outside any rendered component node — including inside a coded\n * Experience Template, which publishes `useContentfulExperienceTemplate()`\n * instead.\n */\nexport function useContentfulComponent(): ContentfulComponent | null {\n return useContext(ContentfulComponentContext);\n}\n\n/**\n * Read the raw Contentful payload for the nearest enclosing Experience Template\n * node. Returns `null` outside an Experience Template's render tree.\n */\nexport function useContentfulExperienceTemplate(): ContentfulExperienceTemplate | null {\n return useContext(ContentfulExperienceTemplateContext);\n}\n\n/**\n * Read the design values the renderer already resolved for the enclosing\n * node or experience template — viewport-cascaded and token-resolved, the same\n * bag that feeds the component's props. Returns `null` outside a rendered\n * node / experience template, which `useDesignValues` treats as \"nothing to read.\"\n */\nexport function useResolvedDesign(): Record<string, unknown> | null {\n return useContext(ResolvedDesignContext);\n}\n"],"mappings":";AAiCS;AAvBT,SAAS,eAAe,kBAAkC;AAI1D,MAAM,oBAAoB,cAAoC,IAAI;AAClE,MAAM,6BAA6B,cAA0C,IAAI;AACjF,MAAM,sCAAsC;AAAA,EAC1C;AACF;AAEA,MAAM,wBAAwB,cAA8C,IAAI;AAMzE,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AACF,GAGc;AACZ,SAAO,oBAAC,kBAAkB,UAAlB,EAA2B,OAAe,UAAS;AAC7D;AAEO,SAAS,4BAA4B;AAAA,EAC1C;AAAA,EACA;AACF,GAGc;AACZ,SACE,oBAAC,2BAA2B,UAA3B,EAAoC,OAClC,UACH;AAEJ;AAEO,SAAS,qCAAqC;AAAA,EACnD;AAAA,EACA;AACF,GAGc;AACZ,SACE,oBAAC,oCAAoC,UAApC,EAA6C,OAC3C,UACH;AAEJ;AAEO,SAAS,uBAAuB;AAAA,EACrC;AAAA,EACA;AACF,GAGc;AACZ,SAAO,oBAAC,sBAAsB,UAAtB,EAA+B,OAAe,UAAS;AACjE;AAOO,SAAS,gBAA+B;AAC7C,QAAM,MAAM,WAAW,iBAAiB;AACxC,MAAI,QAAQ,MAAM;AAChB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAQO,SAAS,yBAAqD;AACnE,SAAO,WAAW,0BAA0B;AAC9C;AAMO,SAAS,kCAAuE;AACrF,SAAO,WAAW,mCAAmC;AACvD;AAQO,SAAS,oBAAoD;AAClE,SAAO,WAAW,qBAAqB;AACzC;","names":[]}
|
package/dist/debug-experience.js
CHANGED
|
@@ -4,7 +4,8 @@ function DebugExperience({
|
|
|
4
4
|
defaultOpen = false
|
|
5
5
|
}) {
|
|
6
6
|
const nodeCount = experience.nodes.length;
|
|
7
|
-
const
|
|
7
|
+
const templateIds = experience.nodes.filter((node) => node.registration.kind === "experienceTemplate").map((node) => node.registration.id);
|
|
8
|
+
const summary = `Experience debug \u2014 ${nodeCount} top-level node${nodeCount === 1 ? "" : "s"}${templateIds.length ? `, experience template${templateIds.length === 1 ? "" : "s"}: ${templateIds.join(", ")}` : ""}`;
|
|
8
9
|
return /* @__PURE__ */ jsxs(
|
|
9
10
|
"details",
|
|
10
11
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/debug-experience.tsx"],"sourcesContent":["/*\n * First-party debug panel. Renders the resolved Experience plan as pretty\n * JSON so a customer can see exactly what the SDK interpreted from the payload\n * — node tree, registrations, resolved props, viewports.\n *\n * Two ways to use it:\n * - Auto-mounted by the renderers when `debug` is on (above the tree).\n * - Mounted manually anywhere: `<DebugExperience experience={plan} />`.\n *\n * v1 is just the JSON dump wrapped in a native <details> so it collapses\n * without any client JS (safe in server components). Room to grow into a\n * node-tree explorer, viewport indicator, and resolveData timing panel — kept\n * deliberately small for now.\n *\n * No React hooks here on purpose: it must render in both server and client\n * renderer subtrees.\n */\n\nimport type { ReactNode } from 'react';\n\nimport type { PortableRenderPlan } from '@contentful/experiences-sdk-core';\n\nexport interface DebugExperienceProps {\n /** The resolved plan to inspect (what a renderer receives as `experience`). */\n experience: PortableRenderPlan;\n /** Start expanded. Defaults to collapsed to stay out of the way. */\n defaultOpen?: boolean;\n}\n\nexport function DebugExperience({\n experience,\n defaultOpen = false,\n}: DebugExperienceProps): ReactNode {\n const nodeCount = experience.nodes.length;\n const summary = `Experience debug — ${nodeCount} top-level node${nodeCount === 1 ? '' : 's'}${\n
|
|
1
|
+
{"version":3,"sources":["../src/debug-experience.tsx"],"sourcesContent":["/*\n * First-party debug panel. Renders the resolved Experience plan as pretty\n * JSON so a customer can see exactly what the SDK interpreted from the payload\n * — node tree, registrations, resolved props, viewports.\n *\n * Two ways to use it:\n * - Auto-mounted by the renderers when `debug` is on (above the tree).\n * - Mounted manually anywhere: `<DebugExperience experience={plan} />`.\n *\n * v1 is just the JSON dump wrapped in a native <details> so it collapses\n * without any client JS (safe in server components). Room to grow into a\n * node-tree explorer, viewport indicator, and resolveData timing panel — kept\n * deliberately small for now.\n *\n * No React hooks here on purpose: it must render in both server and client\n * renderer subtrees.\n */\n\nimport type { ReactNode } from 'react';\n\nimport type { PortableRenderPlan } from '@contentful/experiences-sdk-core';\n\nexport interface DebugExperienceProps {\n /** The resolved plan to inspect (what a renderer receives as `experience`). */\n experience: PortableRenderPlan;\n /** Start expanded. Defaults to collapsed to stay out of the way. */\n defaultOpen?: boolean;\n}\n\nexport function DebugExperience({\n experience,\n defaultOpen = false,\n}: DebugExperienceProps): ReactNode {\n const nodeCount = experience.nodes.length;\n // Coded Experience Templates are ordinary top-level nodes, so name them from\n // the node list — a composite Experience simply has none to report.\n const templateIds = experience.nodes\n .filter((node) => node.registration.kind === 'experienceTemplate')\n .map((node) => node.registration.id);\n const summary = `Experience debug — ${nodeCount} top-level node${nodeCount === 1 ? '' : 's'}${\n templateIds.length\n ? `, experience template${templateIds.length === 1 ? '' : 's'}: ${templateIds.join(', ')}`\n : ''\n }`;\n\n return (\n <details\n open={defaultOpen}\n data-experiences-debug\n style={{\n margin: '1rem 0',\n border: '1px solid #6b7280',\n borderRadius: '6px',\n background: '#0b1021',\n color: '#e2e8f0',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n fontSize: '0.75rem',\n overflow: 'hidden',\n }}\n >\n <summary\n style={{\n cursor: 'pointer',\n padding: '0.5rem 0.75rem',\n background: '#111827',\n userSelect: 'none',\n }}\n >\n {summary}\n </summary>\n <pre\n style={{\n margin: 0,\n padding: '0.75rem',\n overflow: 'auto',\n maxHeight: '32rem',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n }}\n >\n {safeStringify(experience)}\n </pre>\n </details>\n );\n}\n\n/**\n * JSON.stringify with a circular-reference guard. A resolved plan is plain\n * data, but a customer's `resolveData` could stash a non-serializable value on\n * `props.resolved` — degrade to a placeholder rather than throwing inside a\n * debug panel.\n */\nfunction safeStringify(value: unknown): string {\n const seen = new WeakSet<object>();\n try {\n return JSON.stringify(\n value,\n (_key, val) => {\n if (typeof val === 'object' && val !== null) {\n if (seen.has(val)) return '[Circular]';\n seen.add(val);\n }\n if (typeof val === 'function') return `[Function ${val.name || 'anonymous'}]`;\n if (typeof val === 'undefined') return '[undefined]';\n return val;\n },\n 2\n );\n } catch (err) {\n return `[DebugExperience: could not serialize plan — ${(err as Error).message}]`;\n }\n}\n"],"mappings":"AA8CI,SAcE,KAdF;AAjBG,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA,cAAc;AAChB,GAAoC;AAClC,QAAM,YAAY,WAAW,MAAM;AAGnC,QAAM,cAAc,WAAW,MAC5B,OAAO,CAAC,SAAS,KAAK,aAAa,SAAS,oBAAoB,EAChE,IAAI,CAAC,SAAS,KAAK,aAAa,EAAE;AACrC,QAAM,UAAU,2BAAsB,SAAS,kBAAkB,cAAc,IAAI,KAAK,GAAG,GACzF,YAAY,SACR,wBAAwB,YAAY,WAAW,IAAI,KAAK,GAAG,KAAK,YAAY,KAAK,IAAI,CAAC,KACtF,EACN;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM;AAAA,MACN,0BAAsB;AAAA,MACtB,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,UAAU;AAAA,MACZ;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,QAAQ;AAAA,cACR,SAAS;AAAA,cACT,YAAY;AAAA,cACZ,YAAY;AAAA,YACd;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,QAAQ;AAAA,cACR,SAAS;AAAA,cACT,UAAU;AAAA,cACV,WAAW;AAAA,cACX,YAAY;AAAA,cACZ,WAAW;AAAA,YACb;AAAA,YAEC,wBAAc,UAAU;AAAA;AAAA,QAC3B;AAAA;AAAA;AAAA,EACF;AAEJ;AAQA,SAAS,cAAc,OAAwB;AAC7C,QAAM,OAAO,oBAAI,QAAgB;AACjC,MAAI;AACF,WAAO,KAAK;AAAA,MACV;AAAA,MACA,CAAC,MAAM,QAAQ;AACb,YAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,cAAI,KAAK,IAAI,GAAG,EAAG,QAAO;AAC1B,eAAK,IAAI,GAAG;AAAA,QACd;AACA,YAAI,OAAO,QAAQ,WAAY,QAAO,aAAa,IAAI,QAAQ,WAAW;AAC1E,YAAI,OAAO,QAAQ,YAAa,QAAO;AACvC,eAAO;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,qDAAiD,IAAc,OAAO;AAAA,EAC/E;AACF;","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { useContentfulComponent, useContentfulExperienceTemplate, useExperience
|
|
|
8
8
|
export { useDesignValues } from './use-design-values.js';
|
|
9
9
|
export { ToCssOptions, toCss } from './design-utils.js';
|
|
10
10
|
export { ComponentConfig, Components, Config, ContentfulComponent, ContentfulExperienceTemplate, ExperienceTemplateConfig, ExperienceTemplateRegistration, ExperienceTemplates, Registration, RenderContext, defineComponent, defineExperienceTemplate, normalizeComponentRegistration, normalizeExperienceTemplateRegistration } from './types.js';
|
|
11
|
-
export { ComponentNode, ComponentRef, DesignPropValue, DesignToken, ExperienceContext, ExperienceNode, ExperiencePayload, ExperienceSys, ExperienceTemplateNode, ExperienceTemplateRef, ManualDesignValue,
|
|
11
|
+
export { ComponentNode, ComponentRef, DesignPropValue, DesignToken, ExperienceContext, ExperienceNode, ExperiencePayload, ExperienceSys, ExperienceTemplateNode, ExperienceTemplateRef, ManualDesignValue, PortableRegistration, PortableRenderNode, PortableRenderPlan, ResolveContext, ResolveExperienceOptions, ResolveToken, ResolverConfig, ValuesByViewport, ViewportDef, resolveExperience } from '@contentful/experiences-sdk-core';
|
|
12
12
|
export { CSS_PROPERTIES, getValueForViewport, getViewportIndex, isCssProperty, resolveDesignProperties, toCssKey, toCssMediaQuery } from '@contentful/experiences-design';
|
|
13
|
-
export {
|
|
13
|
+
export { ClientOptions, ContentfulViewDelivery, ContentfulViewDeliveryClient, CreateClientOptions, DELIVERY_HOST, ExperienceOptions, NotFoundError, PREVIEW_HOST, ResolveOptions, createClient, fetchExperience } from '@contentful/experiences-client';
|
|
14
14
|
import 'react';
|
package/dist/index.js
CHANGED
|
@@ -26,19 +26,15 @@ import {
|
|
|
26
26
|
toCssMediaQuery
|
|
27
27
|
} from "@contentful/experiences-design";
|
|
28
28
|
import {
|
|
29
|
-
ALPHA_FEATURE_HEADER,
|
|
30
29
|
ContentfulViewDelivery,
|
|
31
30
|
ContentfulViewDeliveryClient,
|
|
32
31
|
DELIVERY_HOST,
|
|
33
|
-
NEW_EXO_ENTITY_TYPES,
|
|
34
|
-
NEW_EXO_ENTITY_TYPES_HEADERS,
|
|
35
32
|
NotFoundError,
|
|
36
33
|
PREVIEW_HOST,
|
|
37
34
|
createClient,
|
|
38
35
|
fetchExperience
|
|
39
36
|
} from "@contentful/experiences-client";
|
|
40
37
|
export {
|
|
41
|
-
ALPHA_FEATURE_HEADER,
|
|
42
38
|
CSS_PROPERTIES,
|
|
43
39
|
ClientExperienceRenderer2 as ClientExperienceRenderer,
|
|
44
40
|
ContentfulViewDelivery,
|
|
@@ -47,8 +43,6 @@ export {
|
|
|
47
43
|
DebugExperience,
|
|
48
44
|
ClientExperienceRenderer as ExperienceRenderer,
|
|
49
45
|
MissingComponent,
|
|
50
|
-
NEW_EXO_ENTITY_TYPES,
|
|
51
|
-
NEW_EXO_ENTITY_TYPES_HEADERS,
|
|
52
46
|
NotFoundError,
|
|
53
47
|
PREVIEW_HOST,
|
|
54
48
|
ServerExperienceRenderer,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/*\n * Public API surface for `@contentful/experiences-react`.\n *\n * Customers add ONLY this package to their app's dependencies. Everything\n * needed to render an Experience — types, the resolver, viewport utilities,\n * the renderer components, the authoring helpers — is re-exported from here.\n * The internal `@contentful/experiences-sdk-core` and\n * `@contentful/experiences-design` packages are workspace-only implementation\n * details; they are not part of the public API.\n *\n * `ExperienceRenderer` is an alias for `ClientExperienceRenderer`; SSR\n * consumers explicitly import `ServerExperienceRenderer`.\n */\n\n// ─── Renderers ─────────────────────────────────────────────────────────────\nexport {\n ClientExperienceRenderer as ExperienceRenderer,\n ClientExperienceRenderer,\n} from './client-renderer';\nexport type { ClientExperienceRendererProps as ExperienceRendererProps } from './client-renderer';\nexport type { ClientExperienceRendererProps } from './client-renderer';\n\nexport { ServerExperienceRenderer } from './server-renderer';\nexport type { ServerExperienceRendererProps } from './server-renderer';\n\nexport { MissingComponent } from './missing-component';\nexport type { MissingComponentProps } from './missing-component';\n\nexport { DebugExperience } from './debug-experience';\nexport type { DebugExperienceProps } from './debug-experience';\n\nexport { useActiveViewport } from './use-active-viewport';\nexport type { UseActiveViewportResult } from './use-active-viewport';\n\nexport type { RenderUnknown } from './nodes-renderer';\n\n// ─── Runtime context hooks ───────────────────────────────────────────────\nexport { useExperience, useContentfulComponent, useContentfulExperienceTemplate } from './context';\nexport { useDesignValues } from './use-design-values';\nexport { toCss } from './design-utils';\nexport type { ToCssOptions } from './design-utils';\n\n// ─── Authoring helpers + Config types ─────────────────────────────────────\nexport {\n defineComponent,\n defineExperienceTemplate,\n normalizeComponentRegistration,\n normalizeExperienceTemplateRegistration,\n} from './types';\nexport type {\n ComponentConfig,\n Components,\n Config,\n ContentfulComponent,\n ContentfulExperienceTemplate,\n ExperienceTemplateConfig,\n ExperienceTemplateRegistration,\n ExperienceTemplates,\n Registration,\n RenderContext,\n ResolveToken,\n} from './types';\n\n// ─── Resolver (re-exported from render-core) ──────────────────────────────\nexport { resolveExperience } from '@contentful/experiences-sdk-core';\nexport type { ResolverConfig, ResolveExperienceOptions } from '@contentful/experiences-sdk-core';\n\n// ─── Core IR + payload types (re-exported from render-core) ───────────────\nexport type {\n ComponentNode,\n ComponentRef,\n DesignPropValue,\n DesignToken,\n ExperienceContext,\n ExperienceNode,\n ExperiencePayload,\n ExperienceSys,\n ExperienceTemplateNode,\n ExperienceTemplateRef,\n ManualDesignValue,\n
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/*\n * Public API surface for `@contentful/experiences-react`.\n *\n * Customers add ONLY this package to their app's dependencies. Everything\n * needed to render an Experience — types, the resolver, viewport utilities,\n * the renderer components, the authoring helpers — is re-exported from here.\n * The internal `@contentful/experiences-sdk-core` and\n * `@contentful/experiences-design` packages are workspace-only implementation\n * details; they are not part of the public API.\n *\n * `ExperienceRenderer` is an alias for `ClientExperienceRenderer`; SSR\n * consumers explicitly import `ServerExperienceRenderer`.\n */\n\n// ─── Renderers ─────────────────────────────────────────────────────────────\nexport {\n ClientExperienceRenderer as ExperienceRenderer,\n ClientExperienceRenderer,\n} from './client-renderer';\nexport type { ClientExperienceRendererProps as ExperienceRendererProps } from './client-renderer';\nexport type { ClientExperienceRendererProps } from './client-renderer';\n\nexport { ServerExperienceRenderer } from './server-renderer';\nexport type { ServerExperienceRendererProps } from './server-renderer';\n\nexport { MissingComponent } from './missing-component';\nexport type { MissingComponentProps } from './missing-component';\n\nexport { DebugExperience } from './debug-experience';\nexport type { DebugExperienceProps } from './debug-experience';\n\nexport { useActiveViewport } from './use-active-viewport';\nexport type { UseActiveViewportResult } from './use-active-viewport';\n\nexport type { RenderUnknown } from './nodes-renderer';\n\n// ─── Runtime context hooks ───────────────────────────────────────────────\nexport { useExperience, useContentfulComponent, useContentfulExperienceTemplate } from './context';\nexport { useDesignValues } from './use-design-values';\nexport { toCss } from './design-utils';\nexport type { ToCssOptions } from './design-utils';\n\n// ─── Authoring helpers + Config types ─────────────────────────────────────\nexport {\n defineComponent,\n defineExperienceTemplate,\n normalizeComponentRegistration,\n normalizeExperienceTemplateRegistration,\n} from './types';\nexport type {\n ComponentConfig,\n Components,\n Config,\n ContentfulComponent,\n ContentfulExperienceTemplate,\n ExperienceTemplateConfig,\n ExperienceTemplateRegistration,\n ExperienceTemplates,\n Registration,\n RenderContext,\n ResolveToken,\n} from './types';\n\n// ─── Resolver (re-exported from render-core) ──────────────────────────────\nexport { resolveExperience } from '@contentful/experiences-sdk-core';\nexport type { ResolverConfig, ResolveExperienceOptions } from '@contentful/experiences-sdk-core';\n\n// ─── Core IR + payload types (re-exported from render-core) ───────────────\nexport type {\n ComponentNode,\n ComponentRef,\n DesignPropValue,\n DesignToken,\n ExperienceContext,\n ExperienceNode,\n ExperiencePayload,\n ExperienceSys,\n ExperienceTemplateNode,\n ExperienceTemplateRef,\n ManualDesignValue,\n PortableRegistration,\n PortableRenderNode,\n PortableRenderPlan,\n ResolveContext,\n ValuesByViewport,\n ViewportDef,\n} from '@contentful/experiences-sdk-core';\n\n// ─── Design utilities (re-exported from design) ───────────────────────────\nexport {\n CSS_PROPERTIES,\n getValueForViewport,\n getViewportIndex,\n isCssProperty,\n resolveDesignProperties,\n toCssKey,\n toCssMediaQuery,\n} from '@contentful/experiences-design';\n\n// ─── Delivery client + fetchExperience ────────────────────────────────────\nexport {\n ContentfulViewDelivery,\n ContentfulViewDeliveryClient,\n DELIVERY_HOST,\n NotFoundError,\n PREVIEW_HOST,\n createClient,\n fetchExperience,\n} from '@contentful/experiences-client';\nexport type {\n ClientOptions,\n CreateClientOptions,\n ExperienceOptions,\n ResolveOptions,\n} from '@contentful/experiences-client';\n"],"mappings":"AAeA;AAAA,EAC8B;AAAA,EAC5B,4BAAAA;AAAA,OACK;AAIP,SAAS,gCAAgC;AAGzC,SAAS,wBAAwB;AAGjC,SAAS,uBAAuB;AAGhC,SAAS,yBAAyB;AAMlC,SAAS,eAAe,wBAAwB,uCAAuC;AACvF,SAAS,uBAAuB;AAChC,SAAS,aAAa;AAItB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAgBP,SAAS,yBAAyB;AAyBlC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":["ClientExperienceRenderer"]}
|
package/dist/nodes-renderer.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { PortableRenderNode, ViewportDef
|
|
2
|
+
import { PortableRenderNode, ViewportDef } from '@contentful/experiences-sdk-core';
|
|
3
3
|
import { MissingComponentProps } from './missing-component.js';
|
|
4
4
|
import { Config } from './types.js';
|
|
5
5
|
|
|
@@ -14,20 +14,5 @@ interface NodesRendererProps {
|
|
|
14
14
|
renderUnknown: RenderUnknown;
|
|
15
15
|
}
|
|
16
16
|
declare function NodesRenderer({ nodes, config, viewports, activeViewportIndex, fallbackViewportIndex, renderUnknown, }: NodesRendererProps): ReactNode;
|
|
17
|
-
interface WrapWithExperienceTemplateProps {
|
|
18
|
-
experienceTemplate: PortableExperienceTemplate | undefined;
|
|
19
|
-
config: Config;
|
|
20
|
-
viewports: ViewportDef[];
|
|
21
|
-
activeViewportIndex: number;
|
|
22
|
-
/** Viewport index the server pre-resolved design against. */
|
|
23
|
-
fallbackViewportIndex: number;
|
|
24
|
-
children: ReactNode;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Wraps the rendered nodes with the page-level Experience Template. If the
|
|
28
|
-
* template is referenced but unregistered, warns once and renders children
|
|
29
|
-
* unwrapped.
|
|
30
|
-
*/
|
|
31
|
-
declare function WrapWithExperienceTemplate({ experienceTemplate, config, viewports, activeViewportIndex, fallbackViewportIndex, children, }: WrapWithExperienceTemplateProps): ReactNode;
|
|
32
17
|
|
|
33
|
-
export { NodesRenderer, type NodesRendererProps, type RenderUnknown
|
|
18
|
+
export { NodesRenderer, type NodesRendererProps, type RenderUnknown };
|
package/dist/nodes-renderer.js
CHANGED
|
@@ -47,12 +47,8 @@ function NodeRenderer({
|
|
|
47
47
|
fallbackViewportIndex,
|
|
48
48
|
renderUnknown
|
|
49
49
|
}) {
|
|
50
|
-
const {
|
|
51
|
-
const
|
|
52
|
-
if (!entry) {
|
|
53
|
-
return createElement(renderUnknown, { componentId, nodeId: node.nodeId });
|
|
54
|
-
}
|
|
55
|
-
const componentConfig = normalizeComponentRegistration(entry);
|
|
50
|
+
const { kind, id } = node.registration;
|
|
51
|
+
const isExperienceTemplate = kind === "experienceTemplate";
|
|
56
52
|
const slotProps = {};
|
|
57
53
|
for (const [slotName, children] of Object.entries(node.slots)) {
|
|
58
54
|
slotProps[slotName] = children.map((child, index) => /* @__PURE__ */ jsx(
|
|
@@ -68,6 +64,19 @@ function NodeRenderer({
|
|
|
68
64
|
child.nodeId ?? index
|
|
69
65
|
));
|
|
70
66
|
}
|
|
67
|
+
const entry = isExperienceTemplate ? config.experienceTemplates?.[id] : config.components[id];
|
|
68
|
+
if (!entry) {
|
|
69
|
+
if (isExperienceTemplate) {
|
|
70
|
+
if (typeof console !== "undefined") {
|
|
71
|
+
console.warn(
|
|
72
|
+
`[@contentful/experiences-react] No experience template registered for id "${id}". Rendering its slot children without the experience template wrapper.`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return /* @__PURE__ */ jsx(Fragment, { children: Object.values(slotProps).flat() });
|
|
76
|
+
}
|
|
77
|
+
return createElement(renderUnknown, { componentId: id, nodeId: node.nodeId });
|
|
78
|
+
}
|
|
79
|
+
const registrationConfig = isExperienceTemplate ? normalizeExperienceTemplateRegistration(entry) : normalizeComponentRegistration(entry);
|
|
71
80
|
const { props: tokenResolvedDesign, unresolved } = selectResolvedDesign(
|
|
72
81
|
node.props,
|
|
73
82
|
viewports,
|
|
@@ -77,73 +86,37 @@ function NodeRenderer({
|
|
|
77
86
|
);
|
|
78
87
|
if (unresolved.length && typeof console !== "undefined") {
|
|
79
88
|
console.warn(
|
|
80
|
-
`[@contentful/experiences-react] resolveToken returned undefined for token id(s) on "${
|
|
89
|
+
`[@contentful/experiences-react] resolveToken returned undefined for token id(s) on ${kind} "${id}": ${unresolved.join(", ")}. useDesignValues() will omit those keys.`
|
|
81
90
|
);
|
|
82
91
|
}
|
|
83
|
-
const contentful = {
|
|
84
|
-
componentId,
|
|
85
|
-
nodeId: node.nodeId,
|
|
86
|
-
content: node.props.content,
|
|
87
|
-
design: node.props.designRaw,
|
|
88
|
-
resolved: node.props.resolved
|
|
89
|
-
};
|
|
90
92
|
const composed = {
|
|
91
|
-
...
|
|
93
|
+
...registrationConfig.defaults,
|
|
92
94
|
...tokenResolvedDesign,
|
|
93
95
|
...node.props.content,
|
|
94
96
|
...node.props.resolved,
|
|
95
97
|
...slotProps
|
|
96
98
|
};
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
})
|
|
107
|
-
if (!experienceTemplate) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
108
|
-
const entry = config.experienceTemplates?.[experienceTemplate.experienceTemplateId];
|
|
109
|
-
if (!entry) {
|
|
110
|
-
if (typeof console !== "undefined") {
|
|
111
|
-
console.warn(
|
|
112
|
-
`[@contentful/experiences-react] No experience template registered for id "${experienceTemplate.experienceTemplateId}". Rendering nodes without the experience template wrapper.`
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
116
|
-
}
|
|
117
|
-
const experienceTemplateConfig = normalizeExperienceTemplateRegistration(entry);
|
|
118
|
-
const { props: tokenResolvedDesign, unresolved } = selectResolvedDesign(
|
|
119
|
-
experienceTemplate.props,
|
|
120
|
-
viewports,
|
|
121
|
-
activeViewportIndex,
|
|
122
|
-
fallbackViewportIndex,
|
|
123
|
-
config.resolveToken
|
|
124
|
-
);
|
|
125
|
-
if (unresolved.length && typeof console !== "undefined") {
|
|
126
|
-
console.warn(
|
|
127
|
-
`[@contentful/experiences-react] resolveToken returned undefined for token id(s) on experience template "${experienceTemplate.experienceTemplateId}": ${unresolved.join(", ")}. useDesignValues() will omit those keys.`
|
|
128
|
-
);
|
|
99
|
+
const element = /* @__PURE__ */ jsx(ResolvedDesignProvider, { value: tokenResolvedDesign, children: createElement(registrationConfig.component, composed) });
|
|
100
|
+
if (isExperienceTemplate) {
|
|
101
|
+
const contentful2 = {
|
|
102
|
+
experienceTemplateId: id,
|
|
103
|
+
nodeId: node.nodeId,
|
|
104
|
+
content: node.props.content,
|
|
105
|
+
design: node.props.designRaw,
|
|
106
|
+
resolved: node.props.resolved
|
|
107
|
+
};
|
|
108
|
+
return /* @__PURE__ */ jsx(ContentfulExperienceTemplateProvider, { value: contentful2, children: element });
|
|
129
109
|
}
|
|
130
110
|
const contentful = {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const composed = {
|
|
137
|
-
...experienceTemplateConfig.defaults,
|
|
138
|
-
...tokenResolvedDesign,
|
|
139
|
-
...experienceTemplate.props.content,
|
|
140
|
-
...experienceTemplate.props.resolved,
|
|
141
|
-
children
|
|
111
|
+
componentId: id,
|
|
112
|
+
nodeId: node.nodeId,
|
|
113
|
+
content: node.props.content,
|
|
114
|
+
design: node.props.designRaw,
|
|
115
|
+
resolved: node.props.resolved
|
|
142
116
|
};
|
|
143
|
-
return /* @__PURE__ */ jsx(
|
|
117
|
+
return /* @__PURE__ */ jsx(ContentfulComponentProvider, { value: contentful, children: element });
|
|
144
118
|
}
|
|
145
119
|
export {
|
|
146
|
-
NodesRenderer
|
|
147
|
-
WrapWithExperienceTemplate
|
|
120
|
+
NodesRenderer
|
|
148
121
|
};
|
|
149
122
|
//# sourceMappingURL=nodes-renderer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/nodes-renderer.tsx"],"sourcesContent":["/*\n * Recursive renderer over PortableRenderNodes. Resolved design values auto-fill\n * matching props (below content/resolveData) and are also available via\n * `useDesignValues()`.\n */\n\nimport { Fragment, createElement, type ReactNode } from 'react';\n\nimport type {\n DesignPropValue,\n PortableExperienceTemplate,\n PortableRenderNode,\n ViewportDef,\n} from '@contentful/experiences-sdk-core';\nimport { applyTokenResolver, resolveDesignProperties } from '@contentful/experiences-design';\n\nimport {\n ContentfulComponentProvider,\n ContentfulExperienceTemplateProvider,\n ResolvedDesignProvider,\n} from './context';\nimport type { MissingComponentProps } from './missing-component';\nimport {\n normalizeComponentRegistration,\n normalizeExperienceTemplateRegistration,\n type ContentfulComponent,\n type ContentfulExperienceTemplate,\n type Config,\n} from './types';\n\nexport type RenderUnknown = (props: MissingComponentProps) => ReactNode;\n\n// Use the server-resolved `props.design` when the active viewport matches the\n// fallback; otherwise recompute the cascade from raw `props.designRaw`.\nfunction selectResolvedDesign(\n props: { design: Record<string, unknown>; designRaw: Record<string, DesignPropValue> },\n viewports: ViewportDef[],\n activeViewportIndex: number,\n fallbackViewportIndex: number,\n resolveToken: Config['resolveToken']\n): { props: Record<string, unknown>; unresolved: string[] } {\n if (activeViewportIndex === fallbackViewportIndex) {\n return { props: props.design, unresolved: [] };\n }\n const resolvedDesign = resolveDesignProperties(props.designRaw, viewports, activeViewportIndex);\n return applyTokenResolver(resolvedDesign, resolveToken);\n}\n\n// Internal renderers take `viewports` + `activeViewportIndex`, not the whole\n// RenderContext object — the context is published once via ExperienceProvider,\n// and re-threading it as an element prop makes React's RSC serializer back-patch\n// a shared reference into frozen props (\"Cannot assign to read only property\").\nexport interface NodesRendererProps {\n nodes: PortableRenderNode[];\n config: Config;\n viewports: ViewportDef[];\n activeViewportIndex: number;\n /** Viewport index the server pre-resolved design against. */\n fallbackViewportIndex: number;\n renderUnknown: RenderUnknown;\n}\n\nexport function NodesRenderer({\n nodes,\n config,\n viewports,\n activeViewportIndex,\n fallbackViewportIndex,\n renderUnknown,\n}: NodesRendererProps): ReactNode {\n if (!nodes.length) return null;\n return (\n <Fragment>\n {nodes.map((node, index) => (\n <NodeRenderer\n key={node.nodeId ?? index}\n node={node}\n config={config}\n viewports={viewports}\n activeViewportIndex={activeViewportIndex}\n fallbackViewportIndex={fallbackViewportIndex}\n renderUnknown={renderUnknown}\n />\n ))}\n </Fragment>\n );\n}\n\ninterface NodeRendererProps {\n node: PortableRenderNode;\n config: Config;\n viewports: ViewportDef[];\n activeViewportIndex: number;\n fallbackViewportIndex: number;\n renderUnknown: RenderUnknown;\n}\n\nfunction NodeRenderer({\n node,\n config,\n viewports,\n activeViewportIndex,\n fallbackViewportIndex,\n renderUnknown,\n}: NodeRendererProps): ReactNode {\n const { componentId } = node.registration;\n const entry = config.components[componentId];\n if (!entry) {\n return createElement(renderUnknown, { componentId, nodeId: node.nodeId });\n }\n const componentConfig = normalizeComponentRegistration(entry);\n\n // Pre-render each slot's children as an *array* of ReactNodes (one keyed\n // element per child), not a single wrapping node. A component can drop the\n // array straight into JSX for the common \"just render them\" case (React\n // renders keyed arrays), or map/filter/wrap the children individually.\n const slotProps: Record<string, ReactNode[]> = {};\n for (const [slotName, children] of Object.entries(node.slots)) {\n slotProps[slotName] = children.map((child, index) => (\n <NodeRenderer\n key={child.nodeId ?? index}\n node={child}\n config={config}\n viewports={viewports}\n activeViewportIndex={activeViewportIndex}\n fallbackViewportIndex={fallbackViewportIndex}\n renderUnknown={renderUnknown}\n />\n ));\n }\n\n const { props: tokenResolvedDesign, unresolved } = selectResolvedDesign(\n node.props,\n viewports,\n activeViewportIndex,\n fallbackViewportIndex,\n config.resolveToken\n );\n if (unresolved.length && typeof console !== 'undefined') {\n console.warn(\n `[@contentful/experiences-react] resolveToken returned undefined for token id(s) on \"${componentId}\": ${unresolved.join(', ')}. useDesignValues() will omit those keys.`\n );\n }\n\n const contentful: ContentfulComponent = {\n componentId,\n nodeId: node.nodeId,\n content: node.props.content,\n design: node.props.designRaw,\n resolved: node.props.resolved,\n };\n\n // Merge precedence (last wins): defaults < design < content < resolveData < slots.\n const composed = {\n ...componentConfig.defaults,\n ...tokenResolvedDesign,\n ...node.props.content,\n ...node.props.resolved,\n ...slotProps,\n };\n\n return (\n <ContentfulComponentProvider value={contentful}>\n <ResolvedDesignProvider value={tokenResolvedDesign}>\n {createElement(componentConfig.component, composed)}\n </ResolvedDesignProvider>\n </ContentfulComponentProvider>\n );\n}\n\nexport interface WrapWithExperienceTemplateProps {\n experienceTemplate: PortableExperienceTemplate | undefined;\n config: Config;\n viewports: ViewportDef[];\n activeViewportIndex: number;\n /** Viewport index the server pre-resolved design against. */\n fallbackViewportIndex: number;\n children: ReactNode;\n}\n\n/**\n * Wraps the rendered nodes with the page-level Experience Template. If the\n * template is referenced but unregistered, warns once and renders children\n * unwrapped.\n */\nexport function WrapWithExperienceTemplate({\n experienceTemplate,\n config,\n viewports,\n activeViewportIndex,\n fallbackViewportIndex,\n children,\n}: WrapWithExperienceTemplateProps): ReactNode {\n if (!experienceTemplate) return <Fragment>{children}</Fragment>;\n const entry = config.experienceTemplates?.[experienceTemplate.experienceTemplateId];\n if (!entry) {\n if (typeof console !== 'undefined') {\n console.warn(\n `[@contentful/experiences-react] No experience template registered for id \"${experienceTemplate.experienceTemplateId}\". Rendering nodes without the experience template wrapper.`\n );\n }\n return <Fragment>{children}</Fragment>;\n }\n const experienceTemplateConfig = normalizeExperienceTemplateRegistration(entry);\n\n const { props: tokenResolvedDesign, unresolved } = selectResolvedDesign(\n experienceTemplate.props,\n viewports,\n activeViewportIndex,\n fallbackViewportIndex,\n config.resolveToken\n );\n if (unresolved.length && typeof console !== 'undefined') {\n console.warn(\n `[@contentful/experiences-react] resolveToken returned undefined for token id(s) on experience template \"${experienceTemplate.experienceTemplateId}\": ${unresolved.join(', ')}. useDesignValues() will omit those keys.`\n );\n }\n\n const contentful: ContentfulExperienceTemplate = {\n experienceTemplateId: experienceTemplate.experienceTemplateId,\n content: experienceTemplate.props.content,\n design: experienceTemplate.props.designRaw,\n resolved: experienceTemplate.props.resolved,\n };\n\n // Same precedence as component nodes, ending in `children`.\n const composed = {\n ...experienceTemplateConfig.defaults,\n ...tokenResolvedDesign,\n ...experienceTemplate.props.content,\n ...experienceTemplate.props.resolved,\n children,\n };\n\n return (\n <ContentfulExperienceTemplateProvider value={contentful}>\n <ResolvedDesignProvider value={tokenResolvedDesign}>\n {createElement(experienceTemplateConfig.component, composed)}\n </ResolvedDesignProvider>\n </ContentfulExperienceTemplateProvider>\n );\n}\n"],"mappings":"AA0EQ;AApER,SAAS,UAAU,qBAAqC;AAQxD,SAAS,oBAAoB,+BAA+B;AAE5D;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,OAIK;AAMP,SAAS,qBACP,OACA,WACA,qBACA,uBACA,cAC0D;AAC1D,MAAI,wBAAwB,uBAAuB;AACjD,WAAO,EAAE,OAAO,MAAM,QAAQ,YAAY,CAAC,EAAE;AAAA,EAC/C;AACA,QAAM,iBAAiB,wBAAwB,MAAM,WAAW,WAAW,mBAAmB;AAC9F,SAAO,mBAAmB,gBAAgB,YAAY;AACxD;AAgBO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkC;AAChC,MAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,SACE,oBAAC,YACE,gBAAM,IAAI,CAAC,MAAM,UAChB;AAAA,IAAC;AAAA;AAAA,MAEC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,IANK,KAAK,UAAU;AAAA,EAOtB,CACD,GACH;AAEJ;AAWA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiC;AAC/B,QAAM,EAAE,YAAY,IAAI,KAAK;AAC7B,QAAM,QAAQ,OAAO,WAAW,WAAW;AAC3C,MAAI,CAAC,OAAO;AACV,WAAO,cAAc,eAAe,EAAE,aAAa,QAAQ,KAAK,OAAO,CAAC;AAAA,EAC1E;AACA,QAAM,kBAAkB,+BAA+B,KAAK;AAM5D,QAAM,YAAyC,CAAC;AAChD,aAAW,CAAC,UAAU,QAAQ,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAG;AAC7D,cAAU,QAAQ,IAAI,SAAS,IAAI,CAAC,OAAO,UACzC;AAAA,MAAC;AAAA;AAAA,QAEC,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,MANK,MAAM,UAAU;AAAA,IAOvB,CACD;AAAA,EACH;AAEA,QAAM,EAAE,OAAO,qBAAqB,WAAW,IAAI;AAAA,IACjD,KAAK;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,EACT;AACA,MAAI,WAAW,UAAU,OAAO,YAAY,aAAa;AACvD,YAAQ;AAAA,MACN,uFAAuF,WAAW,MAAM,WAAW,KAAK,IAAI,CAAC;AAAA,IAC/H;AAAA,EACF;AAEA,QAAM,aAAkC;AAAA,IACtC;AAAA,IACA,QAAQ,KAAK;AAAA,IACb,SAAS,KAAK,MAAM;AAAA,IACpB,QAAQ,KAAK,MAAM;AAAA,IACnB,UAAU,KAAK,MAAM;AAAA,EACvB;AAGA,QAAM,WAAW;AAAA,IACf,GAAG,gBAAgB;AAAA,IACnB,GAAG;AAAA,IACH,GAAG,KAAK,MAAM;AAAA,IACd,GAAG,KAAK,MAAM;AAAA,IACd,GAAG;AAAA,EACL;AAEA,SACE,oBAAC,+BAA4B,OAAO,YAClC,8BAAC,0BAAuB,OAAO,qBAC5B,wBAAc,gBAAgB,WAAW,QAAQ,GACpD,GACF;AAEJ;AAiBO,SAAS,2BAA2B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA+C;AAC7C,MAAI,CAAC,mBAAoB,QAAO,oBAAC,YAAU,UAAS;AACpD,QAAM,QAAQ,OAAO,sBAAsB,mBAAmB,oBAAoB;AAClF,MAAI,CAAC,OAAO;AACV,QAAI,OAAO,YAAY,aAAa;AAClC,cAAQ;AAAA,QACN,6EAA6E,mBAAmB,oBAAoB;AAAA,MACtH;AAAA,IACF;AACA,WAAO,oBAAC,YAAU,UAAS;AAAA,EAC7B;AACA,QAAM,2BAA2B,wCAAwC,KAAK;AAE9E,QAAM,EAAE,OAAO,qBAAqB,WAAW,IAAI;AAAA,IACjD,mBAAmB;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,EACT;AACA,MAAI,WAAW,UAAU,OAAO,YAAY,aAAa;AACvD,YAAQ;AAAA,MACN,2GAA2G,mBAAmB,oBAAoB,MAAM,WAAW,KAAK,IAAI,CAAC;AAAA,IAC/K;AAAA,EACF;AAEA,QAAM,aAA2C;AAAA,IAC/C,sBAAsB,mBAAmB;AAAA,IACzC,SAAS,mBAAmB,MAAM;AAAA,IAClC,QAAQ,mBAAmB,MAAM;AAAA,IACjC,UAAU,mBAAmB,MAAM;AAAA,EACrC;AAGA,QAAM,WAAW;AAAA,IACf,GAAG,yBAAyB;AAAA,IAC5B,GAAG;AAAA,IACH,GAAG,mBAAmB,MAAM;AAAA,IAC5B,GAAG,mBAAmB,MAAM;AAAA,IAC5B;AAAA,EACF;AAEA,SACE,oBAAC,wCAAqC,OAAO,YAC3C,8BAAC,0BAAuB,OAAO,qBAC5B,wBAAc,yBAAyB,WAAW,QAAQ,GAC7D,GACF;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/nodes-renderer.tsx"],"sourcesContent":["/*\n * Recursive renderer over PortableRenderNodes. Resolved design values auto-fill\n * matching props (below content/resolveData) and are also available via\n * `useDesignValues()`.\n */\n\nimport { Fragment, createElement, type ReactNode } from 'react';\n\nimport type {\n DesignPropValue,\n PortableRenderNode,\n ViewportDef,\n} from '@contentful/experiences-sdk-core';\nimport { applyTokenResolver, resolveDesignProperties } from '@contentful/experiences-design';\n\nimport {\n ContentfulComponentProvider,\n ContentfulExperienceTemplateProvider,\n ResolvedDesignProvider,\n} from './context';\nimport type { MissingComponentProps } from './missing-component';\nimport {\n normalizeComponentRegistration,\n normalizeExperienceTemplateRegistration,\n type ContentfulComponent,\n type ContentfulExperienceTemplate,\n type Config,\n} from './types';\n\nexport type RenderUnknown = (props: MissingComponentProps) => ReactNode;\n\n// Use the server-resolved `props.design` when the active viewport matches the\n// fallback; otherwise recompute the cascade from raw `props.designRaw`.\nfunction selectResolvedDesign(\n props: { design: Record<string, unknown>; designRaw: Record<string, DesignPropValue> },\n viewports: ViewportDef[],\n activeViewportIndex: number,\n fallbackViewportIndex: number,\n resolveToken: Config['resolveToken']\n): { props: Record<string, unknown>; unresolved: string[] } {\n if (activeViewportIndex === fallbackViewportIndex) {\n return { props: props.design, unresolved: [] };\n }\n const resolvedDesign = resolveDesignProperties(props.designRaw, viewports, activeViewportIndex);\n return applyTokenResolver(resolvedDesign, resolveToken);\n}\n\n// Internal renderers take `viewports` + `activeViewportIndex`, not the whole\n// RenderContext object — the context is published once via ExperienceProvider,\n// and re-threading it as an element prop makes React's RSC serializer back-patch\n// a shared reference into frozen props (\"Cannot assign to read only property\").\nexport interface NodesRendererProps {\n nodes: PortableRenderNode[];\n config: Config;\n viewports: ViewportDef[];\n activeViewportIndex: number;\n /** Viewport index the server pre-resolved design against. */\n fallbackViewportIndex: number;\n renderUnknown: RenderUnknown;\n}\n\nexport function NodesRenderer({\n nodes,\n config,\n viewports,\n activeViewportIndex,\n fallbackViewportIndex,\n renderUnknown,\n}: NodesRendererProps): ReactNode {\n if (!nodes.length) return null;\n return (\n <Fragment>\n {nodes.map((node, index) => (\n <NodeRenderer\n key={node.nodeId ?? index}\n node={node}\n config={config}\n viewports={viewports}\n activeViewportIndex={activeViewportIndex}\n fallbackViewportIndex={fallbackViewportIndex}\n renderUnknown={renderUnknown}\n />\n ))}\n </Fragment>\n );\n}\n\ninterface NodeRendererProps {\n node: PortableRenderNode;\n config: Config;\n viewports: ViewportDef[];\n activeViewportIndex: number;\n fallbackViewportIndex: number;\n renderUnknown: RenderUnknown;\n}\n\nfunction NodeRenderer({\n node,\n config,\n viewports,\n activeViewportIndex,\n fallbackViewportIndex,\n renderUnknown,\n}: NodeRendererProps): ReactNode {\n const { kind, id } = node.registration;\n const isExperienceTemplate = kind === 'experienceTemplate';\n\n // Pre-render each slot's children as an *array* of ReactNodes (one keyed\n // element per child), not a single wrapping node. A component can drop the\n // array straight into JSX for the common \"just render them\" case (React\n // renders keyed arrays), or map/filter/wrap the children individually.\n //\n // Slot name → prop name, for both node kinds: a coded Experience Template\n // declaring a `content` slot receives a `content` prop. `children` is not a\n // special case, just the conventional default slot name.\n const slotProps: Record<string, ReactNode[]> = {};\n for (const [slotName, children] of Object.entries(node.slots)) {\n slotProps[slotName] = children.map((child, index) => (\n <NodeRenderer\n key={child.nodeId ?? index}\n node={child}\n config={config}\n viewports={viewports}\n activeViewportIndex={activeViewportIndex}\n fallbackViewportIndex={fallbackViewportIndex}\n renderUnknown={renderUnknown}\n />\n ));\n }\n\n const entry = isExperienceTemplate ? config.experienceTemplates?.[id] : config.components[id];\n if (!entry) {\n // An unregistered Experience Template would blank the page if we swapped\n // it for the missing-component box, so warn and render its slot children\n // unwrapped — the content survives, the diagnostic names what's missing.\n if (isExperienceTemplate) {\n if (typeof console !== 'undefined') {\n console.warn(\n `[@contentful/experiences-react] No experience template registered for id \"${id}\". Rendering its slot children without the experience template wrapper.`\n );\n }\n return <Fragment>{Object.values(slotProps).flat()}</Fragment>;\n }\n return createElement(renderUnknown, { componentId: id, nodeId: node.nodeId });\n }\n const registrationConfig = isExperienceTemplate\n ? normalizeExperienceTemplateRegistration(entry)\n : normalizeComponentRegistration(entry);\n\n const { props: tokenResolvedDesign, unresolved } = selectResolvedDesign(\n node.props,\n viewports,\n activeViewportIndex,\n fallbackViewportIndex,\n config.resolveToken\n );\n if (unresolved.length && typeof console !== 'undefined') {\n console.warn(\n `[@contentful/experiences-react] resolveToken returned undefined for token id(s) on ${kind} \"${id}\": ${unresolved.join(', ')}. useDesignValues() will omit those keys.`\n );\n }\n\n // Merge precedence (last wins): defaults < design < content < resolveData < slots.\n const composed = {\n ...registrationConfig.defaults,\n ...tokenResolvedDesign,\n ...node.props.content,\n ...node.props.resolved,\n ...slotProps,\n };\n\n const element = (\n <ResolvedDesignProvider value={tokenResolvedDesign}>\n {createElement(registrationConfig.component, composed)}\n </ResolvedDesignProvider>\n );\n\n if (isExperienceTemplate) {\n const contentful: ContentfulExperienceTemplate = {\n experienceTemplateId: id,\n nodeId: node.nodeId,\n content: node.props.content,\n design: node.props.designRaw,\n resolved: node.props.resolved,\n };\n return (\n <ContentfulExperienceTemplateProvider value={contentful}>\n {element}\n </ContentfulExperienceTemplateProvider>\n );\n }\n\n const contentful: ContentfulComponent = {\n componentId: id,\n nodeId: node.nodeId,\n content: node.props.content,\n design: node.props.designRaw,\n resolved: node.props.resolved,\n };\n return <ContentfulComponentProvider value={contentful}>{element}</ContentfulComponentProvider>;\n}\n"],"mappings":"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","names":["contentful"]}
|
package/dist/server-renderer.js
CHANGED
|
@@ -3,7 +3,7 @@ import { getViewportIndex } from "@contentful/experiences-design";
|
|
|
3
3
|
import { DebugExperience } from "./debug-experience";
|
|
4
4
|
import { ExperienceProvider } from "./context";
|
|
5
5
|
import { MissingComponent } from "./missing-component";
|
|
6
|
-
import { NodesRenderer
|
|
6
|
+
import { NodesRenderer } from "./nodes-renderer";
|
|
7
7
|
const DEFAULT_CONTEXT = {
|
|
8
8
|
debug: false,
|
|
9
9
|
metadata: {},
|
|
@@ -38,24 +38,14 @@ function ServerExperienceRenderer({
|
|
|
38
38
|
return /* @__PURE__ */ jsxs(ExperienceProvider, { value: renderContext, children: [
|
|
39
39
|
debug ? /* @__PURE__ */ jsx(DebugExperience, { experience }) : null,
|
|
40
40
|
/* @__PURE__ */ jsx(
|
|
41
|
-
|
|
41
|
+
NodesRenderer,
|
|
42
42
|
{
|
|
43
|
-
|
|
43
|
+
nodes: experience.nodes,
|
|
44
44
|
config,
|
|
45
45
|
viewports: experience.viewports,
|
|
46
46
|
activeViewportIndex,
|
|
47
47
|
fallbackViewportIndex: experience.fallbackViewportIndex,
|
|
48
|
-
|
|
49
|
-
NodesRenderer,
|
|
50
|
-
{
|
|
51
|
-
nodes: experience.nodes,
|
|
52
|
-
config,
|
|
53
|
-
viewports: experience.viewports,
|
|
54
|
-
activeViewportIndex,
|
|
55
|
-
fallbackViewportIndex: experience.fallbackViewportIndex,
|
|
56
|
-
renderUnknown
|
|
57
|
-
}
|
|
58
|
-
)
|
|
48
|
+
renderUnknown
|
|
59
49
|
}
|
|
60
50
|
)
|
|
61
51
|
] });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server-renderer.tsx"],"sourcesContent":["/*\n * Server-safe Experience renderer. Resolves the active viewport once from\n * `initialViewportId` and renders without any reactive subscription.\n */\n\nimport type { ReactNode } from 'react';\n\nimport type {\n ExperienceContext,\n PortableRenderPlan,\n ViewportDef,\n} from '@contentful/experiences-sdk-core';\nimport { getViewportIndex } from '@contentful/experiences-design';\n\nimport { DebugExperience } from './debug-experience';\nimport { ExperienceProvider } from './context';\nimport { MissingComponent } from './missing-component';\nimport { NodesRenderer,
|
|
1
|
+
{"version":3,"sources":["../src/server-renderer.tsx"],"sourcesContent":["/*\n * Server-safe Experience renderer. Resolves the active viewport once from\n * `initialViewportId` and renders without any reactive subscription.\n */\n\nimport type { ReactNode } from 'react';\n\nimport type {\n ExperienceContext,\n PortableRenderPlan,\n ViewportDef,\n} from '@contentful/experiences-sdk-core';\nimport { getViewportIndex } from '@contentful/experiences-design';\n\nimport { DebugExperience } from './debug-experience';\nimport { ExperienceProvider } from './context';\nimport { MissingComponent } from './missing-component';\nimport { NodesRenderer, type RenderUnknown } from './nodes-renderer';\nimport type { Config, RenderContext } from './types';\n\nconst DEFAULT_CONTEXT: ExperienceContext = {\n debug: false,\n metadata: {},\n viewports: [],\n};\n\n// Keeps `activeViewport` non-null when a payload declares no viewports.\nconst FALLBACK_VIEWPORT: ViewportDef = {\n id: '_',\n query: '*',\n displayName: 'Default',\n previewSize: '100%',\n};\n\nexport interface ServerExperienceRendererProps {\n experience: PortableRenderPlan | null | undefined;\n config: Config;\n /** Initial viewport seed (e.g. derived from User-Agent). Defaults to viewport[0]. */\n initialViewportId?: string;\n /**\n * Arbitrary per-render metadata, readable by descendants via\n * `useExperience()` and by resolvers via `ctx.experience.metadata`.\n */\n metadata?: Record<string, unknown>;\n /**\n * Observability switch. When on: renders the visible missing-component box,\n * turns the default `renderUnknown` fallback into the debug component, and\n * auto-mounts `<DebugExperience>` (the resolved-plan JSON panel) after the\n * tree. Pair with `debug` on `fetchExperience` for end-to-end logging.\n */\n debug?: boolean;\n /** Override the fallback rendered for unregistered component types. */\n renderUnknown?: RenderUnknown;\n}\n\nexport function ServerExperienceRenderer({\n experience,\n config,\n initialViewportId,\n metadata,\n debug = false,\n renderUnknown = MissingComponent,\n}: ServerExperienceRendererProps): ReactNode {\n if (!experience) return null;\n\n const activeViewportIndex = getViewportIndex(experience.viewports, initialViewportId);\n\n // Copy viewports/activeViewport so the context (serialized + frozen by RSC)\n // shares no object identity with the plan arrays the renderers read below —\n // a shared reference makes Flight back-patch into frozen props and throw.\n const contextViewports = experience.viewports.map((v) => ({ ...v }));\n const activeViewport = { ...(experience.viewports[activeViewportIndex] ?? FALLBACK_VIEWPORT) };\n\n const renderContext: RenderContext = {\n ...DEFAULT_CONTEXT,\n debug,\n metadata: { ...DEFAULT_CONTEXT.metadata, ...(metadata ?? {}) },\n viewports: contextViewports,\n activeViewport,\n activeViewportIndex,\n };\n\n return (\n <ExperienceProvider value={renderContext}>\n {debug ? <DebugExperience experience={experience} /> : null}\n <NodesRenderer\n nodes={experience.nodes}\n config={config}\n viewports={experience.viewports}\n activeViewportIndex={activeViewportIndex}\n fallbackViewportIndex={experience.fallbackViewportIndex}\n renderUnknown={renderUnknown}\n />\n </ExperienceProvider>\n );\n}\n"],"mappings":"AAmFI,SACW,KADX;AAvEJ,SAAS,wBAAwB;AAEjC,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AACjC,SAAS,qBAAyC;AAGlD,MAAM,kBAAqC;AAAA,EACzC,OAAO;AAAA,EACP,UAAU,CAAC;AAAA,EACX,WAAW,CAAC;AACd;AAGA,MAAM,oBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,aAAa;AAAA,EACb,aAAa;AACf;AAuBO,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,gBAAgB;AAClB,GAA6C;AAC3C,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,sBAAsB,iBAAiB,WAAW,WAAW,iBAAiB;AAKpF,QAAM,mBAAmB,WAAW,UAAU,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE;AACnE,QAAM,iBAAiB,EAAE,GAAI,WAAW,UAAU,mBAAmB,KAAK,kBAAmB;AAE7F,QAAM,gBAA+B;AAAA,IACnC,GAAG;AAAA,IACH;AAAA,IACA,UAAU,EAAE,GAAG,gBAAgB,UAAU,GAAI,YAAY,CAAC,EAAG;AAAA,IAC7D,WAAW;AAAA,IACX;AAAA,IACA;AAAA,EACF;AAEA,SACE,qBAAC,sBAAmB,OAAO,eACxB;AAAA,YAAQ,oBAAC,mBAAgB,YAAwB,IAAK;AAAA,IACvD;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,WAAW;AAAA,QAClB;AAAA,QACA,WAAW,WAAW;AAAA,QACtB;AAAA,QACA,uBAAuB,WAAW;AAAA,QAClC;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":[]}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComponentType
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
2
|
import { ResolveContext, ResolveToken, DesignPropValue, ExperienceContext, ViewportDef } from '@contentful/experiences-sdk-core';
|
|
3
3
|
export { ResolveContext, ResolveToken } from '@contentful/experiences-sdk-core';
|
|
4
4
|
|
|
@@ -21,12 +21,13 @@ interface ContentfulComponent {
|
|
|
21
21
|
resolved?: Record<string, unknown>;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
-
* Same shape as `ContentfulComponent`, but for
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* Same shape as `ContentfulComponent`, but for an Experience Template node.
|
|
25
|
+
* Exposed via `useContentfulExperienceTemplate()` inside an Experience
|
|
26
|
+
* Template's component tree.
|
|
27
27
|
*/
|
|
28
28
|
interface ContentfulExperienceTemplate {
|
|
29
29
|
experienceTemplateId: string;
|
|
30
|
+
nodeId?: string;
|
|
30
31
|
content: Record<string, unknown>;
|
|
31
32
|
design: Record<string, DesignPropValue>;
|
|
32
33
|
resolved?: Record<string, unknown>;
|
|
@@ -76,23 +77,22 @@ interface ComponentConfig<Props extends object = Record<string, unknown>> {
|
|
|
76
77
|
*/
|
|
77
78
|
type Registration<Props extends object = Record<string, unknown>> = ComponentType<Props> | ComponentConfig<Props>;
|
|
78
79
|
/**
|
|
79
|
-
* Customer-supplied configuration for a
|
|
80
|
-
*
|
|
80
|
+
* Customer-supplied configuration for a coded Experience Template. Identical in
|
|
81
|
+
* shape and behavior to `ComponentConfig` — an Experience Template is just a
|
|
82
|
+
* node whose implementation lives in the `experienceTemplates` registry. Its
|
|
83
|
+
* slots arrive as named props (a `content` slot becomes a `content` prop), so
|
|
84
|
+
* there is no `children` special case.
|
|
81
85
|
*/
|
|
82
86
|
interface ExperienceTemplateConfig<Props extends object = Record<string, unknown>> {
|
|
83
87
|
defaults?: Partial<Props>;
|
|
84
88
|
resolveData?: (ctx: ResolveContext) => Partial<Props> | Promise<Partial<Props>>;
|
|
85
|
-
component: ComponentType<Props
|
|
86
|
-
children?: ReactNode;
|
|
87
|
-
}>;
|
|
89
|
+
component: ComponentType<Props>;
|
|
88
90
|
}
|
|
89
91
|
/**
|
|
90
92
|
* Registry value for Experience Templates. Same dual-shape as component
|
|
91
93
|
* registrations.
|
|
92
94
|
*/
|
|
93
|
-
type ExperienceTemplateRegistration<Props extends object = Record<string, unknown>> = ComponentType<Props
|
|
94
|
-
children?: ReactNode;
|
|
95
|
-
}> | ExperienceTemplateConfig<Props>;
|
|
95
|
+
type ExperienceTemplateRegistration<Props extends object = Record<string, unknown>> = ComponentType<Props> | ExperienceTemplateConfig<Props>;
|
|
96
96
|
/**
|
|
97
97
|
* Identity helper — returns the config as-is, but narrows the `resolveData`
|
|
98
98
|
* and `component` parameter types to your declared `Props`.
|
|
@@ -111,7 +111,9 @@ declare function defineExperienceTemplate<Props extends object = Record<string,
|
|
|
111
111
|
type Components = Record<string, Registration<any>>;
|
|
112
112
|
/**
|
|
113
113
|
* Experience Template registry — keyed by `experienceTemplateId` (last
|
|
114
|
-
* slash-segment of
|
|
114
|
+
* slash-segment of an Experience Template node's own
|
|
115
|
+
* `experienceTemplate.sys.urn`). Not read from `payload.sys`; templates are
|
|
116
|
+
* ordinary nodes.
|
|
115
117
|
*/
|
|
116
118
|
type ExperienceTemplates = Record<string, ExperienceTemplateRegistration<any>>;
|
|
117
119
|
interface Config {
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { ComponentType
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { ComponentType } from 'react';\n\nimport type {\n DesignPropValue,\n ExperienceContext,\n ResolveContext,\n ResolveToken,\n ViewportDef,\n} from '@contentful/experiences-sdk-core';\n\n/**\n * Re-exported for ergonomics: customer code authoring `resolveData` doesn't\n * have to dig into the core package for the context type.\n */\nexport type { ResolveContext, ResolveToken };\n\n/**\n * The full Contentful-side payload for a single component instance, exposed\n * via `useContentfulComponent()` to any descendant of a rendered Experience\n * node. Useful for custom design-property resolution outside the SDK's\n * cascade, branching by `componentId` in a generic wrapper, keying\n * analytics on `nodeId`, or rendering a raw-payload panel in preview.\n *\n * Design properties stay in their **raw discriminated form** here (the same\n * shape `ctx.design` carries inside `resolveData`). The viewport-cascaded,\n * token-resolved values are what `useDesignValues()` returns.\n */\nexport interface ContentfulComponent {\n componentId: string;\n nodeId?: string;\n content: Record<string, unknown>;\n design: Record<string, DesignPropValue>;\n resolved?: Record<string, unknown>;\n}\n\n/**\n * Same shape as `ContentfulComponent`, but for an Experience Template node.\n * Exposed via `useContentfulExperienceTemplate()` inside an Experience\n * Template's component tree.\n */\nexport interface ContentfulExperienceTemplate {\n experienceTemplateId: string;\n nodeId?: string;\n content: Record<string, unknown>;\n design: Record<string, DesignPropValue>;\n resolved?: Record<string, unknown>;\n}\n\n/**\n * Render-time experience context. Extends the core `ExperienceContext` with\n * the active viewport — a render-time value that resolvers cannot see (they\n * run once before viewport resolution and are not re-triggered by viewport\n * changes). Exposed via `useExperience()` to any descendant of the renderer.\n */\nexport interface RenderContext extends ExperienceContext {\n activeViewport: ViewportDef;\n activeViewportIndex: number;\n}\n\n/**\n * Customer-supplied configuration for a single component. The `component`\n * receives the merged props (design + content + resolveData + slots); resolved\n * design values auto-fill matching props and are also readable via\n * `useDesignValues()`. Runtime context and raw payload come from\n * `useExperience()` / `useContentfulComponent()`.\n */\nexport interface ComponentConfig<Props extends object = Record<string, unknown>> {\n /**\n * Lowest-precedence prop bag. Merged in before content / resolveData /\n * slots. Useful for variant fallbacks the editorial layer doesn't always supply.\n */\n defaults?: Partial<Props>;\n /**\n * Optional sync-or-async hook that derives final props from the raw\n * Experience inputs. Runs once during `resolveExperience`, before render —\n * does NOT re-fire on viewport changes.\n */\n resolveData?: (ctx: ResolveContext) => Partial<Props> | Promise<Partial<Props>>;\n /**\n * The React component to render. Receives the merged prop bag as its props.\n */\n component: ComponentType<Props>;\n}\n\n/**\n * Registry value. Register a bare React component for the common case, or\n * the full `ComponentConfig` shape when you need defaults or a `resolveData`\n * hook.\n *\n * button: Button, // bare\n * header: { component: Header, defaults: {...} }, // with defaults\n * card: defineComponent<CardProps>({ component: Card, resolveData: ... }),\n */\nexport type Registration<Props extends object = Record<string, unknown>> =\n | ComponentType<Props>\n | ComponentConfig<Props>;\n\n/**\n * Customer-supplied configuration for a coded Experience Template. Identical in\n * shape and behavior to `ComponentConfig` — an Experience Template is just a\n * node whose implementation lives in the `experienceTemplates` registry. Its\n * slots arrive as named props (a `content` slot becomes a `content` prop), so\n * there is no `children` special case.\n */\nexport interface ExperienceTemplateConfig<Props extends object = Record<string, unknown>> {\n defaults?: Partial<Props>;\n resolveData?: (ctx: ResolveContext) => Partial<Props> | Promise<Partial<Props>>;\n component: ComponentType<Props>;\n}\n\n/**\n * Registry value for Experience Templates. Same dual-shape as component\n * registrations.\n */\nexport type ExperienceTemplateRegistration<Props extends object = Record<string, unknown>> =\n | ComponentType<Props>\n | ExperienceTemplateConfig<Props>;\n\n/**\n * Identity helper — returns the config as-is, but narrows the `resolveData`\n * and `component` parameter types to your declared `Props`.\n */\nexport function defineComponent<Props extends object = Record<string, unknown>>(\n config: ComponentConfig<Props>\n): ComponentConfig<Props> {\n return config;\n}\n\n/**\n * Identity helper — returns the Experience Template config as-is, with `Props`\n * narrowing.\n */\nexport function defineExperienceTemplate<Props extends object = Record<string, unknown>>(\n config: ExperienceTemplateConfig<Props>\n): ExperienceTemplateConfig<Props> {\n return config;\n}\n\n/**\n * Component registry — keyed by `componentId` (last slash-segment of\n * `component.sys.urn`). Per-entry prop narrowing happens at\n * `defineComponent<Props>` or at the bare-component's own type.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- per-entry narrowing happens at the registration author's call site.\nexport type Components = Record<string, Registration<any>>;\n\n/**\n * Experience Template registry — keyed by `experienceTemplateId` (last\n * slash-segment of an Experience Template node's own\n * `experienceTemplate.sys.urn`). Not read from `payload.sys`; templates are\n * ordinary nodes.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- per-entry narrowing happens at the registration author's call site.\nexport type ExperienceTemplates = Record<string, ExperienceTemplateRegistration<any>>;\n\nexport interface Config {\n components: Components;\n experienceTemplates?: ExperienceTemplates;\n /**\n * Resolves `DesignToken` values to runtime values before they reach a\n * component. If omitted, they pass through unchanged. See `ResolveToken`\n * in `@contentful/experiences-sdk-core` for the full contract.\n */\n resolveToken?: ResolveToken;\n}\n\n/**\n * Normalize a registry entry — bare component OR config object — into the\n * common `ComponentConfig` shape used by the renderer.\n *\n * React function components are plain functions; `React.memo` /\n * `React.forwardRef` yield objects carrying a `$$typeof` symbol. Both count\n * as bare components; a config object is discriminated by having a\n * `component` field and no `$$typeof`.\n */\nexport function normalizeComponentRegistration<P extends object>(\n reg: Registration<P>\n): ComponentConfig<P> {\n if (typeof reg === 'object' && reg !== null && !('$$typeof' in reg) && 'component' in reg) {\n return reg as ComponentConfig<P>;\n }\n return { component: reg as ComponentType<P> };\n}\n\nexport function normalizeExperienceTemplateRegistration<P extends object>(\n reg: ExperienceTemplateRegistration<P>\n): ExperienceTemplateConfig<P> {\n if (typeof reg === 'object' && reg !== null && !('$$typeof' in reg) && 'component' in reg) {\n return reg as ExperienceTemplateConfig<P>;\n }\n return { component: reg as ComponentType<P> };\n}\n"],"mappings":"AA0HO,SAAS,gBACd,QACwB;AACxB,SAAO;AACT;AAMO,SAAS,yBACd,QACiC;AACjC,SAAO;AACT;AAuCO,SAAS,+BACd,KACoB;AACpB,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,EAAE,cAAc,QAAQ,eAAe,KAAK;AACzF,WAAO;AAAA,EACT;AACA,SAAO,EAAE,WAAW,IAAwB;AAC9C;AAEO,SAAS,wCACd,KAC6B;AAC7B,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,EAAE,cAAc,QAAQ,eAAe,KAAK;AACzF,WAAO;AAAA,EACT;AACA,SAAO,EAAE,WAAW,IAAwB;AAC9C;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/experiences-react",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.6",
|
|
4
4
|
"description": "React adapter for Contentful Experiences — Server and Client renderers over a PortableRenderPlan",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"directory": "packages/adapter-react"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@contentful/experiences-client": "0.3.
|
|
34
|
-
"@contentful/experiences-sdk-core": "0.7.
|
|
35
|
-
"@contentful/experiences-design": "0.7.
|
|
33
|
+
"@contentful/experiences-client": "0.3.5",
|
|
34
|
+
"@contentful/experiences-sdk-core": "0.7.5",
|
|
35
|
+
"@contentful/experiences-design": "0.7.5"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"react": "^18.0.0 || ^19.0.0",
|