@contentful/experiences-core 1.36.0-dev-20250417T0749-6e3b573.0 → 1.36.0-dev-20250417T1301-b6204ec.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.
|
@@ -12,7 +12,7 @@ declare abstract class EntityStoreBase {
|
|
|
12
12
|
entities: Array<Entry | Asset>;
|
|
13
13
|
locale: string;
|
|
14
14
|
});
|
|
15
|
-
get entities(): (
|
|
15
|
+
get entities(): (Asset<ChainModifiers, string> | Entry)[];
|
|
16
16
|
updateEntity(entity: Entry | Asset): void;
|
|
17
17
|
getEntryOrAsset(linkOrEntryOrAsset: UnresolvedLink<'Entry' | 'Asset'> | Asset | Entry, path: string): Entry | Asset | undefined;
|
|
18
18
|
/**
|
|
@@ -24,7 +24,7 @@ declare abstract class EntityStoreBase {
|
|
|
24
24
|
getValue(entityLink: UnresolvedLink<'Entry' | 'Asset'>, path: string[]): string | undefined;
|
|
25
25
|
getEntityFromLink(link: UnresolvedLink<'Entry' | 'Asset'>): Asset | Entry | undefined;
|
|
26
26
|
protected getEntitiesFromMap(type: 'Entry' | 'Asset', ids: string[]): {
|
|
27
|
-
resolved: (
|
|
27
|
+
resolved: (Asset<ChainModifiers, string> | Entry)[];
|
|
28
28
|
missing: string[];
|
|
29
29
|
};
|
|
30
30
|
protected addEntity(entity: Entry | Asset): void;
|
package/dist/index.js
CHANGED
|
@@ -1645,6 +1645,69 @@ const resetBreakpointsRegistry = () => {
|
|
|
1645
1645
|
breakpointsRegistry = [];
|
|
1646
1646
|
};
|
|
1647
1647
|
|
|
1648
|
+
function getOptimizedImageUrl(url, width, quality, format) {
|
|
1649
|
+
if (url.startsWith('//')) {
|
|
1650
|
+
url = 'https:' + url;
|
|
1651
|
+
}
|
|
1652
|
+
const params = new URLSearchParams();
|
|
1653
|
+
if (width) {
|
|
1654
|
+
params.append('w', width.toString());
|
|
1655
|
+
}
|
|
1656
|
+
if (quality && quality > 0 && quality < 100) {
|
|
1657
|
+
params.append('q', quality.toString());
|
|
1658
|
+
}
|
|
1659
|
+
if (format) {
|
|
1660
|
+
params.append('fm', format);
|
|
1661
|
+
}
|
|
1662
|
+
const queryString = params.toString();
|
|
1663
|
+
return `${url}${queryString ? '?' + queryString : ''}`;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
function validateParams(file, quality, format) {
|
|
1667
|
+
if (!file.details.image) {
|
|
1668
|
+
throw Error('No image in file asset to transform');
|
|
1669
|
+
}
|
|
1670
|
+
if (quality < 0 || quality > 100) {
|
|
1671
|
+
throw Error('Quality must be between 0 and 100');
|
|
1672
|
+
}
|
|
1673
|
+
if (format && !SUPPORTED_IMAGE_FORMATS.includes(format)) {
|
|
1674
|
+
throw Error(`Format must be one of ${SUPPORTED_IMAGE_FORMATS.join(', ')}`);
|
|
1675
|
+
}
|
|
1676
|
+
return true;
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
const MAX_WIDTH_ALLOWED$1 = 2000;
|
|
1680
|
+
const getOptimizedBackgroundImageAsset = (file, widthStyle, quality = '100%', format) => {
|
|
1681
|
+
const qualityNumber = Number(quality.replace('%', ''));
|
|
1682
|
+
if (!validateParams(file, qualityNumber, format)) ;
|
|
1683
|
+
if (!validateParams(file, qualityNumber, format)) ;
|
|
1684
|
+
const url = file.url;
|
|
1685
|
+
const { width1x, width2x } = getWidths(widthStyle, file);
|
|
1686
|
+
const imageUrl1x = getOptimizedImageUrl(url, width1x, qualityNumber, format);
|
|
1687
|
+
const imageUrl2x = getOptimizedImageUrl(url, width2x, qualityNumber, format);
|
|
1688
|
+
const srcSet = [`url(${imageUrl1x}) 1x`, `url(${imageUrl2x}) 2x`];
|
|
1689
|
+
const returnedUrl = getOptimizedImageUrl(url, width2x, qualityNumber, format);
|
|
1690
|
+
const optimizedBackgroundImageAsset = {
|
|
1691
|
+
url: returnedUrl,
|
|
1692
|
+
srcSet,
|
|
1693
|
+
file,
|
|
1694
|
+
};
|
|
1695
|
+
return optimizedBackgroundImageAsset;
|
|
1696
|
+
function getWidths(widthStyle, file) {
|
|
1697
|
+
let width1x = 0;
|
|
1698
|
+
let width2x = 0;
|
|
1699
|
+
const intrinsicImageWidth = file.details.image.width;
|
|
1700
|
+
if (widthStyle.endsWith('px')) {
|
|
1701
|
+
width1x = Math.min(Number(widthStyle.replace('px', '')), intrinsicImageWidth);
|
|
1702
|
+
}
|
|
1703
|
+
else {
|
|
1704
|
+
width1x = Math.min(MAX_WIDTH_ALLOWED$1, intrinsicImageWidth);
|
|
1705
|
+
}
|
|
1706
|
+
width2x = Math.min(width1x * 2, intrinsicImageWidth);
|
|
1707
|
+
return { width1x, width2x };
|
|
1708
|
+
}
|
|
1709
|
+
};
|
|
1710
|
+
|
|
1648
1711
|
const detachExperienceStyles = (experience) => {
|
|
1649
1712
|
const experienceTreeRoot = experience.entityStore?.experienceEntryFields
|
|
1650
1713
|
?.componentTree;
|
|
@@ -1664,17 +1727,25 @@ const detachExperienceStyles = (experience) => {
|
|
|
1664
1727
|
}), {});
|
|
1665
1728
|
// getting the breakpoint ids
|
|
1666
1729
|
const breakpointIds = Object.keys(mediaQueryDataByBreakpoint);
|
|
1667
|
-
const iterateOverTreeAndExtractStyles = ({ componentTree, dataSource, unboundValues, componentSettings, componentVariablesOverwrites, patternWrapper, wrappingPatternIds,
|
|
1730
|
+
const iterateOverTreeAndExtractStyles = ({ componentTree, dataSource, unboundValues, componentSettings, componentVariablesOverwrites, patternWrapper, wrappingPatternIds, parentChainArr = [], }) => {
|
|
1668
1731
|
// traversing the tree
|
|
1669
1732
|
const queue = [];
|
|
1670
|
-
queue.push(...componentTree.children)
|
|
1671
|
-
|
|
1733
|
+
queue.push(...componentTree.children.map((child) => ({
|
|
1734
|
+
node: child,
|
|
1735
|
+
parentChain: [...parentChainArr],
|
|
1736
|
+
})));
|
|
1672
1737
|
// for each tree node
|
|
1673
1738
|
while (queue.length) {
|
|
1674
|
-
|
|
1739
|
+
const queueItem = queue.shift();
|
|
1740
|
+
if (!queueItem) {
|
|
1741
|
+
break;
|
|
1742
|
+
}
|
|
1743
|
+
const { node: currentNode, parentChain } = queueItem;
|
|
1675
1744
|
if (!currentNode) {
|
|
1676
1745
|
break;
|
|
1677
1746
|
}
|
|
1747
|
+
const currentNodeParentChain = [...parentChain, currentNode.id || ''];
|
|
1748
|
+
const currentPatternNodeIdsChain = currentNodeParentChain.join('');
|
|
1678
1749
|
const usedComponents = experience.entityStore?.usedComponents ?? [];
|
|
1679
1750
|
const isPatternNode = checkIsAssemblyNode({
|
|
1680
1751
|
componentId: currentNode.definitionId,
|
|
@@ -1712,7 +1783,7 @@ const detachExperienceStyles = (experience) => {
|
|
|
1712
1783
|
// pass top-level pattern node to store instance-specific child styles for rendering
|
|
1713
1784
|
patternWrapper: currentNode,
|
|
1714
1785
|
wrappingPatternIds: new Set([...wrappingPatternIds, currentNode.definitionId]),
|
|
1715
|
-
|
|
1786
|
+
parentChainArr: currentNodeParentChain,
|
|
1716
1787
|
});
|
|
1717
1788
|
continue;
|
|
1718
1789
|
}
|
|
@@ -1798,13 +1869,12 @@ const detachExperienceStyles = (experience) => {
|
|
|
1798
1869
|
// making sure that we respect the order of breakpoints from
|
|
1799
1870
|
// we can achieve "desktop first" or "mobile first" approach to style over-writes
|
|
1800
1871
|
if (patternWrapper) {
|
|
1801
|
-
currentNode.id = currentNode.id || generateRandomId(5);
|
|
1802
1872
|
// @ts-expect-error -- valueByBreakpoint is not explicitly defined, but it's already defined in the patternWrapper styles
|
|
1803
1873
|
patternWrapper.variables.cfSsrClassName = {
|
|
1804
1874
|
...(patternWrapper.variables.cfSsrClassName ?? {}),
|
|
1805
1875
|
type: 'DesignValue',
|
|
1806
1876
|
// Chain IDs to avoid overwriting styles across multiple instances of the same pattern
|
|
1807
|
-
[
|
|
1877
|
+
[currentPatternNodeIdsChain]: {
|
|
1808
1878
|
valuesByBreakpoint: {
|
|
1809
1879
|
[breakpointIds[0]]: currentNodeClassNames.join(' '),
|
|
1810
1880
|
},
|
|
@@ -1819,7 +1889,10 @@ const detachExperienceStyles = (experience) => {
|
|
|
1819
1889
|
},
|
|
1820
1890
|
};
|
|
1821
1891
|
}
|
|
1822
|
-
queue.push(...currentNode.children)
|
|
1892
|
+
queue.push(...currentNode.children.map((child) => ({
|
|
1893
|
+
node: child,
|
|
1894
|
+
parentChain: currentNodeParentChain,
|
|
1895
|
+
})));
|
|
1823
1896
|
}
|
|
1824
1897
|
};
|
|
1825
1898
|
iterateOverTreeAndExtractStyles({
|
|
@@ -1941,7 +2014,28 @@ const maybePopulateDesignTokenValue = (variableName, variableValue, mapOfDesignV
|
|
|
1941
2014
|
// Not trimming would end up with a trailing space that breaks the check in `calculateNodeDefaultHeight`
|
|
1942
2015
|
return resolvedValue.trim();
|
|
1943
2016
|
};
|
|
1944
|
-
const
|
|
2017
|
+
const transformMedia$1 = (boundAsset, width, options) => {
|
|
2018
|
+
try {
|
|
2019
|
+
const asset = boundAsset;
|
|
2020
|
+
// Target width (px/rem/em) will be applied to the css url if it's lower than the original image width (in px)
|
|
2021
|
+
const assetDetails = asset.fields.file?.details;
|
|
2022
|
+
const assetWidth = assetDetails?.image?.width || 0; // This is always in px
|
|
2023
|
+
if (!options) {
|
|
2024
|
+
return asset.fields.file?.url;
|
|
2025
|
+
}
|
|
2026
|
+
const targetWidthObject = parseCSSValue(options.targetSize); // Contains value and unit (px/rem/em) so convert and then compare to assetWidth
|
|
2027
|
+
const targetValue = targetWidthObject ? getTargetValueInPixels(targetWidthObject) : assetWidth;
|
|
2028
|
+
if (targetValue < assetWidth)
|
|
2029
|
+
width = `${targetValue}px`;
|
|
2030
|
+
const value = getOptimizedBackgroundImageAsset(asset.fields.file, width, options.quality, options.format);
|
|
2031
|
+
return value;
|
|
2032
|
+
}
|
|
2033
|
+
catch (error) {
|
|
2034
|
+
console.error('Error transforming image asset', error);
|
|
2035
|
+
}
|
|
2036
|
+
return boundAsset.fields.file?.url;
|
|
2037
|
+
};
|
|
2038
|
+
const resolveBackgroundImageBinding = ({ variableData, getBoundEntityById, dataSource = {}, unboundValues = {}, componentVariablesOverwrites, componentSettings = { variableDefinitions: {} }, options, width, }) => {
|
|
1945
2039
|
if (variableData.type === 'UnboundValue') {
|
|
1946
2040
|
const uuid = variableData.key;
|
|
1947
2041
|
return unboundValues[uuid]?.value;
|
|
@@ -1966,6 +2060,8 @@ const resolveBackgroundImageBinding = ({ variableData, getBoundEntityById, dataS
|
|
|
1966
2060
|
unboundValues,
|
|
1967
2061
|
componentVariablesOverwrites,
|
|
1968
2062
|
componentSettings,
|
|
2063
|
+
options,
|
|
2064
|
+
width,
|
|
1969
2065
|
});
|
|
1970
2066
|
return resolvedValue || defaultValue;
|
|
1971
2067
|
}
|
|
@@ -1978,7 +2074,7 @@ const resolveBackgroundImageBinding = ({ variableData, getBoundEntityById, dataS
|
|
|
1978
2074
|
return;
|
|
1979
2075
|
}
|
|
1980
2076
|
if (boundEntity.sys.type === 'Asset') {
|
|
1981
|
-
return boundEntity
|
|
2077
|
+
return transformMedia$1(boundEntity, width, options);
|
|
1982
2078
|
}
|
|
1983
2079
|
else {
|
|
1984
2080
|
// '/lUERH7tX7nJTaPX6f0udB/fields/assetReference/~locale/fields/file/~locale'
|
|
@@ -2002,11 +2098,31 @@ const resolveBackgroundImageBinding = ({ variableData, getBoundEntityById, dataS
|
|
|
2002
2098
|
if (!referencedAsset) {
|
|
2003
2099
|
return;
|
|
2004
2100
|
}
|
|
2005
|
-
return referencedAsset
|
|
2101
|
+
return transformMedia$1(referencedAsset, width, options);
|
|
2006
2102
|
}
|
|
2007
2103
|
}
|
|
2008
2104
|
}
|
|
2009
2105
|
};
|
|
2106
|
+
const resolveVariable = ({ variableData, defaultBreakpoint, componentSettings = { variableDefinitions: {} }, componentVariablesOverwrites, }) => {
|
|
2107
|
+
if (variableData?.type === 'DesignValue') {
|
|
2108
|
+
return variableData.valuesByBreakpoint[defaultBreakpoint] || {};
|
|
2109
|
+
}
|
|
2110
|
+
else if (variableData?.type === 'ComponentValue') {
|
|
2111
|
+
const variableDefinitionKey = variableData.key;
|
|
2112
|
+
const variableDefinition = componentSettings.variableDefinitions[variableDefinitionKey];
|
|
2113
|
+
const defaultValue = variableDefinition.defaultValue;
|
|
2114
|
+
const userSetValue = componentVariablesOverwrites?.[variableDefinitionKey];
|
|
2115
|
+
if (!userSetValue || userSetValue.type === 'ComponentValue') {
|
|
2116
|
+
return defaultValue?.valuesByBreakpoint[defaultBreakpoint] || '';
|
|
2117
|
+
}
|
|
2118
|
+
return resolveVariable({
|
|
2119
|
+
variableData: userSetValue,
|
|
2120
|
+
defaultBreakpoint,
|
|
2121
|
+
componentSettings,
|
|
2122
|
+
componentVariablesOverwrites,
|
|
2123
|
+
});
|
|
2124
|
+
}
|
|
2125
|
+
};
|
|
2010
2126
|
/**
|
|
2011
2127
|
* Takes the initial set of properties, filters only design properties that will be mapped to CSS and
|
|
2012
2128
|
* re-organizes them to be indexed by breakpoint ID ("breakpoint > variable > value"). It will
|
|
@@ -2057,6 +2173,22 @@ const indexByBreakpoint = ({ variables, breakpointIds, getBoundEntityById, unbou
|
|
|
2057
2173
|
if (variableName === 'cfBackgroundImageUrl' ||
|
|
2058
2174
|
// TODO: Test this for nested patterns as the name might be just a random hash without the actual name (needs to be validated).
|
|
2059
2175
|
variableName.startsWith('cfBackgroundImageUrl_')) {
|
|
2176
|
+
const width = resolveVariable({
|
|
2177
|
+
variableData: variables['cfWidth'],
|
|
2178
|
+
defaultBreakpoint,
|
|
2179
|
+
componentSettings,
|
|
2180
|
+
componentVariablesOverwrites,
|
|
2181
|
+
});
|
|
2182
|
+
const options = resolveVariable({
|
|
2183
|
+
variableData: variables['cfBackgroundImageOptions'],
|
|
2184
|
+
defaultBreakpoint,
|
|
2185
|
+
componentSettings,
|
|
2186
|
+
componentVariablesOverwrites,
|
|
2187
|
+
});
|
|
2188
|
+
if (!options) {
|
|
2189
|
+
console.error(`Error transforming image asset: Required variable [cfBackgroundImageOptions] missing from component definition`);
|
|
2190
|
+
continue;
|
|
2191
|
+
}
|
|
2060
2192
|
const imageUrl = resolveBackgroundImageBinding({
|
|
2061
2193
|
variableData,
|
|
2062
2194
|
getBoundEntityById,
|
|
@@ -2064,6 +2196,8 @@ const indexByBreakpoint = ({ variables, breakpointIds, getBoundEntityById, unbou
|
|
|
2064
2196
|
dataSource,
|
|
2065
2197
|
componentSettings,
|
|
2066
2198
|
componentVariablesOverwrites,
|
|
2199
|
+
width,
|
|
2200
|
+
options,
|
|
2067
2201
|
});
|
|
2068
2202
|
if (imageUrl) {
|
|
2069
2203
|
variableValuesByBreakpoints[defaultBreakpoint][variableName] = imageUrl;
|
|
@@ -2203,69 +2337,6 @@ const resolveLinks = (node, entityStore) => {
|
|
|
2203
2337
|
}
|
|
2204
2338
|
};
|
|
2205
2339
|
|
|
2206
|
-
function getOptimizedImageUrl(url, width, quality, format) {
|
|
2207
|
-
if (url.startsWith('//')) {
|
|
2208
|
-
url = 'https:' + url;
|
|
2209
|
-
}
|
|
2210
|
-
const params = new URLSearchParams();
|
|
2211
|
-
if (width) {
|
|
2212
|
-
params.append('w', width.toString());
|
|
2213
|
-
}
|
|
2214
|
-
if (quality && quality > 0 && quality < 100) {
|
|
2215
|
-
params.append('q', quality.toString());
|
|
2216
|
-
}
|
|
2217
|
-
if (format) {
|
|
2218
|
-
params.append('fm', format);
|
|
2219
|
-
}
|
|
2220
|
-
const queryString = params.toString();
|
|
2221
|
-
return `${url}${queryString ? '?' + queryString : ''}`;
|
|
2222
|
-
}
|
|
2223
|
-
|
|
2224
|
-
function validateParams(file, quality, format) {
|
|
2225
|
-
if (!file.details.image) {
|
|
2226
|
-
throw Error('No image in file asset to transform');
|
|
2227
|
-
}
|
|
2228
|
-
if (quality < 0 || quality > 100) {
|
|
2229
|
-
throw Error('Quality must be between 0 and 100');
|
|
2230
|
-
}
|
|
2231
|
-
if (format && !SUPPORTED_IMAGE_FORMATS.includes(format)) {
|
|
2232
|
-
throw Error(`Format must be one of ${SUPPORTED_IMAGE_FORMATS.join(', ')}`);
|
|
2233
|
-
}
|
|
2234
|
-
return true;
|
|
2235
|
-
}
|
|
2236
|
-
|
|
2237
|
-
const MAX_WIDTH_ALLOWED$1 = 2000;
|
|
2238
|
-
const getOptimizedBackgroundImageAsset = (file, widthStyle, quality = '100%', format) => {
|
|
2239
|
-
const qualityNumber = Number(quality.replace('%', ''));
|
|
2240
|
-
if (!validateParams(file, qualityNumber, format)) ;
|
|
2241
|
-
if (!validateParams(file, qualityNumber, format)) ;
|
|
2242
|
-
const url = file.url;
|
|
2243
|
-
const { width1x, width2x } = getWidths(widthStyle, file);
|
|
2244
|
-
const imageUrl1x = getOptimizedImageUrl(url, width1x, qualityNumber, format);
|
|
2245
|
-
const imageUrl2x = getOptimizedImageUrl(url, width2x, qualityNumber, format);
|
|
2246
|
-
const srcSet = [`url(${imageUrl1x}) 1x`, `url(${imageUrl2x}) 2x`];
|
|
2247
|
-
const returnedUrl = getOptimizedImageUrl(url, width2x, qualityNumber, format);
|
|
2248
|
-
const optimizedBackgroundImageAsset = {
|
|
2249
|
-
url: returnedUrl,
|
|
2250
|
-
srcSet,
|
|
2251
|
-
file,
|
|
2252
|
-
};
|
|
2253
|
-
return optimizedBackgroundImageAsset;
|
|
2254
|
-
function getWidths(widthStyle, file) {
|
|
2255
|
-
let width1x = 0;
|
|
2256
|
-
let width2x = 0;
|
|
2257
|
-
const intrinsicImageWidth = file.details.image.width;
|
|
2258
|
-
if (widthStyle.endsWith('px')) {
|
|
2259
|
-
width1x = Math.min(Number(widthStyle.replace('px', '')), intrinsicImageWidth);
|
|
2260
|
-
}
|
|
2261
|
-
else {
|
|
2262
|
-
width1x = Math.min(MAX_WIDTH_ALLOWED$1, intrinsicImageWidth);
|
|
2263
|
-
}
|
|
2264
|
-
width2x = Math.min(width1x * 2, intrinsicImageWidth);
|
|
2265
|
-
return { width1x, width2x };
|
|
2266
|
-
}
|
|
2267
|
-
};
|
|
2268
|
-
|
|
2269
2340
|
const MAX_WIDTH_ALLOWED = 4000;
|
|
2270
2341
|
const getOptimizedImageAsset = ({ file, sizes, loading, quality = '100%', format, }) => {
|
|
2271
2342
|
const qualityNumber = Number(quality.replace('%', ''));
|