@contentful/experiences-core 0.0.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +16 -0
- package/dist/index.d.ts +2 -24
- package/dist/index.js +5 -2402
- package/dist/index.js.map +1 -1
- package/dist/resolve-experience.d.ts +35 -0
- package/dist/resolve-experience.js +119 -0
- package/dist/resolve-experience.js.map +1 -0
- package/dist/types.d.ts +196 -235
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/package.json +23 -66
- package/LICENSE +0 -21
- package/dist/communication/sendMessage.d.ts +0 -6
- package/dist/constants.d.ts +0 -106
- package/dist/constants.js +0 -144
- package/dist/constants.js.map +0 -1
- package/dist/deep-binding/DeepReference.d.ts +0 -28
- package/dist/definitions/components.d.ts +0 -8
- package/dist/definitions/styles.d.ts +0 -11
- package/dist/entity/EditorEntityStore.d.ts +0 -34
- package/dist/entity/EditorModeEntityStore.d.ts +0 -29
- package/dist/entity/EntityStore.d.ts +0 -68
- package/dist/entity/EntityStoreBase.d.ts +0 -49
- package/dist/enums.d.ts +0 -6
- package/dist/exports.d.ts +0 -3
- package/dist/exports.js +0 -2
- package/dist/exports.js.map +0 -1
- package/dist/fetchers/createExperience.d.ts +0 -20
- package/dist/fetchers/fetchById.d.ts +0 -20
- package/dist/fetchers/fetchBySlug.d.ts +0 -20
- package/dist/registries/designTokenRegistry.d.ts +0 -12
- package/dist/utils/breakpoints.d.ts +0 -12
- package/dist/utils/components.d.ts +0 -4
- package/dist/utils/domValues.d.ts +0 -15
- package/dist/utils/isLink.d.ts +0 -5
- package/dist/utils/isLinkToAsset.d.ts +0 -5
- package/dist/utils/pathSchema.d.ts +0 -30
- package/dist/utils/styleUtils/stylesUtils.d.ts +0 -20
- package/dist/utils/supportedModes.d.ts +0 -5
- package/dist/utils/transformers/transformBoundContentValue.d.ts +0 -8
- package/dist/utils/typeguards.d.ts +0 -6
- package/dist/utils/utils.d.ts +0 -46
- package/dist/utils/validations.d.ts +0 -15
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/resolve-experience.ts"],"sourcesContent":["/*\n * Single async entry that turns an XDA Experience payload into a\n * runtime-neutral PortableRenderPlan ready to render.\n *\n * v1 behavior:\n * - Walk the payload's nodes recursively. Each ComponentType node becomes\n * a PortableRenderNode with `registration.componentTypeId` extracted\n * from `componentType.sys.urn` (last slash-segment).\n * - Split content + design properties onto `node.props.{content,design}`.\n * Design-prop envelopes (DesignToken / ManualDesignValue / ValuesByViewport)\n * are preserved on the IR; the design package unwraps them at render time.\n * - Template-variant nodes are skipped with a console.warn — out of v1 scope.\n * - For every component whose registration declares `resolveData`, run the\n * resolver (sync or async) in parallel with peers, and attach the result\n * to `node.props.resolved`.\n * - Unknown component-type-id is a render-time concern (handled by the\n * framework adapter via `renderUnknown`); the IR still emits the node.\n */\n\nimport type {\n ComponentTypeNode,\n DesignPropValue,\n ExperienceContext,\n ExperienceNode,\n ExperiencePayload,\n PortableRenderNode,\n PortableRenderPlan,\n PortableTemplate,\n ResolveContext,\n} from './types';\n\n/**\n * Structural type the resolver walker depends on. Matches the React\n * adapter's `Config` shape but doesn't require importing it — render-core\n * stays decoupled from React.\n */\nexport interface ResolverConfig {\n components: Record<\n string,\n {\n resolveData?: (\n ctx: ResolveContext\n ) => Record<string, unknown> | Promise<Record<string, unknown>>;\n }\n >;\n templates?: Record<\n string,\n {\n resolveData?: (\n ctx: ResolveContext\n ) => Record<string, unknown> | Promise<Record<string, unknown>>;\n }\n >;\n}\n\nexport interface ResolveExperienceOptions {\n /**\n * Per-render runtime context exposed to every resolver as `ctx.experience`.\n * Defaults to `{ isPreview: false, metadata: {} }`.\n */\n experience?: Partial<ExperienceContext>;\n}\n\nconst DEFAULT_EXPERIENCE: ExperienceContext = {\n isPreview: false,\n metadata: {},\n viewports: [],\n};\n\nfunction isComponentTypeNode(node: ExperienceNode): node is ComponentTypeNode {\n return 'componentType' in node;\n}\n\n/**\n * Extract the flat id (componentType or template) from its `ResourceLink`\n * URN. Real URN shapes:\n * crn:contentful:::experience:spaces/$self/environments/$self/componentTypes/<id>\n * crn:contentful:::experience:spaces/$self/environments/$self/templates/<id>\n *\n * The id is the final path segment. We split on `/` and take the last\n * non-empty piece so this also tolerates trailing slashes or alternative\n * prefix shapes.\n */\nfunction extractIdFromUrn(urn: string): string {\n const segments = urn.split('/').filter((s) => s.length > 0);\n return segments[segments.length - 1] ?? urn;\n}\n\n/**\n * Recursively turn a payload node into an IR node. The collected `nodeRefs`\n * array is for the resolver pass — every built node with a registered\n * resolver gets a reference appended so we can run them in parallel without\n * walking the tree twice.\n */\nfunction buildNode(\n node: ExperienceNode,\n config: ResolverConfig,\n nodeRefs: PortableRenderNode[]\n): PortableRenderNode | null {\n if (!isComponentTypeNode(node)) {\n if (typeof console !== 'undefined') {\n console.warn(\n '[@contentful/experiences-core] Skipping Template-variant node — Templates are not supported in v1.'\n );\n }\n return null;\n }\n\n const componentTypeId = extractIdFromUrn(node.componentType.sys.urn);\n\n const slots: Record<string, PortableRenderNode[]> = {};\n if (node.slots) {\n for (const [slotName, children] of Object.entries(node.slots)) {\n if (!Array.isArray(children)) {\n throw new TypeError(\n `Slot \"${slotName}\" on component \"${componentTypeId}\" must be an array of nodes.`\n );\n }\n const built: PortableRenderNode[] = [];\n for (const child of children) {\n const childNode = buildNode(child, config, nodeRefs);\n if (childNode === null) continue;\n built.push(childNode);\n }\n slots[slotName] = built;\n }\n }\n\n const built: PortableRenderNode = {\n registration: { componentTypeId },\n props: {\n content: { ...(node.contentProperties ?? {}) },\n design: { ...(node.designProperties ?? {}) } as Record<string, DesignPropValue>,\n },\n slots,\n };\n if (node.id) built.nodeId = node.id;\n if (config.components[componentTypeId]?.resolveData) {\n nodeRefs.push(built);\n }\n return built;\n}\n\n/**\n * Turns an Experience payload (XDA response shape) into a PortableRenderPlan\n * ready to hand to a renderer. Walks the tree, classifies props, captures\n * slots, and runs any component-declared `resolveData` hooks (sync or async)\n * in parallel.\n *\n * Implementation note: the function is always async — even when no component\n * declares a resolver, the cost is one microtask. Customers get a single\n * uniform call site.\n */\nexport async function resolveExperience(\n payload: ExperiencePayload,\n config: ResolverConfig,\n options: ResolveExperienceOptions = {}\n): Promise<PortableRenderPlan> {\n // Pass 1: walk the payload into the IR. Collect refs to nodes that need\n // resolveData so pass 2 can run them in parallel without re-walking.\n const nodeRefs: PortableRenderNode[] = [];\n const nodes: PortableRenderNode[] = [];\n for (const node of payload.nodes) {\n const built = buildNode(node, config, nodeRefs);\n if (built !== null) nodes.push(built);\n }\n\n // Build the page-level template stub if the payload carries one. XDA\n // payloads don't yet emit template-level content/design properties, so\n // the IR carries empty bags.\n const templateUrn = payload.sys?.template?.sys.urn;\n let template: PortableTemplate | undefined;\n if (typeof templateUrn === 'string' && templateUrn.length > 0) {\n template = {\n templateId: extractIdFromUrn(templateUrn),\n props: { content: {}, design: {} },\n };\n }\n\n // Pass 2: run resolveData hooks for components AND the template in parallel.\n // `viewports` is always sourced from the payload — caller-supplied\n // options.experience.viewports is ignored (the list is fact, not opinion).\n const experience: ExperienceContext = {\n ...DEFAULT_EXPERIENCE,\n ...options.experience,\n metadata: {\n ...DEFAULT_EXPERIENCE.metadata,\n ...(options.experience?.metadata ?? {}),\n },\n viewports: payload.viewports,\n };\n\n const tasks: Array<Promise<void>> = [];\n\n for (const node of nodeRefs) {\n const resolver = config.components[node.registration.componentTypeId]?.resolveData;\n if (!resolver) continue;\n const ctx: ResolveContext = {\n content: node.props.content,\n design: node.props.design,\n experience,\n };\n tasks.push(\n Promise.resolve(resolver(ctx)).then((resolved) => {\n node.props.resolved = resolved;\n })\n );\n }\n\n if (template) {\n const tplResolver = config.templates?.[template.templateId]?.resolveData;\n if (tplResolver) {\n const ctx: ResolveContext = {\n content: template.props.content,\n design: template.props.design,\n experience,\n };\n const tpl = template;\n tasks.push(\n Promise.resolve(tplResolver(ctx)).then((resolved) => {\n tpl.props.resolved = resolved;\n })\n );\n }\n }\n\n if (tasks.length > 0) await Promise.all(tasks);\n\n return {\n viewports: payload.viewports,\n nodes,\n ...(template ? { template } : {}),\n };\n}\n"],"mappings":"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","names":["built"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,244 +1,205 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
interface Link<T extends string> {
|
|
17
|
-
sys: {
|
|
18
|
-
type: 'Link';
|
|
19
|
-
linkType: T;
|
|
20
|
-
id: string;
|
|
21
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Per-render runtime context attached to every customer component as the
|
|
3
|
+
* `experience` prop, and passed to every `resolveData` hook as `ctx.experience`.
|
|
4
|
+
* The conventional, single injection point — kept small at v1.
|
|
5
|
+
*
|
|
6
|
+
* `viewports` (the *list*) is here so customer resolvers can inspect what
|
|
7
|
+
* viewports an Experience declares (e.g. "is there a mobile viewport?").
|
|
8
|
+
* The *active* viewport is render-time only and lives on the framework
|
|
9
|
+
* adapter's RenderContext — exposing it here would mean async resolvers
|
|
10
|
+
* re-fire on every viewport change, which would be a footgun.
|
|
11
|
+
*/
|
|
12
|
+
interface ExperienceContext {
|
|
13
|
+
isPreview: boolean;
|
|
14
|
+
metadata: Record<string, unknown>;
|
|
15
|
+
viewports: ViewportDef[];
|
|
22
16
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
};
|
|
33
|
-
interface ComponentDefinitionVariableBase<T extends ComponentDefinitionPropertyType> {
|
|
34
|
-
type: T;
|
|
35
|
-
validations?: ComponentDefinitionVariableValidation<T>;
|
|
36
|
-
group?: 'style' | 'content';
|
|
37
|
-
description?: string;
|
|
38
|
-
displayName?: string;
|
|
39
|
-
defaultValue?: string | boolean | number | Record<any, any>;
|
|
40
|
-
}
|
|
41
|
-
type ComponentDefinitionVariable<T extends ComponentDefinitionPropertyType = ComponentDefinitionPropertyType> = ComponentDefinitionVariableBase<T>;
|
|
42
|
-
type ComponentDefinition<T extends ComponentDefinitionPropertyType = ComponentDefinitionPropertyType> = {
|
|
17
|
+
/**
|
|
18
|
+
* One viewport definition from a delivered Experience. The `query` is the
|
|
19
|
+
* Contentful media-query DSL ("*" | "<992px" | ">1200px"), not raw CSS.
|
|
20
|
+
*
|
|
21
|
+
* The first viewport in the list is conventionally the wildcard ("*") that
|
|
22
|
+
* always matches. The viewport order encodes the cascade direction —
|
|
23
|
+
* desktop-first (descending) or mobile-first (ascending).
|
|
24
|
+
*/
|
|
25
|
+
interface ViewportDef {
|
|
43
26
|
id: string;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
27
|
+
query: string;
|
|
28
|
+
displayName: string;
|
|
29
|
+
previewSize: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Discriminated design-property value as it arrives from XDA. v1 accepts:
|
|
33
|
+
* - ManualDesignValue: an explicit scalar (no viewport involved).
|
|
34
|
+
* - ValuesByViewport: a viewport-keyed bag where each entry is itself a
|
|
35
|
+
* ManualDesignValue or DesignToken.
|
|
36
|
+
* - DesignToken: a token reference, passed through to customer components
|
|
37
|
+
* as-is for v1. Resolution lands in the future tokens package.
|
|
38
|
+
*/
|
|
39
|
+
type DesignPropValue = ManualDesignValue | DesignToken | ValuesByViewport;
|
|
40
|
+
interface ManualDesignValue {
|
|
41
|
+
type: 'ManualDesignValue';
|
|
42
|
+
value: string | number | boolean;
|
|
43
|
+
}
|
|
44
|
+
interface DesignToken {
|
|
45
|
+
type: 'DesignToken';
|
|
46
|
+
value: string;
|
|
47
|
+
}
|
|
48
|
+
interface ValuesByViewport {
|
|
49
|
+
type: 'ValuesByViewport';
|
|
50
|
+
values: Record<string, ManualDesignValue | DesignToken>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Resource-link reference to a registered Component Type. The `urn` carries
|
|
54
|
+
* the type id; the build-plan extracts the id by taking the segment after
|
|
55
|
+
* the last slash.
|
|
56
|
+
*/
|
|
57
|
+
interface ComponentTypeRef {
|
|
58
|
+
sys: {
|
|
59
|
+
type: 'ResourceLink';
|
|
60
|
+
linkType: 'Contentful:ComponentType';
|
|
61
|
+
urn: string;
|
|
53
62
|
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Resource-link reference to a Template. Templates are out of v1 scope and
|
|
66
|
+
* are skipped at plan-build time with a diagnostic.
|
|
67
|
+
*/
|
|
68
|
+
interface TemplateRef {
|
|
69
|
+
sys: {
|
|
70
|
+
type: 'ResourceLink';
|
|
71
|
+
linkType: 'Contentful:Template';
|
|
72
|
+
urn: string;
|
|
61
73
|
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* One node from `GetExperienceViewResponse.nodes` (or any `slots[name]`).
|
|
77
|
+
* Discriminated by which of `componentType` / `template` is present.
|
|
78
|
+
*/
|
|
79
|
+
type ExperienceNode = ComponentTypeNode | TemplateNode;
|
|
80
|
+
interface ComponentTypeNode {
|
|
81
|
+
componentType: ComponentTypeRef;
|
|
82
|
+
id?: string;
|
|
83
|
+
contentProperties?: Record<string, unknown>;
|
|
84
|
+
designProperties?: Record<string, DesignPropValue>;
|
|
85
|
+
slots?: Record<string, ExperienceNode[]>;
|
|
86
|
+
contentBindings?: string;
|
|
87
|
+
}
|
|
88
|
+
interface TemplateNode {
|
|
89
|
+
template: TemplateRef;
|
|
90
|
+
id?: string;
|
|
91
|
+
contentProperties?: Record<string, unknown>;
|
|
92
|
+
designProperties?: Record<string, DesignPropValue>;
|
|
93
|
+
slots?: Record<string, ExperienceNode[]>;
|
|
94
|
+
contentBindings?: string;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Top-level `sys` block on an Experience payload. The bits the SDK actually
|
|
98
|
+
* reads are typed; everything else is left loose because the upstream
|
|
99
|
+
* type carries dozens of editor/audit fields the renderer doesn't care about.
|
|
100
|
+
*/
|
|
101
|
+
interface ExperienceSys {
|
|
102
|
+
/**
|
|
103
|
+
* Optional page-level template reference. When present, the renderer wraps
|
|
104
|
+
* the experience nodes with the matching template registered in the
|
|
105
|
+
* customer's Config. When absent, nodes render at the top level.
|
|
106
|
+
*/
|
|
107
|
+
template?: TemplateRef;
|
|
108
|
+
[key: string]: unknown;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Top-level Experience payload as returned by the Experience Delivery API
|
|
112
|
+
* (`GetExperienceViewResponse` from `@contentful/experience-delivery`).
|
|
113
|
+
*
|
|
114
|
+
* Structurally compatible with the upstream type — no normalization step
|
|
115
|
+
* required when consuming a delivery-client response.
|
|
116
|
+
*/
|
|
117
|
+
interface ExperiencePayload {
|
|
118
|
+
viewports: ViewportDef[];
|
|
119
|
+
nodes: ExperienceNode[];
|
|
120
|
+
errors?: unknown[];
|
|
121
|
+
extensions?: unknown;
|
|
122
|
+
sys?: ExperienceSys;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Per-node context handed to a component's `resolveData` resolver. Carries
|
|
126
|
+
* the raw content + design props from the payload (design envelopes are NOT
|
|
127
|
+
* pre-resolved against a viewport — viewport resolution stays a render-time
|
|
128
|
+
* concern so client viewport changes don't re-trigger async resolvers).
|
|
129
|
+
*/
|
|
130
|
+
interface ResolveContext {
|
|
131
|
+
content: Record<string, unknown>;
|
|
132
|
+
design: Record<string, DesignPropValue>;
|
|
133
|
+
experience: ExperienceContext;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Registration metadata for a single instance — the SDK's interpreted
|
|
137
|
+
* pointer to the customer's component implementation. Today carries only
|
|
138
|
+
* the resolved component-type id; capabilities (state requirements,
|
|
139
|
+
* supported events, lifecycle hints, fallback ids) land here when needed.
|
|
140
|
+
*/
|
|
141
|
+
interface PortableRegistration {
|
|
142
|
+
componentTypeId: string;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The IR — one node per component instance. The seam that lets non-React
|
|
146
|
+
* adapters (Angular, SwiftUI, Compose) consume the same interpretation.
|
|
147
|
+
*
|
|
148
|
+
* Design props preserve the discriminated envelope as they arrived. Adapters
|
|
149
|
+
* unwrap to plain scalars at render time, given an active viewport.
|
|
150
|
+
* (DesignToken envelopes pass through unwrapped — customer components decide
|
|
151
|
+
* how to resolve them in v1.)
|
|
152
|
+
*
|
|
153
|
+
* `props.resolved` is populated by `resolveExperience` from any
|
|
154
|
+
* customer-supplied `resolveData` resolver and merged into the final prop bag
|
|
155
|
+
* after content + design but before slot props.
|
|
156
|
+
*/
|
|
157
|
+
interface PortableRenderNode {
|
|
158
|
+
/**
|
|
159
|
+
* Optional. Passed through from the XDA payload's `id` field when the
|
|
160
|
+
* editor supplies one. The SDK does NOT auto-generate ids; adapters fall
|
|
161
|
+
* back to the array index for React keys / debug labels when absent.
|
|
162
|
+
*/
|
|
163
|
+
nodeId?: string;
|
|
164
|
+
registration: PortableRegistration;
|
|
165
|
+
props: {
|
|
166
|
+
content: Record<string, unknown>;
|
|
167
|
+
design: Record<string, DesignPropValue>;
|
|
168
|
+
resolved?: Record<string, unknown>;
|
|
92
169
|
};
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
};
|
|
96
|
-
/** Type of the tree data structure exchanged via postMessage between the SDK and Contentful Web app */
|
|
97
|
-
type ExperienceTree = {
|
|
98
|
-
root: ExperienceTreeNode;
|
|
99
|
-
};
|
|
100
|
-
type ExternalSDKMode = 'preview' | 'delivery';
|
|
101
|
-
type InternalSDKMode = ExternalSDKMode | 'editor';
|
|
170
|
+
slots: Record<string, PortableRenderNode[]>;
|
|
171
|
+
}
|
|
102
172
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
173
|
+
* Interpreted page-level template — the optional wrapper around the
|
|
174
|
+
* experience tree. `templateId` is extracted from
|
|
175
|
+
* `payload.sys.template.sys.urn` (last slash-segment).
|
|
176
|
+
*
|
|
177
|
+
* Templates carry the same prop-resolution shape as components: content +
|
|
178
|
+
* design envelopes plus an optional `resolved` bag from a `resolveData` hook.
|
|
179
|
+
* v1 payloads from XDA don't carry template-level content/design properties
|
|
180
|
+
* yet, but the IR makes room for them so the API doesn't need to break later.
|
|
105
181
|
*/
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
cfWidth: string;
|
|
113
|
-
cfMaxWidth: string;
|
|
114
|
-
cfHeight: string;
|
|
115
|
-
cfFlexDirection: 'row' | 'column';
|
|
116
|
-
cfFlexWrap: 'nowrap' | 'wrap';
|
|
117
|
-
cfBorder: string;
|
|
118
|
-
cfBorderRadius: string;
|
|
119
|
-
cfGap: string;
|
|
120
|
-
cfHyperlink: string;
|
|
121
|
-
cfImageAsset: OptimizedImageAsset | string;
|
|
122
|
-
cfImageOptions: ImageOptions;
|
|
123
|
-
cfBackgroundImageUrl: OptimizedBackgroundImageAsset | string;
|
|
124
|
-
cfBackgroundImageOptions: BackgroundImageOptions;
|
|
125
|
-
cfOpenInNewTab: boolean;
|
|
126
|
-
cfFontSize: string;
|
|
127
|
-
cfFontWeight: string;
|
|
128
|
-
cfLineHeight: string;
|
|
129
|
-
cfLetterSpacing: string;
|
|
130
|
-
cfTextColor: string;
|
|
131
|
-
cfTextAlign: 'left' | 'center' | 'right';
|
|
132
|
-
cfTextTransform: 'none' | 'capitalize' | 'uppercase' | 'lowercase';
|
|
133
|
-
cfTextBold: boolean;
|
|
134
|
-
cfTextItalic: boolean;
|
|
135
|
-
cfTextUnderline: boolean;
|
|
136
|
-
cfColumns: string;
|
|
137
|
-
cfColumnSpan: string;
|
|
138
|
-
cfColumnSpanLock: boolean;
|
|
139
|
-
cfWrapColumns: boolean;
|
|
140
|
-
cfWrapColumnsCount: string;
|
|
141
|
-
};
|
|
142
|
-
type CSSProperties = React.CSSProperties;
|
|
143
|
-
type ContainerStyleVariableName = keyof StyleProps;
|
|
144
|
-
type ExperienceFields = {
|
|
145
|
-
title: string;
|
|
146
|
-
slug: string;
|
|
147
|
-
componentTree: ExperienceComponentTree;
|
|
148
|
-
dataSource: ExperienceDataSource;
|
|
149
|
-
unboundValues: ExperienceUnboundValues;
|
|
150
|
-
usedComponents?: ExperienceUsedComponents | Array<ExperienceEntry>;
|
|
151
|
-
componentSettings?: ExperienceComponentSettings;
|
|
152
|
-
};
|
|
153
|
-
type RecursiveDesignTokenDefinition = {
|
|
154
|
-
[key: string]: string | RecursiveDesignTokenDefinition;
|
|
155
|
-
};
|
|
156
|
-
type DesignTokensDefinition = {
|
|
157
|
-
spacing?: Record<string, string>;
|
|
158
|
-
sizing?: Record<string, string>;
|
|
159
|
-
color?: Record<string, string>;
|
|
160
|
-
border?: Record<string, {
|
|
161
|
-
width: string;
|
|
162
|
-
style: 'solid' | 'dashed' | 'dotted';
|
|
163
|
-
color: string;
|
|
164
|
-
}>;
|
|
165
|
-
borderRadius?: Record<string, string>;
|
|
166
|
-
fontSize?: Record<string, string>;
|
|
167
|
-
lineHeight?: Record<string, string>;
|
|
168
|
-
letterSpacing?: Record<string, string>;
|
|
169
|
-
textColor?: Record<string, string>;
|
|
170
|
-
} & RecursiveDesignTokenDefinition;
|
|
171
|
-
/** Type of experience entry JSON data structure as returned by CPA/CDA */
|
|
172
|
-
type ExperienceEntry = {
|
|
173
|
-
sys: Entry['sys'];
|
|
174
|
-
fields: ExperienceFields;
|
|
175
|
-
metadata: Entry['metadata'];
|
|
176
|
-
};
|
|
177
|
-
interface RawCoordinates {
|
|
178
|
-
left: number;
|
|
179
|
-
top: number;
|
|
180
|
-
width: number;
|
|
181
|
-
height: number;
|
|
182
|
-
}
|
|
183
|
-
interface Coordinates extends RawCoordinates {
|
|
184
|
-
childrenCoordinates: RawCoordinates[];
|
|
185
|
-
}
|
|
186
|
-
interface HoveredElement {
|
|
187
|
-
blockType: string | undefined;
|
|
188
|
-
nodeId: string | undefined;
|
|
189
|
-
blockId: string | undefined;
|
|
190
|
-
}
|
|
191
|
-
interface Experience<T extends EntityStore = EntityStore> {
|
|
192
|
-
entityStore?: T;
|
|
193
|
-
}
|
|
194
|
-
type ResolveDesignValueType = (valuesByBreakpoint: ValuesByBreakpoint, variableName: string) => PrimitiveValue;
|
|
195
|
-
type ManagementEntity = (Entry | Asset) & {
|
|
196
|
-
sys: {
|
|
197
|
-
version: number;
|
|
182
|
+
interface PortableTemplate {
|
|
183
|
+
templateId: string;
|
|
184
|
+
props: {
|
|
185
|
+
content: Record<string, unknown>;
|
|
186
|
+
design: Record<string, DesignPropValue>;
|
|
187
|
+
resolved?: Record<string, unknown>;
|
|
198
188
|
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
quality?: number;
|
|
215
|
-
format?: string;
|
|
216
|
-
file: AssetFile;
|
|
217
|
-
};
|
|
218
|
-
type OptimizedBackgroundImageAsset = {
|
|
219
|
-
url: string;
|
|
220
|
-
srcSet?: string[];
|
|
221
|
-
file: AssetFile;
|
|
222
|
-
};
|
|
223
|
-
type ImageObjectFitOption = 'contain' | 'cover' | 'none';
|
|
224
|
-
type ImageObjectPositionOption = 'left' | 'right' | 'top' | 'bottom' | 'left top' | 'left center' | 'left bottom' | 'right top' | 'right center' | 'right bottom' | 'center top' | 'center center' | 'center bottom';
|
|
225
|
-
type ImageOptions = {
|
|
226
|
-
format?: string;
|
|
227
|
-
width: string;
|
|
228
|
-
height: string;
|
|
229
|
-
objectFit?: ImageObjectFitOption;
|
|
230
|
-
objectPosition?: ImageObjectPositionOption;
|
|
231
|
-
quality?: string;
|
|
232
|
-
targetSize: string;
|
|
233
|
-
};
|
|
234
|
-
type BackgroundImageScalingOption = 'fit' | 'fill' | 'tile';
|
|
235
|
-
type BackgroundImageAlignmentOption = 'left' | 'right' | 'top' | 'bottom' | 'left top' | 'left center' | 'left bottom' | 'right top' | 'right center' | 'right bottom' | 'center top' | 'center center' | 'center bottom';
|
|
236
|
-
type BackgroundImageOptions = {
|
|
237
|
-
format?: string;
|
|
238
|
-
scaling: BackgroundImageScalingOption;
|
|
239
|
-
alignment: BackgroundImageAlignmentOption;
|
|
240
|
-
quality?: string;
|
|
241
|
-
targetSize: string;
|
|
242
|
-
};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* The interpreted experience tree.
|
|
192
|
+
*
|
|
193
|
+
* Top-level is `nodes: PortableRenderNode[]` (array, not single root) to
|
|
194
|
+
* match the actual XDA payload shape. Renderers iterate top-level nodes
|
|
195
|
+
* and recurse into `node.slots`. When `template` is present, the renderer
|
|
196
|
+
* wraps the nodes with the matching template config; otherwise nodes
|
|
197
|
+
* render at the top level.
|
|
198
|
+
*/
|
|
199
|
+
interface PortableRenderPlan {
|
|
200
|
+
viewports: ViewportDef[];
|
|
201
|
+
nodes: PortableRenderNode[];
|
|
202
|
+
template?: PortableTemplate;
|
|
203
|
+
}
|
|
243
204
|
|
|
244
|
-
export type {
|
|
205
|
+
export type { ComponentTypeNode, ComponentTypeRef, DesignPropValue, DesignToken, ExperienceContext, ExperienceNode, ExperiencePayload, ExperienceSys, ManualDesignValue, PortableRegistration, PortableRenderNode, PortableRenderPlan, PortableTemplate, ResolveContext, TemplateNode, TemplateRef, ValuesByViewport, ViewportDef };
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,75 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/experiences-core",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "",
|
|
5
|
-
"
|
|
6
|
-
"module": "dist/index.js",
|
|
7
|
-
"types": "dist/index.d.ts",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Runtime-neutral types + experience resolution for Contentful Experiences",
|
|
5
|
+
"license": "MIT",
|
|
8
6
|
"type": "module",
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"sideEffects": false,
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"./package.json": "./package.json"
|
|
12
18
|
},
|
|
13
19
|
"files": [
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md",
|
|
22
|
+
"CHANGELOG.md"
|
|
17
23
|
],
|
|
18
|
-
"exports": {
|
|
19
|
-
".": "./dist/index.js",
|
|
20
|
-
"./constants": "./dist/constants.js"
|
|
21
|
-
},
|
|
22
24
|
"publishConfig": {
|
|
23
|
-
"
|
|
24
|
-
},
|
|
25
|
-
"typesVersions": {
|
|
26
|
-
"*": {
|
|
27
|
-
"types": [
|
|
28
|
-
"./dist/types.d.ts"
|
|
29
|
-
],
|
|
30
|
-
"constants": [
|
|
31
|
-
"./dist/constants.d.ts"
|
|
32
|
-
]
|
|
33
|
-
}
|
|
25
|
+
"access": "public"
|
|
34
26
|
},
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
"dev": "rollup -c ./rollup.config.mjs --watch --environment DEV",
|
|
41
|
-
"lint": "eslint src --ext '.ts,.tsx,.js,.jsx' --max-warnings 0 --ignore-path ../../.eslintignore",
|
|
42
|
-
"lint:fix": "eslint src --ext '.ts,.tsx,.js,.jsx' --fix",
|
|
43
|
-
"test": "vitest",
|
|
44
|
-
"test:coverage": "vitest run --coverage",
|
|
45
|
-
"depcruise": "depcruise src"
|
|
46
|
-
},
|
|
47
|
-
"author": "",
|
|
48
|
-
"license": "MIT",
|
|
49
|
-
"devDependencies": {
|
|
50
|
-
"@rollup/plugin-commonjs": "^25.0.7",
|
|
51
|
-
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
52
|
-
"@rollup/plugin-terser": "^0.4.4",
|
|
53
|
-
"@rollup/plugin-typescript": "^11.1.5",
|
|
54
|
-
"@types/lodash-es": "^4.17.12",
|
|
55
|
-
"@typescript-eslint/eslint-plugin": "^7.0.2",
|
|
56
|
-
"@typescript-eslint/parser": "^7.0.2",
|
|
57
|
-
"@vitest/coverage-v8": "^1.0.4",
|
|
58
|
-
"contentful": "^10.6.4",
|
|
59
|
-
"eslint": "^8.54.0",
|
|
60
|
-
"happy-dom": "^13.3.8",
|
|
61
|
-
"rimraf": "^5.0.5",
|
|
62
|
-
"rollup-plugin-dts": "^6.1.0",
|
|
63
|
-
"rollup-plugin-ts": "^3.4.5",
|
|
64
|
-
"vite-tsconfig-paths": "^4.2.2",
|
|
65
|
-
"vitest": "^1.0.4"
|
|
66
|
-
},
|
|
67
|
-
"dependencies": {
|
|
68
|
-
"@contentful/experiences-validators": "^0.0.1",
|
|
69
|
-
"@contentful/rich-text-types": "^16.3.0"
|
|
70
|
-
},
|
|
71
|
-
"peerDependencies": {
|
|
72
|
-
"contentful": ">=10.6.0"
|
|
73
|
-
},
|
|
74
|
-
"gitHead": "4b635ce38f276566da970c47ef8aec0cde771608"
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/contentful/experiences.git",
|
|
30
|
+
"directory": "packages/core"
|
|
31
|
+
}
|
|
75
32
|
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2023 Contentful
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|