@contentful/experiences-react 0.5.1 → 0.5.4

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 CHANGED
@@ -1,3 +1,35 @@
1
+ ## 0.5.4 (2026-07-24)
2
+
3
+ ### 🧱 Updated Dependencies
4
+
5
+ - Updated client to 0.1.4
6
+ - Updated design to 0.5.4
7
+ - Updated core to 0.5.4
8
+
9
+ ## 0.5.3 (2026-07-21)
10
+
11
+ ### 🩹 Fixes
12
+
13
+ - render missing-component fallback as element in RSC [AIS-316] ([#79](https://github.com/contentful/experiences/pull/79))
14
+
15
+ ### 🧱 Updated Dependencies
16
+
17
+ - Updated client to 0.1.3
18
+ - Updated design to 0.5.3
19
+ - Updated core to 0.5.3
20
+
21
+ ## 0.5.2 (2026-07-20)
22
+
23
+ ### 🩹 Fixes
24
+
25
+ - rename experiences-core to experiences-sdk-core [AIS-305] ([#76](https://github.com/contentful/experiences/pull/76))
26
+
27
+ ### 🧱 Updated Dependencies
28
+
29
+ - Updated client to 0.1.2
30
+ - Updated design to 0.5.2
31
+ - Updated core to 0.5.2
32
+
1
33
  ## 0.5.1 (2026-07-17)
2
34
 
3
35
  ### 🚀 Features
package/README.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # @contentful/experiences-react
2
2
 
3
- > ⚠️ **Pre-alpha.** Not yet published to npm. APIs are unstable and will change.
3
+ > ⚠️ **Alpha.** Published to npm. APIs are unstable and will change.
4
4
 
5
- The React adapter for the Contentful Experiences SDK suite. Renders Experience payloads from the Experience Delivery API (XDA) using customer-supplied React components.
5
+ The React adapter for the Contentful Experiences SDK. You bring your own React components; it renders Experience payloads from the Experience Delivery API (XDA) with them.
6
6
 
7
7
  ```sh
8
8
  npm install @contentful/experiences-react
9
9
  ```
10
10
 
11
- This is the **only SDK package customers install** — it re-exports everything from `@contentful/experiences-core`, `@contentful/experiences-design`, and `@contentful/experiences-client` that consumers need. The other packages are workspace-internal.
11
+ This is the **only SDK package you install**. It re-exports everything you need from `@contentful/experiences-sdk-core`, `@contentful/experiences-design`, and `@contentful/experiences-client`. The other packages are workspace-internal.
12
12
 
13
13
  ---
14
14
 
@@ -24,7 +24,7 @@ defineTemplate<Props>(config); // Same shape, for page-level template wrappers
24
24
  ### Fetching
25
25
 
26
26
  ```ts
27
- fetchExperience(experienceOptions, clientOptions, resolveOptions) // Async — fetches from XDA + resolves in one call
27
+ fetchExperience(experienceOptions, clientOptions, resolveOptions) // Async; fetches from XDA and resolves in one call
28
28
  createClient(options) // Functional constructor matching the SDK's option shape
29
29
  ContentfulViewDeliveryClient // Re-exported delivery client for advanced use cases
30
30
  NotFoundError // Thrown when the Experience ID doesn't exist
@@ -35,7 +35,7 @@ type ExperienceOptions, ClientOptions, ResolveOptions, CreateClientOptions
35
35
  ### Resolver
36
36
 
37
37
  ```ts
38
- resolveExperience(payload, config, opts?) // Async — walks payload, runs resolveData, returns a PortableRenderPlan
38
+ resolveExperience(payload, config, opts?) // Async; walks payload, runs resolveData, returns a PortableRenderPlan
39
39
  ```
40
40
 
41
41
  ### Renderers
@@ -44,25 +44,39 @@ resolveExperience(payload, config, opts?) // Async — walks payload, runs res
44
44
  ServerExperienceRenderer; // RSC-friendly, active viewport seeded from initialViewportId
45
45
  ClientExperienceRenderer; // 'use client', subscribes to window.matchMedia, alias: ExperienceRenderer
46
46
  MissingComponent; // Default fallback for unregistered component types
47
- useActiveViewport; // Hook used inside ClientExperienceRenderer (rarely needed by consumers)
47
+ useActiveViewport; // Hook used inside ClientExperienceRenderer (you'll rarely need it directly)
48
48
  ```
49
49
 
50
+ ### Styling + runtime context (hooks)
51
+
52
+ ```ts
53
+ useDesignValues<T>(); // Resolved design values for the current node (viewport-cascaded + token-resolved)
54
+ toCss(design, options?); // Turns a design record into CSSProperties, keeping only real CSS keys
55
+ useExperience(); // RenderContext: isPreview, metadata, viewports, activeViewport
56
+ useContentfulComponent(); // Raw payload for the enclosing node (or null)
57
+ useContentfulTemplate(); // Same, for the page-level template
58
+ type ToCssOptions;
59
+ ```
60
+
61
+ Design is **not** injected as props; components read it via `useDesignValues()`. Token resolution is configured with `resolveToken` on your `Config` (`type ResolveToken`).
62
+
50
63
  ### Re-exported types and utilities
51
64
 
52
65
  ```ts
53
66
  // From core
54
- type Config, Components, Templates,
67
+ type Config, Components, Templates, Registration, TemplateRegistration,
55
68
  type ComponentConfig, TemplateConfig,
56
- type ComponentProps, TemplateProps,
57
- type RenderContext,
69
+ type ContentfulComponent, ContentfulTemplate,
70
+ type RenderContext, ResolveToken,
58
71
  type ExperiencePayload, ExperienceNode, ComponentTypeNode, TemplateNode,
59
72
  type PortableRenderPlan, PortableRenderNode, PortableTemplate,
60
73
  type DesignPropValue, ManualDesignValue, DesignToken, ValuesByViewport,
61
74
  type ViewportDef, ExperienceContext, ResolveContext,
62
75
  type ResolverConfig, ResolveExperienceOptions
63
76
 
64
- // From design (for customers who want to do their own viewport-aware resolution)
65
- getValueForViewport, getViewportIndex, resolveDesignProperties, toCssMediaQuery
77
+ // From design (if you want to do your own viewport-aware resolution)
78
+ getValueForViewport, getViewportIndex, resolveDesignProperties, toCssMediaQuery,
79
+ isCssProperty, toCssKey, CSS_PROPERTIES
66
80
  ```
67
81
 
68
82
  ---
@@ -70,42 +84,54 @@ getValueForViewport, getViewportIndex, resolveDesignProperties, toCssMediaQuery
70
84
  ## Quick reference
71
85
 
72
86
  ```tsx
73
- import { notFound } from 'next/navigation';
87
+ // components/Button.tsx: reads content props; reads design via the hook
88
+ 'use client';
89
+ import { toCss, useDesignValues } from '@contentful/experiences-react';
90
+
91
+ export function Button({ label, url }: { label?: string; url?: string }) {
92
+ const design = useDesignValues();
93
+ return (
94
+ <a href={url} style={toCss(design)}>
95
+ {label}
96
+ </a>
97
+ );
98
+ }
99
+ ```
100
+
101
+ ```tsx
102
+ // lib/experience-config.tsx
74
103
  import {
75
104
  defineComponent,
76
- defineTemplate,
77
- fetchExperience,
78
- NotFoundError,
79
- ServerExperienceRenderer,
80
- type Config,
81
105
  type Components,
82
- type Templates,
106
+ type Config,
107
+ type ResolveToken,
83
108
  } from '@contentful/experiences-react';
84
109
 
85
- import { Button, type ButtonProps } from './components/Button';
110
+ import { Button } from './components/Button';
86
111
 
87
112
  const components: Components = {
88
- button: defineComponent<ButtonProps>({
89
- defaults: { type: 'primary' },
113
+ // Bare component, or defineComponent({...}) when you need defaults/resolveData.
114
+ Button: defineComponent({
90
115
  resolveData: ({ content }) => ({ url: ensureScheme(content.url) }),
91
- render: Button,
116
+ component: Button,
92
117
  }),
93
118
  };
94
119
 
95
- const experienceConfig: Config = { components };
120
+ const resolveToken: ResolveToken = (token) => designTokens[token.value];
96
121
 
97
- // In a server component:
98
- try {
99
- const experience = await fetchExperience(
100
- { spaceId: process.env.SPACE_ID!, environmentId: 'master', experienceId: slug },
101
- { accessToken: process.env.CDA_TOKEN! },
102
- { config: experienceConfig }
103
- );
104
- return <ServerExperienceRenderer experience={experience} config={experienceConfig} />;
105
- } catch (err) {
106
- if (err instanceof NotFoundError) notFound();
107
- throw err;
108
- }
122
+ export const experienceConfig: Config = { components, resolveToken };
123
+ ```
124
+
125
+ ```tsx
126
+ // app/[slug]/page.tsx: in a server component
127
+ import { fetchExperience, ServerExperienceRenderer } from '@contentful/experiences-react';
128
+
129
+ const experience = await fetchExperience(
130
+ { spaceId: process.env.SPACE_ID!, environmentId: 'master', experienceId: slug },
131
+ { accessToken: process.env.CDA_TOKEN! },
132
+ { config: experienceConfig }
133
+ );
134
+ return <ServerExperienceRenderer experience={experience} config={experienceConfig} />;
109
135
  ```
110
136
 
111
137
  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).
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
- import { PortableRenderPlan, ExperienceContext } from '@contentful/experiences-core';
2
+ import { PortableRenderPlan, ExperienceContext } from '@contentful/experiences-sdk-core';
3
3
  import { RenderUnknown } from './nodes-renderer.js';
4
4
  import { Config } from './types.js';
5
5
  import './missing-component.js';
@@ -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-core';\n\nimport { ExperienceProvider } from './context';\nimport { MissingComponent } from './missing-component';\nimport { NodesRenderer, WrapWithTemplate, type RenderUnknown } from './nodes-renderer';\nimport type { Config, RenderContext } from './types';\nimport { useActiveViewport } from './use-active-viewport';\n\nconst DEFAULT_CONTEXT: ExperienceContext = {\n isPreview: 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 context?: Partial<ExperienceContext>;\n renderUnknown?: RenderUnknown;\n}\n\nexport function ClientExperienceRenderer({\n experience,\n config,\n initialViewportId,\n context,\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 ...context,\n metadata: { ...DEFAULT_CONTEXT.metadata, ...(context?.metadata ?? {}) },\n viewports: contextViewports,\n activeViewport,\n activeViewportIndex,\n };\n\n return (\n <ExperienceProvider value={renderContext}>\n <WrapWithTemplate\n template={experience.template}\n config={config}\n viewports={experience.viewports}\n activeViewportIndex={activeViewportIndex}\n >\n <NodesRenderer\n nodes={experience.nodes}\n config={config}\n viewports={experience.viewports}\n activeViewportIndex={activeViewportIndex}\n renderUnknown={renderUnknown}\n />\n </WrapWithTemplate>\n </ExperienceProvider>\n );\n}\n"],"mappings":";AA4EQ;AA3DR,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AACjC,SAAS,eAAe,wBAA4C;AAEpE,SAAS,yBAAyB;AAElC,MAAM,kBAAqC;AAAA,EACzC,WAAW;AAAA,EACX,UAAU,CAAC;AAAA,EACX,WAAW,CAAC;AACd;AAEA,MAAM,oBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,aAAa;AAAA,EACb,aAAa;AACf;AAWO,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,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,GAAG;AAAA,IACH,UAAU,EAAE,GAAG,gBAAgB,UAAU,GAAI,SAAS,YAAY,CAAC,EAAG;AAAA,IACtE,WAAW;AAAA,IACX;AAAA,IACA;AAAA,EACF;AAEA,SACE,oBAAC,sBAAmB,OAAO,eACzB;AAAA,IAAC;AAAA;AAAA,MACC,UAAU,WAAW;AAAA,MACrB;AAAA,MACA,WAAW,WAAW;AAAA,MACtB;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,WAAW;AAAA,UAClB;AAAA,UACA,WAAW,WAAW;AAAA,UACtB;AAAA,UACA;AAAA;AAAA,MACF;AAAA;AAAA,EACF,GACF;AAEJ;","names":[]}
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 { ExperienceProvider } from './context';\nimport { MissingComponent } from './missing-component';\nimport { NodesRenderer, WrapWithTemplate, type RenderUnknown } from './nodes-renderer';\nimport type { Config, RenderContext } from './types';\nimport { useActiveViewport } from './use-active-viewport';\n\nconst DEFAULT_CONTEXT: ExperienceContext = {\n isPreview: 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 context?: Partial<ExperienceContext>;\n renderUnknown?: RenderUnknown;\n}\n\nexport function ClientExperienceRenderer({\n experience,\n config,\n initialViewportId,\n context,\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 ...context,\n metadata: { ...DEFAULT_CONTEXT.metadata, ...(context?.metadata ?? {}) },\n viewports: contextViewports,\n activeViewport,\n activeViewportIndex,\n };\n\n return (\n <ExperienceProvider value={renderContext}>\n <WrapWithTemplate\n template={experience.template}\n config={config}\n viewports={experience.viewports}\n activeViewportIndex={activeViewportIndex}\n >\n <NodesRenderer\n nodes={experience.nodes}\n config={config}\n viewports={experience.viewports}\n activeViewportIndex={activeViewportIndex}\n renderUnknown={renderUnknown}\n />\n </WrapWithTemplate>\n </ExperienceProvider>\n );\n}\n"],"mappings":";AA4EQ;AA3DR,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AACjC,SAAS,eAAe,wBAA4C;AAEpE,SAAS,yBAAyB;AAElC,MAAM,kBAAqC;AAAA,EACzC,WAAW;AAAA,EACX,UAAU,CAAC;AAAA,EACX,WAAW,CAAC;AACd;AAEA,MAAM,oBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,aAAa;AAAA,EACb,aAAa;AACf;AAWO,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,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,GAAG;AAAA,IACH,UAAU,EAAE,GAAG,gBAAgB,UAAU,GAAI,SAAS,YAAY,CAAC,EAAG;AAAA,IACtE,WAAW;AAAA,IACX;AAAA,IACA;AAAA,EACF;AAEA,SACE,oBAAC,sBAAmB,OAAO,eACzB;AAAA,IAAC;AAAA;AAAA,MACC,UAAU,WAAW;AAAA,MACrB;AAAA,MACA,WAAW,WAAW;AAAA,MACtB;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,WAAW;AAAA,UAClB;AAAA,UACA,WAAW,WAAW;AAAA,UACtB;AAAA,UACA;AAAA;AAAA,MACF;AAAA;AAAA,EACF,GACF;AAEJ;","names":[]}
package/dist/context.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { ContentfulComponent, ContentfulTemplate, RenderContext } from './types.js';
3
- import '@contentful/experiences-core';
3
+ import '@contentful/experiences-sdk-core';
4
4
 
5
5
  declare function ExperienceProvider({ value, children, }: {
6
6
  value: RenderContext;
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ export { useContentfulComponent, useContentfulTemplate, useExperience } from './
7
7
  export { useDesignValues } from './use-design-values.js';
8
8
  export { ToCssOptions, toCss } from './design-utils.js';
9
9
  export { ComponentConfig, Components, Config, ContentfulComponent, ContentfulTemplate, Registration, RenderContext, TemplateConfig, TemplateRegistration, Templates, defineComponent, defineTemplate, normalizeComponentRegistration, normalizeTemplateRegistration } from './types.js';
10
- export { ComponentTypeNode, ComponentTypeRef, DesignPropValue, DesignToken, ExperienceContext, ExperienceNode, ExperiencePayload, ExperienceSys, ManualDesignValue, PortableRegistration, PortableRenderNode, PortableRenderPlan, PortableTemplate, ResolveContext, ResolveExperienceOptions, ResolveToken, ResolverConfig, TemplateNode, TemplateRef, ValuesByViewport, ViewportDef, resolveExperience } from '@contentful/experiences-core';
10
+ export { ComponentTypeNode, ComponentTypeRef, DesignPropValue, DesignToken, ExperienceContext, ExperienceNode, ExperiencePayload, ExperienceSys, ManualDesignValue, PortableRegistration, PortableRenderNode, PortableRenderPlan, PortableTemplate, ResolveContext, ResolveExperienceOptions, ResolveToken, ResolverConfig, TemplateNode, TemplateRef, ValuesByViewport, ViewportDef, resolveExperience } from '@contentful/experiences-sdk-core';
11
11
  export { CSS_PROPERTIES, getValueForViewport, getViewportIndex, isCssProperty, resolveDesignProperties, toCssKey, toCssMediaQuery } from '@contentful/experiences-design';
12
12
  export { ClientOptions, ContentfulViewDelivery, ContentfulViewDeliveryClient, CreateClientOptions, ExperienceOptions, NotFoundError, ResolveOptions, createClient, fetchExperience } from '@contentful/experiences-client';
13
13
  import 'react';
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  normalizeComponentRegistration,
15
15
  normalizeTemplateRegistration
16
16
  } from "./types";
17
- import { resolveExperience } from "@contentful/experiences-core";
17
+ import { resolveExperience } from "@contentful/experiences-sdk-core";
18
18
  import {
19
19
  CSS_PROPERTIES,
20
20
  getValueForViewport,
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-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 { 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, useContentfulTemplate } 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 defineTemplate,\n normalizeComponentRegistration,\n normalizeTemplateRegistration,\n} from './types';\nexport type {\n ComponentConfig,\n Components,\n Config,\n ContentfulComponent,\n ContentfulTemplate,\n Registration,\n RenderContext,\n ResolveToken,\n TemplateConfig,\n TemplateRegistration,\n Templates,\n} from './types';\n\n// ─── Resolver (re-exported from render-core) ──────────────────────────────\nexport { resolveExperience } from '@contentful/experiences-core';\nexport type { ResolverConfig, ResolveExperienceOptions } from '@contentful/experiences-core';\n\n// ─── Core IR + payload types (re-exported from render-core) ───────────────\nexport type {\n ComponentTypeNode,\n ComponentTypeRef,\n DesignPropValue,\n DesignToken,\n ExperienceContext,\n ExperienceNode,\n ExperiencePayload,\n ExperienceSys,\n ManualDesignValue,\n PortableRegistration,\n PortableRenderNode,\n PortableRenderPlan,\n PortableTemplate,\n ResolveContext,\n TemplateNode,\n TemplateRef,\n ValuesByViewport,\n ViewportDef,\n} from '@contentful/experiences-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 NotFoundError,\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,yBAAyB;AAMlC,SAAS,eAAe,wBAAwB,6BAA6B;AAC7E,SAAS,uBAAuB;AAChC,SAAS,aAAa;AAItB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAgBP,SAAS,yBAAyB;AA0BlC;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,OACK;","names":["ClientExperienceRenderer"]}
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 { 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, useContentfulTemplate } 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 defineTemplate,\n normalizeComponentRegistration,\n normalizeTemplateRegistration,\n} from './types';\nexport type {\n ComponentConfig,\n Components,\n Config,\n ContentfulComponent,\n ContentfulTemplate,\n Registration,\n RenderContext,\n ResolveToken,\n TemplateConfig,\n TemplateRegistration,\n Templates,\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 ComponentTypeNode,\n ComponentTypeRef,\n DesignPropValue,\n DesignToken,\n ExperienceContext,\n ExperienceNode,\n ExperiencePayload,\n ExperienceSys,\n ManualDesignValue,\n PortableRegistration,\n PortableRenderNode,\n PortableRenderPlan,\n PortableTemplate,\n ResolveContext,\n TemplateNode,\n TemplateRef,\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 NotFoundError,\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,yBAAyB;AAMlC,SAAS,eAAe,wBAAwB,6BAA6B;AAC7E,SAAS,uBAAuB;AAChC,SAAS,aAAa;AAItB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAgBP,SAAS,yBAAyB;AA0BlC;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,OACK;","names":["ClientExperienceRenderer"]}
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { jsx, jsxs } from "react/jsx-runtime";
2
3
  import { useExperience } from "./context";
3
4
  function MissingComponent({ componentTypeId, nodeId }) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/missing-component.tsx"],"sourcesContent":["/*\n * Default fallback rendered when an instance references a component type\n * not present in the Config.\n *\n * Behavior: a visible red error box in preview, silent null in production.\n * Customers can override per-render via <ExperienceRenderer renderUnknown=...>.\n */\n\nimport type { ReactNode } from 'react';\n\nimport { useExperience } from './context';\n\nexport interface MissingComponentProps {\n componentTypeId: string;\n /** Optional — only present when the payload supplied an id for this node. */\n nodeId?: string;\n}\n\nexport function MissingComponent({ componentTypeId, nodeId }: MissingComponentProps): ReactNode {\n const { isPreview } = useExperience();\n if (typeof console !== 'undefined') {\n const idLabel = nodeId ? ` (nodeId: ${nodeId})` : '';\n console.warn(\n `[@contentful/experiences] No component registered for type \"${componentTypeId}\"${idLabel}.`\n );\n }\n if (!isPreview) return null;\n return (\n <div\n style={{\n border: '2px solid red',\n padding: '1rem',\n color: 'red',\n background: '#fff',\n }}\n data-experiences-missing={componentTypeId}\n >\n <strong>Missing component &lsquo;{componentTypeId}&rsquo;</strong>\n <p>\n This component is referenced by the Experience payload but is not registered in the Config.\n </p>\n </div>\n );\n}\n"],"mappings":"AAqCM,SACA,KADA;AA3BN,SAAS,qBAAqB;AAQvB,SAAS,iBAAiB,EAAE,iBAAiB,OAAO,GAAqC;AAC9F,QAAM,EAAE,UAAU,IAAI,cAAc;AACpC,MAAI,OAAO,YAAY,aAAa;AAClC,UAAM,UAAU,SAAS,aAAa,MAAM,MAAM;AAClD,YAAQ;AAAA,MACN,+DAA+D,eAAe,IAAI,OAAO;AAAA,IAC3F;AAAA,EACF;AACA,MAAI,CAAC,UAAW,QAAO;AACvB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,QACP,YAAY;AAAA,MACd;AAAA,MACA,4BAA0B;AAAA,MAE1B;AAAA,6BAAC,YAAO;AAAA;AAAA,UAA0B;AAAA,UAAgB;AAAA,WAAO;AAAA,QACzD,oBAAC,OAAE,yGAEH;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/missing-component.tsx"],"sourcesContent":["/*\n * Default fallback rendered when an instance references a component type\n * not present in the Config.\n *\n * Behavior: a visible red error box in preview, silent null in production.\n * Customers can override per-render via <ExperienceRenderer renderUnknown=...>.\n */\n'use client';\n\nimport type { ReactNode } from 'react';\n\nimport { useExperience } from './context';\n\nexport interface MissingComponentProps {\n componentTypeId: string;\n /** Optional — only present when the payload supplied an id for this node. */\n nodeId?: string;\n}\n\nexport function MissingComponent({ componentTypeId, nodeId }: MissingComponentProps): ReactNode {\n const { isPreview } = useExperience();\n if (typeof console !== 'undefined') {\n const idLabel = nodeId ? ` (nodeId: ${nodeId})` : '';\n console.warn(\n `[@contentful/experiences] No component registered for type \"${componentTypeId}\"${idLabel}.`\n );\n }\n if (!isPreview) return null;\n return (\n <div\n style={{\n border: '2px solid red',\n padding: '1rem',\n color: 'red',\n background: '#fff',\n }}\n data-experiences-missing={componentTypeId}\n >\n <strong>Missing component &lsquo;{componentTypeId}&rsquo;</strong>\n <p>\n This component is referenced by the Experience payload but is not registered in the Config.\n </p>\n </div>\n );\n}\n"],"mappings":";AAsCM,SACA,KADA;AA3BN,SAAS,qBAAqB;AAQvB,SAAS,iBAAiB,EAAE,iBAAiB,OAAO,GAAqC;AAC9F,QAAM,EAAE,UAAU,IAAI,cAAc;AACpC,MAAI,OAAO,YAAY,aAAa;AAClC,UAAM,UAAU,SAAS,aAAa,MAAM,MAAM;AAClD,YAAQ;AAAA,MACN,+DAA+D,eAAe,IAAI,OAAO;AAAA,IAC3F;AAAA,EACF;AACA,MAAI,CAAC,UAAW,QAAO;AACvB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,QACP,YAAY;AAAA,MACd;AAAA,MACA,4BAA0B;AAAA,MAE1B;AAAA,6BAAC,YAAO;AAAA;AAAA,UAA0B;AAAA,UAAgB;AAAA,WAAO;AAAA,QACzD,oBAAC,OAAE,yGAEH;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
- import { PortableRenderNode, ViewportDef, PortableTemplate } from '@contentful/experiences-core';
2
+ import { PortableRenderNode, ViewportDef, PortableTemplate } from '@contentful/experiences-sdk-core';
3
3
  import { MissingComponentProps } from './missing-component.js';
4
4
  import { Config } from './types.js';
5
5
 
@@ -40,7 +40,7 @@ function NodeRenderer({
40
40
  const { componentTypeId } = node.registration;
41
41
  const entry = config.components[componentTypeId];
42
42
  if (!entry) {
43
- return renderUnknown({ componentTypeId, nodeId: node.nodeId });
43
+ return createElement(renderUnknown, { componentTypeId, nodeId: node.nodeId });
44
44
  }
45
45
  const componentConfig = normalizeComponentRegistration(entry);
46
46
  const slotProps = {};
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/nodes-renderer.tsx"],"sourcesContent":["/*\n * Recursive renderer over PortableRenderNodes. Customer components receive the\n * merged prop bag (defaults + content + resolveData + slots); design values\n * are read via `useDesignValues()`, not injected as props.\n */\n\nimport { Fragment, createElement, type ReactNode } from 'react';\n\nimport type {\n PortableRenderNode,\n PortableTemplate,\n ViewportDef,\n} from '@contentful/experiences-core';\nimport { applyTokenResolver, resolveDesignProperties } from '@contentful/experiences-design';\n\nimport {\n ContentfulComponentProvider,\n ContentfulTemplateProvider,\n ResolvedDesignProvider,\n} from './context';\nimport type { MissingComponentProps } from './missing-component';\nimport {\n normalizeComponentRegistration,\n normalizeTemplateRegistration,\n type ContentfulComponent,\n type ContentfulTemplate,\n type Config,\n} from './types';\n\nexport type RenderUnknown = (props: MissingComponentProps) => ReactNode;\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 renderUnknown: RenderUnknown;\n}\n\nexport function NodesRenderer({\n nodes,\n config,\n viewports,\n activeViewportIndex,\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 renderUnknown={renderUnknown}\n />\n ))}\n </Fragment>\n );\n}\n\ninterface NodeRendererProps {\n node: PortableRenderNode;\n config: Config;\n viewports: ViewportDef[];\n activeViewportIndex: number;\n renderUnknown: RenderUnknown;\n}\n\nfunction NodeRenderer({\n node,\n config,\n viewports,\n activeViewportIndex,\n renderUnknown,\n}: NodeRendererProps): ReactNode {\n const { componentTypeId } = node.registration;\n const entry = config.components[componentTypeId];\n if (!entry) {\n return renderUnknown({ componentTypeId, nodeId: node.nodeId });\n }\n const componentConfig = normalizeComponentRegistration(entry);\n\n // Pre-render slot subtrees so components receive ReactNodes by slot name.\n const slotProps: Record<string, ReactNode> = {};\n for (const [slotName, children] of Object.entries(node.slots)) {\n slotProps[slotName] = (\n <NodesRenderer\n nodes={children}\n config={config}\n viewports={viewports}\n activeViewportIndex={activeViewportIndex}\n renderUnknown={renderUnknown}\n />\n );\n }\n\n // Cascade design to the active viewport, then resolve DesignToken envelopes.\n // Published on context for useDesignValues() — never spread onto props.\n const resolvedDesign = resolveDesignProperties(node.props.design, viewports, activeViewportIndex);\n const { props: tokenResolvedDesign, unresolved } = applyTokenResolver(\n resolvedDesign,\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 \"${componentTypeId}\": ${unresolved.join(', ')}. useDesignValues() will omit those keys.`\n );\n }\n\n const contentful: ContentfulComponent = {\n componentTypeId,\n nodeId: node.nodeId,\n content: node.props.content,\n design: node.props.design,\n resolved: node.props.resolved,\n };\n\n // Merge precedence (last wins): defaults < content < resolveData < slots.\n const composed = {\n ...componentConfig.defaults,\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 WrapWithTemplateProps {\n template: PortableTemplate | undefined;\n config: Config;\n viewports: ViewportDef[];\n activeViewportIndex: number;\n children: ReactNode;\n}\n\n/**\n * Wraps the rendered nodes with the page-level template. If the template is\n * referenced but unregistered, warns once and renders children unwrapped.\n */\nexport function WrapWithTemplate({\n template,\n config,\n viewports,\n activeViewportIndex,\n children,\n}: WrapWithTemplateProps): ReactNode {\n if (!template) return <Fragment>{children}</Fragment>;\n const entry = config.templates?.[template.templateId];\n if (!entry) {\n if (typeof console !== 'undefined') {\n console.warn(\n `[@contentful/experiences-react] No template registered for id \"${template.templateId}\". Rendering nodes without the template wrapper.`\n );\n }\n return <Fragment>{children}</Fragment>;\n }\n const templateConfig = normalizeTemplateRegistration(entry);\n\n const resolvedDesign = resolveDesignProperties(\n template.props.design,\n viewports,\n activeViewportIndex\n );\n\n const { props: tokenResolvedDesign, unresolved } = applyTokenResolver(\n resolvedDesign,\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 template \"${template.templateId}\": ${unresolved.join(', ')}. useDesignValues() will omit those keys.`\n );\n }\n\n const contentful: ContentfulTemplate = {\n templateId: template.templateId,\n content: template.props.content,\n design: template.props.design,\n resolved: template.props.resolved,\n };\n\n const composed = {\n ...templateConfig.defaults,\n ...template.props.content,\n ...template.props.resolved,\n children,\n };\n\n return (\n <ContentfulTemplateProvider value={contentful}>\n <ResolvedDesignProvider value={tokenResolvedDesign}>\n {createElement(templateConfig.component, composed)}\n </ResolvedDesignProvider>\n </ContentfulTemplateProvider>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/nodes-renderer.tsx"],"sourcesContent":["/*\n * Recursive renderer over PortableRenderNodes. Customer components receive the\n * merged prop bag (defaults + content + resolveData + slots); design values\n * are read via `useDesignValues()`, not injected as props.\n */\n\nimport { Fragment, createElement, type ReactNode } from 'react';\n\nimport type {\n PortableRenderNode,\n PortableTemplate,\n ViewportDef,\n} from '@contentful/experiences-sdk-core';\nimport { applyTokenResolver, resolveDesignProperties } from '@contentful/experiences-design';\n\nimport {\n ContentfulComponentProvider,\n ContentfulTemplateProvider,\n ResolvedDesignProvider,\n} from './context';\nimport type { MissingComponentProps } from './missing-component';\nimport {\n normalizeComponentRegistration,\n normalizeTemplateRegistration,\n type ContentfulComponent,\n type ContentfulTemplate,\n type Config,\n} from './types';\n\nexport type RenderUnknown = (props: MissingComponentProps) => ReactNode;\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 renderUnknown: RenderUnknown;\n}\n\nexport function NodesRenderer({\n nodes,\n config,\n viewports,\n activeViewportIndex,\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 renderUnknown={renderUnknown}\n />\n ))}\n </Fragment>\n );\n}\n\ninterface NodeRendererProps {\n node: PortableRenderNode;\n config: Config;\n viewports: ViewportDef[];\n activeViewportIndex: number;\n renderUnknown: RenderUnknown;\n}\n\nfunction NodeRenderer({\n node,\n config,\n viewports,\n activeViewportIndex,\n renderUnknown,\n}: NodeRendererProps): ReactNode {\n const { componentTypeId } = node.registration;\n const entry = config.components[componentTypeId];\n if (!entry) {\n return createElement(renderUnknown, { componentTypeId, nodeId: node.nodeId });\n }\n const componentConfig = normalizeComponentRegistration(entry);\n\n // Pre-render slot subtrees so components receive ReactNodes by slot name.\n const slotProps: Record<string, ReactNode> = {};\n for (const [slotName, children] of Object.entries(node.slots)) {\n slotProps[slotName] = (\n <NodesRenderer\n nodes={children}\n config={config}\n viewports={viewports}\n activeViewportIndex={activeViewportIndex}\n renderUnknown={renderUnknown}\n />\n );\n }\n\n // Cascade design to the active viewport, then resolve DesignToken envelopes.\n // Published on context for useDesignValues() — never spread onto props.\n const resolvedDesign = resolveDesignProperties(node.props.design, viewports, activeViewportIndex);\n const { props: tokenResolvedDesign, unresolved } = applyTokenResolver(\n resolvedDesign,\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 \"${componentTypeId}\": ${unresolved.join(', ')}. useDesignValues() will omit those keys.`\n );\n }\n\n const contentful: ContentfulComponent = {\n componentTypeId,\n nodeId: node.nodeId,\n content: node.props.content,\n design: node.props.design,\n resolved: node.props.resolved,\n };\n\n // Merge precedence (last wins): defaults < content < resolveData < slots.\n const composed = {\n ...componentConfig.defaults,\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 WrapWithTemplateProps {\n template: PortableTemplate | undefined;\n config: Config;\n viewports: ViewportDef[];\n activeViewportIndex: number;\n children: ReactNode;\n}\n\n/**\n * Wraps the rendered nodes with the page-level template. If the template is\n * referenced but unregistered, warns once and renders children unwrapped.\n */\nexport function WrapWithTemplate({\n template,\n config,\n viewports,\n activeViewportIndex,\n children,\n}: WrapWithTemplateProps): ReactNode {\n if (!template) return <Fragment>{children}</Fragment>;\n const entry = config.templates?.[template.templateId];\n if (!entry) {\n if (typeof console !== 'undefined') {\n console.warn(\n `[@contentful/experiences-react] No template registered for id \"${template.templateId}\". Rendering nodes without the template wrapper.`\n );\n }\n return <Fragment>{children}</Fragment>;\n }\n const templateConfig = normalizeTemplateRegistration(entry);\n\n const resolvedDesign = resolveDesignProperties(\n template.props.design,\n viewports,\n activeViewportIndex\n );\n\n const { props: tokenResolvedDesign, unresolved } = applyTokenResolver(\n resolvedDesign,\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 template \"${template.templateId}\": ${unresolved.join(', ')}. useDesignValues() will omit those keys.`\n );\n }\n\n const contentful: ContentfulTemplate = {\n templateId: template.templateId,\n content: template.props.content,\n design: template.props.design,\n resolved: template.props.resolved,\n };\n\n const composed = {\n ...templateConfig.defaults,\n ...template.props.content,\n ...template.props.resolved,\n children,\n };\n\n return (\n <ContentfulTemplateProvider value={contentful}>\n <ResolvedDesignProvider value={tokenResolvedDesign}>\n {createElement(templateConfig.component, composed)}\n </ResolvedDesignProvider>\n </ContentfulTemplateProvider>\n );\n}\n"],"mappings":"AAsDQ;AAhDR,SAAS,UAAU,qBAAqC;AAOxD,SAAS,oBAAoB,+BAA+B;AAE5D;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,OAIK;AAgBA,SAAS,cAAc;AAAA,EAC5B;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;AAAA,IALK,KAAK,UAAU;AAAA,EAMtB,CACD,GACH;AAEJ;AAUA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiC;AAC/B,QAAM,EAAE,gBAAgB,IAAI,KAAK;AACjC,QAAM,QAAQ,OAAO,WAAW,eAAe;AAC/C,MAAI,CAAC,OAAO;AACV,WAAO,cAAc,eAAe,EAAE,iBAAiB,QAAQ,KAAK,OAAO,CAAC;AAAA,EAC9E;AACA,QAAM,kBAAkB,+BAA+B,KAAK;AAG5D,QAAM,YAAuC,CAAC;AAC9C,aAAW,CAAC,UAAU,QAAQ,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAG;AAC7D,cAAU,QAAQ,IAChB;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF;AAAA,EAEJ;AAIA,QAAM,iBAAiB,wBAAwB,KAAK,MAAM,QAAQ,WAAW,mBAAmB;AAChG,QAAM,EAAE,OAAO,qBAAqB,WAAW,IAAI;AAAA,IACjD;AAAA,IACA,OAAO;AAAA,EACT;AACA,MAAI,WAAW,UAAU,OAAO,YAAY,aAAa;AACvD,YAAQ;AAAA,MACN,uFAAuF,eAAe,MAAM,WAAW,KAAK,IAAI,CAAC;AAAA,IACnI;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,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;AAcO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqC;AACnC,MAAI,CAAC,SAAU,QAAO,oBAAC,YAAU,UAAS;AAC1C,QAAM,QAAQ,OAAO,YAAY,SAAS,UAAU;AACpD,MAAI,CAAC,OAAO;AACV,QAAI,OAAO,YAAY,aAAa;AAClC,cAAQ;AAAA,QACN,kEAAkE,SAAS,UAAU;AAAA,MACvF;AAAA,IACF;AACA,WAAO,oBAAC,YAAU,UAAS;AAAA,EAC7B;AACA,QAAM,iBAAiB,8BAA8B,KAAK;AAE1D,QAAM,iBAAiB;AAAA,IACrB,SAAS,MAAM;AAAA,IACf;AAAA,IACA;AAAA,EACF;AAEA,QAAM,EAAE,OAAO,qBAAqB,WAAW,IAAI;AAAA,IACjD;AAAA,IACA,OAAO;AAAA,EACT;AACA,MAAI,WAAW,UAAU,OAAO,YAAY,aAAa;AACvD,YAAQ;AAAA,MACN,gGAAgG,SAAS,UAAU,MAAM,WAAW,KAAK,IAAI,CAAC;AAAA,IAChJ;AAAA,EACF;AAEA,QAAM,aAAiC;AAAA,IACrC,YAAY,SAAS;AAAA,IACrB,SAAS,SAAS,MAAM;AAAA,IACxB,QAAQ,SAAS,MAAM;AAAA,IACvB,UAAU,SAAS,MAAM;AAAA,EAC3B;AAEA,QAAM,WAAW;AAAA,IACf,GAAG,eAAe;AAAA,IAClB,GAAG,SAAS,MAAM;AAAA,IAClB,GAAG,SAAS,MAAM;AAAA,IAClB;AAAA,EACF;AAEA,SACE,oBAAC,8BAA2B,OAAO,YACjC,8BAAC,0BAAuB,OAAO,qBAC5B,wBAAc,eAAe,WAAW,QAAQ,GACnD,GACF;AAEJ;","names":[]}
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
- import { PortableRenderPlan, ExperienceContext } from '@contentful/experiences-core';
2
+ import { PortableRenderPlan, ExperienceContext } from '@contentful/experiences-sdk-core';
3
3
  import { RenderUnknown } from './nodes-renderer.js';
4
4
  import { Config } from './types.js';
5
5
  import './missing-component.js';
@@ -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-core';\nimport { getViewportIndex } from '@contentful/experiences-design';\n\nimport { ExperienceProvider } from './context';\nimport { MissingComponent } from './missing-component';\nimport { NodesRenderer, WrapWithTemplate, type RenderUnknown } from './nodes-renderer';\nimport type { Config, RenderContext } from './types';\n\nconst DEFAULT_CONTEXT: ExperienceContext = {\n isPreview: 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 /** Per-render context shallow-merged onto defaults. */\n context?: Partial<ExperienceContext>;\n /** Override the fallback rendered for unregistered component types. */\n renderUnknown?: RenderUnknown;\n}\n\nexport function ServerExperienceRenderer({\n experience,\n config,\n initialViewportId,\n context,\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 ...context,\n metadata: { ...DEFAULT_CONTEXT.metadata, ...(context?.metadata ?? {}) },\n viewports: contextViewports,\n activeViewport,\n activeViewportIndex,\n };\n\n return (\n <ExperienceProvider value={renderContext}>\n <WrapWithTemplate\n template={experience.template}\n config={config}\n viewports={experience.viewports}\n activeViewportIndex={activeViewportIndex}\n >\n <NodesRenderer\n nodes={experience.nodes}\n config={config}\n viewports={experience.viewports}\n activeViewportIndex={activeViewportIndex}\n renderUnknown={renderUnknown}\n />\n </WrapWithTemplate>\n </ExperienceProvider>\n );\n}\n"],"mappings":"AA8EQ;AAlER,SAAS,wBAAwB;AAEjC,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AACjC,SAAS,eAAe,wBAA4C;AAGpE,MAAM,kBAAqC;AAAA,EACzC,WAAW;AAAA,EACX,UAAU,CAAC;AAAA,EACX,WAAW,CAAC;AACd;AAGA,MAAM,oBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,aAAa;AAAA,EACb,aAAa;AACf;AAaO,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,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,GAAG;AAAA,IACH,UAAU,EAAE,GAAG,gBAAgB,UAAU,GAAI,SAAS,YAAY,CAAC,EAAG;AAAA,IACtE,WAAW;AAAA,IACX;AAAA,IACA;AAAA,EACF;AAEA,SACE,oBAAC,sBAAmB,OAAO,eACzB;AAAA,IAAC;AAAA;AAAA,MACC,UAAU,WAAW;AAAA,MACrB;AAAA,MACA,WAAW,WAAW;AAAA,MACtB;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,WAAW;AAAA,UAClB;AAAA,UACA,WAAW,WAAW;AAAA,UACtB;AAAA,UACA;AAAA;AAAA,MACF;AAAA;AAAA,EACF,GACF;AAEJ;","names":[]}
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 { ExperienceProvider } from './context';\nimport { MissingComponent } from './missing-component';\nimport { NodesRenderer, WrapWithTemplate, type RenderUnknown } from './nodes-renderer';\nimport type { Config, RenderContext } from './types';\n\nconst DEFAULT_CONTEXT: ExperienceContext = {\n isPreview: 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 /** Per-render context shallow-merged onto defaults. */\n context?: Partial<ExperienceContext>;\n /** Override the fallback rendered for unregistered component types. */\n renderUnknown?: RenderUnknown;\n}\n\nexport function ServerExperienceRenderer({\n experience,\n config,\n initialViewportId,\n context,\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 ...context,\n metadata: { ...DEFAULT_CONTEXT.metadata, ...(context?.metadata ?? {}) },\n viewports: contextViewports,\n activeViewport,\n activeViewportIndex,\n };\n\n return (\n <ExperienceProvider value={renderContext}>\n <WrapWithTemplate\n template={experience.template}\n config={config}\n viewports={experience.viewports}\n activeViewportIndex={activeViewportIndex}\n >\n <NodesRenderer\n nodes={experience.nodes}\n config={config}\n viewports={experience.viewports}\n activeViewportIndex={activeViewportIndex}\n renderUnknown={renderUnknown}\n />\n </WrapWithTemplate>\n </ExperienceProvider>\n );\n}\n"],"mappings":"AA8EQ;AAlER,SAAS,wBAAwB;AAEjC,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AACjC,SAAS,eAAe,wBAA4C;AAGpE,MAAM,kBAAqC;AAAA,EACzC,WAAW;AAAA,EACX,UAAU,CAAC;AAAA,EACX,WAAW,CAAC;AACd;AAGA,MAAM,oBAAiC;AAAA,EACrC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,aAAa;AAAA,EACb,aAAa;AACf;AAaO,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,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,GAAG;AAAA,IACH,UAAU,EAAE,GAAG,gBAAgB,UAAU,GAAI,SAAS,YAAY,CAAC,EAAG;AAAA,IACtE,WAAW;AAAA,IACX;AAAA,IACA;AAAA,EACF;AAEA,SACE,oBAAC,sBAAmB,OAAO,eACzB;AAAA,IAAC;AAAA;AAAA,MACC,UAAU,WAAW;AAAA,MACrB;AAAA,MACA,WAAW,WAAW;AAAA,MACtB;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,WAAW;AAAA,UAClB;AAAA,UACA,WAAW,WAAW;AAAA,UACtB;AAAA,UACA;AAAA;AAAA,MACF;AAAA;AAAA,EACF,GACF;AAEJ;","names":[]}
package/dist/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ComponentType, ReactNode } from 'react';
2
- import { ResolveContext, ResolveToken, DesignPropValue, ExperienceContext, ViewportDef } from '@contentful/experiences-core';
3
- export { ResolveContext, ResolveToken } from '@contentful/experiences-core';
2
+ import { ResolveContext, ResolveToken, DesignPropValue, ExperienceContext, ViewportDef } from '@contentful/experiences-sdk-core';
3
+ export { ResolveContext, ResolveToken } from '@contentful/experiences-sdk-core';
4
4
 
5
5
  /**
6
6
  * The full Contentful-side payload for a single component instance, exposed
@@ -116,7 +116,7 @@ interface Config {
116
116
  /**
117
117
  * Resolves `DesignToken` envelopes to runtime values before they reach a
118
118
  * component. If omitted, envelopes pass through unchanged. See `ResolveToken`
119
- * in `@contentful/experiences-core` for the full contract.
119
+ * in `@contentful/experiences-sdk-core` for the full contract.
120
120
  */
121
121
  resolveToken?: ResolveToken;
122
122
  }
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { ComponentType, ReactNode } from 'react';\n\nimport type {\n DesignPropValue,\n ExperienceContext,\n ResolveContext,\n ResolveToken,\n ViewportDef,\n} from '@contentful/experiences-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 `componentTypeId` 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 envelope form** here (the same shape\n * `ctx.design` carries inside `resolveData`). The viewport-cascaded, token-\n * resolved values are what `useDesignValues()` returns.\n */\nexport interface ContentfulComponent {\n componentTypeId: 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 the page-level template.\n * Exposed via `useContentfulTemplate()` inside a template's component tree.\n */\nexport interface ContentfulTemplate {\n templateId: 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 type. The `component`\n * receives the merged prop bag (content + resolveData + slots). Design values\n * are not injected — a component reads them via `useDesignValues()`. Runtime\n * context and raw payload come from `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 page-level template. The template's\n * component receives the rendered Experience nodes as `children`.\n */\nexport interface TemplateConfig<Props extends object = Record<string, unknown>> {\n defaults?: Partial<Props>;\n resolveData?: (ctx: ResolveContext) => Partial<Props> | Promise<Partial<Props>>;\n component: ComponentType<Props & { children?: ReactNode }>;\n}\n\n/**\n * Registry value for templates. Same dual-shape as component registrations.\n */\nexport type TemplateRegistration<Props extends object = Record<string, unknown>> =\n | ComponentType<Props & { children?: ReactNode }>\n | TemplateConfig<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 template config as-is, with `Props` narrowing.\n */\nexport function defineTemplate<Props extends object = Record<string, unknown>>(\n config: TemplateConfig<Props>\n): TemplateConfig<Props> {\n return config;\n}\n\n/**\n * Component registry — keyed by `componentTypeId` (last slash-segment of\n * `componentType.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 * Template registry — keyed by `templateId` (last slash-segment of\n * `payload.sys.template.sys.urn`).\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- per-entry narrowing happens at the registration author's call site.\nexport type Templates = Record<string, TemplateRegistration<any>>;\n\nexport interface Config {\n components: Components;\n templates?: Templates;\n /**\n * Resolves `DesignToken` envelopes to runtime values before they reach a\n * component. If omitted, envelopes pass through unchanged. See `ResolveToken`\n * in `@contentful/experiences-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 normalizeTemplateRegistration<P extends object>(\n reg: TemplateRegistration<P>\n): TemplateConfig<P> {\n if (typeof reg === 'object' && reg !== null && !('$$typeof' in reg) && 'component' in reg) {\n return reg as TemplateConfig<P>;\n }\n return { component: reg as ComponentType<P & { children?: ReactNode }> };\n}\n"],"mappings":"AAmHO,SAAS,gBACd,QACwB;AACxB,SAAO;AACT;AAKO,SAAS,eACd,QACuB;AACvB,SAAO;AACT;AAqCO,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,8BACd,KACmB;AACnB,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,EAAE,cAAc,QAAQ,eAAe,KAAK;AACzF,WAAO;AAAA,EACT;AACA,SAAO,EAAE,WAAW,IAAmD;AACzE;","names":[]}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { ComponentType, ReactNode } 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 `componentTypeId` 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 envelope form** here (the same shape\n * `ctx.design` carries inside `resolveData`). The viewport-cascaded, token-\n * resolved values are what `useDesignValues()` returns.\n */\nexport interface ContentfulComponent {\n componentTypeId: 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 the page-level template.\n * Exposed via `useContentfulTemplate()` inside a template's component tree.\n */\nexport interface ContentfulTemplate {\n templateId: 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 type. The `component`\n * receives the merged prop bag (content + resolveData + slots). Design values\n * are not injected — a component reads them via `useDesignValues()`. Runtime\n * context and raw payload come from `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 page-level template. The template's\n * component receives the rendered Experience nodes as `children`.\n */\nexport interface TemplateConfig<Props extends object = Record<string, unknown>> {\n defaults?: Partial<Props>;\n resolveData?: (ctx: ResolveContext) => Partial<Props> | Promise<Partial<Props>>;\n component: ComponentType<Props & { children?: ReactNode }>;\n}\n\n/**\n * Registry value for templates. Same dual-shape as component registrations.\n */\nexport type TemplateRegistration<Props extends object = Record<string, unknown>> =\n | ComponentType<Props & { children?: ReactNode }>\n | TemplateConfig<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 template config as-is, with `Props` narrowing.\n */\nexport function defineTemplate<Props extends object = Record<string, unknown>>(\n config: TemplateConfig<Props>\n): TemplateConfig<Props> {\n return config;\n}\n\n/**\n * Component registry — keyed by `componentTypeId` (last slash-segment of\n * `componentType.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 * Template registry — keyed by `templateId` (last slash-segment of\n * `payload.sys.template.sys.urn`).\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- per-entry narrowing happens at the registration author's call site.\nexport type Templates = Record<string, TemplateRegistration<any>>;\n\nexport interface Config {\n components: Components;\n templates?: Templates;\n /**\n * Resolves `DesignToken` envelopes to runtime values before they reach a\n * component. If omitted, envelopes 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 normalizeTemplateRegistration<P extends object>(\n reg: TemplateRegistration<P>\n): TemplateConfig<P> {\n if (typeof reg === 'object' && reg !== null && !('$$typeof' in reg) && 'component' in reg) {\n return reg as TemplateConfig<P>;\n }\n return { component: reg as ComponentType<P & { children?: ReactNode }> };\n}\n"],"mappings":"AAmHO,SAAS,gBACd,QACwB;AACxB,SAAO;AACT;AAKO,SAAS,eACd,QACuB;AACvB,SAAO;AACT;AAqCO,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,8BACd,KACmB;AACnB,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,EAAE,cAAc,QAAQ,eAAe,KAAK;AACzF,WAAO;AAAA,EACT;AACA,SAAO,EAAE,WAAW,IAAmD;AACzE;","names":[]}
@@ -1,4 +1,4 @@
1
- import { ViewportDef } from '@contentful/experiences-core';
1
+ import { ViewportDef } from '@contentful/experiences-sdk-core';
2
2
 
3
3
  interface UseActiveViewportResult {
4
4
  activeViewportIndex: number;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/use-active-viewport.ts"],"sourcesContent":["/*\n * Reactive viewport-matcher hook.\n *\n * \"Active viewport\" = the last-matching media query in the ordered viewports\n * list. With desktop-first ordering (`*`, `<992px`, `<576px`), the narrowest\n * matching query wins. With mobile-first ordering, the widest wins. Either\n * way: the last `findLastIndex` of `mediaQueryMatches[i] === true`.\n *\n * Pass `initialViewportId` (typically derived from User-Agent on the server)\n * to seed the first render so SSR + client agree on viewport before\n * window.matchMedia takes over.\n */\n\n'use client';\n\nimport { useEffect, useState } from 'react';\n\nimport type { ViewportDef } from '@contentful/experiences-core';\nimport { getViewportIndex, toCssMediaQuery } from '@contentful/experiences-design';\n\ninterface MediaQueryMatcher {\n index: number;\n signal: MediaQueryList;\n}\n\nfunction createMediaQueryMatchers(viewports: ViewportDef[]): [MediaQueryMatcher[], boolean[]] {\n const mediaQueryMatches: boolean[] = new Array(viewports.length).fill(false);\n // The first viewport is the wildcard \"*\" and always matches.\n mediaQueryMatches[0] = true;\n\n const mediaQueryMatchers: MediaQueryMatcher[] = [];\n if (typeof window === 'undefined') {\n return [mediaQueryMatchers, mediaQueryMatches];\n }\n for (let index = 0; index < viewports.length; index++) {\n const viewport = viewports[index];\n if (!viewport) continue;\n const cssQuery = toCssMediaQuery(viewport);\n if (!cssQuery) continue;\n const matcher = window.matchMedia(cssQuery);\n mediaQueryMatches[index] = matcher.matches;\n mediaQueryMatchers.push({ index, signal: matcher });\n }\n return [mediaQueryMatchers, mediaQueryMatches];\n}\n\nfunction useMediaQueryMatchers(viewports: ViewportDef[]): boolean[] {\n const [, initialMatches] = createMediaQueryMatchers(viewports);\n const [matches, setMatches] = useState<boolean[]>(initialMatches);\n\n useEffect(() => {\n const [matchers] = createMediaQueryMatchers(viewports);\n const listeners = matchers.map(({ index, signal }) => {\n const onChange = (): void =>\n setMatches((prev) => {\n const next = [...prev];\n next[index] = signal.matches;\n return next;\n });\n signal.addEventListener('change', onChange);\n return onChange;\n });\n return () => {\n listeners.forEach((listener, i) => {\n const matcher = matchers[i];\n if (matcher) matcher.signal.removeEventListener('change', listener);\n });\n };\n }, [viewports]);\n\n return matches;\n}\n\nexport interface UseActiveViewportResult {\n activeViewportIndex: number;\n}\n\nexport function useActiveViewport(\n viewports: ViewportDef[],\n initialViewportId?: string\n): UseActiveViewportResult {\n const matches = useMediaQueryMatchers(viewports);\n const [activeViewportIndex, setActiveViewportIndex] = useState<number>(() =>\n getViewportIndex(viewports, initialViewportId)\n );\n\n useEffect(() => {\n const currentIndex = matches.findLastIndex((isMatch) => isMatch);\n if (currentIndex !== -1 && currentIndex !== activeViewportIndex) {\n setActiveViewportIndex(currentIndex);\n }\n }, [activeViewportIndex, matches]);\n\n return { activeViewportIndex };\n}\n"],"mappings":";AAeA,SAAS,WAAW,gBAAgB;AAGpC,SAAS,kBAAkB,uBAAuB;AAOlD,SAAS,yBAAyB,WAA4D;AAC5F,QAAM,oBAA+B,IAAI,MAAM,UAAU,MAAM,EAAE,KAAK,KAAK;AAE3E,oBAAkB,CAAC,IAAI;AAEvB,QAAM,qBAA0C,CAAC;AACjD,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,CAAC,oBAAoB,iBAAiB;AAAA,EAC/C;AACA,WAAS,QAAQ,GAAG,QAAQ,UAAU,QAAQ,SAAS;AACrD,UAAM,WAAW,UAAU,KAAK;AAChC,QAAI,CAAC,SAAU;AACf,UAAM,WAAW,gBAAgB,QAAQ;AACzC,QAAI,CAAC,SAAU;AACf,UAAM,UAAU,OAAO,WAAW,QAAQ;AAC1C,sBAAkB,KAAK,IAAI,QAAQ;AACnC,uBAAmB,KAAK,EAAE,OAAO,QAAQ,QAAQ,CAAC;AAAA,EACpD;AACA,SAAO,CAAC,oBAAoB,iBAAiB;AAC/C;AAEA,SAAS,sBAAsB,WAAqC;AAClE,QAAM,CAAC,EAAE,cAAc,IAAI,yBAAyB,SAAS;AAC7D,QAAM,CAAC,SAAS,UAAU,IAAI,SAAoB,cAAc;AAEhE,YAAU,MAAM;AACd,UAAM,CAAC,QAAQ,IAAI,yBAAyB,SAAS;AACrD,UAAM,YAAY,SAAS,IAAI,CAAC,EAAE,OAAO,OAAO,MAAM;AACpD,YAAM,WAAW,MACf,WAAW,CAAC,SAAS;AACnB,cAAM,OAAO,CAAC,GAAG,IAAI;AACrB,aAAK,KAAK,IAAI,OAAO;AACrB,eAAO;AAAA,MACT,CAAC;AACH,aAAO,iBAAiB,UAAU,QAAQ;AAC1C,aAAO;AAAA,IACT,CAAC;AACD,WAAO,MAAM;AACX,gBAAU,QAAQ,CAAC,UAAU,MAAM;AACjC,cAAM,UAAU,SAAS,CAAC;AAC1B,YAAI,QAAS,SAAQ,OAAO,oBAAoB,UAAU,QAAQ;AAAA,MACpE,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,SAAS,CAAC;AAEd,SAAO;AACT;AAMO,SAAS,kBACd,WACA,mBACyB;AACzB,QAAM,UAAU,sBAAsB,SAAS;AAC/C,QAAM,CAAC,qBAAqB,sBAAsB,IAAI;AAAA,IAAiB,MACrE,iBAAiB,WAAW,iBAAiB;AAAA,EAC/C;AAEA,YAAU,MAAM;AACd,UAAM,eAAe,QAAQ,cAAc,CAAC,YAAY,OAAO;AAC/D,QAAI,iBAAiB,MAAM,iBAAiB,qBAAqB;AAC/D,6BAAuB,YAAY;AAAA,IACrC;AAAA,EACF,GAAG,CAAC,qBAAqB,OAAO,CAAC;AAEjC,SAAO,EAAE,oBAAoB;AAC/B;","names":[]}
1
+ {"version":3,"sources":["../src/use-active-viewport.ts"],"sourcesContent":["/*\n * Reactive viewport-matcher hook.\n *\n * \"Active viewport\" = the last-matching media query in the ordered viewports\n * list. With desktop-first ordering (`*`, `<992px`, `<576px`), the narrowest\n * matching query wins. With mobile-first ordering, the widest wins. Either\n * way: the last `findLastIndex` of `mediaQueryMatches[i] === true`.\n *\n * Pass `initialViewportId` (typically derived from User-Agent on the server)\n * to seed the first render so SSR + client agree on viewport before\n * window.matchMedia takes over.\n */\n\n'use client';\n\nimport { useEffect, useState } from 'react';\n\nimport type { ViewportDef } from '@contentful/experiences-sdk-core';\nimport { getViewportIndex, toCssMediaQuery } from '@contentful/experiences-design';\n\ninterface MediaQueryMatcher {\n index: number;\n signal: MediaQueryList;\n}\n\nfunction createMediaQueryMatchers(viewports: ViewportDef[]): [MediaQueryMatcher[], boolean[]] {\n const mediaQueryMatches: boolean[] = new Array(viewports.length).fill(false);\n // The first viewport is the wildcard \"*\" and always matches.\n mediaQueryMatches[0] = true;\n\n const mediaQueryMatchers: MediaQueryMatcher[] = [];\n if (typeof window === 'undefined') {\n return [mediaQueryMatchers, mediaQueryMatches];\n }\n for (let index = 0; index < viewports.length; index++) {\n const viewport = viewports[index];\n if (!viewport) continue;\n const cssQuery = toCssMediaQuery(viewport);\n if (!cssQuery) continue;\n const matcher = window.matchMedia(cssQuery);\n mediaQueryMatches[index] = matcher.matches;\n mediaQueryMatchers.push({ index, signal: matcher });\n }\n return [mediaQueryMatchers, mediaQueryMatches];\n}\n\nfunction useMediaQueryMatchers(viewports: ViewportDef[]): boolean[] {\n const [, initialMatches] = createMediaQueryMatchers(viewports);\n const [matches, setMatches] = useState<boolean[]>(initialMatches);\n\n useEffect(() => {\n const [matchers] = createMediaQueryMatchers(viewports);\n const listeners = matchers.map(({ index, signal }) => {\n const onChange = (): void =>\n setMatches((prev) => {\n const next = [...prev];\n next[index] = signal.matches;\n return next;\n });\n signal.addEventListener('change', onChange);\n return onChange;\n });\n return () => {\n listeners.forEach((listener, i) => {\n const matcher = matchers[i];\n if (matcher) matcher.signal.removeEventListener('change', listener);\n });\n };\n }, [viewports]);\n\n return matches;\n}\n\nexport interface UseActiveViewportResult {\n activeViewportIndex: number;\n}\n\nexport function useActiveViewport(\n viewports: ViewportDef[],\n initialViewportId?: string\n): UseActiveViewportResult {\n const matches = useMediaQueryMatchers(viewports);\n const [activeViewportIndex, setActiveViewportIndex] = useState<number>(() =>\n getViewportIndex(viewports, initialViewportId)\n );\n\n useEffect(() => {\n const currentIndex = matches.findLastIndex((isMatch) => isMatch);\n if (currentIndex !== -1 && currentIndex !== activeViewportIndex) {\n setActiveViewportIndex(currentIndex);\n }\n }, [activeViewportIndex, matches]);\n\n return { activeViewportIndex };\n}\n"],"mappings":";AAeA,SAAS,WAAW,gBAAgB;AAGpC,SAAS,kBAAkB,uBAAuB;AAOlD,SAAS,yBAAyB,WAA4D;AAC5F,QAAM,oBAA+B,IAAI,MAAM,UAAU,MAAM,EAAE,KAAK,KAAK;AAE3E,oBAAkB,CAAC,IAAI;AAEvB,QAAM,qBAA0C,CAAC;AACjD,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,CAAC,oBAAoB,iBAAiB;AAAA,EAC/C;AACA,WAAS,QAAQ,GAAG,QAAQ,UAAU,QAAQ,SAAS;AACrD,UAAM,WAAW,UAAU,KAAK;AAChC,QAAI,CAAC,SAAU;AACf,UAAM,WAAW,gBAAgB,QAAQ;AACzC,QAAI,CAAC,SAAU;AACf,UAAM,UAAU,OAAO,WAAW,QAAQ;AAC1C,sBAAkB,KAAK,IAAI,QAAQ;AACnC,uBAAmB,KAAK,EAAE,OAAO,QAAQ,QAAQ,CAAC;AAAA,EACpD;AACA,SAAO,CAAC,oBAAoB,iBAAiB;AAC/C;AAEA,SAAS,sBAAsB,WAAqC;AAClE,QAAM,CAAC,EAAE,cAAc,IAAI,yBAAyB,SAAS;AAC7D,QAAM,CAAC,SAAS,UAAU,IAAI,SAAoB,cAAc;AAEhE,YAAU,MAAM;AACd,UAAM,CAAC,QAAQ,IAAI,yBAAyB,SAAS;AACrD,UAAM,YAAY,SAAS,IAAI,CAAC,EAAE,OAAO,OAAO,MAAM;AACpD,YAAM,WAAW,MACf,WAAW,CAAC,SAAS;AACnB,cAAM,OAAO,CAAC,GAAG,IAAI;AACrB,aAAK,KAAK,IAAI,OAAO;AACrB,eAAO;AAAA,MACT,CAAC;AACH,aAAO,iBAAiB,UAAU,QAAQ;AAC1C,aAAO;AAAA,IACT,CAAC;AACD,WAAO,MAAM;AACX,gBAAU,QAAQ,CAAC,UAAU,MAAM;AACjC,cAAM,UAAU,SAAS,CAAC;AAC1B,YAAI,QAAS,SAAQ,OAAO,oBAAoB,UAAU,QAAQ;AAAA,MACpE,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,SAAS,CAAC;AAEd,SAAO;AACT;AAMO,SAAS,kBACd,WACA,mBACyB;AACzB,QAAM,UAAU,sBAAsB,SAAS;AAC/C,QAAM,CAAC,qBAAqB,sBAAsB,IAAI;AAAA,IAAiB,MACrE,iBAAiB,WAAW,iBAAiB;AAAA,EAC/C;AAEA,YAAU,MAAM;AACd,UAAM,eAAe,QAAQ,cAAc,CAAC,YAAY,OAAO;AAC/D,QAAI,iBAAiB,MAAM,iBAAiB,qBAAqB;AAC/D,6BAAuB,YAAY;AAAA,IACrC;AAAA,EACF,GAAG,CAAC,qBAAqB,OAAO,CAAC;AAEjC,SAAO,EAAE,oBAAoB;AAC/B;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experiences-react",
3
- "version": "0.5.1",
3
+ "version": "0.5.4",
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.1.1",
34
- "@contentful/experiences-core": "0.5.1",
35
- "@contentful/experiences-design": "0.5.1"
33
+ "@contentful/experiences-client": "0.1.4",
34
+ "@contentful/experiences-sdk-core": "0.5.4",
35
+ "@contentful/experiences-design": "0.5.4"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "react": "^18.0.0 || ^19.0.0",