@contentful/experiences-core 1.34.0 → 1.34.1-dev-20250305T1630-a40e5df.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/dist/index.d.ts +2 -2
- package/dist/index.js +189 -201
- package/dist/index.js.map +1 -1
- package/dist/utils/breakpoints.d.ts +1 -1
- package/dist/utils/styleUtils/ssrStyles.d.ts +49 -15
- package/dist/utils/styleUtils/stylesUtils.d.ts +46 -3
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { isComponentAllowedOnRoot, isContentfulComponent, isContentfulStructureComponent, isPatternComponent, isStructureWithRelativeHeight } from './utils/components.js';
|
|
2
2
|
export { findOutermostCoordinates, getElementCoordinates } from './utils/domValues.js';
|
|
3
3
|
export { doesMismatchMessageSchema, tryParseMessage, validateExperienceBuilderConfig } from './utils/validations.js';
|
|
4
|
-
export { buildCfStyles, buildStyleTag, calculateNodeDefaultHeight, toCSSAttribute } from './utils/styleUtils/stylesUtils.js';
|
|
5
|
-
export { detachExperienceStyles, flattenDesignTokenRegistry, indexByBreakpoint, isCfStyleAttribute, maybePopulateDesignTokenValue, resolveBackgroundImageBinding,
|
|
4
|
+
export { addMinHeightForEmptyStructures, buildCfStyles, buildStyleTag, calculateNodeDefaultHeight, stringifyCssProperties, toCSSAttribute } from './utils/styleUtils/stylesUtils.js';
|
|
5
|
+
export { detachExperienceStyles, flattenDesignTokenRegistry, indexByBreakpoint, isCfStyleAttribute, maybePopulateDesignTokenValue, resolveBackgroundImageBinding, toMediaQuery } from './utils/styleUtils/ssrStyles.js';
|
|
6
6
|
export { transformBoundContentValue } from './utils/transformers/transformBoundContentValue.js';
|
|
7
7
|
export { checkIsAssembly, checkIsAssemblyDefinition, checkIsAssemblyEntry, checkIsAssemblyNode, generateRandomId, getDataFromTree, getInsertionData, getTargetValueInPixels, parseCSSValue } from './utils/utils.js';
|
|
8
8
|
export { isExperienceEntry } from './utils/typeguards.js';
|
package/dist/index.js
CHANGED
|
@@ -380,45 +380,102 @@ const toCSSAttribute = (key) => {
|
|
|
380
380
|
val = val.replace(/\d+$/, '');
|
|
381
381
|
return val;
|
|
382
382
|
};
|
|
383
|
-
|
|
384
|
-
|
|
383
|
+
/**
|
|
384
|
+
* Turns a list of CSSProperties into a joined CSS string that can be
|
|
385
|
+
* used for <style> tags. Per default it creates a minimized version.
|
|
386
|
+
* For editor mode, use the `useWhitespaces` flag to create a more readable version.
|
|
387
|
+
*
|
|
388
|
+
* @param cssProperties list of CSS properties
|
|
389
|
+
* @param useWhitespaces adds whitespaces and newlines between each rule
|
|
390
|
+
* @returns a string of CSS rules
|
|
391
|
+
*/
|
|
392
|
+
const stringifyCssProperties = (cssProperties, useWhitespaces = false) => {
|
|
393
|
+
const rules = Object.entries(cssProperties)
|
|
385
394
|
.filter(([, value]) => value !== undefined)
|
|
386
|
-
.
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
395
|
+
.map(([key, value]) => useWhitespaces ? `${toCSSAttribute(key)}: ${value};` : `${toCSSAttribute(key)}:${value};`);
|
|
396
|
+
return rules.join(useWhitespaces ? '\n' : '');
|
|
397
|
+
};
|
|
398
|
+
const buildStyleTag = ({ styles, nodeId }) => {
|
|
399
|
+
const generatedStyles = stringifyCssProperties(styles, true);
|
|
400
|
+
const className = `cfstyles-${nodeId ? nodeId : md5(generatedStyles)}`;
|
|
401
|
+
const styleRule = `.${className}{ ${generatedStyles} }`;
|
|
390
402
|
return [className, styleRule];
|
|
391
403
|
};
|
|
392
|
-
|
|
393
|
-
|
|
404
|
+
/**
|
|
405
|
+
* Takes plain design values and transforms them into CSS properties. Undefined values will
|
|
406
|
+
* be filtered out.
|
|
407
|
+
*
|
|
408
|
+
* **Example Input**
|
|
409
|
+
* ```
|
|
410
|
+
* values = {
|
|
411
|
+
* cfVisibility: 'visible',
|
|
412
|
+
* cfMargin: '10px',
|
|
413
|
+
* cfFlexReverse: true,
|
|
414
|
+
* cfImageOptions: { objectFit: 'cover' },
|
|
415
|
+
* // ...
|
|
416
|
+
* }
|
|
417
|
+
* ```
|
|
418
|
+
* **Example Output**
|
|
419
|
+
* ```
|
|
420
|
+
* cssProperties = {
|
|
421
|
+
* margin: '10px',
|
|
422
|
+
* flexDirection: 'row-reverse',
|
|
423
|
+
* objectFit: 'cover',
|
|
424
|
+
* // ...
|
|
425
|
+
* }
|
|
426
|
+
* ```
|
|
427
|
+
*/
|
|
428
|
+
const buildCfStyles = (values) => {
|
|
429
|
+
const cssProperties = {
|
|
394
430
|
boxSizing: 'border-box',
|
|
395
|
-
...transformVisibility(cfVisibility),
|
|
396
|
-
margin: cfMargin,
|
|
397
|
-
padding: cfPadding,
|
|
398
|
-
backgroundColor: cfBackgroundColor,
|
|
399
|
-
width: transformFill(cfWidth || cfImageOptions?.width),
|
|
400
|
-
height: transformFill(cfHeight || cfImageOptions?.height),
|
|
401
|
-
maxWidth: cfMaxWidth,
|
|
402
|
-
...transformGridColumn(cfColumnSpan),
|
|
403
|
-
...transformBorderStyle(cfBorder),
|
|
404
|
-
borderRadius: cfBorderRadius,
|
|
405
|
-
gap: cfGap,
|
|
406
|
-
...transformAlignment(cfHorizontalAlignment, cfVerticalAlignment, cfFlexDirection),
|
|
407
|
-
flexDirection: cfFlexReverse && cfFlexDirection
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
431
|
+
...transformVisibility(values.cfVisibility),
|
|
432
|
+
margin: values.cfMargin,
|
|
433
|
+
padding: values.cfPadding,
|
|
434
|
+
backgroundColor: values.cfBackgroundColor,
|
|
435
|
+
width: transformFill(values.cfWidth || values.cfImageOptions?.width),
|
|
436
|
+
height: transformFill(values.cfHeight || values.cfImageOptions?.height),
|
|
437
|
+
maxWidth: values.cfMaxWidth,
|
|
438
|
+
...transformGridColumn(values.cfColumnSpan),
|
|
439
|
+
...transformBorderStyle(values.cfBorder),
|
|
440
|
+
borderRadius: values.cfBorderRadius,
|
|
441
|
+
gap: values.cfGap,
|
|
442
|
+
...transformAlignment(values.cfHorizontalAlignment, values.cfVerticalAlignment, values.cfFlexDirection),
|
|
443
|
+
flexDirection: values.cfFlexReverse && values.cfFlexDirection
|
|
444
|
+
? `${values.cfFlexDirection}-reverse`
|
|
445
|
+
: values.cfFlexDirection,
|
|
446
|
+
flexWrap: values.cfFlexWrap,
|
|
447
|
+
...transformBackgroundImage(values.cfBackgroundImageUrl, values.cfBackgroundImageOptions),
|
|
448
|
+
fontSize: values.cfFontSize,
|
|
449
|
+
fontWeight: values.cfTextBold ? 'bold' : values.cfFontWeight,
|
|
450
|
+
fontStyle: values.cfTextItalic ? 'italic' : undefined,
|
|
451
|
+
textDecoration: values.cfTextUnderline ? 'underline' : undefined,
|
|
452
|
+
lineHeight: values.cfLineHeight,
|
|
453
|
+
letterSpacing: values.cfLetterSpacing,
|
|
454
|
+
color: values.cfTextColor,
|
|
455
|
+
textAlign: values.cfTextAlign,
|
|
456
|
+
textTransform: values.cfTextTransform,
|
|
457
|
+
objectFit: values.cfImageOptions?.objectFit,
|
|
458
|
+
objectPosition: values.cfImageOptions?.objectPosition,
|
|
421
459
|
};
|
|
460
|
+
const cssPropertiesWithoutUndefined = Object.fromEntries(Object.entries(cssProperties).filter(([, value]) => value !== undefined));
|
|
461
|
+
return cssPropertiesWithoutUndefined;
|
|
462
|
+
};
|
|
463
|
+
/**
|
|
464
|
+
* **Only meant to be used in editor mode!**
|
|
465
|
+
*
|
|
466
|
+
* If the node is an empty structure component with a relative height (e.g. '100%'),
|
|
467
|
+
* it might render with a zero height. In this case, add a min height of 80px to ensure
|
|
468
|
+
* that child nodes can be added via drag & drop.
|
|
469
|
+
*/
|
|
470
|
+
const addMinHeightForEmptyStructures = (cssProperties, node) => {
|
|
471
|
+
if (!node.children.length &&
|
|
472
|
+
isStructureWithRelativeHeight(node.definitionId, cssProperties.height)) {
|
|
473
|
+
return {
|
|
474
|
+
...cssProperties,
|
|
475
|
+
minHeight: EMPTY_CONTAINER_HEIGHT,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
return cssProperties;
|
|
422
479
|
};
|
|
423
480
|
/**
|
|
424
481
|
* Container/section default behavior:
|
|
@@ -1594,41 +1651,17 @@ const detachExperienceStyles = (experience) => {
|
|
|
1594
1651
|
}
|
|
1595
1652
|
const mapOfDesignVariableKeys = flattenDesignTokenRegistry(designTokensRegistry);
|
|
1596
1653
|
// getting breakpoints from the entry componentTree field
|
|
1597
|
-
/**
|
|
1598
|
-
* breakpoints [
|
|
1599
|
-
{
|
|
1600
|
-
id: 'desktop',
|
|
1601
|
-
query: '*',
|
|
1602
|
-
displayName: 'All Sizes',
|
|
1603
|
-
previewSize: '100%'
|
|
1604
|
-
},
|
|
1605
|
-
{
|
|
1606
|
-
id: 'tablet',
|
|
1607
|
-
query: '<992px',
|
|
1608
|
-
displayName: 'Tablet',
|
|
1609
|
-
previewSize: '820px'
|
|
1610
|
-
},
|
|
1611
|
-
{
|
|
1612
|
-
id: 'mobile',
|
|
1613
|
-
query: '<576px',
|
|
1614
|
-
displayName: 'Mobile',
|
|
1615
|
-
previewSize: '390px'
|
|
1616
|
-
}
|
|
1617
|
-
]
|
|
1618
|
-
*/
|
|
1619
1654
|
const { breakpoints } = experienceTreeRoot;
|
|
1620
1655
|
// creating the structure which I thought would work best for aggregation
|
|
1621
|
-
const
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
};
|
|
1629
|
-
}, {});
|
|
1656
|
+
const mediaQueryDataByBreakpoint = breakpoints.reduce((mediaQueryTemplate, breakpoint) => ({
|
|
1657
|
+
...mediaQueryTemplate,
|
|
1658
|
+
[breakpoint.id]: {
|
|
1659
|
+
condition: breakpoint.query,
|
|
1660
|
+
cssByClassName: {},
|
|
1661
|
+
},
|
|
1662
|
+
}), {});
|
|
1630
1663
|
// getting the breakpoint ids
|
|
1631
|
-
const breakpointIds = Object.keys(
|
|
1664
|
+
const breakpointIds = Object.keys(mediaQueryDataByBreakpoint);
|
|
1632
1665
|
const iterateOverTreeAndExtractStyles = ({ componentTree, dataSource, unboundValues, componentSettings, componentVariablesOverwrites, patternWrapper, wrappingPatternIds, patternNodeIdsChain = '', }) => {
|
|
1633
1666
|
// traversing the tree
|
|
1634
1667
|
const queue = [];
|
|
@@ -1654,29 +1687,6 @@ const detachExperienceStyles = (experience) => {
|
|
|
1654
1687
|
if (!patternEntry || !('fields' in patternEntry)) {
|
|
1655
1688
|
continue;
|
|
1656
1689
|
}
|
|
1657
|
-
const defaultPatternDivStyles = Object.fromEntries(Object.entries(buildCfStyles({}))
|
|
1658
|
-
.filter(([, value]) => value !== undefined)
|
|
1659
|
-
.map(([key, value]) => [toCSSAttribute(key), value]));
|
|
1660
|
-
// I create a hash of the object above because that would ensure hash stability
|
|
1661
|
-
const styleHash = md5(JSON.stringify(defaultPatternDivStyles));
|
|
1662
|
-
// and prefix the className to make sure the value can be processed
|
|
1663
|
-
const className = `cf-${styleHash}`;
|
|
1664
|
-
for (const breakpointId of breakpointIds) {
|
|
1665
|
-
if (!mediaQueriesTemplate[breakpointId].cssByClassName[className]) {
|
|
1666
|
-
mediaQueriesTemplate[breakpointId].cssByClassName[className] =
|
|
1667
|
-
toCSSString(defaultPatternDivStyles);
|
|
1668
|
-
}
|
|
1669
|
-
}
|
|
1670
|
-
// When iterating over instances of the same pattern, we will iterate over the identical
|
|
1671
|
-
// pattern nodes again for every instance. Make sure to not overwrite the values from previous instances.
|
|
1672
|
-
if (!currentNode.variables.cfSsrClassName) {
|
|
1673
|
-
currentNode.variables.cfSsrClassName = {
|
|
1674
|
-
type: 'DesignValue',
|
|
1675
|
-
valuesByBreakpoint: {
|
|
1676
|
-
[breakpointIds[0]]: className,
|
|
1677
|
-
},
|
|
1678
|
-
};
|
|
1679
|
-
}
|
|
1680
1690
|
const nextComponentVariablesOverwrites = resolveComponentVariablesOverwrites({
|
|
1681
1691
|
patternNode: currentNode,
|
|
1682
1692
|
wrapperComponentVariablesOverwrites: componentVariablesOverwrites,
|
|
@@ -1704,36 +1714,15 @@ const detachExperienceStyles = (experience) => {
|
|
|
1704
1714
|
});
|
|
1705
1715
|
continue;
|
|
1706
1716
|
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
},
|
|
1717
|
-
cfWidth: { type: 'DesignValue', valuesByBreakpoint: { desktop: 'fill' } },
|
|
1718
|
-
cfHeight: {
|
|
1719
|
-
type: 'DesignValue',
|
|
1720
|
-
valuesByBreakpoint: { desktop: 'fit-content' }
|
|
1721
|
-
},
|
|
1722
|
-
cfMaxWidth: { type: 'DesignValue', valuesByBreakpoint: { desktop: 'none' } },
|
|
1723
|
-
cfFlexDirection: { type: 'DesignValue', valuesByBreakpoint: { desktop: 'column' } },
|
|
1724
|
-
cfFlexWrap: { type: 'DesignValue', valuesByBreakpoint: { desktop: 'nowrap' } },
|
|
1725
|
-
cfBorder: {
|
|
1726
|
-
type: 'DesignValue',
|
|
1727
|
-
valuesByBreakpoint: { desktop: '0px solid rgba(0, 0, 0, 0)' }
|
|
1728
|
-
},
|
|
1729
|
-
cfBorderRadius: { type: 'DesignValue', valuesByBreakpoint: { desktop: '0px' } },
|
|
1730
|
-
cfGap: { type: 'DesignValue', valuesByBreakpoint: { desktop: '0px 0px' } },
|
|
1731
|
-
cfHyperlink: { type: 'UnboundValue', key: 'VNc49Qyepd6IzN7rmKUyS' },
|
|
1732
|
-
cfOpenInNewTab: { type: 'UnboundValue', key: 'ZA5YqB2fmREQ4pTKqY5hX' },
|
|
1733
|
-
cfBackgroundImageUrl: { type: 'UnboundValue', key: 'FeskH0WbYD5_RQVXX-1T8' },
|
|
1734
|
-
cfBackgroundImageOptions: { type: 'DesignValue', valuesByBreakpoint: { desktop: [Object] } }
|
|
1735
|
-
}
|
|
1736
|
-
*/
|
|
1717
|
+
/* [Data format] `currentNode.variables` uses the following serialized shape:
|
|
1718
|
+
* {
|
|
1719
|
+
* cfMargin: { type: 'DesignValue', valuesByBreakpoint: { desktop: '1px', tablet: '2px' } },
|
|
1720
|
+
* cfPadding: { type: 'DesignValue', valuesByBreakpoint: { desktop: '3px' } }
|
|
1721
|
+
* cfBackgroundImageUrl: { type: 'BoundValue', path: '/lUERH7tX7nJTaPX6f0udB/fields/assetReference/~locale/fields/file/~locale' }
|
|
1722
|
+
* asdf1234: { type: 'ComponentValue', key: 'qwer567' }
|
|
1723
|
+
* // ...
|
|
1724
|
+
* }
|
|
1725
|
+
*/
|
|
1737
1726
|
// so first, I convert it into a map to help me make it easier to access the values
|
|
1738
1727
|
const propsByBreakpoint = indexByBreakpoint({
|
|
1739
1728
|
variables: currentNode.variables,
|
|
@@ -1746,30 +1735,18 @@ const detachExperienceStyles = (experience) => {
|
|
|
1746
1735
|
return experience.entityStore?.entities.find((entity) => entity.sys.id === id);
|
|
1747
1736
|
},
|
|
1748
1737
|
});
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
cfMaxWidth: 'none',
|
|
1760
|
-
cfFlexDirection: 'column',
|
|
1761
|
-
cfFlexWrap: 'nowrap',
|
|
1762
|
-
cfBorder: '0px solid rgba(0, 0, 0, 0)',
|
|
1763
|
-
cfBorderRadius: '0px',
|
|
1764
|
-
cfGap: '0px 0px',
|
|
1765
|
-
cfBackgroundImageOptions: { scaling: 'fill', alignment: 'left top', targetSize: '2000px' }
|
|
1766
|
-
},
|
|
1767
|
-
tablet: {},
|
|
1768
|
-
mobile: {}
|
|
1769
|
-
}
|
|
1770
|
-
*/
|
|
1738
|
+
/* [Data format] `propsByBreakpoint` is a map of "breakpointId > propertyName > plainValue":
|
|
1739
|
+
* {
|
|
1740
|
+
* desktop: {
|
|
1741
|
+
* cfMargin: '1px',
|
|
1742
|
+
* cfWidth: 'fill',
|
|
1743
|
+
* cfBackgroundImageUrl: 'https://example.com/image.jpg'
|
|
1744
|
+
* //...
|
|
1745
|
+
* }
|
|
1746
|
+
* }
|
|
1747
|
+
*/
|
|
1771
1748
|
const currentNodeClassNames = [];
|
|
1772
|
-
//
|
|
1749
|
+
// For each breakpoint, resolve design tokens, create the CSS and generate a unique className.
|
|
1773
1750
|
for (const breakpointId of breakpointIds) {
|
|
1774
1751
|
const propsByBreakpointWithResolvedDesignTokens = Object.entries(propsByBreakpoint[breakpointId]).reduce((acc, [variableName, variableValue]) => {
|
|
1775
1752
|
return {
|
|
@@ -1777,36 +1754,24 @@ const detachExperienceStyles = (experience) => {
|
|
|
1777
1754
|
[variableName]: maybePopulateDesignTokenValue(variableName, variableValue, mapOfDesignVariableKeys),
|
|
1778
1755
|
};
|
|
1779
1756
|
}, {});
|
|
1780
|
-
//
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
border: '0px solid rgba(0, 0, 0, 0)',
|
|
1795
|
-
'border-radius': '0px',
|
|
1796
|
-
gap: '0px 0px',
|
|
1797
|
-
'align-items': 'center',
|
|
1798
|
-
'justify-content': 'safe center',
|
|
1799
|
-
'flex-direction': 'column',
|
|
1800
|
-
'flex-wrap': 'nowrap',
|
|
1801
|
-
'font-style': 'normal',
|
|
1802
|
-
'text-decoration': 'none',
|
|
1803
|
-
'box-sizing': 'border-box'
|
|
1804
|
-
}
|
|
1805
|
-
*/
|
|
1757
|
+
// Convert CF-specific property names to CSS variables, e.g. `cfMargin` -> `margin`
|
|
1758
|
+
const cfStyles = buildCfStyles(propsByBreakpointWithResolvedDesignTokens);
|
|
1759
|
+
/* [Data format] `cfStyles` is a list of CSSProperties (React format):
|
|
1760
|
+
* {
|
|
1761
|
+
* margin: '1px',
|
|
1762
|
+
* width: '100%',
|
|
1763
|
+
* backgroundImage: 'url(https://example.com/image.jpg)'
|
|
1764
|
+
* //...
|
|
1765
|
+
* }
|
|
1766
|
+
*/
|
|
1767
|
+
const generatedCss = stringifyCssProperties(cfStyles);
|
|
1768
|
+
/* [Data format] `generatedCss` is the minimized CSS string that will be added to the DOM:
|
|
1769
|
+
* generatedCss = "margin: 1px;width: 100%;..."
|
|
1770
|
+
*/
|
|
1806
1771
|
// I create a hash of the object above because that would ensure hash stability
|
|
1807
1772
|
// Adding breakpointId to ensure not using the same IDs between breakpoints as this leads to
|
|
1808
1773
|
// conflicts between different breakpoint values from multiple nodes where the hash would be equal
|
|
1809
|
-
const styleHash = md5(breakpointId +
|
|
1774
|
+
const styleHash = md5(breakpointId + generatedCss);
|
|
1810
1775
|
// and prefix the className to make sure the value can be processed
|
|
1811
1776
|
const className = `cf-${styleHash}`;
|
|
1812
1777
|
// I save the generated hashes into an array to later save it in the tree node
|
|
@@ -1816,11 +1781,11 @@ const detachExperienceStyles = (experience) => {
|
|
|
1816
1781
|
currentNodeClassNames.push(className);
|
|
1817
1782
|
}
|
|
1818
1783
|
// if there is already the similar hash - no need to over-write it
|
|
1819
|
-
if (
|
|
1784
|
+
if (mediaQueryDataByBreakpoint[breakpointId].cssByClassName[className]) {
|
|
1820
1785
|
continue;
|
|
1821
1786
|
}
|
|
1822
1787
|
// otherwise, save it to the stylesheet
|
|
1823
|
-
|
|
1788
|
+
mediaQueryDataByBreakpoint[breakpointId].cssByClassName[className] = generatedCss;
|
|
1824
1789
|
}
|
|
1825
1790
|
// all generated classNames are saved in the tree node
|
|
1826
1791
|
// to be handled by the sdk later
|
|
@@ -1864,10 +1829,8 @@ const detachExperienceStyles = (experience) => {
|
|
|
1864
1829
|
});
|
|
1865
1830
|
// once the whole tree was traversed, for each breakpoint, I aggregate the styles
|
|
1866
1831
|
// for each generated className into one css string
|
|
1867
|
-
const
|
|
1868
|
-
|
|
1869
|
-
}, '');
|
|
1870
|
-
return styleSheet;
|
|
1832
|
+
const stylesheet = Object.entries(mediaQueryDataByBreakpoint).reduce((acc, [, mediaQueryData]) => `${acc}${toMediaQuery(mediaQueryData)}`, '');
|
|
1833
|
+
return stylesheet;
|
|
1871
1834
|
};
|
|
1872
1835
|
/**
|
|
1873
1836
|
* Rendering pattern nodes inside pattern entry by injecting default values from the top:
|
|
@@ -2042,6 +2005,41 @@ const resolveBackgroundImageBinding = ({ variableData, getBoundEntityById, dataS
|
|
|
2042
2005
|
}
|
|
2043
2006
|
}
|
|
2044
2007
|
};
|
|
2008
|
+
/**
|
|
2009
|
+
* Takes the initial set of properties, filters only design properties that will be mapped to CSS and
|
|
2010
|
+
* re-organizes them to be indexed by breakpoint ID ("breakpoint > variable > value"). It will
|
|
2011
|
+
* also resolve the design/ component values to plain values.
|
|
2012
|
+
*
|
|
2013
|
+
* **Example Input**
|
|
2014
|
+
* ```
|
|
2015
|
+
* variables = {
|
|
2016
|
+
* cfMargin: { type: 'DesignValue', valuesByBreakpoint: { desktop: '1px', tablet: '2px' } },
|
|
2017
|
+
* cfPadding: { type: 'DesignValue', valuesByBreakpoint: { desktop: '3px', mobile: '4px' } }
|
|
2018
|
+
* }
|
|
2019
|
+
* ```
|
|
2020
|
+
*
|
|
2021
|
+
* **Example Output**
|
|
2022
|
+
* ```
|
|
2023
|
+
* variableValuesByBreakpoints = {
|
|
2024
|
+
* desktop: {
|
|
2025
|
+
* cfMargin: '1px',
|
|
2026
|
+
* cfPadding: '3px'
|
|
2027
|
+
* },
|
|
2028
|
+
* tablet: {
|
|
2029
|
+
* cfMargin: '2px'
|
|
2030
|
+
* },
|
|
2031
|
+
* mobile: {
|
|
2032
|
+
* cfPadding: '4px'
|
|
2033
|
+
* }
|
|
2034
|
+
* }
|
|
2035
|
+
* ```
|
|
2036
|
+
*
|
|
2037
|
+
* **Note**
|
|
2038
|
+
* - The property cfBackgroundImageUrl is the only content property that gets mapped to CSS as well.
|
|
2039
|
+
* It will be solely stored on the default breakpoint.
|
|
2040
|
+
* - For ComponentValues, it will either take the override from the pattern instance or fallback to
|
|
2041
|
+
* the defaultValue defined in variableDefinitions.
|
|
2042
|
+
*/
|
|
2045
2043
|
const indexByBreakpoint = ({ variables, breakpointIds, getBoundEntityById, unboundValues = {}, dataSource = {}, componentVariablesOverwrites, componentSettings = { variableDefinitions: {} }, }) => {
|
|
2046
2044
|
const variableValuesByBreakpoints = breakpointIds.reduce((acc, breakpointId) => {
|
|
2047
2045
|
return {
|
|
@@ -2052,9 +2050,10 @@ const indexByBreakpoint = ({ variables, breakpointIds, getBoundEntityById, unbou
|
|
|
2052
2050
|
const defaultBreakpoint = breakpointIds[0];
|
|
2053
2051
|
for (const [variableName, variableData] of Object.entries(variables)) {
|
|
2054
2052
|
// handling the special case - cfBackgroundImageUrl variable, which can be bound or unbound
|
|
2055
|
-
// so, we need to resolve it here and pass it down as a css property to be
|
|
2053
|
+
// so, we need to resolve it here and pass it down as a css property to be converted into the CSS
|
|
2056
2054
|
// I used .startsWith() cause it can be part of a pattern node
|
|
2057
2055
|
if (variableName === 'cfBackgroundImageUrl' ||
|
|
2056
|
+
// TODO: Test this for nested patterns as the name might be just a random hash without the actual name (needs to be validated).
|
|
2058
2057
|
variableName.startsWith('cfBackgroundImageUrl_')) {
|
|
2059
2058
|
const imageUrl = resolveBackgroundImageBinding({
|
|
2060
2059
|
variableData,
|
|
@@ -2095,17 +2094,9 @@ const indexByBreakpoint = ({ variables, breakpointIds, getBoundEntityById, unbou
|
|
|
2095
2094
|
};
|
|
2096
2095
|
/**
|
|
2097
2096
|
* Flattens the object from
|
|
2098
|
-
* {
|
|
2099
|
-
* color: {
|
|
2100
|
-
* [key]: [value]
|
|
2101
|
-
* }
|
|
2102
|
-
* }
|
|
2103
|
-
*
|
|
2097
|
+
* `{ color: { [key]: [value] } }`
|
|
2104
2098
|
* to
|
|
2105
|
-
*
|
|
2106
|
-
* {
|
|
2107
|
-
* 'color.key': [value]
|
|
2108
|
-
* }
|
|
2099
|
+
* `{ 'color.key': [value] }`
|
|
2109
2100
|
*/
|
|
2110
2101
|
const flattenDesignTokenRegistry = (designTokenRegistry) => {
|
|
2111
2102
|
return Object.entries(designTokenRegistry).reduce((acc, [categoryName, tokenCategory]) => {
|
|
@@ -2121,24 +2112,21 @@ const flattenDesignTokenRegistry = (designTokenRegistry) => {
|
|
|
2121
2112
|
};
|
|
2122
2113
|
}, {});
|
|
2123
2114
|
};
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
const toMediaQuery = (
|
|
2132
|
-
const mediaQueryStyles = Object.entries(
|
|
2115
|
+
/**
|
|
2116
|
+
* Create a single CSS string containing all class definitions for a given media query.
|
|
2117
|
+
*
|
|
2118
|
+
* @param condition e.g. "*", "<520px", ">520px"
|
|
2119
|
+
* @param cssByClassName map of class names to CSS strings containing all rules for each class
|
|
2120
|
+
* @returns joined string of all CSS class definitions wrapped into media queries
|
|
2121
|
+
*/
|
|
2122
|
+
const toMediaQuery = ({ condition, cssByClassName }) => {
|
|
2123
|
+
const mediaQueryStyles = Object.entries(cssByClassName).reduce((acc, [className, css]) => {
|
|
2133
2124
|
return `${acc}.${className}{${css}}`;
|
|
2134
2125
|
}, ``);
|
|
2135
|
-
if (
|
|
2126
|
+
if (condition === '*') {
|
|
2136
2127
|
return mediaQueryStyles;
|
|
2137
2128
|
}
|
|
2138
|
-
const [evaluation, pixelValue] = [
|
|
2139
|
-
breakpointPayload.condition[0],
|
|
2140
|
-
breakpointPayload.condition.substring(1),
|
|
2141
|
-
];
|
|
2129
|
+
const [evaluation, pixelValue] = [condition[0], condition.substring(1)];
|
|
2142
2130
|
const mediaQueryRule = evaluation === '<' ? 'max-width' : 'min-width';
|
|
2143
2131
|
return `@media(${mediaQueryRule}:${pixelValue}){${mediaQueryStyles}}`;
|
|
2144
2132
|
};
|
|
@@ -3917,5 +3905,5 @@ async function fetchById({ client, experienceTypeId, id, localeCode, isEditorMod
|
|
|
3917
3905
|
}
|
|
3918
3906
|
}
|
|
3919
3907
|
|
|
3920
|
-
export { DeepReference, EditorModeEntityStore, EntityStore, EntityStoreBase, MEDIA_QUERY_REGEXP, VisualEditorMode, addLocale, breakpointsRegistry, buildCfStyles, buildStyleTag, buildTemplate, builtInStyles, calculateNodeDefaultHeight, checkIsAssembly, checkIsAssemblyDefinition, checkIsAssemblyEntry, checkIsAssemblyNode, columnsBuiltInStyles, containerBuiltInStyles, createExperience, defineBreakpoints, defineDesignTokens, designTokensRegistry, detachExperienceStyles, dividerBuiltInStyles, doesMismatchMessageSchema, fetchAllAssets, fetchAllEntries, fetchById, fetchBySlug, findOutermostCoordinates, flattenDesignTokenRegistry, gatherDeepReferencesFromExperienceEntry, gatherDeepReferencesFromTree, generateRandomId, getActiveBreakpointIndex, getBreakpointRegistration, getDataFromTree, getDesignTokenRegistration, getElementCoordinates, getFallbackBreakpointIndex, getInsertionData, getTargetValueInPixels, getTemplateValue, getValueForBreakpoint, indexByBreakpoint, isCfStyleAttribute, isComponentAllowedOnRoot, isContentfulComponent, isContentfulStructureComponent, isDeepPath, isExperienceEntry, isLink, isLinkToAsset, isPatternComponent, isStructureWithRelativeHeight, isValidBreakpointValue, lastPathNamedSegmentEq, maybePopulateDesignTokenValue, mediaQueryMatcher, optionalBuiltInStyles, parseCSSValue, parseDataSourcePathIntoFieldset, parseDataSourcePathWithL1DeepBindings, resetBreakpointsRegistry, resetDesignTokenRegistry, resolveBackgroundImageBinding, resolveHyperlinkPattern, runBreakpointsValidation, sanitizeNodeProps, sectionBuiltInStyles, sendMessage, singleColumnBuiltInStyles,
|
|
3908
|
+
export { DeepReference, EditorModeEntityStore, EntityStore, EntityStoreBase, MEDIA_QUERY_REGEXP, VisualEditorMode, addLocale, addMinHeightForEmptyStructures, breakpointsRegistry, buildCfStyles, buildStyleTag, buildTemplate, builtInStyles, calculateNodeDefaultHeight, checkIsAssembly, checkIsAssemblyDefinition, checkIsAssemblyEntry, checkIsAssemblyNode, columnsBuiltInStyles, containerBuiltInStyles, createExperience, defineBreakpoints, defineDesignTokens, designTokensRegistry, detachExperienceStyles, dividerBuiltInStyles, doesMismatchMessageSchema, fetchAllAssets, fetchAllEntries, fetchById, fetchBySlug, findOutermostCoordinates, flattenDesignTokenRegistry, gatherDeepReferencesFromExperienceEntry, gatherDeepReferencesFromTree, generateRandomId, getActiveBreakpointIndex, getBreakpointRegistration, getDataFromTree, getDesignTokenRegistration, getElementCoordinates, getFallbackBreakpointIndex, getInsertionData, getTargetValueInPixels, getTemplateValue, getValueForBreakpoint, indexByBreakpoint, isCfStyleAttribute, isComponentAllowedOnRoot, isContentfulComponent, isContentfulStructureComponent, isDeepPath, isExperienceEntry, isLink, isLinkToAsset, isPatternComponent, isStructureWithRelativeHeight, isValidBreakpointValue, lastPathNamedSegmentEq, maybePopulateDesignTokenValue, mediaQueryMatcher, optionalBuiltInStyles, parseCSSValue, parseDataSourcePathIntoFieldset, parseDataSourcePathWithL1DeepBindings, resetBreakpointsRegistry, resetDesignTokenRegistry, resolveBackgroundImageBinding, resolveHyperlinkPattern, runBreakpointsValidation, sanitizeNodeProps, sectionBuiltInStyles, sendMessage, singleColumnBuiltInStyles, stringifyCssProperties, toCSSAttribute, toMediaQuery, transformBoundContentValue, tryParseMessage, validateExperienceBuilderConfig };
|
|
3921
3909
|
//# sourceMappingURL=index.js.map
|