@contentful/experiences-core 1.31.0-dev-20250211T1859-e07efed.0 → 1.31.0-dev-20250217T1404-270aced.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.js CHANGED
@@ -1601,7 +1601,7 @@ const detachExperienceStyles = (experience) => {
1601
1601
  }, {});
1602
1602
  // getting the breakpoint ids
1603
1603
  const breakpointIds = Object.keys(mediaQueriesTemplate);
1604
- const iterateOverTreeAndExtractStyles = ({ componentTree, dataSource, unboundValues, componentSettings, componentVariablesOverwrites, patternWrapper, wrappingPatternIds, }) => {
1604
+ const iterateOverTreeAndExtractStyles = ({ componentTree, dataSource, unboundValues, componentSettings, componentVariablesOverwrites, patternWrapper, wrappingPatternIds, patternNodeIdsChain = '', }) => {
1605
1605
  // traversing the tree
1606
1606
  const queue = [];
1607
1607
  queue.push(...componentTree.children);
@@ -1639,12 +1639,21 @@ const detachExperienceStyles = (experience) => {
1639
1639
  toCSSString(defaultPatternDivStyles);
1640
1640
  }
1641
1641
  }
1642
- currentNode.variables.cfSsrClassName = {
1643
- type: 'DesignValue',
1644
- valuesByBreakpoint: {
1645
- [breakpointIds[0]]: className,
1646
- },
1647
- };
1642
+ // When iterating over instances of the same pattern, we will iterate over the identical
1643
+ // pattern nodes again for every instance. Make sure to not overwrite the values from previous instances.
1644
+ if (!currentNode.variables.cfSsrClassName) {
1645
+ currentNode.variables.cfSsrClassName = {
1646
+ type: 'DesignValue',
1647
+ valuesByBreakpoint: {
1648
+ [breakpointIds[0]]: className,
1649
+ },
1650
+ };
1651
+ }
1652
+ const nextComponentVariablesOverwrites = resolveComponentVariablesOverwrites({
1653
+ patternNode: currentNode,
1654
+ wrapperComponentVariablesOverwrites: componentVariablesOverwrites,
1655
+ wrapperComponentSettings: componentSettings,
1656
+ });
1648
1657
  // the node of a used pattern contains only the definitionId (id of the patter entry)
1649
1658
  // as well as the variables overwrites
1650
1659
  // the layout of a pattern is stored in it's entry
@@ -1659,10 +1668,11 @@ const detachExperienceStyles = (experience) => {
1659
1668
  componentSettings: patternEntry.fields.componentSettings,
1660
1669
  // and this is where the over-writes for the default values are stored
1661
1670
  // yes, I know, it's a bit confusing
1662
- componentVariablesOverwrites: currentNode.variables,
1671
+ componentVariablesOverwrites: nextComponentVariablesOverwrites,
1663
1672
  // pass top-level pattern node to store instance-specific child styles for rendering
1664
1673
  patternWrapper: currentNode,
1665
1674
  wrappingPatternIds: new Set([...wrappingPatternIds, currentNode.definitionId]),
1675
+ patternNodeIdsChain: `${patternNodeIdsChain}${currentNode.id}`,
1666
1676
  });
1667
1677
  continue;
1668
1678
  }
@@ -1766,7 +1776,9 @@ const detachExperienceStyles = (experience) => {
1766
1776
  }
1767
1777
  */
1768
1778
  // I create a hash of the object above because that would ensure hash stability
1769
- const styleHash = md5(JSON.stringify(stylesForBreakpointWithoutUndefined));
1779
+ // Adding breakpointId to ensure not using the same IDs between breakpoints as this leads to
1780
+ // conflicts between different breakpoint values from multiple nodes where the hash would be equal
1781
+ const styleHash = md5(breakpointId + JSON.stringify(stylesForBreakpointWithoutUndefined));
1770
1782
  // and prefix the className to make sure the value can be processed
1771
1783
  const className = `cf-${styleHash}`;
1772
1784
  // I save the generated hashes into an array to later save it in the tree node
