@contentful/experiences-core 1.34.0 → 1.34.1-beta.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 +196 -206
- 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:
|
|
@@ -1176,11 +1233,13 @@ const VariableMappingsSchema = z.record(propertyKeySchema, VariableMappingSchema
|
|
|
1176
1233
|
// https://contentful.atlassian.net/browse/LUMOS-523
|
|
1177
1234
|
const PatternPropertyDefinitionSchema = z.object({
|
|
1178
1235
|
defaultValue: z
|
|
1179
|
-
.object({
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1236
|
+
.record(z.string(), z.object({
|
|
1237
|
+
sys: z.object({
|
|
1238
|
+
type: z.literal('Link'),
|
|
1239
|
+
id: z.string(),
|
|
1240
|
+
linkType: z.enum(['Entry']),
|
|
1241
|
+
}),
|
|
1242
|
+
}))
|
|
1184
1243
|
.optional(),
|
|
1185
1244
|
contentTypes: z.record(z.string(), z.any()),
|
|
1186
1245
|
});
|
|
@@ -1594,41 +1653,17 @@ const detachExperienceStyles = (experience) => {
|
|
|
1594
1653
|
}
|
|
1595
1654
|
const mapOfDesignVariableKeys = flattenDesignTokenRegistry(designTokensRegistry);
|
|
1596
1655
|
// 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
1656
|
const { breakpoints } = experienceTreeRoot;
|
|
1620
1657
|
// creating the structure which I thought would work best for aggregation
|
|
1621
|
-
const
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
};
|
|
1629
|
-
}, {});
|
|
1658
|
+
const mediaQueryDataByBreakpoint = breakpoints.reduce((mediaQueryTemplate, breakpoint) => ({
|
|
1659
|
+
...mediaQueryTemplate,
|
|
1660
|
+
[breakpoint.id]: {
|
|
1661
|
+
condition: breakpoint.query,
|
|
1662
|
+
cssByClassName: {},
|
|
1663
|
+
},
|
|
1664
|
+
}), {});
|
|
1630
1665
|
// getting the breakpoint ids
|
|
1631
|
-
const breakpointIds = Object.keys(
|
|
1666
|
+
const breakpointIds = Object.keys(mediaQueryDataByBreakpoint);
|
|
1632
1667
|
const iterateOverTreeAndExtractStyles = ({ componentTree, dataSource, unboundValues, componentSettings, componentVariablesOverwrites, patternWrapper, wrappingPatternIds, patternNodeIdsChain = '', }) => {
|
|
1633
1668
|
// traversing the tree
|
|
1634
1669
|
const queue = [];
|
|
@@ -1654,29 +1689,6 @@ const detachExperienceStyles = (experience) => {
|
|
|
1654
1689
|
if (!patternEntry || !('fields' in patternEntry)) {
|
|
1655
1690
|
continue;
|
|
1656
1691
|
}
|
|
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
1692
|
const nextComponentVariablesOverwrites = resolveComponentVariablesOverwrites({
|
|
1681
1693
|
patternNode: currentNode,
|
|
1682
1694
|
wrapperComponentVariablesOverwrites: componentVariablesOverwrites,
|
|
@@ -1704,36 +1716,15 @@ const detachExperienceStyles = (experience) => {
|
|
|
1704
1716
|
});
|
|
1705
1717
|
continue;
|
|
1706
1718
|
}
|
|
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
|
-
*/
|
|
1719
|
+
/* [Data format] `currentNode.variables` uses the following serialized shape:
|
|
1720
|
+
* {
|
|
1721
|
+
* cfMargin: { type: 'DesignValue', valuesByBreakpoint: { desktop: '1px', tablet: '2px' } },
|
|
1722
|
+
* cfPadding: { type: 'DesignValue', valuesByBreakpoint: { desktop: '3px' } }
|
|
1723
|
+
* cfBackgroundImageUrl: { type: 'BoundValue', path: '/lUERH7tX7nJTaPX6f0udB/fields/assetReference/~locale/fields/file/~locale' }
|
|
1724
|
+
* asdf1234: { type: 'ComponentValue', key: 'qwer567' }
|
|
1725
|
+
* // ...
|
|
1726
|
+
* }
|
|
1727
|
+
*/
|
|
1737
1728
|
// so first, I convert it into a map to help me make it easier to access the values
|
|
1738
1729
|
const propsByBreakpoint = indexByBreakpoint({
|
|
1739
1730
|
variables: currentNode.variables,
|
|
@@ -1746,30 +1737,18 @@ const detachExperienceStyles = (experience) => {
|
|
|
1746
1737
|
return experience.entityStore?.entities.find((entity) => entity.sys.id === id);
|
|
1747
1738
|
},
|
|
1748
1739
|
});
|
|
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
|
-
*/
|
|
1740
|
+
/* [Data format] `propsByBreakpoint` is a map of "breakpointId > propertyName > plainValue":
|
|
1741
|
+
* {
|
|
1742
|
+
* desktop: {
|
|
1743
|
+
* cfMargin: '1px',
|
|
1744
|
+
* cfWidth: 'fill',
|
|
1745
|
+
* cfBackgroundImageUrl: 'https://example.com/image.jpg'
|
|
1746
|
+
* //...
|
|
1747
|
+
* }
|
|
1748
|
+
* }
|
|
1749
|
+
*/
|
|
1771
1750
|
const currentNodeClassNames = [];
|
|
1772
|
-
//
|
|
1751
|
+
// For each breakpoint, resolve design tokens, create the CSS and generate a unique className.
|
|
1773
1752
|
for (const breakpointId of breakpointIds) {
|
|
1774
1753
|
const propsByBreakpointWithResolvedDesignTokens = Object.entries(propsByBreakpoint[breakpointId]).reduce((acc, [variableName, variableValue]) => {
|
|
1775
1754
|
return {
|
|
@@ -1777,36 +1756,24 @@ const detachExperienceStyles = (experience) => {
|
|
|
1777
1756
|
[variableName]: maybePopulateDesignTokenValue(variableName, variableValue, mapOfDesignVariableKeys),
|
|
1778
1757
|
};
|
|
1779
1758
|
}, {});
|
|
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
|
-
*/
|
|
1759
|
+
// Convert CF-specific property names to CSS variables, e.g. `cfMargin` -> `margin`
|
|
1760
|
+
const cfStyles = buildCfStyles(propsByBreakpointWithResolvedDesignTokens);
|
|
1761
|
+
/* [Data format] `cfStyles` is a list of CSSProperties (React format):
|
|
1762
|
+
* {
|
|
1763
|
+
* margin: '1px',
|
|
1764
|
+
* width: '100%',
|
|
1765
|
+
* backgroundImage: 'url(https://example.com/image.jpg)'
|
|
1766
|
+
* //...
|
|
1767
|
+
* }
|
|
1768
|
+
*/
|
|
1769
|
+
const generatedCss = stringifyCssProperties(cfStyles);
|
|
1770
|
+
/* [Data format] `generatedCss` is the minimized CSS string that will be added to the DOM:
|
|
1771
|
+
* generatedCss = "margin: 1px;width: 100%;..."
|
|
1772
|
+
*/
|
|
1806
1773
|
// I create a hash of the object above because that would ensure hash stability
|
|
1807
1774
|
// Adding breakpointId to ensure not using the same IDs between breakpoints as this leads to
|
|
1808
1775
|
// conflicts between different breakpoint values from multiple nodes where the hash would be equal
|
|
1809
|
-
const styleHash = md5(breakpointId +
|
|
1776
|
+
const styleHash = md5(breakpointId + generatedCss);
|
|
1810
1777
|
// and prefix the className to make sure the value can be processed
|
|
1811
1778
|
const className = `cf-${styleHash}`;
|
|
1812
1779
|
// I save the generated hashes into an array to later save it in the tree node
|
|
@@ -1816,11 +1783,11 @@ const detachExperienceStyles = (experience) => {
|
|
|
1816
1783
|
currentNodeClassNames.push(className);
|
|
1817
1784
|
}
|
|
1818
1785
|
// if there is already the similar hash - no need to over-write it
|
|
1819
|
-
if (
|
|
1786
|
+
if (mediaQueryDataByBreakpoint[breakpointId].cssByClassName[className]) {
|
|
1820
1787
|
continue;
|
|
1821
1788
|
}
|
|
1822
1789
|
// otherwise, save it to the stylesheet
|
|
1823
|
-
|
|
1790
|
+
mediaQueryDataByBreakpoint[breakpointId].cssByClassName[className] = generatedCss;
|
|
1824
1791
|
}
|
|
1825
1792
|
// all generated classNames are saved in the tree node
|
|
1826
1793
|
// to be handled by the sdk later
|
|
@@ -1864,10 +1831,8 @@ const detachExperienceStyles = (experience) => {
|
|
|
1864
1831
|
});
|
|
1865
1832
|
// once the whole tree was traversed, for each breakpoint, I aggregate the styles
|
|
1866
1833
|
// for each generated className into one css string
|
|
1867
|
-
const
|
|
1868
|
-
|
|
1869
|
-
}, '');
|
|
1870
|
-
return styleSheet;
|
|
1834
|
+
const stylesheet = Object.entries(mediaQueryDataByBreakpoint).reduce((acc, [, mediaQueryData]) => `${acc}${toMediaQuery(mediaQueryData)}`, '');
|
|
1835
|
+
return stylesheet;
|
|
1871
1836
|
};
|
|
1872
1837
|
/**
|
|
1873
1838
|
* Rendering pattern nodes inside pattern entry by injecting default values from the top:
|
|
@@ -2042,6 +2007,41 @@ const resolveBackgroundImageBinding = ({ variableData, getBoundEntityById, dataS
|
|
|
2042
2007
|
}
|
|
2043
2008
|
}
|
|
2044
2009
|
};
|
|
2010
|
+
/**
|
|
2011
|
+
* Takes the initial set of properties, filters only design properties that will be mapped to CSS and
|
|
2012
|
+
* re-organizes them to be indexed by breakpoint ID ("breakpoint > variable > value"). It will
|
|
2013
|
+
* also resolve the design/ component values to plain values.
|
|
2014
|
+
*
|
|
2015
|
+
* **Example Input**
|
|
2016
|
+
* ```
|
|
2017
|
+
* variables = {
|
|
2018
|
+
* cfMargin: { type: 'DesignValue', valuesByBreakpoint: { desktop: '1px', tablet: '2px' } },
|
|
2019
|
+
* cfPadding: { type: 'DesignValue', valuesByBreakpoint: { desktop: '3px', mobile: '4px' } }
|
|
2020
|
+
* }
|
|
2021
|
+
* ```
|
|
2022
|
+
*
|
|
2023
|
+
* **Example Output**
|
|
2024
|
+
* ```
|
|
2025
|
+
* variableValuesByBreakpoints = {
|
|
2026
|
+
* desktop: {
|
|
2027
|
+
* cfMargin: '1px',
|
|
2028
|
+
* cfPadding: '3px'
|
|
2029
|
+
* },
|
|
2030
|
+
* tablet: {
|
|
2031
|
+
* cfMargin: '2px'
|
|
2032
|
+
* },
|
|
2033
|
+
* mobile: {
|
|
2034
|
+
* cfPadding: '4px'
|
|
2035
|
+
* }
|
|
2036
|
+
* }
|
|
2037
|
+
* ```
|
|
2038
|
+
*
|
|
2039
|
+
* **Note**
|
|
2040
|
+
* - The property cfBackgroundImageUrl is the only content property that gets mapped to CSS as well.
|
|
2041
|
+
* It will be solely stored on the default breakpoint.
|
|
2042
|
+
* - For ComponentValues, it will either take the override from the pattern instance or fallback to
|
|
2043
|
+
* the defaultValue defined in variableDefinitions.
|
|
2044
|
+
*/
|
|
2045
2045
|
const indexByBreakpoint = ({ variables, breakpointIds, getBoundEntityById, unboundValues = {}, dataSource = {}, componentVariablesOverwrites, componentSettings = { variableDefinitions: {} }, }) => {
|
|
2046
2046
|
const variableValuesByBreakpoints = breakpointIds.reduce((acc, breakpointId) => {
|
|
2047
2047
|
return {
|
|
@@ -2052,9 +2052,10 @@ const indexByBreakpoint = ({ variables, breakpointIds, getBoundEntityById, unbou
|
|
|
2052
2052
|
const defaultBreakpoint = breakpointIds[0];
|
|
2053
2053
|
for (const [variableName, variableData] of Object.entries(variables)) {
|
|
2054
2054
|
// 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
|
|
2055
|
+
// so, we need to resolve it here and pass it down as a css property to be converted into the CSS
|
|
2056
2056
|
// I used .startsWith() cause it can be part of a pattern node
|
|
2057
2057
|
if (variableName === 'cfBackgroundImageUrl' ||
|
|
2058
|
+
// TODO: Test this for nested patterns as the name might be just a random hash without the actual name (needs to be validated).
|
|
2058
2059
|
variableName.startsWith('cfBackgroundImageUrl_')) {
|
|
2059
2060
|
const imageUrl = resolveBackgroundImageBinding({
|
|
2060
2061
|
variableData,
|
|
@@ -2095,17 +2096,9 @@ const indexByBreakpoint = ({ variables, breakpointIds, getBoundEntityById, unbou
|
|
|
2095
2096
|
};
|
|
2096
2097
|
/**
|
|
2097
2098
|
* Flattens the object from
|
|
2098
|
-
* {
|
|
2099
|
-
* color: {
|
|
2100
|
-
* [key]: [value]
|
|
2101
|
-
* }
|
|
2102
|
-
* }
|
|
2103
|
-
*
|
|
2099
|
+
* `{ color: { [key]: [value] } }`
|
|
2104
2100
|
* to
|
|
2105
|
-
*
|
|
2106
|
-
* {
|
|
2107
|
-
* 'color.key': [value]
|
|
2108
|
-
* }
|
|
2101
|
+
* `{ 'color.key': [value] }`
|
|
2109
2102
|
*/
|
|
2110
2103
|
const flattenDesignTokenRegistry = (designTokenRegistry) => {
|
|
2111
2104
|
return Object.entries(designTokenRegistry).reduce((acc, [categoryName, tokenCategory]) => {
|
|
@@ -2121,24 +2114,21 @@ const flattenDesignTokenRegistry = (designTokenRegistry) => {
|
|
|
2121
2114
|
};
|
|
2122
2115
|
}, {});
|
|
2123
2116
|
};
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
const toMediaQuery = (
|
|
2132
|
-
const mediaQueryStyles = Object.entries(
|
|
2117
|
+
/**
|
|
2118
|
+
* Create a single CSS string containing all class definitions for a given media query.
|
|
2119
|
+
*
|
|
2120
|
+
* @param condition e.g. "*", "<520px", ">520px"
|
|
2121
|
+
* @param cssByClassName map of class names to CSS strings containing all rules for each class
|
|
2122
|
+
* @returns joined string of all CSS class definitions wrapped into media queries
|
|
2123
|
+
*/
|
|
2124
|
+
const toMediaQuery = ({ condition, cssByClassName }) => {
|
|
2125
|
+
const mediaQueryStyles = Object.entries(cssByClassName).reduce((acc, [className, css]) => {
|
|
2133
2126
|
return `${acc}.${className}{${css}}`;
|
|
2134
2127
|
}, ``);
|
|
2135
|
-
if (
|
|
2128
|
+
if (condition === '*') {
|
|
2136
2129
|
return mediaQueryStyles;
|
|
2137
2130
|
}
|
|
2138
|
-
const [evaluation, pixelValue] = [
|
|
2139
|
-
breakpointPayload.condition[0],
|
|
2140
|
-
breakpointPayload.condition.substring(1),
|
|
2141
|
-
];
|
|
2131
|
+
const [evaluation, pixelValue] = [condition[0], condition.substring(1)];
|
|
2142
2132
|
const mediaQueryRule = evaluation === '<' ? 'max-width' : 'min-width';
|
|
2143
2133
|
return `@media(${mediaQueryRule}:${pixelValue}){${mediaQueryStyles}}`;
|
|
2144
2134
|
};
|
|
@@ -3917,5 +3907,5 @@ async function fetchById({ client, experienceTypeId, id, localeCode, isEditorMod
|
|
|
3917
3907
|
}
|
|
3918
3908
|
}
|
|
3919
3909
|
|
|
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,
|
|
3910
|
+
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
3911
|
//# sourceMappingURL=index.js.map
|