@contentful/experiences-react 0.7.6 → 0.7.8
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,23 @@
|
|
|
1
|
+
## 0.7.8 (2026-08-21)
|
|
2
|
+
|
|
3
|
+
### 🧱 Updated Dependencies
|
|
4
|
+
|
|
5
|
+
- Updated client to 0.3.7
|
|
6
|
+
- Updated design to 0.7.7
|
|
7
|
+
- Updated core to 0.7.7
|
|
8
|
+
|
|
9
|
+
## 0.7.7 (2026-08-20)
|
|
10
|
+
|
|
11
|
+
### 🚀 Features
|
|
12
|
+
|
|
13
|
+
- **adapter-angular:** scaffold @contentful/experiences-angular [AIS-361] ([#134](https://github.com/contentful/experiences/pull/134))
|
|
14
|
+
|
|
15
|
+
### 🧱 Updated Dependencies
|
|
16
|
+
|
|
17
|
+
- Updated client to 0.3.6
|
|
18
|
+
- Updated design to 0.7.6
|
|
19
|
+
- Updated core to 0.7.6
|
|
20
|
+
|
|
1
21
|
## 0.7.6 (2026-08-12)
|
|
2
22
|
|
|
3
23
|
### 🩹 Fixes
|
package/dist/nodes-renderer.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Fragment, createElement } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { selectResolvedDesign } from "@contentful/experiences-design";
|
|
4
4
|
import {
|
|
5
5
|
ContentfulComponentProvider,
|
|
6
6
|
ContentfulExperienceTemplateProvider,
|
|
@@ -10,13 +10,6 @@ import {
|
|
|
10
10
|
normalizeComponentRegistration,
|
|
11
11
|
normalizeExperienceTemplateRegistration
|
|
12
12
|
} from "./types";
|
|
13
|
-
function selectResolvedDesign(props, viewports, activeViewportIndex, fallbackViewportIndex, resolveToken) {
|
|
14
|
-
if (activeViewportIndex === fallbackViewportIndex) {
|
|
15
|
-
return { props: props.design, unresolved: [] };
|
|
16
|
-
}
|
|
17
|
-
const resolvedDesign = resolveDesignProperties(props.designRaw, viewports, activeViewportIndex);
|
|
18
|
-
return applyTokenResolver(resolvedDesign, resolveToken);
|
|
19
|
-
}
|
|
20
13
|
function NodesRenderer({
|
|
21
14
|
nodes,
|
|
22
15
|
config,
|
|
@@ -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 {
|
|
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 { PortableRenderNode, ViewportDef } from '@contentful/experiences-sdk-core';\nimport { selectResolvedDesign } 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// 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/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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
|
|
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> | 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> | 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":"AAwHO,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":[]}
|
|
@@ -1,24 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
|
-
import {
|
|
4
|
-
function createMediaQueryMatchers(viewports) {
|
|
5
|
-
const mediaQueryMatches = new Array(viewports.length).fill(false);
|
|
6
|
-
mediaQueryMatches[0] = true;
|
|
7
|
-
const mediaQueryMatchers = [];
|
|
8
|
-
if (typeof window === "undefined") {
|
|
9
|
-
return [mediaQueryMatchers, mediaQueryMatches];
|
|
10
|
-
}
|
|
11
|
-
for (let index = 0; index < viewports.length; index++) {
|
|
12
|
-
const viewport = viewports[index];
|
|
13
|
-
if (!viewport) continue;
|
|
14
|
-
const cssQuery = toCssMediaQuery(viewport);
|
|
15
|
-
if (!cssQuery) continue;
|
|
16
|
-
const matcher = window.matchMedia(cssQuery);
|
|
17
|
-
mediaQueryMatches[index] = matcher.matches;
|
|
18
|
-
mediaQueryMatchers.push({ index, signal: matcher });
|
|
19
|
-
}
|
|
20
|
-
return [mediaQueryMatchers, mediaQueryMatches];
|
|
21
|
-
}
|
|
3
|
+
import { createMediaQueryMatchers, getViewportIndex } from "@contentful/experiences-design";
|
|
22
4
|
function useMediaQueryMatchers(viewports) {
|
|
23
5
|
const [, initialMatches] = createMediaQueryMatchers(viewports);
|
|
24
6
|
const [matches, setMatches] = useState(initialMatches);
|
|
@@ -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-sdk-core';\nimport {
|
|
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 { createMediaQueryMatchers, getViewportIndex } from '@contentful/experiences-design';\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,0BAA0B,wBAAwB;AAE3D,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.7.
|
|
3
|
+
"version": "0.7.8",
|
|
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.7",
|
|
34
|
+
"@contentful/experiences-sdk-core": "0.7.7",
|
|
35
|
+
"@contentful/experiences-design": "0.7.7"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"react": "^18.0.0 || ^19.0.0",
|