@@ -1791,12 +1803,13 @@ const detachExperienceStyles = (experience) => {
1791
1803
  // making sure that we respect the order of breakpoints from
1792
1804
  // we can achieve "desktop first" or "mobile first" approach to style over-writes
1793
1805
  if (patternWrapper) {
1794
- currentNode.id = currentNode.id ?? generateRandomId(15);
1806
+ currentNode.id = currentNode.id || generateRandomId(5);
1795
1807
  // @ts-expect-error -- valueByBreakpoint is not explicitly defined, but it's already defined in the patternWrapper styles
1796
1808
  patternWrapper.variables.cfSsrClassName = {
1797
1809
  ...(patternWrapper.variables.cfSsrClassName ?? {}),
1798
1810
  type: 'DesignValue',
1799
- [currentNode.id]: {
1811
+ // Chain IDs to avoid overwriting styles across multiple instances of the same pattern
1812
+ [`${patternNodeIdsChain}${currentNode.id}`]: {
1800
1813
  valuesByBreakpoint: {
1801
1814
  [breakpointIds[0]]: currentNodeClassNames.join(' '),
1802
1815
  },
@@ -1828,6 +1841,70 @@ const detachExperienceStyles = (experience) => {
1828
1841
  }, '');
1829
1842
  return styleSheet;
1830
1843
  };
1844
+ /**
1845
+ * Rendering pattern nodes inside pattern entry by injecting default values from the top:
1846
+ * When there is a ComponentValue but the recursive logic is not wrapped by a pattern node (no `componentVariablesOverwrites`),
1847
+ * a pattern entry is rendered directly. In this case, we replace each ComponentValue with the default value from componentSettings.
1848
+ */
1849
+ const injectDefaultValuesForComponentValues = ({ patternNode, wrapperComponentSettings, }) => {
1850
+ const propertyDefinitions = wrapperComponentSettings?.variableDefinitions;
1851
+ const resolvedProperties = Object.entries(patternNode.variables).reduce((resolvedProperties, [propertyName, propertyValue]) => {
1852
+ if (propertyValue.type === 'ComponentValue') {
1853
+ const componentValueKey = propertyValue.key;
1854
+ const componentDefaultValue = propertyDefinitions?.[componentValueKey].defaultValue;
1855
+ // We're only considering design properties for styles generation
1856
+ if (componentDefaultValue?.type === 'DesignValue') {
1857
+ resolvedProperties[propertyName] = componentDefaultValue;
1858
+ }
1859
+ }
1860
+ else {
1861
+ // Do nothing when it's not a ComponentValue & just keep the defined value
1862
+ resolvedProperties[propertyName] = propertyValue;
1863
+ }
1864
+ return resolvedProperties;
1865
+ }, {});
1866
+ return resolvedProperties;
1867
+ };
1868
+ /**
1869
+ * In case of nested patterns, we need to resolve the ComponentValue properties and overwrite them with the value
1870
+ * stored in the parent component.
1871
+ *
1872
+ *
1873
+ * @param patternNode - pattern node which contains the variables
1874
+ * @param componentVariablesOverwrites - object which contains the variables of the parent component
1875
+ */
1876
+ const resolveComponentVariablesOverwrites = ({ patternNode, wrapperComponentVariablesOverwrites, wrapperComponentSettings, }) => {
1877
+ // In case of rendering a pattern entry, there are no custom ComponentValues.
1878
+ // So we pass down the default values from this pattern node down to each deeper pattern level.
1879
+ if (!wrapperComponentVariablesOverwrites) {
1880
+ const nextComponentVariablesOverwrites = injectDefaultValuesForComponentValues({
1881
+ patternNode,
1882
+ wrapperComponentSettings,
1883
+ });
1884
+ return nextComponentVariablesOverwrites;
1885
+ }
1886
+ // Rendering (nested) pattern node inside another pattern node (for both experience & pattern entry):
1887
+ // The `wrapperComponentVariablesOverwrites` from the top-most pattern node is passed through to each child
1888
+ // node (and nested pattern nodes). It replaces each ComponentValue in the subtree with either the overwrite
1889
+ // or the default value.
1890
+ const nextComponentVariablesOverwrites = Object.entries(patternNode?.variables).reduce((resolvedValues, [propertyName, propertyValue]) => {
1891
+ if (propertyValue.type === 'ComponentValue') {
1892
+ // Copying the values from the parent node
1893
+ const overwritingValue = wrapperComponentVariablesOverwrites?.[propertyValue.key];
1894
+ // Property definition from the parent pattern
1895
+ const propertyDefinition = wrapperComponentSettings?.variableDefinitions?.[propertyValue.key];
1896
+ // The overwriting value is either a custom value from the experience or default value from a
1897
+ // wrapping pattern node that got trickled down to this nesting level.
1898
+ resolvedValues[propertyName] = overwritingValue ?? propertyDefinition?.defaultValue;
1899
+ }
1900
+ else {
1901
+ // Keep raw values
1902
+ resolvedValues[propertyName] = propertyValue;
1903
+ }
1904
+ return resolvedValues;
1905
+ }, {});
1906
+ return nextComponentVariablesOverwrites;
1907
+ };
1831
1908
  const isCfStyleAttribute = (variableName) => {
1832
1909
  return CF_STYLE_ATTRIBUTES.includes(variableName);
1833
1910
  };