@contentful/experiences-sdk-react 1.1.0 → 1.2.0-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 CHANGED
@@ -64,4 +64,6 @@ declare const defineComponents: (componentRegistrations: ComponentRegistration[]
64
64
  */
65
65
  declare const maintainBasicComponentIdsWithoutPrefix: () => void;
66
66
 
67
- export { ExperienceRoot, defineComponents, maintainBasicComponentIdsWithoutPrefix, useFetchById, useFetchBySlug };
67
+ declare const detachExperienceStyles: (experience: Experience) => string | undefined;
68
+
69
+ export { ExperienceRoot, defineComponents, detachExperienceStyles, maintainBasicComponentIdsWithoutPrefix, useFetchById, useFetchBySlug };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
- import { containerDefinition, sectionDefinition, columnsDefinition, singleColumnDefinition, dividerDefinition, builtInStyles, optionalBuiltInStyles, sendMessage, designTokensRegistry, buildStyleTag, checkIsAssemblyNode, resolveHyperlinkPattern, transformBoundContentValue, buildCfStyles, isEmptyStructureWithRelativeHeight, mediaQueryMatcher, getFallbackBreakpointIndex, getActiveBreakpointIndex, getValueForBreakpoint, doesMismatchMessageSchema, tryParseMessage, fetchById, fetchBySlug, validateExperienceBuilderConfig, VisualEditorMode } from '@contentful/experiences-core';
2
+ import { containerDefinition, sectionDefinition, columnsDefinition, singleColumnDefinition, dividerDefinition, builtInStyles, optionalBuiltInStyles, sendMessage, designTokensRegistry, buildStyleTag, checkIsAssemblyNode, resolveHyperlinkPattern, transformBoundContentValue, buildCfStyles, isEmptyStructureWithRelativeHeight, mediaQueryMatcher, getFallbackBreakpointIndex, getActiveBreakpointIndex, getValueForBreakpoint, doesMismatchMessageSchema, tryParseMessage, fetchById, fetchBySlug, validateExperienceBuilderConfig, VisualEditorMode, toCSSAttribute } from '@contentful/experiences-core';
3
3
  export { VisualEditorMode, createExperience, defineDesignTokens, fetchById, fetchBySlug } from '@contentful/experiences-core';
4
4
  import React, { useMemo, useLayoutEffect, useState, useEffect, useCallback, useRef, Suspense } from 'react';
5
5
  import { omit } from 'lodash-es';
@@ -8,8 +8,9 @@ export { CF_STYLE_ATTRIBUTES, CONTENTFUL_COMPONENTS, LATEST_SCHEMA_VERSION } fro
8
8
  import * as Components from '@contentful/experiences-components-react';
9
9
  import { ContentfulContainer, Columns, SingleColumn } from '@contentful/experiences-components-react';
10
10
  import styleInject from 'style-inject';
11
+ import md5 from 'md5';
11
12
 
12
- const SDK_VERSION = '1.1.0-beta.0';
13
+ const SDK_VERSION = '1.1.0';
13
14
 
14
15
  var util;
15
16
  (function (util) {
@@ -4787,7 +4788,10 @@ const CompositionBlock = ({ node: rawNode, locale, entityStore, hyperlinkPattern
4787
4788
  if (isEmptyStructureWithRelativeHeight(node.children.length, node.definitionId, cfStyles.height)) {
4788
4789
  cfStyles.minHeight = EMPTY_CONTAINER_HEIGHT;
4789
4790
  }
4790
- const { className } = useStyleTag({ styles: cfStyles });
4791
+ const { className: runtimeClassname } = useStyleTag({ styles: cfStyles });
4792
+ const className = node.variables.cfSsrClassName
4793
+ ? resolveDesignValue(node.variables.cfSsrClassName.valuesByBreakpoint, 'cfSsrClassName')
4794
+ : runtimeClassname;
4791
4795
  if (!componentRegistration) {
4792
4796
  return null;
4793
4797
  }
@@ -5068,6 +5072,429 @@ const ExperienceRoot = ({ locale, experience, visualEditorMode = VisualEditorMod
5068
5072
  return jsx(PreviewDeliveryRoot, { locale: locale, experience: experience });
5069
5073
  };
5070
5074
 
5075
+ const detachExperienceStyles = (experience) => {
5076
+ const experienceTreeRoot = experience.entityStore?.experienceEntryFields
5077
+ ?.componentTree;
5078
+ if (!experienceTreeRoot) {
5079
+ return;
5080
+ }
5081
+ const mapOfDesignVariableKeys = flattenDesignTokenRegistry(designTokensRegistry);
5082
+ // getting breakpoints from the entry componentTree field
5083
+ /**
5084
+ * breakpoints [
5085
+ {
5086
+ id: 'desktop',
5087
+ query: '*',
5088
+ displayName: 'All Sizes',
5089
+ previewSize: '100%'
5090
+ },
5091
+ {
5092
+ id: 'tablet',
5093
+ query: '<992px',
5094
+ displayName: 'Tablet',
5095
+ previewSize: '820px'
5096
+ },
5097
+ {
5098
+ id: 'mobile',
5099
+ query: '<576px',
5100
+ displayName: 'Mobile',
5101
+ previewSize: '390px'
5102
+ }
5103
+ ]
5104
+ */
5105
+ const { breakpoints } = experienceTreeRoot;
5106
+ // creating the structure which I thought would work best for aggregation
5107
+ const mediaQueriesTemplate = breakpoints.reduce((mediaQueryTemplate, breakpoint) => {
5108
+ return {
5109
+ ...mediaQueryTemplate,
5110
+ [breakpoint.id]: {
5111
+ condition: breakpoint.query,
5112
+ cssByClassName: {},
5113
+ },
5114
+ };
5115
+ }, {});
5116
+ // getting the breakpoint ids
5117
+ const breakpointIds = Object.keys(mediaQueriesTemplate);
5118
+ const iterateOverTreeAndExtractStyles = ({ componentTree, dataSource, unboundValues, componentSettings, componentVariablesOverwrites, }) => {
5119
+ // traversing the tree
5120
+ const queue = [];
5121
+ queue.push(...componentTree.children);
5122
+ let currentNode = undefined;
5123
+ const registeredComponenIds = Array.from(componentRegistry.values()).map(({ definition }) => definition.id);
5124
+ // for each tree node
5125
+ while (queue.length) {
5126
+ currentNode = queue.shift();
5127
+ if (!currentNode) {
5128
+ break;
5129
+ }
5130
+ const isPatternNode = !registeredComponenIds.includes(currentNode.definitionId);
5131
+ if (isPatternNode) {
5132
+ const patternEntry = experience.entityStore?.entities.find((entry) => entry.sys.id === currentNode.definitionId);
5133
+ if (!patternEntry) {
5134
+ continue;
5135
+ }
5136
+ // the node of a used pattern contains only the definitionId (id of the patter entry)
5137
+ // as well as the variables overwrites
5138
+ // the layout of a pattern is stored in it's entry
5139
+ iterateOverTreeAndExtractStyles({
5140
+ // that is why we pass it here to iterate of the pattern tree
5141
+ componentTree: patternEntry.fields.componentTree,
5142
+ // but we pass the data source of the experience entry cause that's where the binding is stored
5143
+ dataSource,
5144
+ // unbound values of a pattern store the default values of pattern variables
5145
+ unboundValues: patternEntry.fields.unboundValues,
5146
+ // this is where we can map the pattern variable to it's default value
5147
+ componentSettings: patternEntry.fields.componentSettings,
5148
+ // and this is where the over-writes for the default values are stored
5149
+ // yes, I know, it's a bit confusing
5150
+ componentVariablesOverwrites: currentNode.variables,
5151
+ });
5152
+ continue;
5153
+ }
5154
+ /** Variables value is stored in `valuesByBreakpoint` object
5155
+ * {
5156
+ cfVerticalAlignment: { type: 'DesignValue', valuesByBreakpoint: { desktop: 'center' } },
5157
+ cfHorizontalAlignment: { type: 'DesignValue', valuesByBreakpoint: { desktop: 'center' } },
5158
+ cfMargin: { type: 'DesignValue', valuesByBreakpoint: { desktop: '0 0 0 0' } },
5159
+ cfPadding: { type: 'DesignValue', valuesByBreakpoint: { desktop: '0 0 0 0' } },
5160
+ cfBackgroundColor: {
5161
+ type: 'DesignValue',
5162
+ valuesByBreakpoint: { desktop: 'rgba(246, 246, 246, 1)' }
5163
+ },
5164
+ cfWidth: { type: 'DesignValue', valuesByBreakpoint: { desktop: 'fill' } },
5165
+ cfHeight: {
5166
+ type: 'DesignValue',
5167
+ valuesByBreakpoint: { desktop: 'fit-content' }
5168
+ },
5169
+ cfMaxWidth: { type: 'DesignValue', valuesByBreakpoint: { desktop: 'none' } },
5170
+ cfFlexDirection: { type: 'DesignValue', valuesByBreakpoint: { desktop: 'column' } },
5171
+ cfFlexWrap: { type: 'DesignValue', valuesByBreakpoint: { desktop: 'nowrap' } },
5172
+ cfBorder: {
5173
+ type: 'DesignValue',
5174
+ valuesByBreakpoint: { desktop: '0px solid rgba(0, 0, 0, 0)' }
5175
+ },
5176
+ cfBorderRadius: { type: 'DesignValue', valuesByBreakpoint: { desktop: '0px' } },
5177
+ cfGap: { type: 'DesignValue', valuesByBreakpoint: { desktop: '0px 0px' } },
5178
+ cfHyperlink: { type: 'UnboundValue', key: 'VNc49Qyepd6IzN7rmKUyS' },
5179
+ cfOpenInNewTab: { type: 'UnboundValue', key: 'ZA5YqB2fmREQ4pTKqY5hX' },
5180
+ cfBackgroundImageUrl: { type: 'UnboundValue', key: 'FeskH0WbYD5_RQVXX-1T8' },
5181
+ cfBackgroundImageOptions: { type: 'DesignValue', valuesByBreakpoint: { desktop: [Object] } }
5182
+ }
5183
+ */
5184
+ // so first, I convert it into a map to help me make it easier to access the values
5185
+ const propsByBreakpoint = indexByBreakpoint({
5186
+ variables: currentNode.variables,
5187
+ breakpointIds,
5188
+ unboundValues: unboundValues,
5189
+ dataSource: dataSource,
5190
+ componentSettings,
5191
+ componentVariablesOverwrites,
5192
+ getBoundEntityById: (id) => {
5193
+ return experience.entityStore?.entities.find((entity) => entity.sys.id === id);
5194
+ },
5195
+ });
5196
+ /**
5197
+ * propsByBreakpoint {
5198
+ desktop: {
5199
+ cfVerticalAlignment: 'center',
5200
+ cfHorizontalAlignment: 'center',
5201
+ cfMargin: '0 0 0 0',
5202
+ cfPadding: '0 0 0 0',
5203
+ cfBackgroundColor: 'rgba(246, 246, 246, 1)',
5204
+ cfWidth: 'fill',
5205
+ cfHeight: 'fit-content',
5206
+ cfMaxWidth: 'none',
5207
+ cfFlexDirection: 'column',
5208
+ cfFlexWrap: 'nowrap',
5209
+ cfBorder: '0px solid rgba(0, 0, 0, 0)',
5210
+ cfBorderRadius: '0px',
5211
+ cfGap: '0px 0px',
5212
+ cfBackgroundImageOptions: { scaling: 'fill', alignment: 'left top', targetSize: '2000px' }
5213
+ },
5214
+ tablet: {},
5215
+ mobile: {}
5216
+ }
5217
+ */
5218
+ const currentNodeClassNames = [];
5219
+ // then for each breakpoint
5220
+ for (const breakpointId of breakpointIds) {
5221
+ const propsByBreakpointWithResolvedDesignTokens = Object.entries(propsByBreakpoint[breakpointId]).reduce((acc, [variableName, variableValue]) => {
5222
+ return {
5223
+ ...acc,
5224
+ [variableName]: maybePopulateDesignTokenValue(variableName, variableValue, mapOfDesignVariableKeys),
5225
+ };
5226
+ }, {});
5227
+ // We convert cryptic prop keys to css variables
5228
+ // Eg: cfMargin to margin
5229
+ const stylesForBreakpoint = buildCfStyles(propsByBreakpointWithResolvedDesignTokens, currentNode.definitionId);
5230
+ const stylesForBreakpointWithoutUndefined = Object.fromEntries(Object.entries(stylesForBreakpoint)
5231
+ .filter(([, value]) => value !== undefined)
5232
+ .map(([key, value]) => [toCSSAttribute(key), value]));
5233
+ /**
5234
+ * stylesForBreakpoint {
5235
+ margin: '0 0 0 0',
5236
+ padding: '0 0 0 0',
5237
+ 'background-color': 'rgba(246, 246, 246, 1)',
5238
+ width: '100%',
5239
+ height: 'fit-content',
5240
+ 'max-width': 'none',
5241
+ border: '0px solid rgba(0, 0, 0, 0)',
5242
+ 'border-radius': '0px',
5243
+ gap: '0px 0px',
5244
+ 'align-items': 'center',
5245
+ 'justify-content': 'safe center',
5246
+ 'flex-direction': 'column',
5247
+ 'flex-wrap': 'nowrap',
5248
+ 'font-style': 'normal',
5249
+ 'text-decoration': 'none',
5250
+ 'box-sizing': 'border-box'
5251
+ }
5252
+ */
5253
+ // I create a hash of the object above because that would ensure hash stability
5254
+ const styleHash = md5(JSON.stringify(stylesForBreakpointWithoutUndefined));
5255
+ // and prefix the className to make sure the value can be processed
5256
+ const className = `cf-${styleHash}`;
5257
+ // I save the generated hashes into an array to later save it in the tree node
5258
+ // as cfSsrClassName prop
5259
+ // making sure to avoid the duplicates in case styles for > 1 breakpoints are the same
5260
+ if (!currentNodeClassNames.includes(className)) {
5261
+ currentNodeClassNames.push(className);
5262
+ }
5263
+ // if there is already the similar hash - no need to over-write it
5264
+ if (mediaQueriesTemplate[breakpointId].cssByClassName[className]) {
5265
+ continue;
5266
+ }
5267
+ // otherwise, save it to the stylesheet
5268
+ mediaQueriesTemplate[breakpointId].cssByClassName[className] = toCSSString(stylesForBreakpointWithoutUndefined);
5269
+ }
5270
+ // all generated classNames are saved in the tree node
5271
+ // to be handled by the sdk later
5272
+ // each node will get N classNames, where N is the number of breakpoints
5273
+ // browsers process classNames in the order they are defined
5274
+ // meaning that in case of className1 className2 className3
5275
+ // className3 will win over className2 and className1
5276
+ // making sure that we respect the order of breakpoints from
5277
+ // we can achieve "desktop first" or "mobile first" approach to style over-writes
5278
+ currentNode.variables.cfSsrClassName = {
5279
+ type: 'DesignValue',
5280
+ valuesByBreakpoint: {
5281
+ [breakpointIds[0]]: currentNodeClassNames.join(' '),
5282
+ },
5283
+ };
5284
+ queue.push(...currentNode.children);
5285
+ }
5286
+ };
5287
+ iterateOverTreeAndExtractStyles({
5288
+ componentTree: experienceTreeRoot,
5289
+ dataSource: experience.entityStore?.dataSource ?? {},
5290
+ unboundValues: experience.entityStore?.unboundValues ?? {},
5291
+ componentSettings: experience.entityStore?.experienceEntryFields?.componentSettings,
5292
+ });
5293
+ // once the whole tree was traversed, for each breakpoint, I aggregate the styles
5294
+ // for each generated className into one css string
5295
+ const styleSheet = Object.entries(mediaQueriesTemplate).reduce((acc, [, breakpointPayload]) => {
5296
+ return `${acc}${toMediaQuery(breakpointPayload)}`;
5297
+ }, '');
5298
+ return styleSheet;
5299
+ };
5300
+ const isCfStyleAttribute = (variableName) => {
5301
+ return CF_STYLE_ATTRIBUTES.includes(variableName);
5302
+ };
5303
+ const maybePopulateDesignTokenValue = (variableName, variableValue, mapOfDesignVariableKeys) => {
5304
+ // TODO: refactor to reuse fn from core package
5305
+ if (typeof variableValue !== 'string') {
5306
+ return variableValue;
5307
+ }
5308
+ if (!isCfStyleAttribute(variableName)) {
5309
+ return variableValue;
5310
+ }
5311
+ const resolveSimpleDesignToken = (variableName, variableValue) => {
5312
+ const nonTemplateDesignTokenValue = variableValue.replace(templateStringRegex, '$1');
5313
+ const tokenValue = mapOfDesignVariableKeys[nonTemplateDesignTokenValue];
5314
+ if (!tokenValue) {
5315
+ if (builtInStyles[variableName]) {
5316
+ return builtInStyles[variableName].defaultValue;
5317
+ }
5318
+ if (optionalBuiltInStyles[variableName]) {
5319
+ return optionalBuiltInStyles[variableName].defaultValue;
5320
+ }
5321
+ return '0px';
5322
+ }
5323
+ if (variableName === 'cfBorder' || variableName.startsWith('cfBorder_')) {
5324
+ const { width, style, color } = tokenValue;
5325
+ return `${width} ${style} ${color}`;
5326
+ }
5327
+ return tokenValue;
5328
+ };
5329
+ const templateStringRegex = /\${(.+?)}/g;
5330
+ const parts = variableValue.split(' ');
5331
+ let resolvedValue = '';
5332
+ for (const part of parts) {
5333
+ const tokenValue = templateStringRegex.test(part)
5334
+ ? resolveSimpleDesignToken(variableName, part)
5335
+ : part;
5336
+ resolvedValue += `${tokenValue} `;
5337
+ }
5338
+ // Not trimming would end up with a trailing space that breaks the check in `calculateNodeDefaultHeight`
5339
+ return resolvedValue.trim();
5340
+ };
5341
+ const resolveBackgroundImageBinding = ({ variableData, getBoundEntityById, dataSource = {}, unboundValues = {}, componentVariablesOverwrites, componentSettings = { variableDefinitions: {} }, }) => {
5342
+ if (variableData.type === 'UnboundValue') {
5343
+ const uuid = variableData.key;
5344
+ return unboundValues[uuid]?.value;
5345
+ }
5346
+ if (variableData.type === 'ComponentValue') {
5347
+ const variableDefinitionKey = variableData.key;
5348
+ const variableDefinition = componentSettings.variableDefinitions[variableDefinitionKey];
5349
+ // @ts-expect-error TODO: fix the types as it thinks taht `defaultValue` is of type string
5350
+ const defaultValueKey = variableDefinition.defaultValue?.key;
5351
+ const defaultValue = unboundValues[defaultValueKey].value;
5352
+ const userSetValue = componentVariablesOverwrites?.[variableDefinitionKey];
5353
+ if (!userSetValue) {
5354
+ return defaultValue;
5355
+ }
5356
+ // at this point userSetValue will either be type of 'DesignValue' or 'BoundValue'
5357
+ // so we recursively run resolution again to resolve it
5358
+ const resolvedValue = resolveBackgroundImageBinding({
5359
+ variableData: userSetValue,
5360
+ getBoundEntityById,
5361
+ dataSource,
5362
+ unboundValues,
5363
+ componentVariablesOverwrites,
5364
+ componentSettings,
5365
+ });
5366
+ return resolvedValue || defaultValue;
5367
+ }
5368
+ if (variableData.type === 'BoundValue') {
5369
+ // '/lUERH7tX7nJTaPX6f0udB/fields/assetReference/~locale/fields/file/~locale'
5370
+ const [, uuid] = variableData.path.split('/');
5371
+ const binding = dataSource[uuid];
5372
+ const boundEntity = getBoundEntityById(binding.sys.id);
5373
+ if (!boundEntity) {
5374
+ return;
5375
+ }
5376
+ if (boundEntity.sys.type === 'Asset') {
5377
+ return boundEntity.fields.file?.url;
5378
+ }
5379
+ else {
5380
+ // '/lUERH7tX7nJTaPX6f0udB/fields/assetReference/~locale/fields/file/~locale'
5381
+ // becomes
5382
+ // '/fields/assetReference/~locale/fields/file/~locale'
5383
+ const pathWithoutUUID = variableData.path.split(uuid)[1];
5384
+ // '/fields/assetReference/~locale/fields/file/~locale'
5385
+ // becomes
5386
+ // '/fields/assetReference/'
5387
+ const pathToReferencedAsset = pathWithoutUUID.split('~locale')[0];
5388
+ // '/fields/assetReference/'
5389
+ // becomes
5390
+ // '[fields, assetReference]'
5391
+ const [, fieldName] = pathToReferencedAsset.substring(1).split('/') ?? undefined;
5392
+ const referenceToAsset = boundEntity.fields[fieldName];
5393
+ if (!referenceToAsset) {
5394
+ return;
5395
+ }
5396
+ if (referenceToAsset.sys?.linkType === 'Asset') {
5397
+ const referencedAsset = getBoundEntityById(referenceToAsset.sys.id);
5398
+ if (!referencedAsset) {
5399
+ return;
5400
+ }
5401
+ return referencedAsset.fields.file?.url;
5402
+ }
5403
+ }
5404
+ }
5405
+ };
5406
+ const indexByBreakpoint = ({ variables, breakpointIds, getBoundEntityById, unboundValues = {}, dataSource = {}, componentVariablesOverwrites, componentSettings = { variableDefinitions: {} }, }) => {
5407
+ const variableValuesByBreakpoints = breakpointIds.reduce((acc, breakpointId) => {
5408
+ return {
5409
+ ...acc,
5410
+ [breakpointId]: {},
5411
+ };
5412
+ }, {});
5413
+ const defaultBreakpoint = breakpointIds[0];
5414
+ for (const [variableName, variableData] of Object.entries(variables)) {
5415
+ // handling the special case - cfBackgroundImageUrl variable, which can be bound or unbound
5416
+ // so, we need to resolve it here and pass it down as a css property to be convereted into the CSS
5417
+ // I used .startsWith() cause it can be part of a pattern node
5418
+ if (variableName === 'cfBackgroundImageUrl' ||
5419
+ variableName.startsWith('cfBackgroundImageUrl_')) {
5420
+ const imageUrl = resolveBackgroundImageBinding({
5421
+ variableData,
5422
+ getBoundEntityById,
5423
+ unboundValues,
5424
+ dataSource,
5425
+ componentSettings,
5426
+ componentVariablesOverwrites,
5427
+ });
5428
+ if (imageUrl) {
5429
+ variableValuesByBreakpoints[defaultBreakpoint][variableName] = imageUrl;
5430
+ }
5431
+ continue;
5432
+ }
5433
+ if (variableData.type !== 'DesignValue') {
5434
+ continue;
5435
+ }
5436
+ for (const [breakpointId, variableValue] of Object.entries(variableData.valuesByBreakpoint)) {
5437
+ if (!variableValue) {
5438
+ continue;
5439
+ }
5440
+ variableValuesByBreakpoints[breakpointId] = {
5441
+ ...variableValuesByBreakpoints[breakpointId],
5442
+ [variableName]: variableValue,
5443
+ };
5444
+ }
5445
+ }
5446
+ return variableValuesByBreakpoints;
5447
+ };
5448
+ /**
5449
+ * Flattens the object from
5450
+ * {
5451
+ * color: {
5452
+ * [key]: [value]
5453
+ * }
5454
+ * }
5455
+ *
5456
+ * to
5457
+ *
5458
+ * {
5459
+ * 'color.key': [value]
5460
+ * }
5461
+ */
5462
+ const flattenDesignTokenRegistry = (designTokenRegistry) => {
5463
+ return Object.entries(designTokenRegistry).reduce((acc, [categoryName, tokenCategory]) => {
5464
+ const tokensWithCategory = Object.entries(tokenCategory).reduce((acc, [tokenName, tokenValue]) => {
5465
+ return {
5466
+ ...acc,
5467
+ [`${categoryName}.${tokenName}`]: tokenValue,
5468
+ };
5469
+ }, {});
5470
+ return {
5471
+ ...acc,
5472
+ ...tokensWithCategory,
5473
+ };
5474
+ }, {});
5475
+ };
5476
+ // Replaces camelCase with kebab-case
5477
+ // converts the <key, value> object into a css string
5478
+ const toCSSString = (breakpointStyles) => {
5479
+ return Object.entries(breakpointStyles)
5480
+ .map(([key, value]) => `${key}:${value};`)
5481
+ .join('');
5482
+ };
5483
+ const toMediaQuery = (breakpointPayload) => {
5484
+ const mediaQueryStyles = Object.entries(breakpointPayload.cssByClassName).reduce((acc, [className, css]) => {
5485
+ return `${acc}.${className}{${css}}`;
5486
+ }, ``);
5487
+ if (breakpointPayload.condition === '*') {
5488
+ return mediaQueryStyles;
5489
+ }
5490
+ const [evaluation, pixelValue] = [
5491
+ breakpointPayload.condition[0],
5492
+ breakpointPayload.condition.substring(1),
5493
+ ];
5494
+ const mediaQueryRule = evaluation === '<' ? 'max-width' : 'min-width';
5495
+ return `@media(${mediaQueryRule}:${pixelValue}){${mediaQueryStyles}}`;
5496
+ };
5497
+
5071
5498
  // Simple state store to store a few things that are needed across the SDK
5072
5499
  if (typeof window !== 'undefined') {
5073
5500
  window.__EB__ = {
@@ -5075,5 +5502,5 @@ if (typeof window !== 'undefined') {
5075
5502
  };
5076
5503
  }
5077
5504
 
5078
- export { ExperienceRoot, defineComponents, maintainBasicComponentIdsWithoutPrefix, useFetchById, useFetchBySlug };
5505
+ export { ExperienceRoot, defineComponents, detachExperienceStyles, maintainBasicComponentIdsWithoutPrefix, useFetchById, useFetchBySlug };
5079
5506
  //# sourceMappingURL=index.js.map